Bug Summary

File:src/usr.sbin/npppd/npppd/../pppoe/pppoed.c
Warning:line 472, column 2
Value stored to 'do_start' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name pppoed.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/npppd/npppd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/npppd/npppd/../common -I /usr/src/usr.sbin/npppd/npppd -I /usr/src/usr.sbin/npppd/npppd/../pptp -I /usr/src/usr.sbin/npppd/npppd/../l2tp -I /usr/src/usr.sbin/npppd/npppd/../pppoe -D USE_NPPPD_PPTP -D USE_NPPPD_L2TP -D USE_NPPPD_PPPOE -D __COPYRIGHT(x)= -D __RCSID(x)= -D NPPPD_MAX_IFACE=8 -D NPPPD_MAX_POOL=8 -D USE_NPPPD_MPPE -D USE_NPPPD_PIPEX -D USE_NPPPD_RADIUS -D USE_SA_COOKIE -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/npppd/npppd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/npppd/npppd/../pppoe/pppoed.c
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
74static 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
84static void pppoed_log (pppoed *, int, const char *, ...) __printflike(3,4)__attribute__((__format__ (__printf__, 3, 4)));
85static void pppoed_listener_init(pppoed *, pppoed_listener *);
86static int pppoed_output (pppoed_listener *, u_char *, u_char *, int);
87static int pppoed_listener_start (pppoed_listener *, int);
88static void pppoed_io_event (int, short, void *);
89static void pppoed_input (pppoed_listener *, uint8_t [ETHER_ADDR_LEN6], int, u_char *, int);
90static void pppoed_recv_PADR (pppoed_listener *, uint8_t [ETHER_ADDR_LEN6], slist *);
91static void pppoed_recv_PADI (pppoed_listener *, uint8_t [ETHER_ADDR_LEN6], slist *);
92static int session_id_cmp (void *, void *);
93static uint32_t session_id_hash (void *, size_t);
94
95#ifdef PPPOE_TEST
96static void pppoed_on_sigterm (int, short, void *);
97static void usage (void);
98#endif
99static const char *pppoe_code_string(int);
100#ifdef PPPOED_DEBUG
101static const char *pppoe_tag_string(int);
102#endif
103
104/*
105 * daemon
106 */
107
108/* initialize PPPoE daemon */
109int
110pppoed_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;
166fail:
167 pppoed_uninit(_this);
168 return 1;
169}
170
171static void
172pppoed_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 */
181int
182pppoed_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
202static int
203pppoed_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;
327fail:
328 if (_this->bpf >= 0) {
329 close(_this->bpf);
330 _this->bpf = -1;
331 }
332
333 return 1;
334}
335
336/* start PPPoE daemon */
337int
338pppoed_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 */
365static void
366pppoed_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 */
388void
389pppoed_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 */
419void
420pppoed_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 */
436void
437pppoed_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 */
457int
458pppoed_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;
565fail:
566 slist_fini(&rmlist);
567 slist_fini(&newlist);
568
569 return 1;
570}
571
572/*
573 * I/O
574 */
575
576static void
577pppoed_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);
615next_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
623static void
624pppoed_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;
751fail:
752 slist_fini(&tag_list);
753bad_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
761static int
762pppoed_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 = &ether;
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
795static void
796pppoed_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 */
843fail:
844 if (session != NULL((void *)0))
845 pppoe_session_fini(session);
846 return;
847}
848
849static void
850pppoed_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 */
1005fail:
1006 bytebuffer_unwrap(buf);
1007 bytebuffer_destroy(buf);
1008}
1009
1010/*
1011 * log
1012 */
1013static void
1014pppoed_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 }
1031static 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 }
1067LABEL_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
1069LABEL_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
1072const char *
1073pppoed_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 */
1091static int
1092session_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
1102static uint32_t
1103session_id_hash(void *a, size_t siz)
1104{
1105 int ia;
1106
1107 ia = (intptr_t)a;
1108
1109 return ia % siz;
1110}