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