1 /*	$OpenBSD: pppoe_session.c,v 1.8 2014/11/18 20:54:28 krw 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 
29 /**@file
30  * Session management of PPPoE protocol
31  * $Id: pppoe_session.c,v 1.8 2014/11/18 20:54:28 krw Exp $
32  */
33 
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/param.h>
37 #include <sys/uio.h>
38 #include <netinet/in.h>
39 #include <net/if.h>
40 #if defined(__NetBSD__)
41 #include <net/if_ether.h>
42 #else
43 #include <netinet/if_ether.h>
44 #endif
45 #include <net/if_dl.h>
46 #include <time.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <event.h>
51 #include <syslog.h>
52 #include <stdarg.h>
53 
54 #include "hash.h"
55 #include "slist.h"
56 #include "debugutil.h"
57 #include "bytebuf.h"
58 #include "pppoe.h"
59 #include "pppoe_local.h"
60 
61 #include "npppd.h"
62 #include "ppp.h"
63 
64 #ifdef	PPPOE_SESSION_DEBUG
65 #define	PPPOE_SESSION_ASSERT(x)	ASSERT(x)
66 #define	PPPOE_SESSION_DBG(x)	pppoe_session_log x
67 #else
68 #define	PPPOE_SESSION_ASSERT(x)
69 #define	PPPOE_SESSION_DBG(x)
70 #endif
71 
72 #define	pppoed_listener_this(sess)					\
73 	((pppoed_listener *)slist_get(&(sess)->pppoed->listener, 	\
74 	    (sess)->listener_index))
75 
76 static void  pppoe_session_log (pppoe_session *, int, const char *, ...) __printflike(3,4);
77 static int   pppoe_session_send_PADS (pppoe_session *, struct pppoe_tlv *,
78     struct pppoe_tlv *);
79 static int   pppoe_session_send_PADT (pppoe_session *);
80 static int   pppoe_session_ppp_output (npppd_ppp *, u_char *, int, int);
81 static void  pppoe_session_close_by_ppp(npppd_ppp *);
82 static int   pppoe_session_bind_ppp (pppoe_session *);
83 static void  pppoe_session_dispose_event(int, short, void *);
84 
85 /* Initialize PPPoE session context */
86 int
87 pppoe_session_init(pppoe_session *_this, pppoed *_pppoed, int idx,
88     int session_id, u_char *ether_addr)
89 {
90 	memset(_this, 0, sizeof(pppoe_session));
91 
92 	_this->pppoed = _pppoed;
93 	_this->session_id = session_id;
94 	_this->listener_index = idx;
95 	memcpy(_this->ether_addr, ether_addr, ETHER_ADDR_LEN);
96 
97 	memcpy(_this->ehdr.ether_dhost, ether_addr, ETHER_ADDR_LEN);
98 	memcpy(_this->ehdr.ether_shost, pppoe_session_sock_ether_addr(_this),
99 	    ETHER_ADDR_LEN);
100 
101 	evtimer_set(&_this->ev_disposing, pppoe_session_dispose_event, _this);
102 
103 	return 0;
104 }
105 
106 /* Disconnect PPPoE session */
107 void
108 pppoe_session_disconnect(pppoe_session *_this)
109 {
110 	struct timeval tv;
111 
112 	if (_this->state != PPPOE_SESSION_STATE_DISPOSING) {
113 		pppoe_session_send_PADT(_this);
114 
115 		/* free process should be par event */
116 		timerclear(&tv);
117 		evtimer_add(&_this->ev_disposing, &tv);
118 		_this->state = PPPOE_SESSION_STATE_DISPOSING;
119 	}
120 	if (_this->ppp != NULL)
121 		ppp_phy_downed(_this->ppp);
122 }
123 
124 /* Stop PPPoE session */
125 void
126 pppoe_session_stop(pppoe_session *_this)
127 {
128 	if (_this->state != PPPOE_SESSION_STATE_DISPOSING)
129 		pppoe_session_disconnect(_this);
130 
131 }
132 
133 /* Finish PPPoE session */
134 void
135 pppoe_session_fini(pppoe_session *_this)
136 {
137 	evtimer_del(&_this->ev_disposing);
138 }
139 
140 /* call back function from event(3) */
141 static void
142 pppoe_session_dispose_event(int fd, short ev, void *ctx)
143 {
144 	pppoe_session *_this;
145 
146 	_this = ctx;
147 	pppoed_pppoe_session_close_notify(_this->pppoed, _this);
148 }
149 
150 /*
151  * I/O
152  */
153 void
154 pppoe_session_input(pppoe_session *_this, u_char *pkt, int lpkt)
155 {
156 	int rval;
157 	npppd_ppp *ppp;
158 
159 	ppp = _this->ppp;
160 	if (_this->ppp == NULL)
161 		return;
162 
163 	if (_this->state != PPPOE_SESSION_STATE_RUNNING)
164 		return;
165 
166 	rval = ppp->recv_packet(ppp, pkt, lpkt, 0);
167 	if (_this->ppp == NULL)	/* ppp is freed */
168 		return;
169 
170 	if (rval == 2) {
171 		/*
172 		 * Quit this function before statistics counter
173 		 * is processed when the packet will be processed by
174 		 * PIPEX. Because current NPPPD PPPOE implementation
175 		 * is recieving all packet from BPF even though the
176 		 * PIPEX will process it.
177 		 */
178 	} else if (rval != 0)  {
179 		ppp->ierrors++;
180 	} else {
181 		ppp->ipackets++;
182 		ppp->ibytes += lpkt;
183 	}
184 
185 	return;
186 }
187 
188 static int
189 pppoe_session_output(pppoe_session *_this, int is_disc, u_char *pkt,
190     int lpkt)
191 {
192 	int sz, niov, tlen;
193 	struct iovec iov[4];
194 	struct pppoe_header pppoe0, *pppoe;
195 	char pad[ETHERMIN];
196 
197 
198 	niov = 0;
199 	tlen = 0;
200 	iov[niov].iov_base = &_this->ehdr;
201 	iov[niov++].iov_len = sizeof(_this->ehdr);
202 
203 	if (is_disc) {
204 		_this->ehdr.ether_type = htons(ETHERTYPE_PPPOEDISC);
205 		iov[niov].iov_base = pkt;
206 		iov[niov++].iov_len = lpkt;
207 		pppoe = (struct pppoe_header *)pkt;
208 		pppoe->length = htons(lpkt - sizeof(pppoe0));
209 		tlen += lpkt;
210 	} else {
211 		_this->ehdr.ether_type = htons(ETHERTYPE_PPPOE);
212 		pppoe0.ver = PPPOE_RFC2516_VER;
213 		pppoe0.type = PPPOE_RFC2516_TYPE;
214 		pppoe0.code = 0;
215 		pppoe0.session_id = htons(_this->session_id);
216 		pppoe0.length = htons(lpkt);
217 		iov[niov].iov_base = &pppoe0;
218 		iov[niov++].iov_len = sizeof(pppoe0);
219 		tlen += sizeof(pppoe0);
220 		iov[niov].iov_base = pkt;
221 		iov[niov++].iov_len = lpkt;
222 		tlen += lpkt;
223 	}
224 	if (tlen < ETHERMIN) {
225 		memset(pad, 0, ETHERMIN - tlen);
226 		iov[niov].iov_base = pad;
227 		iov[niov++].iov_len = ETHERMIN - tlen;
228 	}
229 
230 	sz = writev(pppoe_session_sock_bpf(_this), iov, niov);
231 
232 	return (sz > 0)? 0 : -1;
233 }
234 
235 static int
236 pppoe_session_send_PADT(pppoe_session *_this)
237 {
238 	u_char bufspace[2048];
239 	bytebuffer *buf;
240 	struct pppoe_header pppoe;
241 	int rval = 0;
242 	struct pppoe_tlv tlv;
243 
244 	if ((buf = bytebuffer_wrap(bufspace, sizeof(bufspace))) == NULL) {
245 		pppoe_session_log(_this, LOG_ERR,
246 		"bytebuffer_wrap() failed on %s(): %m", __func__);
247 		return -1;
248 	}
249 	bytebuffer_clear(buf);
250 
251 	/*
252 	 * PPPoE Header
253 	 */
254 	memset(&pppoe, 0, sizeof(pppoe));
255 	pppoe.ver = PPPOE_RFC2516_VER;
256 	pppoe.type = PPPOE_RFC2516_TYPE;
257 	pppoe.code = PPPOE_CODE_PADT;
258 	pppoe.session_id = htons(_this->session_id);
259 	bytebuffer_put(buf, &pppoe, sizeof(pppoe));
260 
261 	/*
262 	 * Tag - End-of-List
263 	 */
264 	tlv.type = htons(PPPOE_TAG_END_OF_LIST);
265 	tlv.length = 0;
266 	bytebuffer_put(buf, &tlv, sizeof(tlv));
267 	tlv.type = htons(PPPOE_TAG_END_OF_LIST);
268 	tlv.length = 0;
269 	bytebuffer_put(buf, &tlv, sizeof(tlv));
270 
271 	bytebuffer_flip(buf);
272 	if (pppoe_session_output(_this, 1, bytebuffer_pointer(buf),
273 	    bytebuffer_remaining(buf)) != 0) {
274 		pppoe_session_log(_this, LOG_ERR, "pppoed_output failed: %m");
275 		rval = 1;
276 	}
277 	pppoe_session_log(_this, LOG_INFO, "SendPADT");
278 
279 	bytebuffer_unwrap(buf);
280 	bytebuffer_destroy(buf);
281 
282 	return rval;
283 }
284 
285 /* send PADS */
286 static int
287 pppoe_session_send_PADS(pppoe_session *_this, struct pppoe_tlv *hostuniq,
288     struct pppoe_tlv *service_name)
289 {
290 	int rval, len;
291 	u_char bufspace[2048], msgbuf[80];
292 	bytebuffer *buf;
293 	struct pppoe_header pppoe;
294 	struct pppoe_tlv tlv;
295 
296 	if ((buf = bytebuffer_wrap(bufspace, sizeof(bufspace))) == NULL) {
297 		pppoe_session_log(_this, LOG_ERR,
298 		"bytebuffer_wrap() failed on %s(): %m", __func__);
299 		return -1;
300 	}
301 	bytebuffer_clear(buf);
302 
303 	/*
304 	 * PPPoE Header
305 	 */
306 	memset(&pppoe, 0, sizeof(pppoe));
307 	pppoe.ver = PPPOE_RFC2516_VER;
308 	pppoe.type = PPPOE_RFC2516_TYPE;
309 	pppoe.code = PPPOE_CODE_PADS;
310 	pppoe.session_id = htons(_this->session_id);
311 	bytebuffer_put(buf, &pppoe, sizeof(pppoe));
312 
313 	/*
314 	 * Tag - Service-Name
315 	 */
316 	msgbuf[0] = '\0';
317 	if (service_name != NULL) {
318 		tlv.type = htons(PPPOE_TAG_SERVICE_NAME);
319 		tlv.length = htons(service_name->length);
320 		bytebuffer_put(buf, &tlv, sizeof(tlv));
321 
322 		len = service_name->length;
323 		if (len > 0) {
324 			bytebuffer_put(buf, service_name->value, len);
325 			strlcpy(msgbuf, service_name->value,
326 			    MIN(len + 1, sizeof(msgbuf)));
327 		}
328 	}
329 
330 	/*
331 	 * Tag - Host-Uniq
332 	 */
333 	if (hostuniq != NULL) {
334 		tlv.type = htons(PPPOE_TAG_HOST_UNIQ);
335 		tlv.length = htons(hostuniq->length);
336 		bytebuffer_put(buf, &tlv, sizeof(tlv));
337 		bytebuffer_put(buf, hostuniq->value, hostuniq->length);
338 	}
339 	tlv.type = htons(PPPOE_TAG_END_OF_LIST);
340 	tlv.length = 0;
341 	bytebuffer_put(buf, &tlv, sizeof(tlv));
342 
343 	bytebuffer_flip(buf);
344 	rval = 0;
345 	if (pppoe_session_output(_this, 1, bytebuffer_pointer(buf),
346 	    bytebuffer_remaining(buf)) != 0) {
347 		pppoe_session_log(_this, LOG_ERR, "pppoed_output failed: %m");
348 		rval = 1;
349 	}
350 	pppoe_session_log(_this, LOG_INFO, "SendPADS serviceName=%s "
351 	    "hostUniq=%s", msgbuf,
352 	    hostuniq? pppoed_tlv_value_string(hostuniq) : "none");
353 
354 	bytebuffer_unwrap(buf);
355 	bytebuffer_destroy(buf);
356 
357 	return rval;
358 }
359 
360 /* process PADR from the peer */
361 int
362 pppoe_session_recv_PADR(pppoe_session *_this, slist *tag_list)
363 {
364 	pppoed *pppoed0 = _this->pppoed;
365 	struct pppoe_tlv *tlv, *hostuniq, *service_name, *ac_cookie;
366 
367 	service_name = NULL;
368 	hostuniq = NULL;
369 	ac_cookie = NULL;
370 	for (slist_itr_first(tag_list); slist_itr_has_next(tag_list); ) {
371 		tlv = slist_itr_next(tag_list);
372 		if (tlv->type == PPPOE_TAG_HOST_UNIQ)
373 			hostuniq = tlv;
374 		if (tlv->type == PPPOE_TAG_SERVICE_NAME)
375 			service_name = tlv;
376 		if (tlv->type == PPPOE_TAG_AC_COOKIE)
377 			ac_cookie = tlv;
378 	}
379 
380 	if (ac_cookie) {
381 		/* avoid a session which has already has cookie. */
382 		if (hash_lookup(pppoed0->acookie_hash,
383 		    (void *)ac_cookie->value) != NULL)
384 			goto fail;
385 
386 		_this->acookie = *(uint32_t *)(ac_cookie->value);
387 		hash_insert(pppoed0->acookie_hash,
388 			(void *)(intptr_t)_this->acookie, _this);
389 	}
390 
391 	if (pppoe_session_send_PADS(_this, hostuniq, service_name) != 0)
392 		goto fail;
393 
394 	if (pppoe_session_bind_ppp(_this) != 0)
395 		goto fail;
396 
397 	_this->state = PPPOE_SESSION_STATE_RUNNING;
398 	return 0;
399 fail:
400 	return -1;
401 }
402 
403 /* process PADT from the peer */
404 int
405 pppoe_session_recv_PADT(pppoe_session *_this, slist *tag_list)
406 {
407 	pppoe_session_log(_this, LOG_INFO, "RecvPADT");
408 
409 	pppoe_session_stop(_this);
410 	_this->state = PPPOE_SESSION_STATE_DISPOSING;
411 
412 	return 0;
413 }
414 
415 /*
416  * Log
417  */
418 static void
419 pppoe_session_log(pppoe_session *_this, int prio, const char *fmt, ...)
420 {
421 	char logbuf[BUFSIZ];
422 	va_list ap;
423 
424 	PPPOE_SESSION_ASSERT(_this != NULL);
425 	va_start(ap, fmt);
426 #ifdef	PPPOED_MULTIPLE
427 	snprintf(logbuf, sizeof(logbuf), "pppoed id=%u session=%d %s",
428 	    _this->pppoed->id, _this->session_id, fmt);
429 #else
430 	snprintf(logbuf, sizeof(logbuf), "pppoed if=%s session=%d %s",
431 	    pppoe_session_listen_ifname(_this), _this->session_id, fmt);
432 #endif
433 	vlog_printf(prio, logbuf, ap);
434 	va_end(ap);
435 }
436 
437 /*
438  * PPP
439  */
440 static int
441 pppoe_session_ppp_output(npppd_ppp *ppp, u_char *pkt, int lpkt, int flag)
442 {
443 	int rval;
444 	pppoe_session *_this;
445 
446 	_this = ppp->phy_context;
447 
448 	rval = pppoe_session_output(_this, 0, pkt, lpkt);
449 
450 	if (_this->ppp == NULL)		/* ppp is freed */
451 		return 0;
452 
453 	if (rval != 0) {
454 		ppp->oerrors++;
455 	} else {
456 		ppp->opackets++;
457 		ppp->obytes += lpkt;
458 	}
459 
460 	return 0;
461 }
462 
463 static void
464 pppoe_session_close_by_ppp(npppd_ppp *ppp)
465 {
466 	pppoe_session *_this;
467 
468 	_this = ppp->phy_context;
469 	PPPOE_SESSION_ASSERT(_this != NULL);
470 	if (_this != NULL)
471 		/* do this before pptp_call_disconnect() */
472 		_this->ppp = NULL;
473 
474 	pppoe_session_disconnect(_this);
475 }
476 
477 /* bind for PPP */
478 static int
479 pppoe_session_bind_ppp(pppoe_session *_this)
480 {
481 	int len;
482 	npppd_ppp *ppp;
483 	struct sockaddr_dl sdl;
484 
485 	ppp = NULL;
486 	if ((ppp = ppp_create()) == NULL)
487 		goto fail;
488 
489 	PPPOE_SESSION_ASSERT(_this->ppp == NULL);
490 
491 	if (_this->ppp != NULL)
492 		return -1;
493 
494 	_this->ppp = ppp;
495 
496 	ppp->tunnel_type = NPPPD_TUNNEL_PPPOE;
497 	ppp->phy_context = _this;
498 	ppp->send_packet = pppoe_session_ppp_output;
499 	ppp->phy_close = pppoe_session_close_by_ppp;
500 
501 	strlcpy(ppp->phy_label, PPPOE_SESSION_LISTENER_TUN_NAME(_this),
502 	    sizeof(ppp->phy_label));
503 
504 	memset(&sdl, 0, sizeof(sdl));
505 	sdl.sdl_len = sizeof(sdl);
506 	sdl.sdl_family = AF_LINK;
507 	len = strlen(pppoe_session_listen_ifname(_this));
508 	memcpy(sdl.sdl_data, pppoe_session_listen_ifname(_this), len);
509 	sdl.sdl_nlen = len;
510 	sdl.sdl_alen = ETHER_ADDR_LEN;
511 	memcpy(sdl.sdl_data + len, _this->ether_addr, ETHER_ADDR_LEN);
512 
513 	memcpy(&ppp->phy_info.peer_dl, &sdl, sizeof(sdl));
514 
515 	if (ppp_init(npppd_get_npppd(), ppp) != 0)
516 		goto fail;
517 	ppp->has_acf = 0;
518 
519 
520 	pppoe_session_log(_this, LOG_NOTICE, "logtype=PPPBind ppp=%d", ppp->id);
521 	ppp_start(ppp);
522 
523 	return 0;
524 fail:
525 	pppoe_session_log(_this, LOG_ERR, "failed binding ppp");
526 
527 	if (ppp != NULL)
528 		ppp_destroy(ppp);
529 	_this->ppp = NULL;
530 
531 	return 1;
532 }
533