Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/net do not require PPPoE control packet to be put into a...



details:   https://anonhg.NetBSD.org/src/rev/ffe697a590e1
branches:  trunk
changeset: 533134:ffe697a590e1
user:      itojun <itojun%NetBSD.org@localhost>
date:      Sat Jun 22 11:37:48 2002 +0000

description:
do not require PPPoE control packet to be put into a single mbuf.
reviewed/tested by ymmt

diffstat:

 sys/net/if_pppoe.c |  207 +++++++++++++++++++++++++++++++++-------------------
 1 files changed, 129 insertions(+), 78 deletions(-)

diffs (truncated from 377 to 300 lines):

diff -r 4ef4dacbad36 -r ffe697a590e1 sys/net/if_pppoe.c
--- a/sys/net/if_pppoe.c        Sat Jun 22 10:59:54 2002 +0000
+++ b/sys/net/if_pppoe.c        Sat Jun 22 11:37:48 2002 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_pppoe.c,v 1.28 2002/06/22 05:59:27 itojun Exp $ */
+/* $NetBSD: if_pppoe.c,v 1.29 2002/06/22 11:37:48 itojun Exp $ */
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.28 2002/06/22 05:59:27 itojun Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.29 2002/06/22 11:37:48 itojun Exp $");
 
 #include "pppoe.h"
 #include "bpfilter.h"
@@ -67,7 +67,19 @@
 #undef PPPOE_DEBUG             /* XXX - remove this or make it an option */
 /* #define PPPOE_DEBUG 1 */
 
-#define PPPOE_HEADERLEN        6
+struct pppoehdr {
+       u_int8_t vertype;
+       u_int8_t code;
+       u_int16_t session;
+       u_int16_t plen;
+} __attribute__((__packed__));
+
+struct pppoetag {
+       u_int16_t tag;
+       u_int16_t len;
+} __attribute__((__packed__));
+
+#define PPPOE_HEADERLEN        sizeof(struct pppoehdr)
 #define        PPPOE_VERTYPE   0x11    /* VER=1, TYPE = 1 */
 
 #define        PPPOE_TAG_EOL           0x0000          /* end of list */
@@ -90,11 +102,6 @@
 /* two byte PPP protocol discriminator, then IP data */
 #define        PPPOE_MAXMTU    (ETHERMTU-PPPOE_HEADERLEN-2)
 
-/* Read a 16 bit unsigned value from a buffer */
-#define PPPOE_READ_16(PTR, VAL)                                \
-               (VAL) = ((PTR)[0] << 8) | (PTR)[1];     \
-               (PTR)+=2
-
 /* Add a 16 bit unsigned value to a buffer pointed to by PTR */
 #define        PPPOE_ADD_16(PTR, VAL)                  \
                *(PTR)++ = (VAL) / 256;         \
@@ -147,8 +154,8 @@
 /* input routines */
 static void pppoe_input(void);
 static void pppoe_disc_input(struct mbuf *);
-static void pppoe_dispatch_disc_pkt(u_int8_t *, size_t, struct ifnet *, struct ether_header *);
-static void pppoe_data_input(struct mbuf *m);
+static void pppoe_dispatch_disc_pkt(struct mbuf *, int);
+static void pppoe_data_input(struct mbuf *);
 
 /* management routines */
 void pppoeattach(int);
@@ -368,64 +375,106 @@
 }
 
 /* analyze and handle a single received packet while not in session state */
-static void pppoe_dispatch_disc_pkt(u_int8_t *p, size_t size, struct ifnet *rcvif, struct ether_header *eh)
+static void pppoe_dispatch_disc_pkt(struct mbuf *m, int off)
 {
        u_int16_t tag, len;
-       u_int8_t vertype, code;
        u_int16_t session, plen;
        struct pppoe_softc *sc;
        const char *err_msg = NULL;
-       u_int8_t * ac_cookie;
+       u_int8_t *ac_cookie;
        size_t ac_cookie_len;
+       struct pppoehdr *ph;
+       struct pppoetag *pt;
+       struct mbuf *n;
+       int noff;
+       struct ether_header *eh;
+
+       if (m->m_len < sizeof(*eh)) {
+               m = m_pullup(m, sizeof(*eh));
+               if (!m)
+                       goto done;
+       }
+       eh = mtod(m, struct ether_header *);
+       off += sizeof(*eh);
 
        ac_cookie = NULL;
        ac_cookie_len = 0;
        session = 0;
-       if (size <= PPPOE_HEADERLEN) {
-               printf("pppoe: packet too short: %ld\n", (long)size);
-               return;
+       if (m->m_pkthdr.len - off <= PPPOE_HEADERLEN) {
+               printf("pppoe: packet too short: %d\n", m->m_pkthdr.len);
+               goto done;
        }
-       vertype = *p++;
-       if (vertype != PPPOE_VERTYPE) {
-               printf("pppoe: unknown version/type packet: 0x%x\n", vertype);
-               return;
+
+       n = m_pulldown(m, off, sizeof(*ph), &noff);
+       if (!n) {
+               printf("pppoe: could not get PPPoE header\n");
+               m = NULL;
+               goto done;
        }
-       code = *p++;
-       PPPOE_READ_16(p, session);
-       PPPOE_READ_16(p, plen);
-       size -= PPPOE_HEADERLEN;
+       ph = (struct pppoehdr *)(mtod(n, caddr_t) + noff);
+       if (ph->vertype != PPPOE_VERTYPE) {
+               printf("pppoe: unknown version/type packet: 0x%x\n",
+                   ph->vertype);
+               goto done;
+       }
+       session = ntohs(ph->session);
+       plen = ntohs(ph->plen);
+       off += sizeof(*ph);
 
-       if (plen > size) {
-               printf("pppoe: packet content does not fit: data available = %ld, packet size = %ld\n",
-                       (long)size, (long)plen);
-               return;
+       if (plen + off > m->m_pkthdr.len) {
+               printf("pppoe: packet content does not fit: data available = %d, packet size = %u\n",
+                   m->m_pkthdr.len - off, plen);
+               goto done;
        }
-       size = plen;    /* ignore trailing garbage */
+       m_adj(m, off + plen - m->m_pkthdr.len); /* ignore trailing garbage */
        tag = 0;
        len = 0;
        sc = NULL;
-       while (size > 4) {
-               PPPOE_READ_16(p, tag);
-               PPPOE_READ_16(p, len);
-               if (len > size) {
+       while (off + sizeof(*pt) < m->m_pkthdr.len) {
+               n = m_pulldown(m, off, sizeof(*pt), &noff);
+               if (!n) {
+                       printf("%s: parse error\n",
+                           sc ? sc->sc_sppp.pp_if.if_xname : "pppoe");
+                       m = NULL;
+                       goto done;
+               }
+               pt = (struct pppoetag *)(mtod(n, caddr_t) + noff);
+               tag = ntohs(pt->tag);
+               len = ntohs(pt->len);
+               if (off + len > m->m_pkthdr.len) {
                        printf("pppoe: tag 0x%x len 0x%x is too long\n",
                            tag, len);
-                       return;
+                       goto done;
                }
                switch (tag) {
                case PPPOE_TAG_EOL:
-                       size = 0; break;
+                       goto breakbreak;
                case PPPOE_TAG_SNAME:
                        break;  /* ignored */
                case PPPOE_TAG_ACNAME:
                        break;  /* ignored */
                case PPPOE_TAG_HUNIQUE:
-                       if (sc == NULL)
-                               sc = pppoe_find_softc_by_hunique(p, len, rcvif);
+                       if (sc != NULL)
+                               break;
+                       n = m_pulldown(m, off + sizeof(*pt), len, &noff);
+                       if (!n) {
+                               err_msg = "TAG HUNIQUE ERROR";
+                               m = NULL;
+                               goto done;
+                       }
+                       sc = pppoe_find_softc_by_hunique(mtod(n, caddr_t) + noff,
+                           len, m->m_pkthdr.rcvif);
                        break;
                case PPPOE_TAG_ACCOOKIE:
                        if (ac_cookie == NULL) {
-                               ac_cookie = p;
+                               n = m_pulldown(m, off + sizeof(*pt), len,
+                                   &noff);
+                               if (!n) {
+                                       err_msg = "TAG ACCOOKIE ERROR";
+                                       m = NULL;
+                                       break;
+                               }
+                               ac_cookie = mtod(n, caddr_t) + noff;
                                ac_cookie_len = len;
                        }
                        break;
@@ -443,35 +492,33 @@
                        printf("%s: %s\n",
                            sc ? sc->sc_sppp.pp_if.if_xname : "pppoe",
                            err_msg);
-                       return;
+                       goto done;
                }
-               if (size >= 0) {
-                       size -= 4 + len;
-                       if (len > 0)
-                               p += len;
-               }
+               off += sizeof(*pt) + len;
        }
-       switch (code) {
+breakbreak:;
+       switch (ph->code) {
        case PPPOE_CODE_PADI:
        case PPPOE_CODE_PADR:
                /* ignore, we are no access concentrator */
-               return;
+               goto done;
        case PPPOE_CODE_PADO:
                if (sc == NULL) {
                        /* be quiete if there is not a single pppoe instance */
                        if (!LIST_EMPTY(&pppoe_softc_list))
                                printf("pppoe: received PADO but could not find request for it\n");
-                       return;
+                       goto done;
                }
                if (sc->sc_state != PPPOE_STATE_PADI_SENT) {
                        printf("%s: received unexpected PADO\n",
                            sc->sc_sppp.pp_if.if_xname);
-                       return;
+                       goto done;
                }
                if (ac_cookie) {
-                       sc->sc_ac_cookie = malloc(ac_cookie_len, M_DEVBUF, M_DONTWAIT);
+                       sc->sc_ac_cookie = malloc(ac_cookie_len, M_DEVBUF,
+                           M_DONTWAIT);
                        if (sc->sc_ac_cookie == NULL)
-                               return;
+                               goto done;
                        sc->sc_ac_cookie_len = ac_cookie_len;
                        memcpy(sc->sc_ac_cookie, ac_cookie, ac_cookie_len);
                }
@@ -480,13 +527,15 @@
                sc->sc_padr_retried = 0;
                sc->sc_state = PPPOE_STATE_PADR_SENT;
                if (pppoe_send_padr(sc) == 0) 
-                       callout_reset(&sc->sc_timeout, PPPOE_DISC_TIMEOUT*(1+sc->sc_padr_retried), pppoe_timeout, sc);
+                       callout_reset(&sc->sc_timeout,
+                           PPPOE_DISC_TIMEOUT*(1+sc->sc_padr_retried),
+                           pppoe_timeout, sc);
                else
                        pppoe_abort_connect(sc);
                break;
        case PPPOE_CODE_PADS:
                if (sc == NULL)
-                       return;
+                       goto done;
                sc->sc_session = session;
                callout_stop(&sc->sc_timeout);
                if (sc->sc_sppp.pp_if.if_flags & IFF_DEBUG)
@@ -497,7 +546,7 @@
                break;
        case PPPOE_CODE_PADT:
                if (sc == NULL)
-                       return;
+                       goto done;
                /* stop timer (we might be about to transmit a PADT ourself) */
                callout_stop(&sc->sc_timeout);
                if (sc->sc_sppp.pp_if.if_flags & IFF_DEBUG)
@@ -518,62 +567,64 @@
        default:
                printf("%s: unknown code (0x%04x) session = 0x%04x\n",
                    sc? sc->sc_sppp.pp_if.if_xname : "pppoe",
-                   code, session);
+                   ph->code, session);
                break;
        }
+
+done:
+       m_freem(m);
+       return;
 }
 
 static void
 pppoe_disc_input(struct mbuf *m)
 {
-       u_int8_t *p;
-       struct ether_header *eh;
 
        /* avoid error messages if there is not a single pppoe instance */
        if (!LIST_EMPTY(&pppoe_softc_list)) {
-               /* XXX it is not valid to pass pointer outside of mbuf */
-               eh = mtod(m, struct ether_header *);
-               m_adj(m, sizeof(struct ether_header));
-               p = mtod(m, u_int8_t *);
                KASSERT(m->m_flags & M_PKTHDR);
-               pppoe_dispatch_disc_pkt(p, m->m_len, m->m_pkthdr.rcvif, eh);
-       }
-       m_free(m);



Home | Main Index | Thread Index | Old Index