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