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