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