GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/npppd/npppd/../pppoe/pppoed.c Lines: 0 458 0.0 %
Date: 2017-11-07 Branches: 0 218 0.0 %

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