Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pppoe.c Source File

pppoe.c

00001 /*****************************************************************************
00002 * pppoe.c - PPP Over Ethernet implementation for lwIP.
00003 *
00004 * Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.
00005 *
00006 * The authors hereby grant permission to use, copy, modify, distribute,
00007 * and license this software and its documentation for any purpose, provided
00008 * that existing copyright notices are retained in all copies and that this
00009 * notice and the following disclaimer are included verbatim in any 
00010 * distributions. No written agreement, license, or royalty fee is required
00011 * for any of the authorized uses.
00012 *
00013 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
00014 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00015 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
00016 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00017 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00018 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00019 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00020 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00021 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00022 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00023 *
00024 ******************************************************************************
00025 * REVISION HISTORY
00026 *
00027 * 06-01-01 Marc Boucher <marc@mbsi.ca>
00028 *   Ported to lwIP.
00029 *****************************************************************************/
00030 
00031 
00032 
00033 /* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */
00034 
00035 /*-
00036  * Copyright (c) 2002 The NetBSD Foundation, Inc.
00037  * All rights reserved.
00038  *
00039  * This code is derived from software contributed to The NetBSD Foundation
00040  * by Martin Husemann <martin@NetBSD.org>.
00041  *
00042  * Redistribution and use in source and binary forms, with or without
00043  * modification, are permitted provided that the following conditions
00044  * are met:
00045  * 1. Redistributions of source code must retain the above copyright
00046  *    notice, this list of conditions and the following disclaimer.
00047  * 2. Redistributions in binary form must reproduce the above copyright
00048  *    notice, this list of conditions and the following disclaimer in the
00049  *    documentation and/or other materials provided with the distribution.
00050  * 3. All advertising materials mentioning features or use of this software
00051  *    must display the following acknowledgement:
00052  *        This product includes software developed by the NetBSD
00053  *        Foundation, Inc. and its contributors.
00054  * 4. Neither the name of The NetBSD Foundation nor the names of its
00055  *    contributors may be used to endorse or promote products derived
00056  *    from this software without specific prior written permission.
00057  *
00058  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
00059  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00060  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00061  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
00062  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00063  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00064  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00065  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00066  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00067  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00068  * POSSIBILITY OF SUCH DAMAGE.
00069  */
00070 
00071 #include "ppp_opts.h"
00072 #if PPP_SUPPORT && PPPOE_SUPPORT /* don't build if not configured for use in ppp_opts.h */
00073 
00074 #if 0 /* UNUSED */
00075 #include <string.h>
00076 #include <stdio.h>
00077 #endif /* UNUSED */
00078 
00079 #include "ppp_impl.h"
00080 #include "lcp.h"
00081 #include "ipcp.h"
00082 #include "pppoe.h"
00083 
00084 /* Memory pool */
00085 PPP_MEMPOOL_DECLARE(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF")
00086 
00087 /* Add a 16 bit unsigned value to a buffer pointed to by PTR */
00088 #define PPPOE_ADD_16(PTR, VAL) \
00089     *(PTR)++ = (u8_t)((VAL) / 256);    \
00090     *(PTR)++ = (u8_t)((VAL) % 256)
00091 
00092 /* Add a complete PPPoE header to the buffer pointed to by PTR */
00093 #define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN)  \
00094     *(PTR)++ = PPPOE_VERTYPE;  \
00095     *(PTR)++ = (CODE);         \
00096     PPPOE_ADD_16(PTR, SESS);   \
00097     PPPOE_ADD_16(PTR, LEN)
00098 
00099 #define PPPOE_DISC_TIMEOUT (5*1000)  /* base for quick timeout calculation */
00100 #define PPPOE_SLOW_RETRY   (60*1000) /* persistent retry interval */
00101 #define PPPOE_DISC_MAXPADI  4        /* retry PADI four times (quickly) */
00102 #define PPPOE_DISC_MAXPADR  2        /* retry PADR twice */
00103 
00104 #ifdef PPPOE_SERVER
00105 #error "PPPOE_SERVER is not yet supported"
00106 /* from if_spppsubr.c */
00107 #define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */
00108 #endif
00109 
00110 #define PPPOE_ERRORSTRING_LEN     64
00111 
00112 
00113 /* callbacks called from PPP core */
00114 static err_t pppoe_write(ppp_pcb *ppp, void *ctx, struct pbuf *p);
00115 static err_t pppoe_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol);
00116 static void pppoe_connect(ppp_pcb *ppp, void *ctx);
00117 static void pppoe_disconnect(ppp_pcb *ppp, void *ctx);
00118 static err_t pppoe_destroy(ppp_pcb *ppp, void *ctx);
00119 
00120 /* management routines */
00121 static void pppoe_abort_connect(struct pppoe_softc *);
00122 #if 0 /* UNUSED */
00123 static void pppoe_clear_softc(struct pppoe_softc *, const char *);
00124 #endif /* UNUSED */
00125 
00126 /* internal timeout handling */
00127 static void pppoe_timeout(void *);
00128 
00129 /* sending actual protocol controll packets */
00130 static err_t pppoe_send_padi(struct pppoe_softc *);
00131 static err_t pppoe_send_padr(struct pppoe_softc *);
00132 #ifdef PPPOE_SERVER
00133 static err_t pppoe_send_pado(struct pppoe_softc *);
00134 static err_t pppoe_send_pads(struct pppoe_softc *);
00135 #endif
00136 static err_t pppoe_send_padt(struct netif *, u_int, const u8_t *);
00137 
00138 /* internal helper functions */
00139 static err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb);
00140 static struct pppoe_softc* pppoe_find_softc_by_session(u_int session, struct netif *rcvif);
00141 static struct pppoe_softc* pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif);
00142 
00143 /** linked list of created pppoe interfaces */
00144 static struct pppoe_softc *pppoe_softc_list;
00145 
00146 /* Callbacks structure for PPP core */
00147 static const struct link_callbacks pppoe_callbacks = {
00148   pppoe_connect,
00149 #if PPP_SERVER
00150   NULL,
00151 #endif /* PPP_SERVER */
00152   pppoe_disconnect,
00153   pppoe_destroy,
00154   pppoe_write,
00155   pppoe_netif_output,
00156   NULL,
00157   NULL
00158 };
00159 
00160 /*
00161  * Create a new PPP Over Ethernet (PPPoE) connection.
00162  *
00163  * Return 0 on success, an error code on failure.
00164  */
00165 ppp_pcb *pppoe_create(struct netif *pppif,
00166        struct netif *ethif,
00167        const char *service_name, const char *concentrator_name,
00168        ppp_link_status_cb_fn link_status_cb, void *ctx_cb)
00169 {
00170   ppp_pcb *ppp;
00171   struct pppoe_softc *sc;
00172   PPP_UNUSED_ARG(service_name);
00173   PPP_UNUSED_ARG(concentrator_name);
00174 
00175   sc = (struct pppoe_softc *)MEMPOOL_ALLOC(PPPOE_IF);
00176   if (sc == NULL) {
00177     return NULL;
00178   }
00179 
00180   ppp = ppp_new(pppif, &pppoe_callbacks, sc, link_status_cb, ctx_cb);
00181   if (ppp == NULL) {
00182     MEMPOOL_FREE(PPPOE_IF, sc);
00183     return NULL;
00184   }
00185 
00186   memset(sc, 0, sizeof(struct pppoe_softc));
00187   sc->pcb = ppp;
00188   sc->sc_ethif = ethif;
00189   /* put the new interface at the head of the list */
00190   sc->next = pppoe_softc_list;
00191   pppoe_softc_list = sc;
00192   return ppp;
00193 }
00194 
00195 /* Called by PPP core */
00196 static err_t pppoe_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) {
00197   struct pppoe_softc *sc = (struct pppoe_softc *)ctx;
00198   struct pbuf *ph; /* Ethernet + PPPoE header */
00199   err_t ret;
00200 #if MIB2_STATS
00201   u16_t tot_len;
00202 #else /* MIB2_STATS */
00203   PPP_UNUSED_ARG(ppp);
00204 #endif /* MIB2_STATS */
00205 
00206   /* skip address & flags */
00207   pbuf_remove_header(p, 2);
00208 
00209   ph = ppp_memory_buffer_allocate(ppp->netif->memory_manager, (u16_t)(PPPOE_HEADERLEN), PPP_BUF_HEAP);
00210   if(!ph) {
00211     LINK_STATS_INC(link.memerr);
00212     LINK_STATS_INC(link.proterr);
00213     MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
00214     ppp_memory_buffer_free(p);
00215     return ERR_MEM;
00216   }
00217 
00218   pbuf_remove_header(ph, PPPOE_HEADERLEN); /* hide PPPoE header */
00219   pbuf_cat(ph, p);
00220 #if MIB2_STATS
00221   tot_len = ph->tot_len;
00222 #endif /* MIB2_STATS */
00223 
00224   ret = pppoe_xmit(sc, ph);
00225   if (ret != ERR_OK) {
00226     LINK_STATS_INC(link.err);
00227     MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
00228     return ret;
00229   }
00230 
00231   MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, (u16_t)tot_len);
00232   MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts);
00233   LINK_STATS_INC(link.xmit);
00234   return ERR_OK;
00235 }
00236 
00237 /* Called by PPP core */
00238 static err_t pppoe_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol) {
00239   struct pppoe_softc *sc = (struct pppoe_softc *)ctx;
00240   struct pbuf *pb;
00241   u8_t *pl;
00242   err_t err;
00243 #if MIB2_STATS
00244   u16_t tot_len;
00245 #else /* MIB2_STATS */
00246   PPP_UNUSED_ARG(ppp);
00247 #endif /* MIB2_STATS */
00248 
00249   /* @todo: try to use pbuf_header() here! */
00250   pb = ppp_memory_buffer_allocate(ppp->netif->memory_manager, PPPOE_HEADERLEN + sizeof(protocol), PPP_BUF_HEAP);
00251   if(!pb) {
00252     LINK_STATS_INC(link.memerr);
00253     LINK_STATS_INC(link.proterr);
00254     MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
00255     return ERR_MEM;
00256   }
00257 
00258   pbuf_remove_header(pb, PPPOE_HEADERLEN);
00259 
00260   pl = (u8_t*)pb->payload;
00261   PUTSHORT(protocol, pl);
00262 
00263   pbuf_chain(pb, p);
00264 #if MIB2_STATS
00265   tot_len = pb->tot_len;
00266 #endif /* MIB2_STATS */
00267 
00268   if( (err = pppoe_xmit(sc, pb)) != ERR_OK) {
00269     LINK_STATS_INC(link.err);
00270     MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
00271     return err;
00272   }
00273 
00274   MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, tot_len);
00275   MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts);
00276   LINK_STATS_INC(link.xmit);
00277   return ERR_OK;
00278 }
00279 
00280 static err_t
00281 pppoe_destroy(ppp_pcb *ppp, void *ctx)
00282 {
00283   struct pppoe_softc *sc = (struct pppoe_softc *)ctx;
00284   struct pppoe_softc **copp, *freep;
00285   PPP_UNUSED_ARG(ppp);
00286 
00287   sys_untimeout(pppoe_timeout, sc);
00288 
00289   /* remove interface from list */
00290   for (copp = &pppoe_softc_list; (freep = *copp); copp = &freep->next) {
00291     if (freep == sc) {
00292        *copp = freep->next;
00293        break;
00294     }
00295   }
00296 
00297 #ifdef PPPOE_TODO
00298   if (sc->sc_concentrator_name) {
00299     mem_free(sc->sc_concentrator_name);
00300   }
00301   if (sc->sc_service_name) {
00302     mem_free(sc->sc_service_name);
00303   }
00304 #endif /* PPPOE_TODO */
00305   MEMPOOL_FREE(PPPOE_IF, sc);
00306 
00307   return ERR_OK;
00308 }
00309 
00310 /*
00311  * Find the interface handling the specified session.
00312  * Note: O(number of sessions open), this is a client-side only, mean
00313  * and lean implementation, so number of open sessions typically should
00314  * be 1.
00315  */
00316 static struct pppoe_softc* pppoe_find_softc_by_session(u_int session, struct netif *rcvif) {
00317   struct pppoe_softc *sc;
00318 
00319   for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) {
00320     if (sc->sc_state == PPPOE_STATE_SESSION
00321         && sc->sc_session == session
00322          && sc->sc_ethif == rcvif) {
00323            return sc;
00324       }
00325   }
00326   return NULL;
00327 }
00328 
00329 /* Check host unique token passed and return appropriate softc pointer,
00330  * or NULL if token is bogus. */
00331 static struct pppoe_softc* pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif) {
00332   struct pppoe_softc *sc, *t;
00333 
00334   if (len != sizeof sc) {
00335     return NULL;
00336   }
00337   MEMCPY(&t, token, len);
00338 
00339   for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) {
00340     if (sc == t) {
00341       break;
00342     }
00343   }
00344 
00345   if (sc == NULL) {
00346     PPPDEBUG(LOG_DEBUG, ("pppoe: alien host unique tag, no session found\n"));
00347     return NULL;
00348   }
00349 
00350   /* should be safe to access *sc now */
00351   if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) {
00352     PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": host unique tag found, but it belongs to a connection in state %d\n",
00353       sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_state));
00354     return NULL;
00355   }
00356   if (sc->sc_ethif != rcvif) {
00357     PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": wrong interface, not accepting host unique\n",
00358       sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
00359     return NULL;
00360   }
00361   return sc;
00362 }
00363 
00364 /* analyze and handle a single received packet while not in session state */
00365 void
00366 pppoe_disc_input(struct netif *netif, struct pbuf *pb)
00367 {
00368   u16_t tag, len, off;
00369   u16_t session, plen;
00370   struct pppoe_softc *sc;
00371 #if PPP_DEBUG
00372   const char *err_msg = NULL;
00373 #endif /* PPP_DEBUG */
00374   u8_t *ac_cookie;
00375   u16_t ac_cookie_len;
00376 #ifdef PPPOE_SERVER
00377   u8_t *hunique;
00378   size_t hunique_len;
00379 #endif
00380   struct pppoehdr *ph;
00381   struct pppoetag pt;
00382   int err;
00383   struct eth_hdr *ethhdr;
00384 
00385   /* don't do anything if there is not a single PPPoE instance */
00386   if (pppoe_softc_list == NULL) {
00387     ppp_memory_buffer_free(pb);
00388     return;
00389   }
00390 
00391   pb = pbuf_coalesce(pb, PBUF_RAW);
00392 
00393   ethhdr = (struct eth_hdr *)pb->payload;
00394 
00395   ac_cookie = NULL;
00396   ac_cookie_len = 0;
00397 #ifdef PPPOE_SERVER
00398   hunique = NULL;
00399   hunique_len = 0;
00400 #endif
00401   session = 0;
00402   off = sizeof(struct eth_hdr) + sizeof(struct pppoehdr);
00403   if (pb->len < off) {
00404     PPPDEBUG(LOG_DEBUG, ("pppoe: packet too short: %d\n", pb->len));
00405     goto done;
00406   }
00407 
00408   ph = (struct pppoehdr *) (ethhdr + 1);
00409   if (ph->vertype != PPPOE_VERTYPE) {
00410     PPPDEBUG(LOG_DEBUG, ("pppoe: unknown version/type packet: 0x%x\n", ph->vertype));
00411     goto done;
00412   }
00413   session = ppp_ntohs(ph->session);
00414   plen = ppp_ntohs(ph->plen);
00415 
00416   if (plen > (pb->len - off)) {
00417     PPPDEBUG(LOG_DEBUG, ("pppoe: packet content does not fit: data available = %d, packet size = %u\n",
00418         pb->len - off, plen));
00419     goto done;
00420   }
00421   if(pb->tot_len == pb->len) {
00422     u16_t framelen = off + plen;
00423     if (framelen < pb->len) {
00424       /* ignore trailing garbage */
00425       pb->tot_len = pb->len = framelen;
00426     }
00427   }
00428   tag = 0;
00429   len = 0;
00430   sc = NULL;
00431   while (off + sizeof(pt) <= pb->len) {
00432     MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt));
00433     tag = ppp_ntohs(pt.tag);
00434     len = ppp_ntohs(pt.len);
00435     if (off + sizeof(pt) + len > pb->len) {
00436       PPPDEBUG(LOG_DEBUG, ("pppoe: tag 0x%x len 0x%x is too long\n", tag, len));
00437       goto done;
00438     }
00439     switch (tag) {
00440       case PPPOE_TAG_EOL:
00441         goto breakbreak;
00442       case PPPOE_TAG_SNAME:
00443         break;  /* ignored */
00444       case PPPOE_TAG_ACNAME:
00445         break;  /* ignored */
00446       case PPPOE_TAG_HUNIQUE:
00447         if (sc != NULL) {
00448           break;
00449         }
00450 #ifdef PPPOE_SERVER
00451         hunique = (u8_t*)pb->payload + off + sizeof(pt);
00452         hunique_len = len;
00453 #endif
00454         sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif);
00455         break;
00456       case PPPOE_TAG_ACCOOKIE:
00457         if (ac_cookie == NULL) {
00458           if (len > PPPOE_MAX_AC_COOKIE_LEN) {
00459             PPPDEBUG(LOG_DEBUG, ("pppoe: AC cookie is too long: len = %d, max = %d\n", len, PPPOE_MAX_AC_COOKIE_LEN));
00460             goto done;
00461           }
00462           ac_cookie = (u8_t*)pb->payload + off + sizeof(pt);
00463           ac_cookie_len = len;
00464         }
00465         break;
00466 #if PPP_DEBUG
00467       case PPPOE_TAG_SNAME_ERR:
00468         err_msg = "SERVICE NAME ERROR";
00469         break;
00470       case PPPOE_TAG_ACSYS_ERR:
00471         err_msg = "AC SYSTEM ERROR";
00472         break;
00473       case PPPOE_TAG_GENERIC_ERR:
00474         err_msg = "GENERIC ERROR";
00475         break;
00476 #endif /* PPP_DEBUG */
00477       default:
00478         break;
00479     }
00480 #if PPP_DEBUG
00481     if (err_msg != NULL) {
00482       char error_tmp[PPPOE_ERRORSTRING_LEN];
00483       u16_t error_len = PPP_MIN(len, sizeof(error_tmp)-1);
00484       strncpy(error_tmp, (char*)pb->payload + off + sizeof(pt), error_len);
00485       error_tmp[error_len] = '\0';
00486       if (sc) {
00487         PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": %s: %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err_msg, error_tmp));
00488       } else {
00489         PPPDEBUG(LOG_DEBUG, ("pppoe: %s: %s\n", err_msg, error_tmp));
00490       }
00491     }
00492 #endif /* PPP_DEBUG */
00493     off += sizeof(pt) + len;
00494   }
00495 
00496 breakbreak:;
00497   switch (ph->code) {
00498     case PPPOE_CODE_PADI:
00499 #ifdef PPPOE_SERVER
00500       /*
00501        * got service name, concentrator name, and/or host unique.
00502        * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP.
00503        */
00504       if (LIST_EMPTY(&pppoe_softc_list)) {
00505         goto done;
00506       }
00507       LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
00508         if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) {
00509           continue;
00510         }
00511         if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {
00512           continue;
00513         }
00514         if (sc->sc_state == PPPOE_STATE_INITIAL) {
00515           break;
00516         }
00517       }
00518       if (sc == NULL) {
00519         /* PPPDEBUG(LOG_DEBUG, ("pppoe: free passive interface is not found\n")); */
00520         goto done;
00521       }
00522       if (hunique) {
00523         if (sc->sc_hunique) {
00524           mem_free(sc->sc_hunique);
00525         }
00526         sc->sc_hunique = mem_malloc(hunique_len);
00527         if (sc->sc_hunique == NULL) {
00528           goto done;
00529         }
00530         sc->sc_hunique_len = hunique_len;
00531         MEMCPY(sc->sc_hunique, hunique, hunique_len);
00532       }
00533       MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest);
00534       sc->sc_state = PPPOE_STATE_PADO_SENT;
00535       pppoe_send_pado(sc);
00536       break;
00537 #endif /* PPPOE_SERVER */
00538     case PPPOE_CODE_PADR:
00539 #ifdef PPPOE_SERVER
00540       /*
00541        * get sc from ac_cookie if IFF_PASSIVE
00542        */
00543       if (ac_cookie == NULL) {
00544         /* be quiet if there is not a single pppoe instance */
00545         PPPDEBUG(LOG_DEBUG, ("pppoe: received PADR but not includes ac_cookie\n"));
00546         goto done;
00547       }
00548       sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif);
00549       if (sc == NULL) {
00550         /* be quiet if there is not a single pppoe instance */
00551         if (!LIST_EMPTY(&pppoe_softc_list)) {
00552           PPPDEBUG(LOG_DEBUG, ("pppoe: received PADR but could not find request for it\n"));
00553         }
00554         goto done;
00555       }
00556       if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
00557         PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
00558         goto done;
00559       }
00560       if (hunique) {
00561         if (sc->sc_hunique) {
00562           mem_free(sc->sc_hunique);
00563         }
00564         sc->sc_hunique = mem_malloc(hunique_len);
00565         if (sc->sc_hunique == NULL) {
00566           goto done;
00567         }
00568         sc->sc_hunique_len = hunique_len;
00569         MEMCPY(sc->sc_hunique, hunique, hunique_len);
00570       }
00571       pppoe_send_pads(sc);
00572       sc->sc_state = PPPOE_STATE_SESSION;
00573       ppp_start(sc->pcb); /* notify upper layers */
00574       break;
00575 #else
00576       /* ignore, we are no access concentrator */
00577       goto done;
00578 #endif /* PPPOE_SERVER */
00579     case PPPOE_CODE_PADO:
00580       if (sc == NULL) {
00581         /* be quiet if there is not a single pppoe instance */
00582         if (pppoe_softc_list != NULL) {
00583           PPPDEBUG(LOG_DEBUG, ("pppoe: received PADO but could not find request for it\n"));
00584         }
00585         goto done;
00586       }
00587       if (sc->sc_state != PPPOE_STATE_PADI_SENT) {
00588         PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
00589         goto done;
00590       }
00591       if (ac_cookie) {
00592         sc->sc_ac_cookie_len = ac_cookie_len;
00593         MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len);
00594       }
00595       MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr));
00596       sys_untimeout(pppoe_timeout, sc);
00597       sc->sc_padr_retried = 0;
00598       sc->sc_state = PPPOE_STATE_PADR_SENT;
00599       if ((err = pppoe_send_padr(sc)) != 0) {
00600         PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
00601         UNUSED_ARG(err); /* if PPPDEBUG is disabled */
00602       }
00603       sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc);
00604       break;
00605     case PPPOE_CODE_PADS:
00606       if (sc == NULL) {
00607         goto done;
00608       }
00609       sc->sc_session = session;
00610       sys_untimeout(pppoe_timeout, sc);
00611       PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x connected\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, session));
00612       sc->sc_state = PPPOE_STATE_SESSION;
00613       ppp_start(sc->pcb); /* notify upper layers */
00614       break;
00615     case PPPOE_CODE_PADT:
00616       /* Don't disconnect here, we let the LCP Echo/Reply find the fact
00617        * that PPP session is down. Asking the PPP stack to end the session
00618        * require strict checking about the PPP phase to prevent endless
00619        * disconnection loops.
00620        */
00621 #if 0 /* UNUSED */
00622       if (sc == NULL) { /* PADT frames are rarely sent with a hunique tag, this is actually almost always true */
00623         goto done;
00624       }
00625       pppoe_clear_softc(sc, "received PADT");
00626 #endif /* UNUSED */
00627       break;
00628     default:
00629       if(sc) {
00630         PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": unknown code (0x%"X16_F") session = 0x%"X16_F"\n",
00631             sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num,
00632             (u16_t)ph->code, session));
00633       } else {
00634         PPPDEBUG(LOG_DEBUG, ("pppoe: unknown code (0x%"X16_F") session = 0x%"X16_F"\n", (u16_t)ph->code, session));
00635       }
00636       break;
00637   }
00638 
00639 done:
00640   ppp_memory_buffer_free(pb);
00641   return;
00642 }
00643 
00644 void
00645 pppoe_data_input(struct netif *netif, struct pbuf *pb)
00646 {
00647   u16_t session, plen;
00648   struct pppoe_softc *sc;
00649   struct pppoehdr *ph;
00650 #ifdef PPPOE_TERM_UNKNOWN_SESSIONS
00651   u8_t shost[ETHER_ADDR_LEN];
00652 #endif
00653 
00654 #ifdef PPPOE_TERM_UNKNOWN_SESSIONS
00655   MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost));
00656 #endif
00657   if (pbuf_remove_header(pb, sizeof(struct eth_hdr)) != 0) {
00658     /* bail out */
00659     PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_remove_header failed\n"));
00660     LINK_STATS_INC(link.lenerr);
00661     goto drop;
00662   } 
00663 
00664   if (pb->len < sizeof(*ph)) {
00665     PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: could not get PPPoE header\n"));
00666     goto drop;
00667   }
00668   ph = (struct pppoehdr *)pb->payload;
00669 
00670   if (ph->vertype != PPPOE_VERTYPE) {
00671     PPPDEBUG(LOG_DEBUG, ("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype));
00672     goto drop;
00673   }
00674   if (ph->code != 0) {
00675     goto drop;
00676   }
00677 
00678   session = ppp_ntohs(ph->session);
00679   sc = pppoe_find_softc_by_session(session, netif);
00680   if (sc == NULL) {
00681 #ifdef PPPOE_TERM_UNKNOWN_SESSIONS
00682     PPPDEBUG(LOG_DEBUG, ("pppoe: input for unknown session 0x%x, sending PADT\n", session));
00683     pppoe_send_padt(netif, session, shost);
00684 #endif
00685     goto drop;
00686   }
00687 
00688   plen = ppp_ntohs(ph->plen);
00689 
00690   if (pbuf_remove_header(pb, PPPOE_HEADERLEN) != 0) {
00691     /* bail out */
00692     PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_remove_header PPPOE_HEADERLEN failed\n"));
00693     LINK_STATS_INC(link.lenerr);
00694     goto drop;
00695   } 
00696 
00697   PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n",
00698         sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num,
00699         pb->len, plen));
00700 
00701   if (pb->tot_len < plen) {
00702     goto drop;
00703   }
00704 
00705   /* Dispatch the packet thereby consuming it. */
00706   ppp_input(sc->pcb, pb);
00707   return;
00708 
00709 drop:
00710   ppp_memory_buffer_free(pb);
00711 }
00712 
00713 static err_t
00714 pppoe_output(struct pppoe_softc *sc, struct pbuf *pb)
00715 {
00716   struct eth_hdr *ethhdr;
00717   u16_t etype;
00718   err_t res;
00719 
00720   /* make room for Ethernet header - should not fail */
00721   if (pbuf_add_header(pb, sizeof(struct eth_hdr)) != 0) {
00722     /* bail out */
00723     PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_output: could not allocate room for Ethernet header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
00724     LINK_STATS_INC(link.lenerr);
00725     ppp_memory_buffer_free(pb);
00726     return ERR_BUF;
00727   }
00728   ethhdr = (struct eth_hdr *)pb->payload;
00729   etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC;
00730   ethhdr->type = ppp_htons(etype);
00731   MEMCPY(&ethhdr->dest.addr, &sc->sc_dest.addr, sizeof(ethhdr->dest.addr));
00732   MEMCPY(&ethhdr->src.addr, &sc->sc_ethif->hwaddr, sizeof(ethhdr->src.addr));
00733 
00734   PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n",
00735       sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype,
00736       sc->sc_state, sc->sc_session,
00737       sc->sc_dest.addr[0], sc->sc_dest.addr[1], sc->sc_dest.addr[2], sc->sc_dest.addr[3], sc->sc_dest.addr[4], sc->sc_dest.addr[5],
00738       pb->tot_len));
00739 
00740   res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb);
00741 
00742   ppp_memory_buffer_free(pb);
00743 
00744   return res;
00745 }
00746 
00747 static err_t
00748 pppoe_send_padi(struct pppoe_softc *sc)
00749 {
00750   struct pbuf *pb;
00751   u8_t *p;
00752   int len;
00753 #ifdef PPPOE_TODO
00754   int l1 = 0, l2 = 0; /* XXX: gcc */
00755 #endif /* PPPOE_TODO */
00756 
00757   /* calculate length of frame (excluding ethernet header + pppoe header) */
00758   len = 2 + 2 + 2 + 2 + sizeof sc;  /* service name tag is required, host unique is send too */
00759 #ifdef PPPOE_TODO
00760   if (sc->sc_service_name != NULL) {
00761     l1 = (int)strlen(sc->sc_service_name);
00762     len += l1;
00763   }
00764   if (sc->sc_concentrator_name != NULL) {
00765     l2 = (int)strlen(sc->sc_concentrator_name);
00766     len += 2 + 2 + l2;
00767   }
00768 #endif /* PPPOE_TODO */
00769   PPP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff",
00770     sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff);
00771 
00772   /* allocate a buffer */
00773   pb = ppp_memory_buffer_allocate(ppp->netif->memory_manager, (u16_t)(PPPOE_HEADERLEN + len), PPP_BUF_HEAP);
00774   if (!pb) {
00775     return ERR_MEM;
00776   }
00777   PPP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len);
00778 
00779   p = (u8_t*)pb->payload;
00780   /* fill in pkt */
00781   PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, (u16_t)len);
00782   PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
00783 #ifdef PPPOE_TODO
00784   if (sc->sc_service_name != NULL) {
00785     PPPOE_ADD_16(p, l1);
00786     MEMCPY(p, sc->sc_service_name, l1);
00787     p += l1;
00788   } else
00789 #endif /* PPPOE_TODO */
00790   {
00791     PPPOE_ADD_16(p, 0);
00792   }
00793 #ifdef PPPOE_TODO
00794   if (sc->sc_concentrator_name != NULL) {
00795     PPPOE_ADD_16(p, PPPOE_TAG_ACNAME);
00796     PPPOE_ADD_16(p, l2);
00797     MEMCPY(p, sc->sc_concentrator_name, l2);
00798     p += l2;
00799   }
00800 #endif /* PPPOE_TODO */
00801   PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
00802   PPPOE_ADD_16(p, sizeof(sc));
00803   MEMCPY(p, &sc, sizeof sc);
00804 
00805   /* send pkt */
00806   return pppoe_output(sc, pb);
00807 }
00808 
00809 static void
00810 pppoe_timeout(void *arg)
00811 {
00812   u32_t retry_wait;
00813   int err;
00814   struct pppoe_softc *sc = (struct pppoe_softc*)arg;
00815 
00816   PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
00817 
00818   switch (sc->sc_state) {
00819     case PPPOE_STATE_PADI_SENT:
00820       /*
00821        * We have two basic ways of retrying:
00822        *  - Quick retry mode: try a few times in short sequence
00823        *  - Slow retry mode: we already had a connection successfully
00824        *    established and will try infinitely (without user
00825        *    intervention)
00826        * We only enter slow retry mode if IFF_LINK1 (aka autodial)
00827        * is not set.
00828        */
00829       if (sc->sc_padi_retried < 0xff) {
00830         sc->sc_padi_retried++;
00831       }
00832       if (!sc->pcb->settings.persist && sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) {
00833 #if 0
00834         if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) {
00835           /* slow retry mode */
00836           retry_wait = PPPOE_SLOW_RETRY;
00837         } else
00838 #endif
00839         {
00840           pppoe_abort_connect(sc);
00841           return;
00842         }
00843       }
00844       /* initialize for quick retry mode */
00845       retry_wait = PPP_MIN(PPPOE_DISC_TIMEOUT * sc->sc_padi_retried, PPPOE_SLOW_RETRY);
00846       if ((err = pppoe_send_padi(sc)) != 0) {
00847         sc->sc_padi_retried--;
00848         PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
00849         UNUSED_ARG(err); /* if PPPDEBUG is disabled */
00850       }
00851       sys_timeout(retry_wait, pppoe_timeout, sc);
00852       break;
00853 
00854     case PPPOE_STATE_PADR_SENT:
00855       sc->sc_padr_retried++;
00856       if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) {
00857         MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
00858         sc->sc_state = PPPOE_STATE_PADI_SENT;
00859         sc->sc_padr_retried = 0;
00860         if ((err = pppoe_send_padi(sc)) != 0) {
00861           PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
00862           UNUSED_ARG(err); /* if PPPDEBUG is disabled */
00863         }
00864         sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc);
00865         return;
00866       }
00867       if ((err = pppoe_send_padr(sc)) != 0) {
00868         sc->sc_padr_retried--;
00869         PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
00870         UNUSED_ARG(err); /* if PPPDEBUG is disabled */
00871       }
00872       sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc);
00873       break;
00874     default:
00875       return;  /* all done, work in peace */
00876   }
00877 }
00878 
00879 /* Start a connection (i.e. initiate discovery phase) */
00880 static void
00881 pppoe_connect(ppp_pcb *ppp, void *ctx)
00882 {
00883   err_t err;
00884   struct pppoe_softc *sc = (struct pppoe_softc *)ctx;
00885   lcp_options *lcp_wo;
00886   lcp_options *lcp_ao;
00887 #if PPP_IPV4_SUPPORT && VJ_SUPPORT
00888   ipcp_options *ipcp_wo;
00889   ipcp_options *ipcp_ao;
00890 #endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */
00891 
00892   sc->sc_session = 0;
00893   sc->sc_ac_cookie_len = 0;
00894   sc->sc_padi_retried = 0;
00895   sc->sc_padr_retried = 0;
00896   /* changed to real address later */
00897   MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
00898 #ifdef PPPOE_SERVER
00899   /* wait PADI if IFF_PASSIVE */
00900   if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {
00901     return 0;
00902   }
00903 #endif
00904 
00905   lcp_wo = &ppp->lcp_wantoptions;
00906   lcp_wo->mru = sc->sc_ethif->mtu-PPPOE_HEADERLEN-2; /* two byte PPP protocol discriminator, then IP data */
00907   lcp_wo->neg_asyncmap = 0;
00908   lcp_wo->neg_pcompression = 0;
00909   lcp_wo->neg_accompression = 0;
00910   lcp_wo->passive = 0;
00911   lcp_wo->silent = 0;
00912 
00913   lcp_ao = &ppp->lcp_allowoptions;
00914   lcp_ao->mru = sc->sc_ethif->mtu-PPPOE_HEADERLEN-2; /* two byte PPP protocol discriminator, then IP data */
00915   lcp_ao->neg_asyncmap = 0;
00916   lcp_ao->neg_pcompression = 0;
00917   lcp_ao->neg_accompression = 0;
00918 
00919 #if PPP_IPV4_SUPPORT && VJ_SUPPORT
00920   ipcp_wo = &ppp->ipcp_wantoptions;
00921   ipcp_wo->neg_vj = 0;
00922   ipcp_wo->old_vj = 0;
00923 
00924   ipcp_ao = &ppp->ipcp_allowoptions;
00925   ipcp_ao->neg_vj = 0;
00926   ipcp_ao->old_vj = 0;
00927 #endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */
00928 
00929   /* save state, in case we fail to send PADI */
00930   sc->sc_state = PPPOE_STATE_PADI_SENT;
00931   if ((err = pppoe_send_padi(sc)) != 0) {
00932     PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
00933   }
00934   sys_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc);
00935 }
00936 
00937 /* disconnect */
00938 static void
00939 pppoe_disconnect(ppp_pcb *ppp, void *ctx)
00940 {
00941   struct pppoe_softc *sc = (struct pppoe_softc *)ctx;
00942 
00943   PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
00944   if (sc->sc_state == PPPOE_STATE_SESSION) {
00945     pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest);
00946   }
00947 
00948   /* stop any timer, disconnect can be called while initiating is in progress */
00949   sys_untimeout(pppoe_timeout, sc);
00950   sc->sc_state = PPPOE_STATE_INITIAL;
00951 #ifdef PPPOE_SERVER
00952   if (sc->sc_hunique) {
00953     mem_free(sc->sc_hunique);
00954     sc->sc_hunique = NULL; /* probably not necessary, if state is initial we shouldn't have to access hunique anyway  */
00955   }
00956   sc->sc_hunique_len = 0; /* probably not necessary, if state is initial we shouldn't have to access hunique anyway  */
00957 #endif
00958   ppp_link_end(ppp); /* notify upper layers */
00959   return;
00960 }
00961 
00962 /* Connection attempt aborted */
00963 static void
00964 pppoe_abort_connect(struct pppoe_softc *sc)
00965 {
00966   PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
00967   sc->sc_state = PPPOE_STATE_INITIAL;
00968   ppp_link_failed(sc->pcb); /* notify upper layers */
00969 }
00970 
00971 /* Send a PADR packet */
00972 static err_t
00973 pppoe_send_padr(struct pppoe_softc *sc)
00974 {
00975   struct pbuf *pb;
00976   u8_t *p;
00977   size_t len;
00978 #ifdef PPPOE_TODO
00979   size_t l1 = 0; /* XXX: gcc */
00980 #endif /* PPPOE_TODO */
00981 
00982   len = 2 + 2 + 2 + 2 + sizeof(sc);    /* service name, host unique */
00983 #ifdef PPPOE_TODO
00984   if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */
00985     l1 = strlen(sc->sc_service_name);
00986     len += l1;
00987   }
00988 #endif /* PPPOE_TODO */
00989   if (sc->sc_ac_cookie_len > 0) {
00990     len += 2 + 2 + sc->sc_ac_cookie_len;  /* AC cookie */
00991   }
00992   PPP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff",
00993     sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff);
00994   pb = ppp_memory_buffer_allocate(ppp->netif->memory_manager, (u16_t)(PPPOE_HEADERLEN + len), PPP_BUF_HEAP);
00995   if (!pb) {
00996     return ERR_MEM;
00997   }
00998   PPP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len);
00999   p = (u8_t*)pb->payload;
01000   PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len);
01001   PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
01002 #ifdef PPPOE_TODO
01003   if (sc->sc_service_name != NULL) {
01004     PPPOE_ADD_16(p, l1);
01005     MEMCPY(p, sc->sc_service_name, l1);
01006     p += l1;
01007   } else
01008 #endif /* PPPOE_TODO */
01009   {
01010     PPPOE_ADD_16(p, 0);
01011   }
01012   if (sc->sc_ac_cookie_len > 0) {
01013     PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);
01014     PPPOE_ADD_16(p, sc->sc_ac_cookie_len);
01015     MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len);
01016     p += sc->sc_ac_cookie_len;
01017   }
01018   PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
01019   PPPOE_ADD_16(p, sizeof(sc));
01020   MEMCPY(p, &sc, sizeof sc);
01021 
01022   return pppoe_output(sc, pb);
01023 }
01024 
01025 /* send a PADT packet */
01026 static err_t
01027 pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest)
01028 {
01029   struct pbuf *pb;
01030   struct eth_hdr *ethhdr;
01031   err_t res;
01032   u8_t *p;
01033 
01034   pb = ppp_memory_buffer_allocate(ppp->netif->memory_manager, (u16_t)(PPPOE_HEADERLEN), PPP_BUF_HEAP);
01035   if (!pb) {
01036     return ERR_MEM;
01037   }
01038   PPP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len);
01039 
01040   if (pbuf_add_header(pb, sizeof(struct eth_hdr))) {
01041     PPPDEBUG(LOG_ERR, ("pppoe: pppoe_send_padt: could not allocate room for PPPoE header\n"));
01042     LINK_STATS_INC(link.lenerr);
01043     ppp_memory_buffer_free(pb);
01044     return ERR_BUF;
01045   }
01046   ethhdr = (struct eth_hdr *)pb->payload;
01047   ethhdr->type = PP_HTONS(ETHTYPE_PPPOEDISC);
01048   MEMCPY(&ethhdr->dest.addr, dest, sizeof(ethhdr->dest.addr));
01049   MEMCPY(&ethhdr->src.addr, &outgoing_if->hwaddr, sizeof(ethhdr->src.addr));
01050 
01051   p = (u8_t*)(ethhdr + 1);
01052   PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0);
01053 
01054   res = outgoing_if->linkoutput(outgoing_if, pb);
01055 
01056   ppp_memory_buffer_free(pb);
01057 
01058   return res;
01059 }
01060 
01061 #ifdef PPPOE_SERVER
01062 static err_t
01063 pppoe_send_pado(struct pppoe_softc *sc)
01064 {
01065   struct pbuf *pb;
01066   u8_t *p;
01067   size_t len;
01068 
01069   /* calc length */
01070   len = 0;
01071   /* include ac_cookie */
01072   len += 2 + 2 + sizeof(sc);
01073   /* include hunique */
01074   len += 2 + 2 + sc->sc_hunique_len;
01075   pb = ppp_memory_buffer_allocate(ppp->netif->memory_manager, (u16_t)(PPPOE_HEADERLEN + len), PPP_BUF_HEAP);
01076   if (!pb) {
01077     return ERR_MEM;
01078   }
01079   PPP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len);
01080   p = (u8_t*)pb->payload;
01081   PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len);
01082   PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);
01083   PPPOE_ADD_16(p, sizeof(sc));
01084   MEMCPY(p, &sc, sizeof(sc));
01085   p += sizeof(sc);
01086   PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
01087   PPPOE_ADD_16(p, sc->sc_hunique_len);
01088   MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len);
01089   return pppoe_output(sc, pb);
01090 }
01091 
01092 static err_t
01093 pppoe_send_pads(struct pppoe_softc *sc)
01094 {
01095   struct pbuf *pb;
01096   u8_t *p;
01097   size_t len, l1 = 0;  /* XXX: gcc */
01098 
01099   sc->sc_session = mono_time.tv_sec % 0xff + 1;
01100   /* calc length */
01101   len = 0;
01102   /* include hunique */
01103   len += 2 + 2 + 2 + 2 + sc->sc_hunique_len;  /* service name, host unique*/
01104   if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */
01105     l1 = strlen(sc->sc_service_name);
01106     len += l1;
01107   }
01108   pb = ppp_memory_buffer_allocate(ppp->netif->memory_manager, (u16_t)(PPPOE_HEADERLEN + len), PPP_BUF_HEAP);
01109   if (!pb) {
01110     return ERR_MEM;
01111   }
01112   PPP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len);
01113   p = (u8_t*)pb->payload;
01114   PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len);
01115   PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
01116   if (sc->sc_service_name != NULL) {
01117     PPPOE_ADD_16(p, l1);
01118     MEMCPY(p, sc->sc_service_name, l1);
01119     p += l1;
01120   } else {
01121     PPPOE_ADD_16(p, 0);
01122   }
01123   PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
01124   PPPOE_ADD_16(p, sc->sc_hunique_len);
01125   MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len);
01126   return pppoe_output(sc, pb);
01127 }
01128 #endif
01129 
01130 static err_t
01131 pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb)
01132 {
01133   u8_t *p;
01134   size_t len;
01135 
01136   len = pb->tot_len;
01137 
01138   /* make room for PPPoE header - should not fail */
01139   if (pbuf_add_header(pb, PPPOE_HEADERLEN) != 0) {
01140     /* bail out */
01141     PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for PPPoE header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
01142     LINK_STATS_INC(link.lenerr);
01143     ppp_memory_buffer_free(pb);
01144     return ERR_BUF;
01145   }
01146 
01147   p = (u8_t*)pb->payload;
01148   PPPOE_ADD_HEADER(p, 0, sc->sc_session, len);
01149 
01150   return pppoe_output(sc, pb);
01151 }
01152 
01153 #if 0 /*def PFIL_HOOKS*/
01154 static int
01155 pppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir)
01156 {
01157   struct pppoe_softc *sc;
01158   int s;
01159 
01160   if (mp != (struct pbuf **)PFIL_IFNET_DETACH) {
01161     return 0;
01162   }
01163 
01164   LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
01165     if (sc->sc_ethif != ifp) {
01166       continue;
01167     }
01168     if (sc->sc_sppp.pp_if.if_flags & IFF_UP) {
01169       sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
01170       PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": ethernet interface detached, going down\n",
01171           sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
01172     }
01173     sc->sc_ethif = NULL;
01174     pppoe_clear_softc(sc, "ethernet interface detached");
01175   }
01176 
01177   return 0;
01178 }
01179 #endif
01180 
01181 #if 0 /* UNUSED */
01182 static void
01183 pppoe_clear_softc(struct pppoe_softc *sc, const char *message)
01184 {
01185   PPP_UNUSED_ARG(message);
01186 
01187   /* stop timer */
01188   sys_untimeout(pppoe_timeout, sc);
01189   PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message));
01190   sc->sc_state = PPPOE_STATE_INITIAL;
01191   ppp_link_end(sc->pcb);  /* notify upper layers - /!\ dangerous /!\ - see pppoe_disc_input() */
01192 }
01193 #endif /* UNUSED */
01194 #endif /* PPP_SUPPORT && PPPOE_SUPPORT */