Annotation of sys/net/if_pppoe.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_pppoe.c,v 1.12 2007/05/28 06:31:01 mcbride Exp $ */
! 2: /* $NetBSD: if_pppoe.c,v 1.51 2003/11/28 08:56:48 keihan Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2002 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Martin Husemann <martin@NetBSD.org>.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: #include <sys/cdefs.h>
! 41: /*
! 42: __KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.51 2003/11/28 08:56:48 keihan Exp $");
! 43: */
! 44:
! 45: #include "pppoe.h"
! 46: #include "bpfilter.h"
! 47:
! 48: #include <sys/param.h>
! 49: #include <sys/systm.h>
! 50: #include <sys/kernel.h>
! 51: #include <sys/types.h>
! 52: #include <sys/timeout.h>
! 53: #include <sys/malloc.h>
! 54: #include <sys/mbuf.h>
! 55: #include <sys/socket.h>
! 56: #include <sys/syslog.h>
! 57: #include <sys/proc.h>
! 58: #include <sys/ioctl.h>
! 59: #include <net/if.h>
! 60: #include <net/if_types.h>
! 61: #include <net/if_sppp.h>
! 62: #include <net/if_pppoe.h>
! 63: #include <net/netisr.h>
! 64: #include <netinet/in.h>
! 65: #include <netinet/if_ether.h>
! 66:
! 67: /* for arc4random() */
! 68: #include <dev/rndvar.h>
! 69:
! 70: #if NBPFILTER > 0
! 71: #include <net/bpf.h>
! 72: #endif
! 73:
! 74: #undef PPPOE_DEBUG /* XXX - remove this or make it an option */
! 75:
! 76: #define PPPOEDEBUG(a) ((sc->sc_sppp.pp_if.if_flags & IFF_DEBUG) ? printf a : 0)
! 77:
! 78: struct pppoehdr {
! 79: u_int8_t vertype;
! 80: u_int8_t code;
! 81: u_int16_t session;
! 82: u_int16_t plen;
! 83: } __packed;
! 84:
! 85: struct pppoetag {
! 86: u_int16_t tag;
! 87: u_int16_t len;
! 88: } __packed;
! 89:
! 90: #define PPPOE_HEADERLEN sizeof(struct pppoehdr)
! 91: #define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */
! 92:
! 93: #define PPPOE_TAG_EOL 0x0000 /* end of list */
! 94: #define PPPOE_TAG_SNAME 0x0101 /* service name */
! 95: #define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */
! 96: #define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */
! 97: #define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */
! 98: #define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */
! 99: #define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */
! 100: #define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */
! 101: #define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */
! 102: #define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */
! 103:
! 104: #define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */
! 105: #define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */
! 106: #define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */
! 107: #define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */
! 108: #define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */
! 109:
! 110: /* two byte PPP protocol discriminator, then IP data */
! 111: #define PPPOE_MAXMTU (ETHERMTU - PPPOE_HEADERLEN - 2)
! 112:
! 113: /* Add a 16 bit unsigned value to a buffer pointed to by PTR */
! 114: #define PPPOE_ADD_16(PTR, VAL) \
! 115: *(PTR)++ = (VAL) / 256; \
! 116: *(PTR)++ = (VAL) % 256
! 117:
! 118: /* Add a complete PPPoE header to the buffer pointed to by PTR */
! 119: #define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN) \
! 120: *(PTR)++ = PPPOE_VERTYPE; \
! 121: *(PTR)++ = (CODE); \
! 122: PPPOE_ADD_16(PTR, SESS); \
! 123: PPPOE_ADD_16(PTR, LEN)
! 124:
! 125: #define PPPOE_DISC_TIMEOUT (hz*5) /* base for quick timeout calculation */
! 126: #define PPPOE_SLOW_RETRY (hz*60) /* persistent retry interval */
! 127: #define PPPOE_DISC_MAXPADI 4 /* retry PADI four times (quickly) */
! 128: #define PPPOE_DISC_MAXPADR 2 /* retry PADR twice */
! 129:
! 130: #ifdef PPPOE_SERVER
! 131: #define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */
! 132: #endif
! 133:
! 134: struct pppoe_softc {
! 135: struct sppp sc_sppp; /* contains a struct ifnet as first element */
! 136: LIST_ENTRY(pppoe_softc) sc_list;
! 137: struct ifnet *sc_eth_if; /* ethernet interface we are using */
! 138:
! 139: int sc_state; /* discovery phase or session connected */
! 140: struct ether_addr sc_dest; /* hardware address of concentrator */
! 141: u_int16_t sc_session; /* PPPoE session id */
! 142:
! 143: char *sc_service_name; /* if != NULL: requested name of service */
! 144: char *sc_concentrator_name; /* if != NULL: requested concentrator id */
! 145: u_int8_t *sc_ac_cookie; /* content of AC cookie we must echo back */
! 146: size_t sc_ac_cookie_len; /* length of cookie data */
! 147: #ifdef PPPOE_SERVER
! 148: u_int8_t *sc_hunique; /* content of host unique we must echo back */
! 149: size_t sc_hunique_len; /* length of host unique */
! 150: #endif
! 151: u_int32_t sc_unique; /* our unique id */
! 152: struct timeout sc_timeout; /* timeout while not in session state */
! 153: int sc_padi_retried; /* number of PADI retries already done */
! 154: int sc_padr_retried; /* number of PADR retries already done */
! 155:
! 156: struct timeval sc_session_time; /* time the session was established */
! 157: };
! 158:
! 159: /* incoming traffic will be queued here */
! 160: struct ifqueue ppoediscinq = { NULL };
! 161: struct ifqueue ppoeinq = { NULL };
! 162:
! 163: extern int sppp_ioctl(struct ifnet *, unsigned long, void *);
! 164:
! 165: /* input routines */
! 166: static void pppoe_disc_input(struct mbuf *);
! 167: static void pppoe_dispatch_disc_pkt(struct mbuf *, int);
! 168: static void pppoe_data_input(struct mbuf *);
! 169:
! 170: /* management routines */
! 171: void pppoeattach(int);
! 172: static int pppoe_connect(struct pppoe_softc *);
! 173: static int pppoe_disconnect(struct pppoe_softc *);
! 174: static void pppoe_abort_connect(struct pppoe_softc *);
! 175: static int pppoe_ioctl(struct ifnet *, unsigned long, caddr_t);
! 176: static void pppoe_tls(struct sppp *);
! 177: static void pppoe_tlf(struct sppp *);
! 178: static void pppoe_start(struct ifnet *);
! 179:
! 180: /* internal timeout handling */
! 181: static void pppoe_timeout(void *);
! 182:
! 183: /* sending actual protocol controll packets */
! 184: static int pppoe_send_padi(struct pppoe_softc *);
! 185: static int pppoe_send_padr(struct pppoe_softc *);
! 186: #ifdef PPPOE_SERVER
! 187: static int pppoe_send_pado(struct pppoe_softc *);
! 188: static int pppoe_send_pads(struct pppoe_softc *);
! 189: #endif
! 190: static int pppoe_send_padt(struct ifnet *, u_int, const u_int8_t *);
! 191:
! 192: /* raw output */
! 193: static int pppoe_output(struct pppoe_softc *, struct mbuf *);
! 194:
! 195: /* internal helper functions */
! 196: static struct pppoe_softc *pppoe_find_softc_by_session(u_int, struct ifnet *);
! 197: static struct pppoe_softc *pppoe_find_softc_by_hunique(u_int8_t *, size_t, struct ifnet *);
! 198: static struct mbuf *pppoe_get_mbuf(size_t len);
! 199:
! 200: LIST_HEAD(pppoe_softc_head, pppoe_softc) pppoe_softc_list;
! 201:
! 202: /* interface cloning */
! 203: int pppoe_clone_create(struct if_clone *, int);
! 204: int pppoe_clone_destroy(struct ifnet *);
! 205:
! 206: struct if_clone pppoe_cloner =
! 207: IF_CLONE_INITIALIZER("pppoe", pppoe_clone_create, pppoe_clone_destroy);
! 208:
! 209:
! 210: /* ARGSUSED */
! 211: void
! 212: pppoeattach(int count)
! 213: {
! 214: LIST_INIT(&pppoe_softc_list);
! 215: if_clone_attach(&pppoe_cloner);
! 216:
! 217: ppoediscinq.ifq_maxlen = IFQ_MAXLEN;
! 218: ppoeinq.ifq_maxlen = IFQ_MAXLEN;
! 219: }
! 220:
! 221: /* Create a new interface. */
! 222: int
! 223: pppoe_clone_create(struct if_clone *ifc, int unit)
! 224: {
! 225: struct pppoe_softc *sc;
! 226: int s;
! 227:
! 228: MALLOC(sc, struct pppoe_softc *, sizeof(*sc), M_DEVBUF, M_WAITOK);
! 229: if (sc == NULL)
! 230: return (ENOMEM);
! 231: bzero(sc, sizeof(struct pppoe_softc));
! 232:
! 233: sc->sc_unique = arc4random();
! 234:
! 235: snprintf(sc->sc_sppp.pp_if.if_xname,
! 236: sizeof(sc->sc_sppp.pp_if.if_xname),
! 237: "pppoe%d", unit);
! 238: sc->sc_sppp.pp_if.if_softc = sc;
! 239: sc->sc_sppp.pp_if.if_mtu = PPPOE_MAXMTU;
! 240: sc->sc_sppp.pp_if.if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
! 241: sc->sc_sppp.pp_if.if_type = IFT_PPP;
! 242: sc->sc_sppp.pp_if.if_hdrlen = sizeof(struct ether_header) + PPPOE_HEADERLEN;
! 243: sc->sc_sppp.pp_flags |= PP_KEEPALIVE | /* use LCP keepalive */
! 244: PP_NOFRAMING; /* no serial encapsulation */
! 245: sc->sc_sppp.pp_framebytes = PPPOE_HEADERLEN; /* framing added to ppp packets */
! 246: sc->sc_sppp.pp_if.if_ioctl = pppoe_ioctl;
! 247: sc->sc_sppp.pp_if.if_start = pppoe_start;
! 248: sc->sc_sppp.pp_tls = pppoe_tls;
! 249: sc->sc_sppp.pp_tlf = pppoe_tlf;
! 250: IFQ_SET_MAXLEN(&sc->sc_sppp.pp_if.if_snd, IFQ_MAXLEN);
! 251: IFQ_SET_READY(&sc->sc_sppp.pp_if.if_snd);
! 252:
! 253: /* changed to real address later */
! 254: memcpy(&sc->sc_dest, etherbroadcastaddr, sizeof(sc->sc_dest));
! 255:
! 256: /* init timer for interface watchdog */
! 257: timeout_set(&sc->sc_timeout, pppoe_timeout, sc);
! 258:
! 259: if_attach(&sc->sc_sppp.pp_if);
! 260: if_alloc_sadl(&sc->sc_sppp.pp_if);
! 261: sppp_attach(&sc->sc_sppp.pp_if);
! 262: #if NBPFILTER > 0
! 263: bpfattach(&sc->sc_sppp.pp_if.if_bpf, &sc->sc_sppp.pp_if, DLT_PPP_ETHER, 0);
! 264: #endif
! 265:
! 266: s = splnet();
! 267: LIST_INSERT_HEAD(&pppoe_softc_list, sc, sc_list);
! 268: splx(s);
! 269:
! 270: return (0);
! 271: }
! 272:
! 273: /* Destroy a given interface. */
! 274: int
! 275: pppoe_clone_destroy(struct ifnet *ifp)
! 276: {
! 277: struct pppoe_softc *sc = ifp->if_softc;
! 278: int s;
! 279:
! 280: s = splnet();
! 281: LIST_REMOVE(sc, sc_list);
! 282: timeout_del(&sc->sc_timeout);
! 283: splx(s);
! 284:
! 285: sppp_detach(&sc->sc_sppp.pp_if);
! 286: if_detach(ifp);
! 287:
! 288: if (sc->sc_concentrator_name)
! 289: free(sc->sc_concentrator_name, M_DEVBUF);
! 290: if (sc->sc_service_name)
! 291: free(sc->sc_service_name, M_DEVBUF);
! 292: if (sc->sc_ac_cookie)
! 293: free(sc->sc_ac_cookie, M_DEVBUF);
! 294:
! 295: free(sc, M_DEVBUF);
! 296:
! 297: return (0);
! 298: }
! 299:
! 300: /*
! 301: * Find the interface handling the specified session.
! 302: * Note: O(number of sessions open), this is a client-side only, mean
! 303: * and lean implementation, so number of open sessions typically should
! 304: * be 1.
! 305: */
! 306: static struct pppoe_softc *
! 307: pppoe_find_softc_by_session(u_int session, struct ifnet *rcvif)
! 308: {
! 309: struct pppoe_softc *sc;
! 310:
! 311: if (session == 0)
! 312: return (NULL);
! 313:
! 314: LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
! 315: if (sc->sc_state == PPPOE_STATE_SESSION
! 316: && sc->sc_session == session) {
! 317: if (sc->sc_eth_if == rcvif)
! 318: return (sc);
! 319: else
! 320: return (NULL);
! 321: }
! 322: }
! 323: return (NULL);
! 324: }
! 325:
! 326: /*
! 327: * Check host unique token passed and return appropriate softc pointer,
! 328: * or NULL if token is bogus.
! 329: */
! 330: static struct pppoe_softc *
! 331: pppoe_find_softc_by_hunique(u_int8_t *token, size_t len, struct ifnet *rcvif)
! 332: {
! 333: struct pppoe_softc *sc;
! 334: u_int32_t hunique;
! 335:
! 336: if (LIST_EMPTY(&pppoe_softc_list))
! 337: return (NULL);
! 338:
! 339: if (len != sizeof(hunique))
! 340: return (NULL);
! 341: memcpy(&hunique, token, len);
! 342:
! 343: LIST_FOREACH(sc, &pppoe_softc_list, sc_list)
! 344: if (sc->sc_unique == hunique)
! 345: break;
! 346:
! 347: if (sc == NULL) {
! 348: printf("pppoe: alien host unique tag, no session found\n");
! 349: return (NULL);
! 350: }
! 351:
! 352: /* should be safe to access *sc now */
! 353: if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) {
! 354: printf("%s: host unique tag found, but it belongs to a connection in state %d\n",
! 355: sc->sc_sppp.pp_if.if_xname, sc->sc_state);
! 356: return (NULL);
! 357: }
! 358: if (sc->sc_eth_if != rcvif) {
! 359: printf("%s: wrong interface, not accepting host unique\n",
! 360: sc->sc_sppp.pp_if.if_xname);
! 361: return (NULL);
! 362: }
! 363: return (sc);
! 364: }
! 365:
! 366: /* Interface interrupt handler routine. */
! 367: void
! 368: pppoeintr(void)
! 369: {
! 370: struct pppoe_softc *sc;
! 371: struct mbuf *m;
! 372:
! 373: splassert(IPL_SOFTNET);
! 374:
! 375: LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
! 376: while (ppoediscinq.ifq_head) {
! 377: MBUFLOCK(IF_DEQUEUE(&ppoediscinq, m););
! 378: if (m == NULL)
! 379: break;
! 380: pppoe_disc_input(m);
! 381: }
! 382:
! 383: while (ppoeinq.ifq_head) {
! 384: MBUFLOCK(IF_DEQUEUE(&ppoeinq, m););
! 385: if (m == NULL)
! 386: break;
! 387: pppoe_data_input(m);
! 388: }
! 389: }
! 390: }
! 391:
! 392: /* Analyze and handle a single received packet while not in session state. */
! 393: static void pppoe_dispatch_disc_pkt(struct mbuf *m, int off)
! 394: {
! 395: struct pppoe_softc *sc;
! 396: struct pppoehdr *ph;
! 397: struct pppoetag *pt;
! 398: struct mbuf *n;
! 399: struct ether_header *eh;
! 400: const char *err_msg, *devname;
! 401: size_t ac_cookie_len;
! 402: int noff, err, errortag;
! 403: u_int16_t tag, len;
! 404: u_int16_t session, plen;
! 405: u_int8_t *ac_cookie;
! 406: #ifdef PPPOE_SERVER
! 407: u_int8_t *hunique;
! 408: size_t hunique_len;
! 409: #endif
! 410:
! 411: err_msg = NULL;
! 412: devname = "pppoe";
! 413: errortag = 0;
! 414:
! 415: if (m->m_len < sizeof(*eh)) {
! 416: m = m_pullup(m, sizeof(*eh));
! 417: if (m == NULL)
! 418: goto done;
! 419: }
! 420: eh = mtod(m, struct ether_header *);
! 421: off += sizeof(*eh);
! 422:
! 423: ac_cookie = NULL;
! 424: ac_cookie_len = 0;
! 425: #ifdef PPPOE_SERVER
! 426: hunique = NULL;
! 427: hunique_len = 0;
! 428: #endif
! 429:
! 430: session = 0;
! 431: if (m->m_pkthdr.len - off <= PPPOE_HEADERLEN) {
! 432: printf("pppoe: packet too short: %d\n", m->m_pkthdr.len);
! 433: goto done;
! 434: }
! 435:
! 436: n = m_pulldown(m, off, sizeof(*ph), &noff);
! 437: if (n == NULL) {
! 438: printf("pppoe: could not get PPPoE header\n");
! 439: m = NULL;
! 440: goto done;
! 441: }
! 442: ph = (struct pppoehdr *)(mtod(n, caddr_t) + noff);
! 443: if (ph->vertype != PPPOE_VERTYPE) {
! 444: printf("pppoe: unknown version/type packet: 0x%x\n",
! 445: ph->vertype);
! 446: goto done;
! 447: }
! 448:
! 449: session = ntohs(ph->session);
! 450: plen = ntohs(ph->plen);
! 451: off += sizeof(*ph);
! 452: if (plen + off > m->m_pkthdr.len) {
! 453: printf("pppoe: packet content does not fit: data available = %d, packet size = %u\n",
! 454: m->m_pkthdr.len - off, plen);
! 455: goto done;
! 456: }
! 457:
! 458: /* ignore trailing garbage */
! 459: m_adj(m, off + plen - m->m_pkthdr.len);
! 460:
! 461: tag = 0;
! 462: len = 0;
! 463: sc = NULL;
! 464: while (off + sizeof(*pt) <= m->m_pkthdr.len) {
! 465: n = m_pulldown(m, off, sizeof(*pt), &noff);
! 466: if (n == NULL) {
! 467: printf("%s: parse error\n", devname);
! 468: m = NULL;
! 469: goto done;
! 470: }
! 471: pt = (struct pppoetag *)(mtod(n, caddr_t) + noff);
! 472: tag = ntohs(pt->tag);
! 473: len = ntohs(pt->len);
! 474: if (off + len > m->m_pkthdr.len) {
! 475: printf("%s: tag 0x%x len 0x%x is too long\n",
! 476: devname, tag, len);
! 477: goto done;
! 478: }
! 479: switch (tag) {
! 480: case PPPOE_TAG_EOL:
! 481: goto breakbreak;
! 482: case PPPOE_TAG_SNAME:
! 483: break; /* ignored */
! 484: case PPPOE_TAG_ACNAME:
! 485: break; /* ignored */
! 486: case PPPOE_TAG_HUNIQUE:
! 487: if (sc != NULL)
! 488: break;
! 489: n = m_pulldown(m, off + sizeof(*pt), len, &noff);
! 490: if (n == NULL) {
! 491: m = NULL;
! 492: err_msg = "TAG HUNIQUE ERROR";
! 493: break;
! 494: }
! 495: #ifdef PPPOE_SERVER
! 496: hunique = mtod(n, caddr_t) + noff;
! 497: hunique_len = len;
! 498: #endif
! 499: sc = pppoe_find_softc_by_hunique(mtod(n, caddr_t) + noff,
! 500: len, m->m_pkthdr.rcvif);
! 501: if (sc != NULL)
! 502: devname = sc->sc_sppp.pp_if.if_xname;
! 503: break;
! 504: case PPPOE_TAG_ACCOOKIE:
! 505: if (ac_cookie == NULL) {
! 506: n = m_pulldown(m, off + sizeof(*pt), len,
! 507: &noff);
! 508: if (n == NULL) {
! 509: err_msg = "TAG ACCOOKIE ERROR";
! 510: m = NULL;
! 511: break;
! 512: }
! 513: ac_cookie = mtod(n, caddr_t) + noff;
! 514: ac_cookie_len = len;
! 515: }
! 516: break;
! 517: case PPPOE_TAG_SNAME_ERR:
! 518: err_msg = "SERVICE NAME ERROR";
! 519: errortag = 1;
! 520: break;
! 521: case PPPOE_TAG_ACSYS_ERR:
! 522: err_msg = "AC SYSTEM ERROR";
! 523: errortag = 1;
! 524: break;
! 525: case PPPOE_TAG_GENERIC_ERR:
! 526: err_msg = "GENERIC ERROR";
! 527: errortag = 1;
! 528: break;
! 529: }
! 530: if (err_msg) {
! 531: log(LOG_INFO, "%s: %s: ", devname, err_msg);
! 532: if (errortag && len) {
! 533: n = m_pulldown(m, off + sizeof(*pt), len,
! 534: &noff);
! 535: if (n) {
! 536: u_int8_t *et = mtod(n, caddr_t) + noff;
! 537: while (len--)
! 538: addlog("%c", *et++);
! 539: }
! 540: }
! 541: addlog("\n");
! 542: goto done;
! 543: }
! 544: off += sizeof(*pt) + len;
! 545: }
! 546: breakbreak:
! 547: switch (ph->code) {
! 548: case PPPOE_CODE_PADI:
! 549: #ifdef PPPOE_SERVER
! 550: /*
! 551: * Got service name, concentrator name, and/or host unique.
! 552: * Ignore if we have no interfaces with IFF_PASSIVE|IFF_UP.
! 553: */
! 554: if (LIST_EMPTY(&pppoe_softc_list))
! 555: goto done;
! 556:
! 557: LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
! 558: if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP))
! 559: continue;
! 560: if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE))
! 561: continue;
! 562: if (sc->sc_state == PPPOE_STATE_INITIAL)
! 563: break;
! 564: }
! 565: if (sc == NULL) {
! 566: #ifdef PPPOE_DEBUG
! 567: printf("pppoe: free passive interface is not found\n");
! 568: #endif
! 569: goto done;
! 570: }
! 571: if (hunique) {
! 572: if (sc->sc_hunique)
! 573: free(sc->sc_hunique, M_DEVBUF);
! 574: sc->sc_hunique = malloc(hunique_len, M_DEVBUF,
! 575: M_DONTWAIT);
! 576: if (sc->sc_hunique == NULL)
! 577: goto done;
! 578: sc->sc_hunique_len = hunique_len;
! 579: memcpy(sc->sc_hunique, hunique, hunique_len);
! 580: }
! 581:
! 582: memcpy(&sc->sc_dest, eh->ether_shost, sizeof(sc->sc_dest));
! 583: sc->sc_state = PPPOE_STATE_PADO_SENT;
! 584: pppoe_send_pado(sc);
! 585:
! 586: break;
! 587: #endif /* PPPOE_SERVER */
! 588: case PPPOE_CODE_PADR:
! 589: #ifdef PPPOE_SERVER
! 590: /*
! 591: * Get sc from ac_cookie if IFF_PASSIVE.
! 592: */
! 593: if (ac_cookie == NULL) {
! 594: /* be quiet if there is not a single pppoe instance */
! 595: printf("pppoe: received PADR but not includes ac_cookie\n");
! 596: goto done;
! 597: }
! 598:
! 599: sc = pppoe_find_softc_by_hunique(ac_cookie,
! 600: ac_cookie_len,
! 601: m->m_pkthdr.rcvif);
! 602: if (sc == NULL) {
! 603: /* be quiet if there is not a single pppoe instance */
! 604: if (!LIST_EMPTY(&pppoe_softc_list))
! 605: printf("pppoe: received PADR but could not find request for it\n");
! 606: goto done;
! 607: }
! 608: if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
! 609: printf("%s: received unexpected PADR\n",
! 610: sc->sc_sppp.pp_if.if_xname);
! 611: goto done;
! 612: }
! 613: if (hunique) {
! 614: if (sc->sc_hunique)
! 615: free(sc->sc_hunique, M_DEVBUF);
! 616: sc->sc_hunique = malloc(hunique_len, M_DEVBUF,
! 617: M_DONTWAIT);
! 618: if (sc->sc_hunique == NULL)
! 619: goto done;
! 620: sc->sc_hunique_len = hunique_len;
! 621: memcpy(sc->sc_hunique, hunique, hunique_len);
! 622: }
! 623:
! 624: pppoe_send_pads(sc);
! 625: sc->sc_state = PPPOE_STATE_SESSION;
! 626: sc->sc_sppp.pp_up(&sc->sc_sppp);
! 627:
! 628: break;
! 629: #else
! 630: /* ignore, we are no access concentrator */
! 631: goto done;
! 632: #endif /* PPPOE_SERVER */
! 633: case PPPOE_CODE_PADO:
! 634: if (sc == NULL) {
! 635: /* be quiet if there is not a single pppoe instance */
! 636: if (!LIST_EMPTY(&pppoe_softc_list))
! 637: printf("pppoe: received PADO but could not find request for it\n");
! 638: goto done;
! 639: }
! 640: if (sc->sc_state != PPPOE_STATE_PADI_SENT) {
! 641: printf("%s: received unexpected PADO\n",
! 642: sc->sc_sppp.pp_if.if_xname);
! 643: goto done;
! 644: }
! 645: if (ac_cookie) {
! 646: if (sc->sc_ac_cookie)
! 647: free(sc->sc_ac_cookie, M_DEVBUF);
! 648: sc->sc_ac_cookie = malloc(ac_cookie_len, M_DEVBUF,
! 649: M_DONTWAIT);
! 650: if (sc->sc_ac_cookie == NULL)
! 651: goto done;
! 652: sc->sc_ac_cookie_len = ac_cookie_len;
! 653: memcpy(sc->sc_ac_cookie, ac_cookie, ac_cookie_len);
! 654: }
! 655:
! 656: memcpy(&sc->sc_dest, eh->ether_shost, sizeof(sc->sc_dest));
! 657: timeout_del(&sc->sc_timeout);
! 658: sc->sc_padr_retried = 0;
! 659: sc->sc_state = PPPOE_STATE_PADR_SENT;
! 660: if ((err = pppoe_send_padr(sc)) != 0) {
! 661: PPPOEDEBUG(("%s: failed to send PADR, error=%d\n",
! 662: sc->sc_sppp.pp_if.if_xname, err));
! 663: }
! 664: timeout_add(&sc->sc_timeout,
! 665: PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried));
! 666:
! 667: break;
! 668: case PPPOE_CODE_PADS:
! 669: if (sc == NULL)
! 670: goto done;
! 671:
! 672: sc->sc_session = session;
! 673: timeout_del(&sc->sc_timeout);
! 674: PPPOEDEBUG(("%s: session 0x%x connected\n",
! 675: sc->sc_sppp.pp_if.if_xname, session));
! 676: sc->sc_state = PPPOE_STATE_SESSION;
! 677: microtime(&sc->sc_session_time);
! 678: sc->sc_sppp.pp_up(&sc->sc_sppp); /* notify upper layers */
! 679:
! 680: break;
! 681: case PPPOE_CODE_PADT:
! 682: if (sc == NULL)
! 683: goto done;
! 684:
! 685: /* stop timer (we might be about to transmit a PADT ourself) */
! 686: timeout_del(&sc->sc_timeout);
! 687: PPPOEDEBUG(("%s: session 0x%x terminated, received PADT\n",
! 688: sc->sc_sppp.pp_if.if_xname, session));
! 689:
! 690: /* clean up softc */
! 691: sc->sc_state = PPPOE_STATE_INITIAL;
! 692: memcpy(&sc->sc_dest, etherbroadcastaddr, sizeof(sc->sc_dest));
! 693: if (sc->sc_ac_cookie) {
! 694: free(sc->sc_ac_cookie, M_DEVBUF);
! 695: sc->sc_ac_cookie = NULL;
! 696: }
! 697: sc->sc_ac_cookie_len = 0;
! 698: sc->sc_session = 0;
! 699: sc->sc_session_time.tv_sec = 0;
! 700: sc->sc_session_time.tv_usec = 0;
! 701: sc->sc_sppp.pp_down(&sc->sc_sppp); /* signal upper layer */
! 702:
! 703: break;
! 704: default:
! 705: printf("%s: unknown code (0x%04x) session = 0x%04x\n",
! 706: sc ? sc->sc_sppp.pp_if.if_xname : "pppoe",
! 707: ph->code, session);
! 708: break;
! 709: }
! 710:
! 711: done:
! 712: m_freem(m);
! 713: }
! 714:
! 715: /* Input function for discovery packets. */
! 716: static void
! 717: pppoe_disc_input(struct mbuf *m)
! 718: {
! 719: /* avoid error messages if there is not a single pppoe instance */
! 720: if (!LIST_EMPTY(&pppoe_softc_list)) {
! 721: KASSERT(m->m_flags & M_PKTHDR);
! 722: pppoe_dispatch_disc_pkt(m, 0);
! 723: } else
! 724: m_freem(m);
! 725: }
! 726:
! 727: /* Input function for data packets */
! 728: static void
! 729: pppoe_data_input(struct mbuf *m)
! 730: {
! 731: struct pppoe_softc *sc;
! 732: struct pppoehdr *ph;
! 733: u_int16_t session, plen;
! 734: #ifdef PPPOE_TERM_UNKNOWN_SESSIONS
! 735: u_int8_t shost[ETHER_ADDR_LEN];
! 736: #endif
! 737:
! 738: KASSERT(m->m_flags & M_PKTHDR);
! 739:
! 740: #ifdef PPPOE_TERM_UNKNOWN_SESSIONS
! 741: memcpy(shost, mtod(m, struct ether_header*)->ether_shost, ETHER_ADDR_LEN);
! 742: #endif
! 743: m_adj(m, sizeof(struct ether_header));
! 744: if (m->m_pkthdr.len <= PPPOE_HEADERLEN) {
! 745: printf("pppoe (data): dropping too short packet: %d bytes\n",
! 746: m->m_pkthdr.len);
! 747: goto drop;
! 748: }
! 749: if (m->m_len < sizeof(*ph)) {
! 750: m = m_pullup(m, sizeof(*ph));
! 751: if (m == NULL) {
! 752: printf("pppoe (data): could not get PPPoE header\n");
! 753: return;
! 754: }
! 755: }
! 756: ph = mtod(m, struct pppoehdr *);
! 757: if (ph->vertype != PPPOE_VERTYPE) {
! 758: printf("pppoe (data): unknown version/type packet: 0x%x\n",
! 759: ph->vertype);
! 760: goto drop;
! 761: }
! 762: if (ph->code != 0)
! 763: goto drop;
! 764:
! 765: session = ntohs(ph->session);
! 766: sc = pppoe_find_softc_by_session(session, m->m_pkthdr.rcvif);
! 767: if (sc == NULL) {
! 768: #ifdef PPPOE_TERM_UNKNOWN_SESSIONS
! 769: printf("pppoe (data): input for unknown session 0x%x, sending PADT\n",
! 770: session);
! 771: pppoe_send_padt(m->m_pkthdr.rcvif, session, shost);
! 772: #endif
! 773: goto drop;
! 774: }
! 775:
! 776: plen = ntohs(ph->plen);
! 777:
! 778: #if NBPFILTER > 0
! 779: if(sc->sc_sppp.pp_if.if_bpf)
! 780: bpf_mtap(sc->sc_sppp.pp_if.if_bpf, m, BPF_DIRECTION_IN);
! 781: #endif
! 782:
! 783: m_adj(m, PPPOE_HEADERLEN);
! 784:
! 785: #ifdef PPPOE_DEBUG
! 786: {
! 787: struct mbuf *p;
! 788:
! 789: printf("%s: pkthdr.len=%d, pppoe.len=%d",
! 790: sc->sc_sppp.pp_if.if_xname,
! 791: m->m_pkthdr.len, plen);
! 792: p = m;
! 793: while (p) {
! 794: printf(" l=%d", p->m_len);
! 795: p = p->m_next;
! 796: }
! 797: printf("\n");
! 798: }
! 799: #endif
! 800:
! 801: if (m->m_pkthdr.len < plen)
! 802: goto drop;
! 803:
! 804: /* fix incoming interface pointer (not the raw ethernet interface anymore) */
! 805: m->m_pkthdr.rcvif = &sc->sc_sppp.pp_if;
! 806:
! 807: /* pass packet up and account for it */
! 808: sc->sc_sppp.pp_if.if_ipackets++;
! 809: sppp_input(&sc->sc_sppp.pp_if, m);
! 810: return;
! 811:
! 812: drop:
! 813: m_freem(m);
! 814: }
! 815:
! 816: static int
! 817: pppoe_output(struct pppoe_softc *sc, struct mbuf *m)
! 818: {
! 819: struct sockaddr dst;
! 820: struct ether_header *eh;
! 821: u_int16_t etype;
! 822:
! 823: if (sc->sc_eth_if == NULL) {
! 824: m_freem(m);
! 825: return (EIO);
! 826: }
! 827:
! 828: if ((sc->sc_eth_if->if_flags & (IFF_UP|IFF_RUNNING))
! 829: != (IFF_UP|IFF_RUNNING)) {
! 830: m_freem(m);
! 831: return (ENETDOWN);
! 832: }
! 833:
! 834: memset(&dst, 0, sizeof dst);
! 835: dst.sa_family = AF_UNSPEC;
! 836: eh = (struct ether_header*)&dst.sa_data;
! 837: etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHERTYPE_PPPOE : ETHERTYPE_PPPOEDISC;
! 838: eh->ether_type = htons(etype);
! 839: memcpy(&eh->ether_dhost, &sc->sc_dest, sizeof sc->sc_dest);
! 840:
! 841: PPPOEDEBUG(("%s (%x) state=%d, session=0x%x output -> %s, len=%d\n",
! 842: sc->sc_sppp.pp_if.if_xname, etype,
! 843: sc->sc_state, sc->sc_session,
! 844: ether_sprintf((unsigned char *)&sc->sc_dest), m->m_pkthdr.len));
! 845:
! 846: m->m_flags &= ~(M_BCAST|M_MCAST);
! 847: sc->sc_sppp.pp_if.if_opackets++;
! 848: return (sc->sc_eth_if->if_output(sc->sc_eth_if, m, &dst, NULL));
! 849: }
! 850:
! 851: /* The ioctl routine. */
! 852: static int
! 853: pppoe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
! 854: {
! 855: struct proc *p = curproc; /* XXX */
! 856: struct pppoe_softc *sc = (struct pppoe_softc *)ifp;
! 857: int error = 0;
! 858:
! 859: switch (cmd) {
! 860: case PPPOESETPARMS:
! 861: {
! 862: struct pppoediscparms *parms = (struct pppoediscparms *)data;
! 863: int len;
! 864:
! 865: if ((error = suser(p, p->p_acflag)) != 0)
! 866: return (error);
! 867: if (parms->eth_ifname[0] != '\0') {
! 868: sc->sc_eth_if = ifunit(parms->eth_ifname);
! 869: if (sc->sc_eth_if == NULL)
! 870: return (ENXIO);
! 871: }
! 872:
! 873: if (sc->sc_concentrator_name)
! 874: free(sc->sc_concentrator_name, M_DEVBUF);
! 875: sc->sc_concentrator_name = NULL;
! 876:
! 877: len = strlen(parms->ac_name);
! 878: if (len > 0 && len < sizeof(parms->ac_name)) {
! 879: char *p = malloc(len + 1, M_DEVBUF, M_WAITOK);
! 880: if (p == NULL)
! 881: return (ENOMEM);
! 882: strlcpy(p, parms->ac_name, len + 1);
! 883: sc->sc_concentrator_name = p;
! 884: }
! 885:
! 886: if (sc->sc_service_name)
! 887: free(sc->sc_service_name, M_DEVBUF);
! 888: sc->sc_service_name = NULL;
! 889:
! 890: len = strlen(parms->service_name);
! 891: if (len > 0 && len < sizeof(parms->service_name)) {
! 892: char *p = malloc(len + 1, M_DEVBUF, M_WAITOK);
! 893: if (p == NULL)
! 894: return (ENOMEM);
! 895: strlcpy(p, parms->service_name, len + 1);
! 896: sc->sc_service_name = p;
! 897: }
! 898: return (0);
! 899: }
! 900: break;
! 901: case PPPOEGETPARMS:
! 902: {
! 903: struct pppoediscparms *parms = (struct pppoediscparms *)data;
! 904:
! 905: if (sc->sc_eth_if)
! 906: strlcpy(parms->eth_ifname, sc->sc_eth_if->if_xname,
! 907: IFNAMSIZ);
! 908: else
! 909: parms->eth_ifname[0] = '\0';
! 910:
! 911: if (sc->sc_concentrator_name)
! 912: strlcpy(parms->ac_name, sc->sc_concentrator_name,
! 913: sizeof(parms->ac_name));
! 914: else
! 915: parms->ac_name[0] = '\0';
! 916:
! 917: if (sc->sc_service_name)
! 918: strlcpy(parms->service_name, sc->sc_service_name,
! 919: sizeof(parms->service_name));
! 920: else
! 921: parms->service_name[0] = '\0';
! 922:
! 923: return (0);
! 924: }
! 925: break;
! 926: case PPPOEGETSESSION:
! 927: {
! 928: struct pppoeconnectionstate *state =
! 929: (struct pppoeconnectionstate *)data;
! 930: state->state = sc->sc_state;
! 931: state->session_id = sc->sc_session;
! 932: state->padi_retry_no = sc->sc_padi_retried;
! 933: state->padr_retry_no = sc->sc_padr_retried;
! 934: state->session_time.tv_sec = sc->sc_session_time.tv_sec;
! 935: state->session_time.tv_usec = sc->sc_session_time.tv_usec;
! 936: return (0);
! 937: }
! 938: break;
! 939: case SIOCSIFFLAGS:
! 940: {
! 941: struct ifreq *ifr = (struct ifreq *)data;
! 942: /*
! 943: * Prevent running re-establishment timers overriding
! 944: * administrators choice.
! 945: */
! 946: if ((ifr->ifr_flags & IFF_UP) == 0
! 947: && sc->sc_state >= PPPOE_STATE_PADI_SENT
! 948: && sc->sc_state < PPPOE_STATE_SESSION) {
! 949: timeout_del(&sc->sc_timeout);
! 950: sc->sc_state = PPPOE_STATE_INITIAL;
! 951: sc->sc_padi_retried = 0;
! 952: sc->sc_padr_retried = 0;
! 953: memcpy(&sc->sc_dest, etherbroadcastaddr,
! 954: sizeof(sc->sc_dest));
! 955: }
! 956: return (sppp_ioctl(ifp, cmd, data));
! 957: }
! 958: case SIOCSIFMTU:
! 959: {
! 960: struct ifreq *ifr = (struct ifreq *)data;
! 961:
! 962: if (ifr->ifr_mtu > PPPOE_MAXMTU)
! 963: return (EINVAL);
! 964: return (sppp_ioctl(ifp, cmd, data));
! 965: }
! 966: default:
! 967: return (sppp_ioctl(ifp, cmd, data));
! 968: }
! 969: return (0);
! 970: }
! 971:
! 972: /*
! 973: * Allocate a mbuf/cluster with space to store the given data length
! 974: * of payload, leaving space for prepending an ethernet header
! 975: * in front.
! 976: */
! 977: static struct mbuf *
! 978: pppoe_get_mbuf(size_t len)
! 979: {
! 980: struct mbuf *m;
! 981:
! 982: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 983: if (m == NULL)
! 984: return (NULL);
! 985: if (len + sizeof(struct ether_header) > MHLEN) {
! 986: MCLGET(m, M_DONTWAIT);
! 987: if ((m->m_flags & M_EXT) == 0) {
! 988: struct mbuf *n;
! 989:
! 990: MFREE(m, n);
! 991: return (NULL);
! 992: }
! 993: }
! 994: m->m_data += sizeof(struct ether_header);
! 995: m->m_len = len;
! 996: m->m_pkthdr.len = len;
! 997: m->m_pkthdr.rcvif = NULL;
! 998:
! 999: return (m);
! 1000: }
! 1001:
! 1002: /* Send PADI. */
! 1003: static int
! 1004: pppoe_send_padi(struct pppoe_softc *sc)
! 1005: {
! 1006: struct mbuf *m0;
! 1007: int len, l1 = 0, l2 = 0; /* XXX: gcc */
! 1008: u_int8_t *p;
! 1009:
! 1010: if (sc->sc_state > PPPOE_STATE_PADI_SENT)
! 1011: panic("pppoe_send_padi in state %d", sc->sc_state);
! 1012:
! 1013: /* calculate length of frame (excluding ethernet header + pppoe header) */
! 1014: len = 2 + 2 + 2 + 2 + sizeof(sc->sc_unique); /* service name tag is required, host unique is send too */
! 1015: if (sc->sc_service_name != NULL) {
! 1016: l1 = strlen(sc->sc_service_name);
! 1017: len += l1;
! 1018: }
! 1019: if (sc->sc_concentrator_name != NULL) {
! 1020: l2 = strlen(sc->sc_concentrator_name);
! 1021: len += 2 + 2 + l2;
! 1022: }
! 1023:
! 1024: /* allocate a buffer */
! 1025: m0 = pppoe_get_mbuf(len + PPPOE_HEADERLEN); /* header len + payload len */
! 1026: if (m0 == NULL)
! 1027: return (ENOBUFS);
! 1028:
! 1029: /* fill in pkt */
! 1030: p = mtod(m0, u_int8_t *);
! 1031: PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, len);
! 1032: PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
! 1033: if (sc->sc_service_name != NULL) {
! 1034: PPPOE_ADD_16(p, l1);
! 1035: memcpy(p, sc->sc_service_name, l1);
! 1036: p += l1;
! 1037: } else {
! 1038: PPPOE_ADD_16(p, 0);
! 1039: }
! 1040: if (sc->sc_concentrator_name != NULL) {
! 1041: PPPOE_ADD_16(p, PPPOE_TAG_ACNAME);
! 1042: PPPOE_ADD_16(p, l2);
! 1043: memcpy(p, sc->sc_concentrator_name, l2);
! 1044: p += l2;
! 1045: }
! 1046: PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
! 1047: PPPOE_ADD_16(p, sizeof(sc->sc_unique));
! 1048: memcpy(p, &sc->sc_unique, sizeof(sc->sc_unique));
! 1049:
! 1050: #ifdef PPPOE_DEBUG
! 1051: p += sizeof(sc->sc_unique);
! 1052: if (p - mtod(m0, u_int8_t *) != len + PPPOE_HEADERLEN)
! 1053: panic("pppoe_send_padi: garbled output len, should be %ld, is %ld",
! 1054: (long)(len + PPPOE_HEADERLEN), (long)(p - mtod(m0, u_int8_t *)));
! 1055: #endif
! 1056:
! 1057: /* send pkt */
! 1058: return (pppoe_output(sc, m0));
! 1059: }
! 1060:
! 1061: /* Watchdog function. */
! 1062: static void
! 1063: pppoe_timeout(void *arg)
! 1064: {
! 1065: struct pppoe_softc *sc = (struct pppoe_softc *)arg;
! 1066: int x, retry_wait, err;
! 1067:
! 1068: PPPOEDEBUG(("%s: timeout\n", sc->sc_sppp.pp_if.if_xname));
! 1069:
! 1070: switch (sc->sc_state) {
! 1071: case PPPOE_STATE_PADI_SENT:
! 1072: /*
! 1073: * We have two basic ways of retrying:
! 1074: * - Quick retry mode: try a few times in short sequence
! 1075: * - Slow retry mode: we already had a connection successfully
! 1076: * established and will try infinitely (without user
! 1077: * intervention)
! 1078: * We only enter slow retry mode if IFF_LINK1 (aka autodial)
! 1079: * is not set.
! 1080: */
! 1081:
! 1082: /* initialize for quick retry mode */
! 1083: retry_wait = PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried);
! 1084:
! 1085: x = splnet();
! 1086: sc->sc_padi_retried++;
! 1087: if (sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) {
! 1088: if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) {
! 1089: /* slow retry mode */
! 1090: retry_wait = PPPOE_SLOW_RETRY;
! 1091: } else {
! 1092: pppoe_abort_connect(sc);
! 1093: splx(x);
! 1094: return;
! 1095: }
! 1096: }
! 1097: if ((err = pppoe_send_padi(sc)) != 0) {
! 1098: sc->sc_padi_retried--;
! 1099: PPPOEDEBUG(("%s: failed to transmit PADI, error=%d\n",
! 1100: sc->sc_sppp.pp_if.if_xname, err));
! 1101: }
! 1102: timeout_add(&sc->sc_timeout, retry_wait);
! 1103: splx(x);
! 1104:
! 1105: break;
! 1106: case PPPOE_STATE_PADR_SENT:
! 1107: x = splnet();
! 1108: sc->sc_padr_retried++;
! 1109: if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) {
! 1110: memcpy(&sc->sc_dest, etherbroadcastaddr,
! 1111: sizeof(sc->sc_dest));
! 1112: sc->sc_state = PPPOE_STATE_PADI_SENT;
! 1113: sc->sc_padr_retried = 0;
! 1114: if ((err = pppoe_send_padi(sc)) != 0) {
! 1115: PPPOEDEBUG(("%s: failed to send PADI, error=%d\n",
! 1116: sc->sc_sppp.pp_if.if_xname, err));
! 1117: }
! 1118: timeout_add(&sc->sc_timeout,
! 1119: PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried));
! 1120: splx(x);
! 1121: return;
! 1122: }
! 1123: if ((err = pppoe_send_padr(sc)) != 0) {
! 1124: sc->sc_padr_retried--;
! 1125: PPPOEDEBUG(("%s: failed to send PADR, error=%d\n",
! 1126: sc->sc_sppp.pp_if.if_xname, err));
! 1127: }
! 1128: timeout_add(&sc->sc_timeout,
! 1129: PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried));
! 1130: splx(x);
! 1131:
! 1132: break;
! 1133: case PPPOE_STATE_CLOSING:
! 1134: pppoe_disconnect(sc);
! 1135: break;
! 1136: default:
! 1137: return; /* all done, work in peace */
! 1138: }
! 1139: }
! 1140:
! 1141: /* Start a connection (i.e. initiate discovery phase). */
! 1142: static int
! 1143: pppoe_connect(struct pppoe_softc *sc)
! 1144: {
! 1145: int x, err;
! 1146:
! 1147: if (sc->sc_state != PPPOE_STATE_INITIAL)
! 1148: return (EBUSY);
! 1149:
! 1150: #ifdef PPPOE_SERVER
! 1151: /* wait for PADI if IFF_PASSIVE */
! 1152: if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE))
! 1153: return (0);
! 1154: #endif
! 1155: x = splnet();
! 1156:
! 1157: /* save state, in case we fail to send PADI */
! 1158: sc->sc_state = PPPOE_STATE_PADI_SENT;
! 1159: sc->sc_padr_retried = 0;
! 1160: err = pppoe_send_padi(sc);
! 1161: if (err != 0)
! 1162: PPPOEDEBUG(("%s: failed to send PADI, error=%d\n",
! 1163: sc->sc_sppp.pp_if.if_xname, err));
! 1164:
! 1165: timeout_add(&sc->sc_timeout, PPPOE_DISC_TIMEOUT);
! 1166: splx(x);
! 1167:
! 1168: return (err);
! 1169: }
! 1170:
! 1171: /* disconnect */
! 1172: static int
! 1173: pppoe_disconnect(struct pppoe_softc *sc)
! 1174: {
! 1175: int err, x;
! 1176:
! 1177: x = splnet();
! 1178:
! 1179: if (sc->sc_state < PPPOE_STATE_SESSION)
! 1180: err = EBUSY;
! 1181: else {
! 1182: PPPOEDEBUG(("%s: disconnecting\n",
! 1183: sc->sc_sppp.pp_if.if_xname));
! 1184: err = pppoe_send_padt(sc->sc_eth_if, sc->sc_session, (const u_int8_t *)&sc->sc_dest);
! 1185: }
! 1186:
! 1187: /* cleanup softc */
! 1188: sc->sc_state = PPPOE_STATE_INITIAL;
! 1189: memcpy(&sc->sc_dest, etherbroadcastaddr, sizeof(sc->sc_dest));
! 1190: if (sc->sc_ac_cookie) {
! 1191: free(sc->sc_ac_cookie, M_DEVBUF);
! 1192: sc->sc_ac_cookie = NULL;
! 1193: }
! 1194: sc->sc_ac_cookie_len = 0;
! 1195: #ifdef PPPOE_SERVER
! 1196: if (sc->sc_hunique) {
! 1197: free(sc->sc_hunique, M_DEVBUF);
! 1198: sc->sc_hunique = NULL;
! 1199: }
! 1200: sc->sc_hunique_len = 0;
! 1201: #endif
! 1202: sc->sc_session = 0;
! 1203:
! 1204: /* notify upper layer */
! 1205: sc->sc_sppp.pp_down(&sc->sc_sppp);
! 1206:
! 1207: splx(x);
! 1208:
! 1209: return (err);
! 1210: }
! 1211:
! 1212: /* Connection attempt aborted. */
! 1213: static void
! 1214: pppoe_abort_connect(struct pppoe_softc *sc)
! 1215: {
! 1216: printf("%s: could not establish connection\n",
! 1217: sc->sc_sppp.pp_if.if_xname);
! 1218: sc->sc_state = PPPOE_STATE_CLOSING;
! 1219:
! 1220: /* notify upper layer */
! 1221: sc->sc_sppp.pp_down(&sc->sc_sppp);
! 1222:
! 1223: /* clear connection state */
! 1224: memcpy(&sc->sc_dest, etherbroadcastaddr, sizeof(sc->sc_dest));
! 1225: sc->sc_state = PPPOE_STATE_INITIAL;
! 1226: }
! 1227:
! 1228: /* Send a PADR packet */
! 1229: static int
! 1230: pppoe_send_padr(struct pppoe_softc *sc)
! 1231: {
! 1232: struct mbuf *m0;
! 1233: u_int8_t *p;
! 1234: size_t len, l1 = 0; /* XXX: gcc */
! 1235:
! 1236: if (sc->sc_state != PPPOE_STATE_PADR_SENT)
! 1237: return (EIO);
! 1238:
! 1239: len = 2 + 2 + 2 + 2 + sizeof(sc->sc_unique); /* service name, host unique */
! 1240: if (sc->sc_service_name != NULL) { /* service name tag maybe empty */
! 1241: l1 = strlen(sc->sc_service_name);
! 1242: len += l1;
! 1243: }
! 1244: if (sc->sc_ac_cookie_len > 0)
! 1245: len += 2 + 2 + sc->sc_ac_cookie_len; /* AC cookie */
! 1246:
! 1247: m0 = pppoe_get_mbuf(len + PPPOE_HEADERLEN);
! 1248: if (m0 == NULL)
! 1249: return (ENOBUFS);
! 1250:
! 1251: p = mtod(m0, u_int8_t *);
! 1252: PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len);
! 1253: PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
! 1254:
! 1255: if (sc->sc_service_name != NULL) {
! 1256: PPPOE_ADD_16(p, l1);
! 1257: memcpy(p, sc->sc_service_name, l1);
! 1258: p += l1;
! 1259: } else {
! 1260: PPPOE_ADD_16(p, 0);
! 1261: }
! 1262: if (sc->sc_ac_cookie_len > 0) {
! 1263: PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);
! 1264: PPPOE_ADD_16(p, sc->sc_ac_cookie_len);
! 1265: memcpy(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len);
! 1266: p += sc->sc_ac_cookie_len;
! 1267: }
! 1268: PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
! 1269: PPPOE_ADD_16(p, sizeof(sc->sc_unique));
! 1270: memcpy(p, &sc->sc_unique, sizeof(sc->sc_unique));
! 1271:
! 1272: #ifdef PPPOE_DEBUG
! 1273: p += sizeof(sc->sc_unique);
! 1274: if (p - mtod(m0, u_int8_t *) != len + PPPOE_HEADERLEN)
! 1275: panic("pppoe_send_padr: garbled output len, should be %ld, is %ld",
! 1276: (long)(len + PPPOE_HEADERLEN), (long)(p - mtod(m0, u_int8_t *)));
! 1277: #endif
! 1278:
! 1279: return (pppoe_output(sc, m0));
! 1280: }
! 1281:
! 1282: /* Send a PADT packet. */
! 1283: static int
! 1284: pppoe_send_padt(struct ifnet *outgoing_if, u_int session, const u_int8_t *dest)
! 1285: {
! 1286: struct ether_header *eh;
! 1287: struct sockaddr dst;
! 1288: struct mbuf *m0;
! 1289: u_int8_t *p;
! 1290:
! 1291: m0 = pppoe_get_mbuf(PPPOE_HEADERLEN);
! 1292: if (m0 == NULL)
! 1293: return (ENOBUFS);
! 1294:
! 1295: p = mtod(m0, u_int8_t *);
! 1296: PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0);
! 1297:
! 1298: memset(&dst, 0, sizeof(dst));
! 1299: dst.sa_family = AF_UNSPEC;
! 1300: eh = (struct ether_header *)&dst.sa_data;
! 1301: eh->ether_type = htons(ETHERTYPE_PPPOEDISC);
! 1302: memcpy(&eh->ether_dhost, dest, ETHER_ADDR_LEN);
! 1303:
! 1304: m0->m_flags &= ~(M_BCAST|M_MCAST);
! 1305: return (outgoing_if->if_output(outgoing_if, m0, &dst, NULL));
! 1306: }
! 1307:
! 1308: #ifdef PPPOE_SERVER
! 1309: /* Send a PADO packet. */
! 1310: static int
! 1311: pppoe_send_pado(struct pppoe_softc *sc)
! 1312: {
! 1313: struct mbuf *m0;
! 1314: size_t len;
! 1315: u_int8_t *p;
! 1316:
! 1317: if (sc->sc_state != PPPOE_STATE_PADO_SENT)
! 1318: return (EIO);
! 1319:
! 1320: /* calc length */
! 1321: len = 0;
! 1322: /* include ac_cookie */
! 1323: len += 2 + 2 + sizeof(sc->sc_unique);
! 1324: /* include hunique */
! 1325: len += 2 + 2 + sc->sc_hunique_len;
! 1326:
! 1327: m0 = pppoe_get_mbuf(len + PPPOE_HEADERLEN);
! 1328: if (m0 == NULL)
! 1329: return (ENOBUFS);
! 1330:
! 1331: p = mtod(m0, u_int8_t *);
! 1332: PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len);
! 1333: PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);
! 1334: PPPOE_ADD_16(p, sizeof(sc->sc_unique));
! 1335: memcpy(p, &sc, sizeof(sc->sc_unique));
! 1336: p += sizeof(sc->sc_unique);
! 1337: PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
! 1338: PPPOE_ADD_16(p, sc->sc_hunique_len);
! 1339: memcpy(p, sc->sc_hunique, sc->sc_hunique_len);
! 1340:
! 1341: return (pppoe_output(sc, m0));
! 1342: }
! 1343:
! 1344: /* Send a PADS packet. */
! 1345: static int
! 1346: pppoe_send_pads(struct pppoe_softc *sc)
! 1347: {
! 1348: struct mbuf *m0;
! 1349: size_t len, l1;
! 1350: u_int8_t *p;
! 1351:
! 1352: if (sc->sc_state != PPPOE_STATE_PADO_SENT)
! 1353: return (EIO);
! 1354:
! 1355: sc->sc_session = mono_time.tv_sec % 0xff + 1;
! 1356:
! 1357: /* calc length */
! 1358: len = 0;
! 1359: /* include hunique */
! 1360: len += 2 + 2 + 2 + 2 + sc->sc_hunique_len; /* service name, host unique */
! 1361: if (sc->sc_service_name != NULL) { /* service name tag maybe empty */
! 1362: l1 = strlen(sc->sc_service_name);
! 1363: len += l1;
! 1364: }
! 1365:
! 1366: m0 = pppoe_get_mbuf(len + PPPOE_HEADERLEN);
! 1367: if (m0 == NULL)
! 1368: return (ENOBUFS);
! 1369:
! 1370: p = mtod(m0, u_int8_t *);
! 1371: PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len);
! 1372: PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
! 1373: if (sc->sc_service_name != NULL) {
! 1374: PPPOE_ADD_16(p, l1);
! 1375: memcpy(p, sc->sc_service_name, l1);
! 1376: p += l1;
! 1377: } else {
! 1378: PPPOE_ADD_16(p, 0);
! 1379: }
! 1380: PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
! 1381: PPPOE_ADD_16(p, sc->sc_hunique_len);
! 1382: memcpy(p, sc->sc_hunique, sc->sc_hunique_len);
! 1383:
! 1384: return (pppoe_output(sc, m0));
! 1385: }
! 1386: #endif
! 1387:
! 1388: /* this-layer-start function */
! 1389: static void
! 1390: pppoe_tls(struct sppp *sp)
! 1391: {
! 1392: struct pppoe_softc *sc = (void *)sp;
! 1393:
! 1394: if (sc->sc_state != PPPOE_STATE_INITIAL)
! 1395: return;
! 1396: pppoe_connect(sc);
! 1397: }
! 1398:
! 1399: /* this-layer-finish function */
! 1400: static void
! 1401: pppoe_tlf(struct sppp *sp)
! 1402: {
! 1403: struct pppoe_softc *sc = (void *)sp;
! 1404:
! 1405: if (sc->sc_state < PPPOE_STATE_SESSION)
! 1406: return;
! 1407: /*
! 1408: * Do not call pppoe_disconnect here, the upper layer state
! 1409: * machine gets confused by this. We must return from this
! 1410: * function and defer disconnecting to the timeout handler.
! 1411: */
! 1412: sc->sc_state = PPPOE_STATE_CLOSING;
! 1413: timeout_add(&sc->sc_timeout, hz / 50);
! 1414: }
! 1415:
! 1416: static void
! 1417: pppoe_start(struct ifnet *ifp)
! 1418: {
! 1419: struct pppoe_softc *sc = (void *)ifp;
! 1420: struct mbuf *m;
! 1421: size_t len;
! 1422: u_int8_t *p;
! 1423:
! 1424: if (sppp_isempty(ifp))
! 1425: return;
! 1426:
! 1427: /* are we ready to process data yet? */
! 1428: if (sc->sc_state < PPPOE_STATE_SESSION) {
! 1429: sppp_flush(&sc->sc_sppp.pp_if);
! 1430: return;
! 1431: }
! 1432:
! 1433: while ((m = sppp_dequeue(ifp)) != NULL) {
! 1434: len = m->m_pkthdr.len;
! 1435: M_PREPEND(m, PPPOE_HEADERLEN, M_DONTWAIT);
! 1436: if (m == NULL) {
! 1437: ifp->if_oerrors++;
! 1438: continue;
! 1439: }
! 1440: p = mtod(m, u_int8_t *);
! 1441: PPPOE_ADD_HEADER(p, 0, sc->sc_session, len);
! 1442:
! 1443: #if NBPFILTER > 0
! 1444: if(sc->sc_sppp.pp_if.if_bpf)
! 1445: bpf_mtap(sc->sc_sppp.pp_if.if_bpf, m,
! 1446: BPF_DIRECTION_OUT);
! 1447: #endif
! 1448:
! 1449: pppoe_output(sc, m);
! 1450: }
! 1451: }
CVSweb