File: | src/usr.sbin/npppd/npppd/../pppoe/pppoed.c |
Warning: | line 472, column 2 Value stored to 'do_start' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: pppoed.c,v 1.25 2021/03/29 03:54:40 yasuoka Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2009 Internet Initiative Japan Inc. |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. |
27 | */ |
28 | /**@file |
29 | * This file provides the PPPoE(RFC2516) server(access concentrator) |
30 | * implementation. |
31 | * $Id: pppoed.c,v 1.25 2021/03/29 03:54:40 yasuoka Exp $ |
32 | */ |
33 | #include <sys/param.h> /* ALIGN */ |
34 | #include <sys/types.h> |
35 | #include <sys/socket.h> |
36 | #include <sys/ioctl.h> |
37 | #include <sys/uio.h> |
38 | #include <netinet/in.h> |
39 | #include <net/if.h> |
40 | #include <net/if_types.h> |
41 | #if defined(__NetBSD__) |
42 | #include <net/if_ether.h> |
43 | #else |
44 | #include <netinet/if_ether.h> |
45 | #endif |
46 | #include <net/if_dl.h> |
47 | #include <net/ethertypes.h> |
48 | #include <net/bpf.h> |
49 | #include <endian.h> |
50 | #include <string.h> |
51 | #include <syslog.h> |
52 | #include <stdio.h> |
53 | #include <unistd.h> |
54 | #include <fcntl.h> |
55 | #include <time.h> |
56 | #include <event.h> |
57 | #include <signal.h> |
58 | #include <stdlib.h> |
59 | #include <ifaddrs.h> |
60 | #include <stdarg.h> |
61 | #include <errno(*__errno()).h> |
62 | |
63 | #include "debugutil.h" |
64 | #include "slist.h" |
65 | #include "bytebuf.h" |
66 | #include "hash.h" |
67 | #include "privsep.h" |
68 | |
69 | #include "pppoe.h" |
70 | #include "pppoe_local.h" |
71 | |
72 | #define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b)) |
73 | |
74 | static int pppoed_seqno = 0; |
75 | |
76 | #ifdef PPPOED_DEBUG |
77 | #define PPPOED_ASSERT(x) ASSERT(x)((void)0); |
78 | #define PPPOED_DBG(x) pppoed_log x |
79 | #else |
80 | #define PPPOED_ASSERT(x) |
81 | #define PPPOED_DBG(x) |
82 | #endif |
83 | |
84 | static void pppoed_log (pppoed *, int, const char *, ...) __printflike(3,4)__attribute__((__format__ (__printf__, 3, 4))); |
85 | static void pppoed_listener_init(pppoed *, pppoed_listener *); |
86 | static int pppoed_output (pppoed_listener *, u_char *, u_char *, int); |
87 | static int pppoed_listener_start (pppoed_listener *, int); |
88 | static void pppoed_io_event (int, short, void *); |
89 | static void pppoed_input (pppoed_listener *, uint8_t [ETHER_ADDR_LEN6], int, u_char *, int); |
90 | static void pppoed_recv_PADR (pppoed_listener *, uint8_t [ETHER_ADDR_LEN6], slist *); |
91 | static void pppoed_recv_PADI (pppoed_listener *, uint8_t [ETHER_ADDR_LEN6], slist *); |
92 | static int session_id_cmp (void *, void *); |
93 | static uint32_t session_id_hash (void *, size_t); |
94 | |
95 | #ifdef PPPOE_TEST |
96 | static void pppoed_on_sigterm (int, short, void *); |
97 | static void usage (void); |
98 | #endif |
99 | static const char *pppoe_code_string(int); |
100 | #ifdef PPPOED_DEBUG |
101 | static const char *pppoe_tag_string(int); |
102 | #endif |
103 | |
104 | /* |
105 | * daemon |
106 | */ |
107 | |
108 | /* initialize PPPoE daemon */ |
109 | int |
110 | pppoed_init(pppoed *_this) |
111 | { |
112 | int i, off, id; |
113 | |
114 | memset(_this, 0, sizeof(pppoed)); |
115 | _this->id = pppoed_seqno++; |
116 | |
117 | if ((_this->session_hash = hash_create( |
118 | (int (*) (const void *, const void *))session_id_cmp, |
119 | (uint32_t (*) (const void *, int))session_id_hash, |
120 | PPPOE_SESSION_HASH_SIZ557)) == NULL((void *)0)) { |
121 | pppoed_log(_this, LOG_ERR3, "hash_create() failed on %s(): %m", |
122 | __func__); |
123 | goto fail; |
124 | } |
125 | |
126 | slist_init(&_this->session_free_list); |
127 | if (slist_add(&_this->session_free_list, |
128 | (void *)PPPOED_SESSION_SHUFFLE_MARK0x10000000) == NULL((void *)0)) { |
129 | pppoed_log(_this, LOG_ERR3, "slist_add() failed on %s(): %m", |
130 | __func__); |
131 | goto fail; |
132 | } |
133 | |
134 | /* XXX initialize hash of cookies */ |
135 | if ((_this->acookie_hash = hash_create( |
136 | (int (*) (const void *, const void *))session_id_cmp, |
137 | (uint32_t (*) (const void *, int))session_id_hash, |
138 | PPPOE_SESSION_HASH_SIZ557)) == NULL((void *)0)) { |
139 | pppoed_log(_this, LOG_WARNING4, |
140 | "hash_create() failed on %s(): %m", __func__); |
141 | pppoed_log(_this, LOG_WARNING4, "hash_create() failed on %s(): " |
142 | "ac-cookie hash create failed.", __func__); |
143 | _this->acookie_hash = NULL((void *)0); |
144 | } |
145 | _this->acookie_next = arc4random(); |
146 | |
147 | #if PPPOE_NSESSION10000 > 0xffff |
148 | #error PPPOE_NSESSION10000 must be less than 65536 |
149 | #endif |
150 | off = arc4random() & 0xffff; |
151 | for (i = 0; i < PPPOE_NSESSION10000; i++) { |
152 | id = (i + off) & 0xffff; |
153 | if (id == 0) |
154 | id = (off - 1) & 0xffff; |
155 | if (slist_add(&_this->session_free_list, (void *)(intptr_t)id) |
156 | == NULL((void *)0)) { |
157 | pppoed_log(_this, LOG_ERR3, |
158 | "slist_add() failed on %s(): %m", __func__); |
159 | goto fail; |
160 | } |
161 | } |
162 | |
163 | _this->state = PPPOED_STATE_INIT0; |
164 | |
165 | return 0; |
166 | fail: |
167 | pppoed_uninit(_this); |
168 | return 1; |
169 | } |
170 | |
171 | static void |
172 | pppoed_listener_init(pppoed *_this, pppoed_listener *listener) |
173 | { |
174 | memset(listener, 0, sizeof(pppoed_listener)); |
175 | listener->bpf = -1; |
176 | listener->self = _this; |
177 | listener->index = PPPOED_LISTENER_INVALID_INDEX0xffff; |
178 | } |
179 | |
180 | /* reload listener */ |
181 | int |
182 | pppoed_reload_listeners(pppoed *_this) |
183 | { |
184 | int rval = 0; |
185 | |
186 | if (_this->state == PPPOED_STATE_RUNNING1 && |
187 | _this->listen_incomplete != 0) |
188 | rval = pppoed_start(_this); |
189 | |
190 | return rval; |
191 | } |
192 | |
193 | /* |
194 | * Reject any packet except the packet to self and broadcasts, |
195 | * as bpf(4) potentially receive packets for others. |
196 | */ |
197 | #define REJECT_FOREIGN_ADDRESS1 1 |
198 | |
199 | #define ETHER_FIRST_INT(e)((e)[0]<<24|(e)[1]<<16|(e)[2]<<8|(e)[3]) ((e)[0]<<24|(e)[1]<<16|(e)[2]<<8|(e)[3]) |
200 | #define ETHER_LAST_SHORT(e)((e)[4]<<8|(e)[5]) ((e)[4]<<8|(e)[5]) |
201 | |
202 | static int |
203 | pppoed_listener_start(pppoed_listener *_this, int restart) |
204 | { |
205 | int log_level; |
206 | struct ifreq ifreq; |
207 | int ival; |
208 | int found; |
209 | struct ifaddrs *ifa0, *ifa; |
210 | struct sockaddr_dl *sdl; |
211 | struct bpf_insn insns[] = { |
212 | /* check etyer type = PPPOEDESC or PPPOE */ |
213 | BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12){ (u_int16_t)(0x00 +0x08 +0x20), 0, 0, 12 }, |
214 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_PPPOEDISC, 2, 0){ (u_int16_t)(0x05 +0x10 +0x00), 2, 0, 0x8863 }, |
215 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_PPPOE, 1, 0){ (u_int16_t)(0x05 +0x10 +0x00), 1, 0, 0x8864 }, |
216 | BPF_STMT(BPF_RET+BPF_K, (u_int)0){ (u_int16_t)(0x06 +0x00), 0, 0, (u_int)0 }, |
217 | #ifndef REJECT_FOREIGN_ADDRESS1 |
218 | BPF_STMT(BPF_RET+BPF_K, (u_int)-1){ (u_int16_t)(0x06 +0x00), 0, 0, (u_int)-1 }, |
219 | #else |
220 | /* to ff:ff:ff:ff:ff:ff */ |
221 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0){ (u_int16_t)(0x00 +0x00 +0x20), 0, 0, 0 }, |
222 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0xffffffff, 0, 3){ (u_int16_t)(0x05 +0x10 +0x00), 0, 3, 0xffffffff }, |
223 | BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4){ (u_int16_t)(0x00 +0x08 +0x20), 0, 0, 4 }, |
224 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0xffff, 0, 1){ (u_int16_t)(0x05 +0x10 +0x00), 0, 1, 0xffff }, |
225 | BPF_STMT(BPF_RET+BPF_K, (u_int)-1){ (u_int16_t)(0x06 +0x00), 0, 0, (u_int)-1 }, |
226 | /* to self */ |
227 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0){ (u_int16_t)(0x00 +0x00 +0x20), 0, 0, 0 }, |
228 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K,{ (u_int16_t)(0x05 +0x10 +0x00), 0, 3, ((_this->ether_addr )[0]<<24|(_this->ether_addr)[1]<<16|(_this-> ether_addr)[2]<<8|(_this->ether_addr)[3]) } |
229 | ETHER_FIRST_INT(_this->ether_addr), 0, 3){ (u_int16_t)(0x05 +0x10 +0x00), 0, 3, ((_this->ether_addr )[0]<<24|(_this->ether_addr)[1]<<16|(_this-> ether_addr)[2]<<8|(_this->ether_addr)[3]) }, |
230 | BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4){ (u_int16_t)(0x00 +0x08 +0x20), 0, 0, 4 }, |
231 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K,{ (u_int16_t)(0x05 +0x10 +0x00), 0, 1, ((_this->ether_addr )[4]<<8|(_this->ether_addr)[5]) } |
232 | ETHER_LAST_SHORT(_this->ether_addr), 0, 1){ (u_int16_t)(0x05 +0x10 +0x00), 0, 1, ((_this->ether_addr )[4]<<8|(_this->ether_addr)[5]) }, |
233 | BPF_STMT(BPF_RET+BPF_K, (u_int)-1){ (u_int16_t)(0x06 +0x00), 0, 0, (u_int)-1 }, |
234 | BPF_STMT(BPF_RET+BPF_K, (u_int)0){ (u_int16_t)(0x06 +0x00), 0, 0, (u_int)0 }, |
235 | #endif |
236 | }; |
237 | struct bpf_program bf_filter = { |
238 | .bf_len = countof(insns)(sizeof((insns)) / sizeof((insns)[0])), |
239 | .bf_insns = insns |
240 | }; |
241 | pppoed *_pppoed; |
242 | |
243 | if (restart == 0) |
244 | log_level = LOG_ERR3; |
245 | else |
246 | log_level = LOG_INFO6; |
247 | |
248 | _pppoed = _this->self; |
249 | |
250 | ifa0 = NULL((void *)0); |
251 | if (getifaddrs(&ifa0) != 0) { |
252 | pppoed_log(_pppoed, log_level, |
253 | "getifaddrs() failed on %s(): %m", __func__); |
254 | return -1; |
255 | } |
256 | found = 0; |
257 | for (ifa = ifa0; ifa != NULL((void *)0); ifa = ifa->ifa_next) { |
258 | sdl = (struct sockaddr_dl *)ifa->ifa_addr; |
259 | if (sdl == NULL((void *)0) || |
260 | sdl->sdl_family != AF_LINK18 || sdl->sdl_type != IFT_ETHER0x06 || |
261 | sdl->sdl_alen != ETHER_ADDR_LEN6) |
262 | continue; |
263 | if (strcmp(ifa->ifa_name, _this->listen_ifname) == 0) { |
264 | memcpy(_this->ether_addr, |
265 | (caddr_t)LLADDR(sdl)((caddr_t)((sdl)->sdl_data + (sdl)->sdl_nlen)), ETHER_ADDR_LEN6); |
266 | found = 1; |
267 | break; |
268 | } |
269 | } |
270 | freeifaddrs(ifa0); |
271 | if (!found) { |
272 | pppoed_log(_pppoed, log_level, "%s is not available.", |
273 | _this->listen_ifname); |
274 | goto fail; |
275 | } |
276 | |
277 | if ((_this->bpf = priv_open("/dev/bpf", O_RDWR0x0002)) == -1) { |
278 | pppoed_log(_pppoed, log_level, "Cannot open bpf: %m"); |
279 | goto fail; |
280 | } |
281 | |
282 | ival = BPF_CAPTURE_SIZ32768; |
283 | if (ioctl(_this->bpf, BIOCSBLEN(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (u_int) & 0x1fff) << 16) | ((('B')) << 8) | ( (102))), &ival) != 0) { |
284 | pppoed_log(_pppoed, log_level, "ioctl(bpf, BIOCSBLEN(%d)): %m", |
285 | ival); |
286 | goto fail; |
287 | } |
288 | ival = 1; |
289 | if (ioctl(_this->bpf, BIOCIMMEDIATE((unsigned long)0x80000000 | ((sizeof(u_int) & 0x1fff) << 16) | ((('B')) << 8) | ((112))), &ival) != 0) { |
290 | pppoed_log(_pppoed, log_level, "Cannot start bpf on %s: %m", |
291 | _this->listen_ifname); |
292 | goto fail; |
293 | } |
294 | |
295 | /* bind interface */ |
296 | memset(&ifreq, 0, sizeof(ifreq)); |
297 | strlcpy(ifreq.ifr_name, _this->listen_ifname, sizeof(ifreq.ifr_name)); |
298 | if (ioctl(_this->bpf, BIOCSETIF((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('B')) << 8) | ((108))), &ifreq) != 0) { |
299 | pppoed_log(_pppoed, log_level, "Cannot start bpf on %s: %m", |
300 | _this->listen_ifname); |
301 | goto fail; |
302 | } |
303 | |
304 | /* set linklocal address */ |
305 | #ifdef REJECT_FOREIGN_ADDRESS1 |
306 | insns[10].k = ETHER_FIRST_INT(_this->ether_addr)((_this->ether_addr)[0]<<24|(_this->ether_addr)[1 ]<<16|(_this->ether_addr)[2]<<8|(_this->ether_addr )[3]); |
307 | insns[12].k = ETHER_LAST_SHORT(_this->ether_addr)((_this->ether_addr)[4]<<8|(_this->ether_addr)[5] ); |
308 | #endif |
309 | |
310 | /* set filter */ |
311 | if (ioctl(_this->bpf, BIOCSETF((unsigned long)0x80000000 | ((sizeof(struct bpf_program) & 0x1fff) << 16) | ((('B')) << 8) | ((103))), &bf_filter) != 0) { |
312 | pppoed_log(_pppoed, log_level, "ioctl(bpf, BIOCSETF()): %m"); |
313 | goto fail; |
314 | } |
315 | |
316 | event_set(&_this->ev_bpf, _this->bpf, EV_READ0x02 | EV_PERSIST0x10, |
317 | pppoed_io_event, _this); |
318 | event_add(&_this->ev_bpf, NULL((void *)0)); |
319 | |
320 | pppoed_log(_pppoed, LOG_INFO6, "Listening on %s (PPPoE) [%s] " |
321 | "address=%02x:%02x:%02x:%02x:%02x:%02x", _this->listen_ifname, |
322 | _this->tun_name, _this->ether_addr[0], _this->ether_addr[1], |
323 | _this->ether_addr[2], _this->ether_addr[3], _this->ether_addr[4], |
324 | _this->ether_addr[5]); |
325 | |
326 | return 0; |
327 | fail: |
328 | if (_this->bpf >= 0) { |
329 | close(_this->bpf); |
330 | _this->bpf = -1; |
331 | } |
332 | |
333 | return 1; |
334 | } |
335 | |
336 | /* start PPPoE daemon */ |
337 | int |
338 | pppoed_start(pppoed *_this) |
339 | { |
340 | int rval = 0; |
341 | int nlistener_fail = 0; |
342 | pppoed_listener *plistener; |
343 | |
344 | slist_itr_first(&_this->listener); |
345 | while (slist_itr_has_next(&_this->listener)) { |
346 | plistener = slist_itr_next(&_this->listener); |
347 | PPPOED_ASSERT(plistener != NULL); |
348 | if (plistener->bpf < 0) { |
349 | if (pppoed_listener_start(plistener, |
350 | _this->listen_incomplete) != 0) |
351 | nlistener_fail++; |
352 | } |
353 | } |
354 | if (nlistener_fail > 0) |
355 | _this->listen_incomplete = 1; |
356 | else |
357 | _this->listen_incomplete = 0; |
358 | |
359 | _this->state = PPPOED_STATE_RUNNING1; |
360 | |
361 | return rval; |
362 | } |
363 | |
364 | /* stop listener */ |
365 | static void |
366 | pppoed_listener_stop(pppoed_listener *_this) |
367 | { |
368 | pppoed *_pppoed; |
369 | |
370 | PPPOED_ASSERT(_this != NULL); |
371 | _pppoed = _this->self; |
372 | PPPOED_ASSERT(_pppoed != NULL); |
373 | |
374 | if (_this->bpf >= 0) { |
375 | event_del(&_this->ev_bpf); |
376 | close(_this->bpf); |
377 | pppoed_log(_pppoed, LOG_INFO6, "Shutdown %s (PPPoE) [%s] " |
378 | "address=%02x:%02x:%02x:%02x:%02x:%02x", |
379 | _this->listen_ifname, _this->tun_name, |
380 | _this->ether_addr[0], _this->ether_addr[1], |
381 | _this->ether_addr[2], _this->ether_addr[3], |
382 | _this->ether_addr[4], _this->ether_addr[5]); |
383 | _this->bpf = -1; |
384 | } |
385 | } |
386 | |
387 | /* stop PPPoE daemon */ |
388 | void |
389 | pppoed_stop(pppoed *_this) |
390 | { |
391 | pppoed_listener *plistener; |
392 | hash_link *hl; |
393 | pppoe_session *session; |
394 | |
395 | if (!pppoed_is_running(_this)(((_this)->state == 1)? 1 : 0)) |
396 | return; |
397 | |
398 | _this->state = PPPOED_STATE_STOPPED2; |
399 | if (_this->session_hash != NULL((void *)0)) { |
400 | for (hl = hash_first(_this->session_hash); |
401 | hl != NULL((void *)0); |
402 | hl = hash_next(_this->session_hash)) { |
403 | session = (pppoe_session *)hl->item; |
404 | pppoe_session_disconnect(session); |
405 | pppoe_session_stop(session); |
406 | } |
407 | } |
408 | for (slist_itr_first(&_this->listener); |
409 | slist_itr_has_next(&_this->listener);) { |
410 | plistener = slist_itr_next(&_this->listener); |
411 | pppoed_listener_stop(plistener); |
412 | free(plistener); |
413 | slist_itr_remove(&_this->listener); |
414 | } |
415 | PPPOED_DBG((_this, LOG_DEBUG, "Stopped")); |
416 | } |
417 | |
418 | /* uninitialize (free) PPPoE daemon */ |
419 | void |
420 | pppoed_uninit(pppoed *_this) |
421 | { |
422 | if (_this->session_hash != NULL((void *)0)) { |
423 | hash_free(_this->session_hash); |
424 | _this->session_hash = NULL((void *)0); |
425 | } |
426 | if (_this->acookie_hash != NULL((void *)0)) { |
427 | hash_free(_this->acookie_hash); |
428 | _this->acookie_hash = NULL((void *)0); |
429 | } |
430 | slist_fini(&_this->session_free_list); |
431 | /* listener themself has been released already */ |
432 | slist_fini(&_this->listener); |
433 | } |
434 | |
435 | /* it is called when the PPPoE session was closed */ |
436 | void |
437 | pppoed_pppoe_session_close_notify(pppoed *_this, pppoe_session *session) |
438 | { |
439 | slist_add(&_this->session_free_list, |
440 | (void *)(intptr_t)session->session_id); |
441 | |
442 | if (_this->acookie_hash != NULL((void *)0)) |
443 | hash_delete(_this->acookie_hash, |
444 | (void *)(intptr_t)session->acookie, 0); |
445 | if (_this->session_hash != NULL((void *)0)) |
446 | hash_delete(_this->session_hash, |
447 | (void *)(intptr_t)session->session_id, 0); |
448 | |
449 | pppoe_session_fini(session); |
450 | free(session); |
451 | } |
452 | |
453 | /* |
454 | * PPPoE Configuration |
455 | */ |
456 | /* reload configurations for the PPPoE daemon */ |
457 | int |
458 | pppoed_reload(pppoed *_this, struct pppoe_confs *pppoe_conf) |
459 | { |
460 | int i, count, do_start, found; |
461 | struct pppoe_conf *conf; |
462 | slist rmlist, newlist; |
463 | struct { |
464 | char ifname[IF_NAMESIZE16]; |
465 | char name[PPPOED_PHY_LABEL_SIZE16]; |
466 | struct pppoe_conf *conf; |
467 | } listeners[PPPOE_NLISTENER512]; |
468 | pppoed_listener *l; |
469 | pppoe_session *session; |
470 | hash_link *hl; |
471 | |
472 | do_start = 0; |
Value stored to 'do_start' is never read | |
473 | slist_init(&rmlist); |
474 | slist_init(&newlist); |
475 | |
476 | count = 0; |
477 | TAILQ_FOREACH(conf, pppoe_conf, entry)for((conf) = ((pppoe_conf)->tqh_first); (conf) != ((void * )0); (conf) = ((conf)->entry.tqe_next)) { |
478 | strlcpy(listeners[count].ifname, conf->if_name, |
479 | sizeof(listeners[count].ifname)); |
480 | strlcpy(listeners[count].name, conf->name, |
481 | sizeof(listeners[count].name)); |
482 | listeners[count].conf = conf; |
483 | count++; |
484 | } |
485 | |
486 | if (slist_add_all(&rmlist, &_this->listener) != 0) |
487 | goto fail; |
488 | |
489 | for (i = 0; i < count; i++) { |
490 | found = 0; |
491 | l = NULL((void *)0); |
492 | slist_itr_first(&rmlist); |
493 | while (slist_itr_has_next(&rmlist)) { |
494 | l = slist_itr_next(&rmlist); |
495 | if (strcmp(l->listen_ifname, listeners[i].ifname) == 0){ |
496 | slist_itr_remove(&rmlist); |
497 | found = 1; |
498 | break; |
499 | } |
500 | } |
501 | if (!found) { |
502 | if ((l = malloc(sizeof(pppoed_listener))) == NULL((void *)0)) |
503 | goto fail; |
504 | pppoed_listener_init(_this, l); |
505 | } |
506 | l->self = _this; |
507 | strlcpy(l->tun_name, listeners[i].name, sizeof(l->tun_name)); |
508 | strlcpy(l->listen_ifname, listeners[i].ifname, |
509 | sizeof(l->listen_ifname)); |
510 | l->conf = listeners[i].conf; |
511 | if (slist_add(&newlist, l) == NULL((void *)0)) { |
512 | pppoed_log(_this, LOG_ERR3, |
513 | "slist_add() failed in %s(): %m", __func__); |
514 | goto fail; |
515 | } |
516 | } |
517 | |
518 | if (slist_set_size(&_this->listener, count) != 0) |
519 | goto fail; |
520 | |
521 | /* garbage collection of listener context */ |
522 | slist_itr_first(&rmlist); |
523 | while (slist_itr_has_next(&rmlist)) { |
524 | l = slist_itr_next(&rmlist); |
525 | /* handle child PPPoE session */ |
526 | if (_this->session_hash != NULL((void *)0)) { |
527 | for (hl = hash_first(_this->session_hash); hl != NULL((void *)0); |
528 | hl = hash_next(_this->session_hash)) { |
529 | session = (pppoe_session *)hl->item; |
530 | if (session->listener_index == l->index) |
531 | pppoe_session_stop(session); |
532 | } |
533 | } |
534 | pppoed_listener_stop(l); |
535 | free(l); |
536 | } |
537 | slist_remove_all(&_this->listener); |
538 | /* as slist_set_size-ed, it must not fail */ |
539 | (void)slist_add_all(&_this->listener, &newlist); |
540 | |
541 | /* reset indexes */ |
542 | slist_itr_first(&newlist); |
543 | for (i = 0; slist_itr_has_next(&newlist); i++) { |
544 | l = slist_itr_next(&newlist); |
545 | if (l->index != i && l->index != PPPOED_LISTENER_INVALID_INDEX0xffff){ |
546 | PPPOED_DBG((_this, LOG_DEBUG, "listener %d => %d", |
547 | l->index, i)); |
548 | for (hl = hash_first(_this->session_hash); hl != NULL((void *)0); |
549 | hl = hash_next(_this->session_hash)) { |
550 | session = (pppoe_session *)hl->item; |
551 | if (session->listener_index == l->index) |
552 | session->listener_index = i; |
553 | } |
554 | } |
555 | l->index = i; |
556 | } |
557 | |
558 | slist_fini(&rmlist); |
559 | slist_fini(&newlist); |
560 | |
561 | if (pppoed_start(_this) != 0) |
562 | return 1; |
563 | |
564 | return 0; |
565 | fail: |
566 | slist_fini(&rmlist); |
567 | slist_fini(&newlist); |
568 | |
569 | return 1; |
570 | } |
571 | |
572 | /* |
573 | * I/O |
574 | */ |
575 | |
576 | static void |
577 | pppoed_io_event(int fd, short evmask, void *ctx) |
578 | { |
579 | u_char buf[BPF_CAPTURE_SIZ32768], *pkt; |
580 | int lpkt, off; |
581 | pppoed_listener *_this; |
582 | struct ether_header *ether; |
583 | struct bpf_hdr *bpf; |
584 | |
585 | _this = ctx; |
586 | |
587 | PPPOED_ASSERT(_this != NULL); |
588 | |
589 | lpkt = read(_this->bpf, buf, sizeof(buf)); |
590 | pkt = buf; |
591 | while (lpkt > 0) { |
592 | if (lpkt < sizeof(struct bpf_hdr)) { |
593 | pppoed_log(_this->self, LOG_WARNING4, |
594 | "Received bad PPPoE packet: packet too short(%d)", |
595 | lpkt); |
596 | break; |
597 | } |
598 | bpf = (struct bpf_hdr *)pkt; |
599 | ether = (struct ether_header *)(pkt + bpf->bh_hdrlen); |
600 | ether->ether_type = ntohs(ether->ether_type)(__uint16_t)(__builtin_constant_p(ether->ether_type) ? (__uint16_t )(((__uint16_t)(ether->ether_type) & 0xffU) << 8 | ((__uint16_t)(ether->ether_type) & 0xff00U) >> 8) : __swap16md(ether->ether_type)); |
601 | if (memcmp(ether->ether_shost, _this->ether_addr, |
602 | ETHER_ADDR_LEN6) == 0) |
603 | /* the packet is from myself */ |
604 | goto next_pkt; |
605 | off = bpf->bh_hdrlen + sizeof(struct ether_header); |
606 | if (lpkt < off + sizeof(struct pppoe_header)) { |
607 | pppoed_log(_this->self, LOG_WARNING4, |
608 | "Received bad PPPoE packet: packet too short(%d)", |
609 | lpkt); |
610 | break; |
611 | } |
612 | pppoed_input(_this, ether->ether_shost, |
613 | (ether->ether_type == ETHERTYPE_PPPOEDISC0x8863)? 1 : 0, |
614 | pkt + off, lpkt - off); |
615 | next_pkt: |
616 | pkt = pkt + BPF_WORDALIGN(bpf->bh_hdrlen +(((bpf->bh_hdrlen + bpf->bh_caplen) + (sizeof(u_int32_t ) - 1)) & ~(sizeof(u_int32_t) - 1)) |
617 | bpf->bh_caplen)(((bpf->bh_hdrlen + bpf->bh_caplen) + (sizeof(u_int32_t ) - 1)) & ~(sizeof(u_int32_t) - 1)); |
618 | lpkt -= BPF_WORDALIGN(bpf->bh_hdrlen + bpf->bh_caplen)(((bpf->bh_hdrlen + bpf->bh_caplen) + (sizeof(u_int32_t ) - 1)) & ~(sizeof(u_int32_t) - 1)); |
619 | } |
620 | return; |
621 | } |
622 | |
623 | static void |
624 | pppoed_input(pppoed_listener *_this, uint8_t shost[ETHER_ADDR_LEN6], int is_disc, |
625 | u_char *pkt, int lpkt) |
626 | { |
627 | hash_link *hl; |
628 | pppoe_session *session; |
629 | struct pppoe_header *pppoe; |
630 | struct pppoe_tlv *tlv; |
631 | u_char tlvspace[2048], *p_tlvspace; |
632 | int session_id; |
633 | slist tag_list; |
634 | const char *reason; |
635 | #define tlvspace_remaining()(sizeof(tlvspace) - (p_tlvspace - tlvspace)) (sizeof(tlvspace) - (p_tlvspace - tlvspace)) |
636 | |
637 | reason = ""; |
638 | p_tlvspace = tlvspace; |
639 | session = NULL((void *)0); |
640 | |
641 | pppoe = (struct pppoe_header *)pkt; |
642 | session_id = pppoe->session_id = ntohs(pppoe->session_id)(__uint16_t)(__builtin_constant_p(pppoe->session_id) ? (__uint16_t )(((__uint16_t)(pppoe->session_id) & 0xffU) << 8 | ((__uint16_t)(pppoe->session_id) & 0xff00U) >> 8) : __swap16md(pppoe->session_id)); |
643 | pppoe->length = ntohs(pppoe->length)(__uint16_t)(__builtin_constant_p(pppoe->length) ? (__uint16_t )(((__uint16_t)(pppoe->length) & 0xffU) << 8 | ( (__uint16_t)(pppoe->length) & 0xff00U) >> 8) : __swap16md (pppoe->length)); |
644 | |
645 | #ifdef PPPOED_DEBUG |
646 | if (is_disc) { |
647 | PPPOED_DBG((_this->self, DEBUG_LEVEL_1, |
648 | "Recv%s(%02x) ver=%d type=%d session-id=%d if=%s", |
649 | pppoe_code_string(pppoe->code), pppoe->code, |
650 | pppoe->ver, pppoe->type, pppoe->session_id, |
651 | _this->listen_ifname)); |
652 | } |
653 | #endif |
654 | pkt += sizeof(struct pppoe_header); |
655 | lpkt -= sizeof(struct pppoe_header); |
656 | |
657 | if (lpkt < pppoe->length) { |
658 | reason = "received packet is shorter than " |
659 | "pppoe length field."; |
660 | goto bad_packet; |
661 | } |
662 | /* use PPPoE header value as lpkt */ |
663 | lpkt = pppoe->length; |
664 | |
665 | if (pppoe->type != PPPOE_RFC2516_TYPE0x01 || |
666 | pppoe->ver != PPPOE_RFC2516_VER0x01) { |
667 | reason = "received packet has wrong version or type."; |
668 | goto bad_packet; |
669 | } |
670 | |
671 | if (session_id != 0) { |
672 | hl = hash_lookup(_this->self->session_hash, |
673 | (void *)(intptr_t)session_id); |
674 | if (hl != NULL((void *)0)) |
675 | session = (pppoe_session *)hl->item; |
676 | } |
677 | if (!is_disc) { |
678 | if (session != NULL((void *)0)) |
679 | pppoe_session_input(session, pkt, pppoe->length); |
680 | return; |
681 | } |
682 | |
683 | /* |
684 | * PPPoE-Discovery Packet processing. |
685 | */ |
686 | slist_init(&tag_list); |
687 | while (lpkt > 0) { |
688 | if (lpkt < 4) { |
689 | reason = "tlv list is broken. " |
690 | "Remaining octet is too short."; |
691 | goto fail; |
692 | } |
693 | if (tlvspace_remaining()(sizeof(tlvspace) - (p_tlvspace - tlvspace)) < 4) { |
694 | reason = "parsing TAGs reached the buffer size limit."; |
695 | goto fail; |
696 | } |
697 | tlv = (struct pppoe_tlv *)p_tlvspace; |
698 | GETSHORT(tlv->type, pkt){ (tlv->type) = *(pkt)++ << 8; (tlv->type) |= *(pkt )++; }; |
699 | GETSHORT(tlv->length, pkt){ (tlv->length) = *(pkt)++ << 8; (tlv->length) |= *(pkt)++; }; |
700 | p_tlvspace += 4; |
701 | lpkt -= 4; |
702 | if (tlv->length > lpkt) { |
703 | reason = "tlv list is broken. length is wrong."; |
704 | goto fail; |
705 | } |
706 | if (tlvspace_remaining()(sizeof(tlvspace) - (p_tlvspace - tlvspace)) < tlv->length) { |
707 | reason = "parsing TAGs reached the buffer size limit."; |
708 | goto fail; |
709 | } |
710 | if (tlv->length > 0) { |
711 | memcpy(tlv->value, pkt, tlv->length); |
712 | pkt += tlv->length; |
713 | lpkt -= tlv->length; |
714 | p_tlvspace += tlv->length; |
715 | p_tlvspace = (u_char *)ALIGN(p_tlvspace)(((unsigned long)(p_tlvspace) + (sizeof(long) - 1)) &~(sizeof (long) - 1)); |
716 | } |
717 | #ifdef PPPOED_DEBUG |
718 | if (debuglevel >= 2) |
719 | pppoed_log(_this->self, DEBUG_LEVEL_2( 2 << 24), |
720 | "Recv%s tag %s(%04x)=%s", |
721 | pppoe_code_string(pppoe->code), |
722 | pppoe_tag_string(tlv->type), tlv->type, |
723 | pppoed_tlv_value_string(tlv)); |
724 | #endif |
725 | if (tlv->type == PPPOE_TAG_END_OF_LIST0x0000) |
726 | break; |
727 | if (slist_add(&tag_list, tlv) == NULL((void *)0)) { |
728 | goto fail; |
729 | } |
730 | } |
731 | switch (pppoe->code) { |
732 | case PPPOE_CODE_PADI0x09: |
733 | if (_this->self->state != PPPOED_STATE_RUNNING1) |
734 | break; |
735 | pppoed_recv_PADI(_this, shost, &tag_list); |
736 | break; |
737 | case PPPOE_CODE_PADR0x19: |
738 | if (_this->self->state != PPPOED_STATE_RUNNING1) |
739 | break; |
740 | pppoed_recv_PADR(_this, shost, &tag_list); |
741 | break; |
742 | case PPPOE_CODE_PADT0xa7: |
743 | PPPOED_DBG((_this->self, LOG_DEBUG, "RecvPADT")); |
744 | if (session != NULL((void *)0)) |
745 | pppoe_session_recv_PADT(session, &tag_list); |
746 | break; |
747 | } |
748 | slist_fini(&tag_list); |
749 | |
750 | return; |
751 | fail: |
752 | slist_fini(&tag_list); |
753 | bad_packet: |
754 | pppoed_log(_this->self, LOG_INFO6, |
755 | "Received a bad packet: code=%s(%02x) ver=%d type=%d session-id=%d" |
756 | " if=%s: %s", pppoe_code_string(pppoe->code), pppoe->code, |
757 | pppoe->ver, pppoe->type, pppoe->session_id, _this->listen_ifname, |
758 | reason); |
759 | } |
760 | |
761 | static int |
762 | pppoed_output(pppoed_listener *_this, u_char *dhost, u_char *pkt, int lpkt) |
763 | { |
764 | int sz, iovc; |
765 | struct iovec iov[3]; |
766 | struct ether_header ether; |
767 | struct pppoe_header *pppoe; |
768 | u_char pad[ETHERMIN(64 - ((6 * 2) + 2) - 4)]; |
769 | |
770 | memcpy(ether.ether_dhost, dhost, ETHER_ADDR_LEN6); |
771 | memcpy(ether.ether_shost, _this->ether_addr, ETHER_ADDR_LEN6); |
772 | |
773 | iov[0].iov_base = ðer; |
774 | iov[0].iov_len = sizeof(struct ether_header); |
775 | ether.ether_type = htons(ETHERTYPE_PPPOEDISC)(__uint16_t)(__builtin_constant_p(0x8863) ? (__uint16_t)(((__uint16_t )(0x8863) & 0xffU) << 8 | ((__uint16_t)(0x8863) & 0xff00U) >> 8) : __swap16md(0x8863)); |
776 | iov[1].iov_base = pkt; |
777 | iov[1].iov_len = lpkt; |
778 | pppoe = (struct pppoe_header *)pkt; |
779 | pppoe->length = htons(lpkt - sizeof(struct pppoe_header))(__uint16_t)(__builtin_constant_p(lpkt - sizeof(struct pppoe_header )) ? (__uint16_t)(((__uint16_t)(lpkt - sizeof(struct pppoe_header )) & 0xffU) << 8 | ((__uint16_t)(lpkt - sizeof(struct pppoe_header)) & 0xff00U) >> 8) : __swap16md(lpkt - sizeof(struct pppoe_header))); |
780 | |
781 | iovc = 2; |
782 | |
783 | if (lpkt < ETHERMIN(64 - ((6 * 2) + 2) - 4)) { |
784 | memset(pad, 0, ETHERMIN(64 - ((6 * 2) + 2) - 4) - lpkt); |
785 | iov[2].iov_base = pad; |
786 | iov[2].iov_len = ETHERMIN(64 - ((6 * 2) + 2) - 4) - lpkt; |
787 | iovc++; |
788 | } |
789 | |
790 | sz = writev(_this->bpf, iov, iovc); |
791 | |
792 | return (sz > 0)? 0 : -1; |
793 | } |
794 | |
795 | static void |
796 | pppoed_recv_PADR(pppoed_listener *_this, uint8_t shost[ETHER_ADDR_LEN6], |
797 | slist *tag_list) |
798 | { |
799 | int session_id, shuffle_cnt; |
800 | pppoe_session *session; |
801 | pppoed *_pppoed; |
802 | |
803 | _pppoed = _this->self; |
804 | if ((session = malloc(sizeof(pppoe_session))) == NULL((void *)0)) { |
805 | pppoed_log(_pppoed, LOG_ERR3, "malloc() failed on %s(): %m", |
806 | __func__); |
807 | goto fail; |
808 | } |
809 | |
810 | /* create session_id */ |
811 | shuffle_cnt = 0; |
812 | do { |
813 | session_id = (intptr_t)slist_remove_first( |
814 | &_pppoed->session_free_list); |
815 | if (session_id != PPPOED_SESSION_SHUFFLE_MARK0x10000000) |
816 | break; |
817 | PPPOED_ASSERT(shuffle_cnt == 0); |
818 | if (shuffle_cnt++ > 0) { |
819 | pppoed_log(_pppoed, LOG_ERR3, |
820 | "unexpected error in %s(): session_free_list full", |
821 | __func__); |
822 | slist_add(&_pppoed->session_free_list, |
823 | (void *)PPPOED_SESSION_SHUFFLE_MARK0x10000000); |
824 | goto fail; |
825 | } |
826 | slist_shuffle(&_pppoed->session_free_list); |
827 | slist_add(&_pppoed->session_free_list, |
828 | (void *)PPPOED_SESSION_SHUFFLE_MARK0x10000000); |
829 | } while (1); |
830 | |
831 | if (pppoe_session_init(session, _pppoed, _this->index, session_id, |
832 | shost) != 0) |
833 | goto fail; |
834 | |
835 | hash_insert(_pppoed->session_hash, (void *)(intptr_t)session_id, |
836 | session); |
837 | |
838 | if (pppoe_session_recv_PADR(session, tag_list) != 0) |
839 | goto fail; |
840 | |
841 | session = NULL((void *)0); /* don't free */ |
842 | /* FALLTHROUGH */ |
843 | fail: |
844 | if (session != NULL((void *)0)) |
845 | pppoe_session_fini(session); |
846 | return; |
847 | } |
848 | |
849 | static void |
850 | pppoed_recv_PADI(pppoed_listener *_this, uint8_t shost[ETHER_ADDR_LEN6], |
851 | slist *tag_list) |
852 | { |
853 | int len; |
854 | const char *service_name, *ac_name; |
855 | u_char bufspace[2048]; |
856 | u_char sn[2048], ac_name0[40]; |
857 | struct pppoe_header pppoe; |
858 | struct pppoe_tlv tlv, *tlv_hostuniq, *tlv0, *tlv_service_name; |
859 | bytebuffer *buf; |
860 | |
861 | if ((buf = bytebuffer_wrap(bufspace, sizeof(bufspace))) == NULL((void *)0)) { |
862 | pppoed_log(_this->self, LOG_ERR3, |
863 | "bytebuffer_wrap() failed on %s(): %m", __func__); |
864 | return; |
865 | } |
866 | bytebuffer_clear(buf); |
867 | |
868 | tlv_hostuniq = NULL((void *)0); |
869 | tlv_service_name = NULL((void *)0); |
870 | |
871 | service_name = ""; |
872 | if (_this->conf->service_name != NULL((void *)0)) |
873 | service_name = _this->conf->service_name; |
874 | |
875 | for (slist_itr_first(tag_list); slist_itr_has_next(tag_list);) { |
876 | tlv0 = slist_itr_next(tag_list); |
877 | if (tlv0->type == PPPOE_TAG_HOST_UNIQ0x0103) |
878 | tlv_hostuniq = tlv0; |
879 | if (tlv0->type == PPPOE_TAG_SERVICE_NAME0x0101) { |
880 | |
881 | len = tlv0->length; |
882 | if (len >= sizeof(sn)) |
883 | goto fail; |
884 | |
885 | memcpy(sn, tlv0->value, len); |
886 | sn[len] = '\0'; |
887 | |
888 | if (strcmp(service_name, sn) == 0 || |
889 | (sn[0] == '\0' && _this->conf->accept_any_service)) |
890 | tlv_service_name = tlv0; |
891 | } |
892 | } |
893 | if (tlv_service_name == NULL((void *)0)) { |
894 | pppoed_log(_this->self, LOG_INFO6, |
895 | "Deny PADI from=%02x:%02x:%02x:%02x:%02x:%02x " |
896 | "service-name=%s host-uniq=%s if=%s: serviceName is " |
897 | "not allowed.", shost[0], shost[1], |
898 | shost[2], shost[3], shost[4], shost[5], sn, tlv_hostuniq? |
899 | pppoed_tlv_value_string(tlv_hostuniq) : "none", |
900 | _this->listen_ifname); |
901 | goto fail; |
902 | } |
903 | |
904 | pppoed_log(_this->self, LOG_INFO6, |
905 | "RecvPADI from=%02x:%02x:%02x:%02x:%02x:%02x service-name=%s " |
906 | "host-uniq=%s if=%s", shost[0], shost[1], shost[2], shost[3], |
907 | shost[4], shost[5], sn, tlv_hostuniq? |
908 | pppoed_tlv_value_string(tlv_hostuniq) : "none", |
909 | _this->listen_ifname); |
910 | |
911 | /* |
912 | * PPPoE Header |
913 | */ |
914 | memset(&pppoe, 0, sizeof(pppoe)); |
915 | pppoe.ver = PPPOE_RFC2516_VER0x01; |
916 | pppoe.type = PPPOE_RFC2516_TYPE0x01; |
917 | pppoe.code = PPPOE_CODE_PADO0x07; |
918 | bytebuffer_put(buf, &pppoe, sizeof(pppoe)); |
919 | |
920 | /* |
921 | * Tag - Service-Name |
922 | */ |
923 | tlv.type = htons(PPPOE_TAG_SERVICE_NAME)(__uint16_t)(__builtin_constant_p(0x0101) ? (__uint16_t)(((__uint16_t )(0x0101) & 0xffU) << 8 | ((__uint16_t)(0x0101) & 0xff00U) >> 8) : __swap16md(0x0101)); |
924 | len = strlen(service_name); |
925 | tlv.length = htons(len)(__uint16_t)(__builtin_constant_p(len) ? (__uint16_t)(((__uint16_t )(len) & 0xffU) << 8 | ((__uint16_t)(len) & 0xff00U ) >> 8) : __swap16md(len)); |
926 | bytebuffer_put(buf, &tlv, sizeof(tlv)); |
927 | if (len > 0) |
928 | bytebuffer_put(buf, service_name, len); |
929 | |
930 | /* |
931 | * Tag - Access Concentrator Name |
932 | */ |
933 | ac_name = _this->conf->ac_name; |
934 | if (ac_name == NULL((void *)0)) { |
935 | /* |
936 | * use the ethernet address as default AC-Name. |
937 | * suggested by RFC 2516. |
938 | */ |
939 | snprintf(ac_name0, sizeof(ac_name0), |
940 | "%02x:%02x:%02x:%02x:%02x:%02x", _this->ether_addr[0], |
941 | _this->ether_addr[1], _this->ether_addr[2], |
942 | _this->ether_addr[3], _this->ether_addr[4], |
943 | _this->ether_addr[5]); |
944 | ac_name = ac_name0; |
945 | } |
946 | |
947 | tlv.type = htons(PPPOE_TAG_AC_NAME)(__uint16_t)(__builtin_constant_p(0x0102) ? (__uint16_t)(((__uint16_t )(0x0102) & 0xffU) << 8 | ((__uint16_t)(0x0102) & 0xff00U) >> 8) : __swap16md(0x0102)); |
948 | len = strlen(ac_name); |
949 | tlv.length = htons(len)(__uint16_t)(__builtin_constant_p(len) ? (__uint16_t)(((__uint16_t )(len) & 0xffU) << 8 | ((__uint16_t)(len) & 0xff00U ) >> 8) : __swap16md(len)); |
950 | bytebuffer_put(buf, &tlv, sizeof(tlv)); |
951 | bytebuffer_put(buf, ac_name, len); |
952 | |
953 | /* |
954 | * Tag - ac-cookie |
955 | */ |
956 | if (_this->self->acookie_hash != NULL((void *)0)) { |
957 | /* |
958 | * search next ac-cookie. |
959 | * (XXX it will loop in uint32_t boundaly) |
960 | */ |
961 | do { |
962 | _this->self->acookie_next += 1; |
963 | } |
964 | while(hash_lookup(_this->self->acookie_hash, |
965 | (void *)(intptr_t)_this->self->acookie_next) != NULL((void *)0)); |
966 | |
967 | tlv.type = htons(PPPOE_TAG_AC_COOKIE)(__uint16_t)(__builtin_constant_p(0x0104) ? (__uint16_t)(((__uint16_t )(0x0104) & 0xffU) << 8 | ((__uint16_t)(0x0104) & 0xff00U) >> 8) : __swap16md(0x0104)); |
968 | tlv.length = ntohs(sizeof(uint32_t))(__uint16_t)(__builtin_constant_p(sizeof(uint32_t)) ? (__uint16_t )(((__uint16_t)(sizeof(uint32_t)) & 0xffU) << 8 | ( (__uint16_t)(sizeof(uint32_t)) & 0xff00U) >> 8) : __swap16md (sizeof(uint32_t))); |
969 | bytebuffer_put(buf, &tlv, sizeof(tlv)); |
970 | bytebuffer_put(buf, &_this->self->acookie_next, |
971 | sizeof(uint32_t)); |
972 | } |
973 | |
974 | /* |
975 | * Tag - Host-Uniq |
976 | */ |
977 | if (tlv_hostuniq != NULL((void *)0)) { |
978 | tlv.type = htons(PPPOE_TAG_HOST_UNIQ)(__uint16_t)(__builtin_constant_p(0x0103) ? (__uint16_t)(((__uint16_t )(0x0103) & 0xffU) << 8 | ((__uint16_t)(0x0103) & 0xff00U) >> 8) : __swap16md(0x0103)); |
979 | tlv.length = ntohs(tlv_hostuniq->length)(__uint16_t)(__builtin_constant_p(tlv_hostuniq->length) ? ( __uint16_t)(((__uint16_t)(tlv_hostuniq->length) & 0xffU ) << 8 | ((__uint16_t)(tlv_hostuniq->length) & 0xff00U ) >> 8) : __swap16md(tlv_hostuniq->length)); |
980 | bytebuffer_put(buf, &tlv, sizeof(tlv)); |
981 | bytebuffer_put(buf, tlv_hostuniq->value, |
982 | tlv_hostuniq->length); |
983 | } |
984 | |
985 | /* |
986 | * Tag - End-Of-List |
987 | */ |
988 | tlv.type = htons(PPPOE_TAG_END_OF_LIST)(__uint16_t)(__builtin_constant_p(0x0000) ? (__uint16_t)(((__uint16_t )(0x0000) & 0xffU) << 8 | ((__uint16_t)(0x0000) & 0xff00U) >> 8) : __swap16md(0x0000)); |
989 | tlv.length = ntohs(0)(__uint16_t)(__builtin_constant_p(0) ? (__uint16_t)(((__uint16_t )(0) & 0xffU) << 8 | ((__uint16_t)(0) & 0xff00U ) >> 8) : __swap16md(0)); |
990 | bytebuffer_put(buf, &tlv, sizeof(tlv)); |
991 | |
992 | bytebuffer_flip(buf); |
993 | |
994 | if (pppoed_output(_this, shost, bytebuffer_pointer(buf), |
995 | bytebuffer_remaining(buf)) != 0) { |
996 | pppoed_log(_this->self, LOG_ERR3, "pppoed_output() failed:%m"); |
997 | } |
998 | pppoed_log(_this->self, LOG_INFO6, |
999 | "SendPADO to=%02x:%02x:%02x:%02x:%02x:%02x serviceName=%s " |
1000 | "acName=%s hostUniq=%s eol if=%s", shost[0], shost[1], shost[2], |
1001 | shost[3], shost[4], shost[5], service_name, ac_name, |
1002 | tlv_hostuniq? pppoed_tlv_value_string(tlv_hostuniq) : "none", |
1003 | _this->listen_ifname); |
1004 | /* FALLTHROUGH */ |
1005 | fail: |
1006 | bytebuffer_unwrap(buf); |
1007 | bytebuffer_destroy(buf); |
1008 | } |
1009 | |
1010 | /* |
1011 | * log |
1012 | */ |
1013 | static void |
1014 | pppoed_log(pppoed *_this, int prio, const char *fmt, ...) |
1015 | { |
1016 | char logbuf[BUFSIZ1024]; |
1017 | va_list ap; |
1018 | |
1019 | PPPOED_ASSERT(_this != NULL); |
1020 | va_start(ap, fmt)__builtin_va_start((ap), fmt); |
1021 | #ifdef PPPOED_MULTIPLE |
1022 | snprintf(logbuf, sizeof(logbuf), "pppoed id=%u %s", _this->id, fmt); |
1023 | #else |
1024 | snprintf(logbuf, sizeof(logbuf), "pppoed %s", fmt); |
1025 | #endif |
1026 | vlog_printf(prio, logbuf, ap); |
1027 | va_end(ap)__builtin_va_end((ap)); |
1028 | } |
1029 | |
1030 | #define NAME_VAL(x){ x, "x" } { x, #x } |
1031 | static struct _label_name { |
1032 | int label; |
1033 | const char *name; |
1034 | } pppoe_code_labels[] = { |
1035 | NAME_VAL(PPPOE_CODE_PADI){ 0x09, "PPPOE_CODE_PADI" }, |
1036 | NAME_VAL(PPPOE_CODE_PADO){ 0x07, "PPPOE_CODE_PADO" }, |
1037 | NAME_VAL(PPPOE_CODE_PADR){ 0x19, "PPPOE_CODE_PADR" }, |
1038 | NAME_VAL(PPPOE_CODE_PADS){ 0x65, "PPPOE_CODE_PADS" }, |
1039 | NAME_VAL(PPPOE_CODE_PADT){ 0xa7, "PPPOE_CODE_PADT" }, |
1040 | #ifdef PPPOED_DEBUG |
1041 | }, pppoe_tlv_labels[] = { |
1042 | NAME_VAL(PPPOE_TAG_END_OF_LIST){ 0x0000, "PPPOE_TAG_END_OF_LIST" }, |
1043 | NAME_VAL(PPPOE_TAG_SERVICE_NAME){ 0x0101, "PPPOE_TAG_SERVICE_NAME" }, |
1044 | NAME_VAL(PPPOE_TAG_AC_NAME){ 0x0102, "PPPOE_TAG_AC_NAME" }, |
1045 | NAME_VAL(PPPOE_TAG_HOST_UNIQ){ 0x0103, "PPPOE_TAG_HOST_UNIQ" }, |
1046 | NAME_VAL(PPPOE_TAG_AC_COOKIE){ 0x0104, "PPPOE_TAG_AC_COOKIE" }, |
1047 | NAME_VAL(PPPOE_TAG_VENDOR_SPECIFIC){ 0x0105, "PPPOE_TAG_VENDOR_SPECIFIC" }, |
1048 | NAME_VAL(PPPOE_TAG_RELAY_SESSION_ID){ 0x0110, "PPPOE_TAG_RELAY_SESSION_ID" }, |
1049 | NAME_VAL(PPPOE_TAG_SERVICE_NAME_ERROR){ 0x0201, "PPPOE_TAG_SERVICE_NAME_ERROR" }, |
1050 | NAME_VAL(PPPOE_TAG_AC_SYSTEM_ERROR){ 0x0202, "PPPOE_TAG_AC_SYSTEM_ERROR" }, |
1051 | NAME_VAL(PPPOE_TAG_GENERIC_ERROR){ 0x0203, "PPPOE_TAG_GENERIC_ERROR" } |
1052 | #endif |
1053 | }; |
1054 | #define LABEL_TO_STRING(func_name, label_names, prefix_len)static const char * func_name(int code) { int i; for (i = 0; i < (sizeof((label_names)) / sizeof((label_names)[0])); i++ ) { if (label_names[i].label == code) return label_names[i].name + prefix_len; } return "UNKNOWN"; } \ |
1055 | static const char * \ |
1056 | func_name(int code) \ |
1057 | { \ |
1058 | int i; \ |
1059 | \ |
1060 | for (i = 0; i < countof(label_names)(sizeof((label_names)) / sizeof((label_names)[0])); i++) { \ |
1061 | if (label_names[i].label == code) \ |
1062 | return label_names[i].name + prefix_len;\ |
1063 | } \ |
1064 | \ |
1065 | return "UNKNOWN"; \ |
1066 | } |
1067 | LABEL_TO_STRING(pppoe_code_string, pppoe_code_labels, 11)static const char * pppoe_code_string(int code) { int i; for ( i = 0; i < (sizeof((pppoe_code_labels)) / sizeof((pppoe_code_labels )[0])); i++) { if (pppoe_code_labels[i].label == code) return pppoe_code_labels[i].name + 11; } return "UNKNOWN"; } |
1068 | #ifdef PPPOED_DEBUG |
1069 | LABEL_TO_STRING(pppoe_tag_string, pppoe_tlv_labels, 10)static const char * pppoe_tag_string(int code) { int i; for ( i = 0; i < (sizeof((pppoe_tlv_labels)) / sizeof((pppoe_tlv_labels )[0])); i++) { if (pppoe_tlv_labels[i].label == code) return pppoe_tlv_labels [i].name + 10; } return "UNKNOWN"; } |
1070 | #endif |
1071 | |
1072 | const char * |
1073 | pppoed_tlv_value_string(struct pppoe_tlv *tlv) |
1074 | { |
1075 | int i; |
1076 | char buf[3]; |
1077 | static char _tlv_string_value[8192]; |
1078 | |
1079 | _tlv_string_value[0] = '\0'; |
1080 | for (i = 0; i < tlv->length; i++) { |
1081 | snprintf(buf, sizeof(buf), "%02x", tlv->value[i]); |
1082 | strlcat(_tlv_string_value, buf, |
1083 | sizeof(_tlv_string_value)); |
1084 | } |
1085 | return _tlv_string_value; |
1086 | } |
1087 | |
1088 | /* |
1089 | * misc |
1090 | */ |
1091 | static int |
1092 | session_id_cmp(void *a, void *b) |
1093 | { |
1094 | int ia, ib; |
1095 | |
1096 | ia = (intptr_t)a; |
1097 | ib = (intptr_t)b; |
1098 | |
1099 | return ib - ia; |
1100 | } |
1101 | |
1102 | static uint32_t |
1103 | session_id_hash(void *a, size_t siz) |
1104 | { |
1105 | int ia; |
1106 | |
1107 | ia = (intptr_t)a; |
1108 | |
1109 | return ia % siz; |
1110 | } |