Update changelog
[l2tpns.git] / autothrottle.c
1 #include <string.h>
2 #include <linux/rtnetlink.h>
3 #include <netinet/ip6.h>
4 #include "dhcp6.h"
5
6 #include "l2tpns.h"
7 #include "plugin.h"
8
9 /* set up throttling based on RADIUS reply */
10
11 /*
12 * lcp:interface-config#1=service-policy input N
13 * lcp:interface-config#2=service-policy output N
14 *
15 * throttle=N
16 * throttle=yes (use throttle_speed from config)
17 * throttle=no
18 */
19
20 int plugin_api_version = PLUGIN_API_VERSION;
21 static struct pluginfuncs *f = 0;
22
23 #define THROTTLE_KEY "lcp:interface-config"
24
25 int plugin_radius_response(struct param_radius_response *data)
26 {
27 if (!strncmp(data->key, THROTTLE_KEY, sizeof(THROTTLE_KEY) - 1))
28 {
29 char *sp = strchr(data->value, ' ');
30 char type;
31 int rate;
32
33 if (!sp || sp - data->value < 4 ||
34 strncmp("service-policy", data->value, sp - data->value))
35 return PLUGIN_RET_OK;
36
37 while (*sp == ' ') sp++;
38 data->value = sp;
39
40 if (!(sp = strchr(data->value, ' ')) ||
41 (strncmp("input", data->value, sp - data->value) &&
42 strncmp("output", data->value, sp - data->value)))
43 {
44 f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
45 " Not throttling user (invalid type %.*s)\n",
46 sp - data->value, data->value);
47
48 return PLUGIN_RET_OK;
49 }
50
51 type = *data->value;
52
53 while (*sp == ' ') sp++;
54 data->value = sp;
55
56 if ((rate = strtol(data->value, &sp, 10)) < 0 || *sp)
57 {
58 f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
59 " Not throttling user (invalid rate %s)\n",
60 data->value);
61
62 return PLUGIN_RET_OK;
63 }
64
65 if (type == 'i')
66 {
67 data->s->throttle_in = rate;
68 f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
69 " Throttling user input to %dkb/s\n", rate);
70 }
71 else
72 {
73 data->s->throttle_out = rate;
74 f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
75 " Throttling user output to %dkb/s\n", rate);
76 }
77 }
78 else if (!strcmp(data->key, "throttle"))
79 {
80 char *e;
81 int rate;
82
83 if ((rate = strtol(data->value, &e, 10)) < 0 || *e)
84 {
85 rate = -1;
86 if (!strcmp(data->value, "yes"))
87 {
88 unsigned long *ts = f->getconfig("throttle_speed", UNSIGNED_LONG);
89 if (ts)
90 rate = *ts;
91 }
92 else if (!strcmp(data->value, "no"))
93 rate = 0;
94 }
95
96 if (rate < 0)
97 return PLUGIN_RET_OK;
98
99 if (rate)
100 f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
101 " Throttling user to %dkb/s\n", rate);
102 else
103 f->log(3, f->get_id_by_session(data->s), data->s->tunnel,
104 " Not throttling user\n");
105
106 data->s->throttle_in = data->s->throttle_out = rate;
107 }
108
109 return PLUGIN_RET_OK;
110 }
111
112 int plugin_radius_reset(struct param_radius_reset *data)
113 {
114 f->throttle(f->get_id_by_session(data->s), 0, 0);
115 return PLUGIN_RET_OK;
116 }
117
118 int plugin_radius_account(struct param_radius_account *data)
119 {
120 if (data->s->throttle_in || data->s->throttle_out)
121 {
122 uint8_t *p = *data->packet;
123 int i = 1;
124
125 if (data->s->throttle_in)
126 {
127 *p = 26; // vendor-specific
128 *(uint32_t *) (p + 2) = htonl(9); // Cisco
129 p[6] = 1; // Cisco-AVPair
130 p[7] = 2 + sprintf((char *) p + 8,
131 "lcp:interface-config#%d=service-policy input %d", i++,
132 data->s->throttle_in);
133
134 p[1] = p[7] + 6;
135 p += p[1];
136 }
137
138 if (data->s->throttle_out)
139 {
140 *p = 26; // vendor-specific
141 *(uint32_t *) (p + 2) = htonl(9); // Cisco
142 p[6] = 1; // Cisco-AVPair
143 p[7] = 2 + sprintf((char *) p + 8,
144 "lcp:interface-config#%d=service-policy output %d", i++,
145 data->s->throttle_out);
146
147 p[1] = p[7] + 6;
148 p += p[1];
149 }
150
151 *data->packet = p;
152 }
153
154 return PLUGIN_RET_OK;
155 }
156
157 int plugin_init(struct pluginfuncs *funcs)
158 {
159 return ((f = funcs)) ? 1 : 0;
160 }