1 /* $OpenBSD: pppoe_session.c,v 1.11 2015/12/05 16:10:31 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.11 2015/12/05 16:10:31 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 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 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 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 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 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 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 recieving 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 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 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 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 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 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 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 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 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 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