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