Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / lwip / netif / ppp / ppp_oe.c
1 /*****************************************************************************
2 * ppp_oe.c - PPP Over Ethernet implementation for lwIP.
3 *
4 * Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.
5 *
6 * The authors hereby grant permission to use, copy, modify, distribute,
7 * and license this software and its documentation for any purpose, provided
8 * that existing copyright notices are retained in all copies and that this
9 * notice and the following disclaimer are included verbatim in any 
10 * distributions. No written agreement, license, or royalty fee is required
11 * for any of the authorized uses.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
16 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 ******************************************************************************
25 * REVISION HISTORY
26 *
27 * 06-01-01 Marc Boucher <marc@mbsi.ca>
28 *   Ported to lwIP.
29 *****************************************************************************/
30
31
32
33 /* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */
34
35 /*-
36  * Copyright (c) 2002 The NetBSD Foundation, Inc.
37  * All rights reserved.
38  *
39  * This code is derived from software contributed to The NetBSD Foundation
40  * by Martin Husemann <martin@NetBSD.org>.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions
44  * are met:
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, this list of conditions and the following disclaimer.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice, this list of conditions and the following disclaimer in the
49  *    documentation and/or other materials provided with the distribution.
50  * 3. All advertising materials mentioning features or use of this software
51  *    must display the following acknowledgement:
52  *        This product includes software developed by the NetBSD
53  *        Foundation, Inc. and its contributors.
54  * 4. Neither the name of The NetBSD Foundation nor the names of its
55  *    contributors may be used to endorse or promote products derived
56  *    from this software without specific prior written permission.
57  *
58  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
59  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
60  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
61  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
62  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
63  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
64  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
65  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
66  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
67  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
68  * POSSIBILITY OF SUCH DAMAGE.
69  */
70
71 #include "lwip/opt.h"
72
73 #if PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */
74
75 #include "ppp.h"
76 #include "pppdebug.h"
77
78 #include "lwip/sys.h"
79
80 #include "netif/ppp_oe.h"
81 #include "netif/etharp.h"
82
83 #include <string.h>
84 #include <stdio.h>
85
86 /** @todo Replace this part with a simple list like other lwIP lists */
87 #ifndef _SYS_QUEUE_H_
88 #define _SYS_QUEUE_H_
89
90 /*
91  * A list is headed by a single forward pointer (or an array of forward
92  * pointers for a hash table header). The elements are doubly linked
93  * so that an arbitrary element can be removed without a need to
94  * traverse the list. New elements can be added to the list before
95  * or after an existing element or at the head of the list. A list
96  * may only be traversed in the forward direction.
97  *
98  * For details on the use of these macros, see the queue(3) manual page.
99  */
100
101 /*
102  * List declarations.
103  */
104 #define  LIST_HEAD(name, type)                                                 \
105 struct name {                                                                  \
106   struct type *lh_first;  /* first element */                                  \
107 }
108
109 #define  LIST_HEAD_INITIALIZER(head)                                           \
110   { NULL }
111
112 #define  LIST_ENTRY(type)                                                      \
113 struct {                                                                       \
114   struct type *le_next;  /* next element */                                    \
115   struct type **le_prev; /* address of previous next element */                \
116 }
117
118 /*
119  * List functions.
120  */
121
122 #define  LIST_EMPTY(head)  ((head)->lh_first == NULL)
123
124 #define  LIST_FIRST(head)  ((head)->lh_first)
125
126 #define  LIST_FOREACH(var, head, field)                                        \
127   for ((var) = LIST_FIRST((head));                                             \
128       (var);                                                                   \
129       (var) = LIST_NEXT((var), field))
130
131 #define  LIST_INIT(head) do {                                                  \
132   LIST_FIRST((head)) = NULL;                                                   \
133 } while (0)
134
135 #define  LIST_INSERT_AFTER(listelm, elm, field) do {                           \
136   if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)         \
137     LIST_NEXT((listelm), field)->field.le_prev =                               \
138         &LIST_NEXT((elm), field);                                              \
139   LIST_NEXT((listelm), field) = (elm);                                         \
140   (elm)->field.le_prev = &LIST_NEXT((listelm), field);                         \
141 } while (0)
142
143 #define  LIST_INSERT_BEFORE(listelm, elm, field) do {                          \
144   (elm)->field.le_prev = (listelm)->field.le_prev;                             \
145   LIST_NEXT((elm), field) = (listelm);                                         \
146   *(listelm)->field.le_prev = (elm);                                           \
147   (listelm)->field.le_prev = &LIST_NEXT((elm), field);                         \
148 } while (0)
149
150 #define  LIST_INSERT_HEAD(head, elm, field) do {                               \
151   if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)                  \
152     LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);              \
153   LIST_FIRST((head)) = (elm);                                                  \
154   (elm)->field.le_prev = &LIST_FIRST((head));                                  \
155 } while (0)
156
157 #define  LIST_NEXT(elm, field)  ((elm)->field.le_next)
158
159 #define  LIST_REMOVE(elm, field) do {                                          \
160   if (LIST_NEXT((elm), field) != NULL)                                         \
161     LIST_NEXT((elm), field)->field.le_prev =                                   \
162         (elm)->field.le_prev;                                                  \
163   *(elm)->field.le_prev = LIST_NEXT((elm), field);                             \
164 } while (0)
165
166 #endif /* !_SYS_QUEUE_H_ */
167
168
169 /* Add a 16 bit unsigned value to a buffer pointed to by PTR */
170 #define PPPOE_ADD_16(PTR, VAL) \
171     *(PTR)++ = (VAL) / 256;    \
172     *(PTR)++ = (VAL) % 256
173
174 /* Add a complete PPPoE header to the buffer pointed to by PTR */
175 #define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN)  \
176     *(PTR)++ = PPPOE_VERTYPE;  \
177     *(PTR)++ = (CODE);         \
178     PPPOE_ADD_16(PTR, SESS);   \
179     PPPOE_ADD_16(PTR, LEN)
180
181 #define PPPOE_DISC_TIMEOUT (5*1000)  /* base for quick timeout calculation */
182 #define PPPOE_SLOW_RETRY   (60*1000) /* persistent retry interval */
183 #define PPPOE_DISC_MAXPADI  4        /* retry PADI four times (quickly) */
184 #define PPPOE_DISC_MAXPADR  2        /* retry PADR twice */
185
186 #ifdef PPPOE_SERVER
187 /* from if_spppsubr.c */
188 #define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */
189 #endif
190
191 struct pppoe_softc {
192   LIST_ENTRY(pppoe_softc) sc_list;
193   struct netif *sc_ethif;      /* ethernet interface we are using */
194   int sc_pd;                   /* ppp unit number */
195   void (*sc_linkStatusCB)(int pd, int up);
196
197   int sc_state;                /* discovery phase or session connected */
198   struct eth_addr sc_dest;     /* hardware address of concentrator */
199   u16_t sc_session;            /* PPPoE session id */
200
201   char *sc_service_name;       /* if != NULL: requested name of service */
202   char *sc_concentrator_name;  /* if != NULL: requested concentrator id */
203   u8_t *sc_ac_cookie;          /* content of AC cookie we must echo back */
204   size_t sc_ac_cookie_len;     /* length of cookie data */
205 #ifdef PPPOE_SERVER
206   u8_t *sc_hunique;            /* content of host unique we must echo back */
207   size_t sc_hunique_len;       /* length of host unique */
208 #endif
209   int sc_padi_retried;         /* number of PADI retries already done */
210   int sc_padr_retried;         /* number of PADR retries already done */
211 };
212
213 /* input routines */
214 static void pppoe_dispatch_disc_pkt(struct netif *, struct pbuf *);
215
216 /* management routines */
217 static int pppoe_do_disconnect(struct pppoe_softc *);
218 static void pppoe_abort_connect(struct pppoe_softc *);
219 static void pppoe_clear_softc(struct pppoe_softc *, const char *);
220
221 /* internal timeout handling */
222 static void pppoe_timeout(void *);
223
224 /* sending actual protocol controll packets */
225 static err_t pppoe_send_padi(struct pppoe_softc *);
226 static err_t pppoe_send_padr(struct pppoe_softc *);
227 #ifdef PPPOE_SERVER
228 static err_t pppoe_send_pado(struct pppoe_softc *);
229 static err_t pppoe_send_pads(struct pppoe_softc *);
230 #endif
231 static err_t pppoe_send_padt(struct netif *, u_int, const u8_t *);
232
233 /* internal helper functions */
234 static struct pppoe_softc * pppoe_find_softc_by_session(u_int, struct netif *);
235 static struct pppoe_softc * pppoe_find_softc_by_hunique(u8_t *, size_t, struct netif *);
236
237 static LIST_HEAD(pppoe_softc_head, pppoe_softc) pppoe_softc_list;
238
239 int pppoe_hdrlen;
240
241 void
242 pppoe_init(void)
243 {
244   pppoe_hdrlen = sizeof(struct eth_hdr) + PPPOE_HEADERLEN;
245   LIST_INIT(&pppoe_softc_list);
246 }
247
248 err_t
249 pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr)
250 {
251   struct pppoe_softc *sc;
252
253   sc = mem_malloc(sizeof(struct pppoe_softc));
254   if(!sc) {
255     *scptr = NULL;
256     return ERR_MEM;
257   }
258   memset(sc, 0, sizeof(struct pppoe_softc));
259
260   /* changed to real address later */
261   MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
262
263   sc->sc_pd = pd;
264   sc->sc_linkStatusCB = linkStatusCB;
265   sc->sc_ethif = ethif;
266
267   LIST_INSERT_HEAD(&pppoe_softc_list, sc, sc_list);
268
269   *scptr = sc;
270
271   return ERR_OK;
272 }
273
274 err_t
275 pppoe_destroy(struct netif *ifp)
276 {
277   struct pppoe_softc * sc;
278
279   LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
280     if (sc->sc_ethif == ifp) {
281       break;
282     }
283   }
284
285   if(!(sc && (sc->sc_ethif == ifp))) {
286     return ERR_IF;
287   }
288
289   tcpip_untimeout(pppoe_timeout, sc);
290   LIST_REMOVE(sc, sc_list);
291
292   if (sc->sc_concentrator_name) {
293     mem_free(sc->sc_concentrator_name);
294   }
295   if (sc->sc_service_name) {
296     mem_free(sc->sc_service_name);
297   }
298   if (sc->sc_ac_cookie) {
299     mem_free(sc->sc_ac_cookie);
300   }
301   mem_free(sc);
302
303   return ERR_OK;
304 }
305
306 /*
307  * Find the interface handling the specified session.
308  * Note: O(number of sessions open), this is a client-side only, mean
309  * and lean implementation, so number of open sessions typically should
310  * be 1.
311  */
312 static struct pppoe_softc *
313 pppoe_find_softc_by_session(u_int session, struct netif *rcvif)
314 {
315   struct pppoe_softc *sc;
316
317   if (session == 0) {
318     return NULL;
319   }
320
321   LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
322     if (sc->sc_state == PPPOE_STATE_SESSION
323         && sc->sc_session == session) {
324       if (sc->sc_ethif == rcvif) {
325         return sc;
326       } else {
327         return NULL;
328       }
329     }
330   }
331   return NULL;
332 }
333
334 /* Check host unique token passed and return appropriate softc pointer,
335  * or NULL if token is bogus. */
336 static struct pppoe_softc *
337 pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif)
338 {
339   struct pppoe_softc *sc, *t;
340
341   if (LIST_EMPTY(&pppoe_softc_list)) {
342     return NULL;
343   }
344
345   if (len != sizeof sc) {
346     return NULL;
347   }
348   MEMCPY(&t, token, len);
349
350   LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
351     if (sc == t) {
352       break;
353     }
354   }
355
356   if (sc == NULL) {
357     PPPDEBUG((LOG_DEBUG, "pppoe: alien host unique tag, no session found\n"));
358     return NULL;
359   }
360
361   /* should be safe to access *sc now */
362   if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) {
363     printf("%c%c%"U16_F": host unique tag found, but it belongs to a connection in state %d\n",
364       sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_state);
365     return NULL;
366   }
367   if (sc->sc_ethif != rcvif) {
368     printf("%c%c%"U16_F": wrong interface, not accepting host unique\n",
369       sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
370     return NULL;
371   }
372   return sc;
373 }
374
375 static void
376 pppoe_linkstatus_up(void *arg)
377 {
378   struct pppoe_softc *sc = (struct pppoe_softc*)arg;
379
380   sc->sc_linkStatusCB(sc->sc_pd, 1);
381 }
382
383 /* analyze and handle a single received packet while not in session state */
384 static void
385 pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb)
386 {
387   u16_t tag, len;
388   u16_t session, plen;
389   struct pppoe_softc *sc;
390   const char *err_msg;
391   char devname[6];
392   char *error;
393   u8_t *ac_cookie;
394   size_t ac_cookie_len;
395 #ifdef PPPOE_SERVER
396   u8_t *hunique;
397   size_t hunique_len;
398 #endif
399   struct pppoehdr *ph;
400   struct pppoetag pt;
401   int off = 0, err, errortag;
402   struct eth_hdr *ethhdr;
403
404   pb = pppSingleBuf(pb);
405
406   strcpy(devname, "pppoe");  /* as long as we don't know which instance */
407   err_msg = NULL;
408   errortag = 0;
409   if (pb->len < sizeof(*ethhdr)) {
410     goto done;
411   }
412   ethhdr = (struct eth_hdr *)pb->payload;
413   off += sizeof(*ethhdr);
414
415   ac_cookie = NULL;
416   ac_cookie_len = 0;
417 #ifdef PPPOE_SERVER
418   hunique = NULL;
419   hunique_len = 0;
420 #endif
421   session = 0;
422   if (pb->len - off <= PPPOE_HEADERLEN) {
423     printf("pppoe: packet too short: %d\n", pb->len);
424     goto done;
425   }
426
427   ph = (struct pppoehdr *) (ethhdr + 1);
428   if (ph->vertype != PPPOE_VERTYPE) {
429     printf("pppoe: unknown version/type packet: 0x%x\n", ph->vertype);
430     goto done;
431   }
432   session = ntohs(ph->session);
433   plen = ntohs(ph->plen);
434   off += sizeof(*ph);
435
436   if (plen + off > pb->len) {
437     printf("pppoe: packet content does not fit: data available = %d, packet size = %u\n",
438         pb->len - off, plen);
439     goto done;
440   }
441   if(pb->tot_len == pb->len) {
442     pb->tot_len = pb->len = off + plen; /* ignore trailing garbage */
443   }
444   tag = 0;
445   len = 0;
446   sc = NULL;
447   while (off + sizeof(pt) <= pb->len) {
448     MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt));
449     tag = ntohs(pt.tag);
450     len = ntohs(pt.len);
451     if (off + sizeof(pt) + len > pb->len) {
452       printf("pppoe: tag 0x%x len 0x%x is too long\n", tag, len);
453       goto done;
454     }
455     switch (tag) {
456       case PPPOE_TAG_EOL:
457         goto breakbreak;
458       case PPPOE_TAG_SNAME:
459         break;  /* ignored */
460       case PPPOE_TAG_ACNAME:
461         break;  /* ignored */
462       case PPPOE_TAG_HUNIQUE:
463         if (sc != NULL) {
464           break;
465         }
466 #ifdef PPPOE_SERVER
467         hunique = (u8_t*)pb->payload + off + sizeof(pt);
468         hunique_len = len;
469 #endif
470         sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif);
471         if (sc != NULL) {
472           snprintf(devname, sizeof(devname), "%c%c%"U16_F, sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
473         }
474         break;
475       case PPPOE_TAG_ACCOOKIE:
476         if (ac_cookie == NULL) {
477           ac_cookie = (u8_t*)pb->payload + off + sizeof(pt);
478           ac_cookie_len = len;
479         }
480         break;
481       case PPPOE_TAG_SNAME_ERR:
482         err_msg = "SERVICE NAME ERROR";
483         errortag = 1;
484         break;
485       case PPPOE_TAG_ACSYS_ERR:
486         err_msg = "AC SYSTEM ERROR";
487         errortag = 1;
488         break;
489       case PPPOE_TAG_GENERIC_ERR:
490         err_msg = "GENERIC ERROR";
491         errortag = 1;
492         break;
493     }
494     if (err_msg) {
495       error = NULL;
496       if (errortag && len) {
497         error = mem_malloc(len+1);
498         if (error) {
499           strncpy(error, (char*)pb->payload + off + sizeof(pt), len);
500           error[len-1] = '\0';
501         }
502       }
503       if (error) {
504         printf("%s: %s: %s\n", devname, err_msg, error);
505         mem_free(error);
506       } else {
507         printf("%s: %s\n", devname, err_msg);
508       }
509       if (errortag) {
510         goto done;
511       }
512     }
513     off += sizeof(pt) + len;
514   }
515
516 breakbreak:;
517   switch (ph->code) {
518     case PPPOE_CODE_PADI:
519 #ifdef PPPOE_SERVER
520       /*
521        * got service name, concentrator name, and/or host unique.
522        * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP.
523        */
524       if (LIST_EMPTY(&pppoe_softc_list)) {
525         goto done;
526       }
527       LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
528         if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) {
529           continue;
530         }
531         if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {
532           continue;
533         }
534         if (sc->sc_state == PPPOE_STATE_INITIAL) {
535           break;
536         }
537       }
538       if (sc == NULL) {
539         /* printf("pppoe: free passive interface is not found\n"); */
540         goto done;
541       }
542       if (hunique) {
543         if (sc->sc_hunique) {
544           mem_free(sc->sc_hunique);
545         }
546         sc->sc_hunique = mem_malloc(hunique_len);
547         if (sc->sc_hunique == NULL) {
548           goto done;
549         }
550         sc->sc_hunique_len = hunique_len;
551         MEMCPY(sc->sc_hunique, hunique, hunique_len);
552       }
553       MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest);
554       sc->sc_state = PPPOE_STATE_PADO_SENT;
555       pppoe_send_pado(sc);
556       break;
557   #endif /* PPPOE_SERVER */
558     case PPPOE_CODE_PADR:
559   #ifdef PPPOE_SERVER
560       /*
561        * get sc from ac_cookie if IFF_PASSIVE
562        */
563       if (ac_cookie == NULL) {
564         /* be quiet if there is not a single pppoe instance */
565         printf("pppoe: received PADR but not includes ac_cookie\n");
566         goto done;
567       }
568       sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif);
569       if (sc == NULL) {
570         /* be quiet if there is not a single pppoe instance */
571         if (!LIST_EMPTY(&pppoe_softc_list)) {
572           printf("pppoe: received PADR but could not find request for it\n");
573         }
574         goto done;
575       }
576       if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
577         printf("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
578         goto done;
579       }
580       if (hunique) {
581         if (sc->sc_hunique) {
582           mem_free(sc->sc_hunique);
583         }
584         sc->sc_hunique = mem_malloc(hunique_len);
585         if (sc->sc_hunique == NULL) {
586           goto done;
587         }
588         sc->sc_hunique_len = hunique_len;
589         MEMCPY(sc->sc_hunique, hunique, hunique_len);
590       }
591       pppoe_send_pads(sc);
592       sc->sc_state = PPPOE_STATE_SESSION;
593       tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */
594       break;
595   #else
596       /* ignore, we are no access concentrator */
597       goto done;
598   #endif /* PPPOE_SERVER */
599     case PPPOE_CODE_PADO:
600       if (sc == NULL) {
601         /* be quiet if there is not a single pppoe instance */
602         if (!LIST_EMPTY(&pppoe_softc_list)) {
603           printf("pppoe: received PADO but could not find request for it\n");
604         }
605         goto done;
606       }
607       if (sc->sc_state != PPPOE_STATE_PADI_SENT) {
608         printf("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
609         goto done;
610       }
611       if (ac_cookie) {
612         if (sc->sc_ac_cookie) {
613           mem_free(sc->sc_ac_cookie);
614         }
615         sc->sc_ac_cookie = mem_malloc(ac_cookie_len);
616         if (sc->sc_ac_cookie == NULL) {
617           goto done;
618         }
619         sc->sc_ac_cookie_len = ac_cookie_len;
620         MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len);
621       }
622       MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr));
623       tcpip_untimeout(pppoe_timeout, sc);
624       sc->sc_padr_retried = 0;
625       sc->sc_state = PPPOE_STATE_PADR_SENT;
626       if ((err = pppoe_send_padr(sc)) != 0) {
627         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));
628       }
629       tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc);
630       break;
631     case PPPOE_CODE_PADS:
632       if (sc == NULL) {
633         goto done;
634       }
635       sc->sc_session = session;
636       tcpip_untimeout(pppoe_timeout, sc);
637       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));
638       sc->sc_state = PPPOE_STATE_SESSION;
639       tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */
640       break;
641     case PPPOE_CODE_PADT:
642       if (sc == NULL) {
643         goto done;
644       }
645       pppoe_clear_softc(sc, "received PADT");
646       break;
647     default:
648       if(sc) {
649         printf("%c%c%"U16_F": unknown code (0x%04x) session = 0x%04x\n",
650             sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num,
651             ph->code, session);
652       } else {
653         printf("pppoe: unknown code (0x%04x) session = 0x%04x\n", ph->code, session);
654       }
655       break;
656   }
657
658 done:
659   pbuf_free(pb);
660   return;
661 }
662
663 void
664 pppoe_disc_input(struct netif *netif, struct pbuf *p)
665 {
666   /* avoid error messages if there is not a single pppoe instance */
667   if (!LIST_EMPTY(&pppoe_softc_list)) {
668     pppoe_dispatch_disc_pkt(netif, p);
669   } else {
670     pbuf_free(p);
671   }
672 }
673
674 void
675 pppoe_data_input(struct netif *netif, struct pbuf *pb)
676 {
677   u16_t session, plen;
678   struct pppoe_softc *sc;
679   struct pppoehdr *ph;
680 #ifdef PPPOE_TERM_UNKNOWN_SESSIONS
681   u8_t shost[ETHER_ADDR_LEN];
682 #endif
683
684 #ifdef PPPOE_TERM_UNKNOWN_SESSIONS
685   MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost));
686 #endif
687   if (pbuf_header(pb, -(int)sizeof(struct eth_hdr)) != 0) {
688     /* bail out */
689     PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header failed\n"));
690     LINK_STATS_INC(link.lenerr);
691     goto drop;
692   } 
693
694   pb = pppSingleBuf (pb);
695
696   if (pb->len <= PPPOE_HEADERLEN) {
697     printf("pppoe (data): dropping too short packet: %d bytes\n", pb->len);
698     goto drop;
699   }
700
701   if (pb->len < sizeof(*ph)) {
702     printf("pppoe_data_input: could not get PPPoE header\n");
703     goto drop;
704   }
705   ph = (struct pppoehdr *)pb->payload;
706
707   if (ph->vertype != PPPOE_VERTYPE) {
708     printf("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype);
709     goto drop;
710   }
711   if (ph->code != 0) {
712     goto drop;
713   }
714
715   session = ntohs(ph->session);
716   sc = pppoe_find_softc_by_session(session, netif);
717   if (sc == NULL) {
718 #ifdef PPPOE_TERM_UNKNOWN_SESSIONS
719     printf("pppoe: input for unknown session 0x%x, sending PADT\n", session);
720     pppoe_send_padt(netif, session, shost);
721 #endif
722     goto drop;
723   }
724
725   plen = ntohs(ph->plen);
726
727   if (pbuf_header(pb, -(int)(PPPOE_HEADERLEN)) != 0) {
728     /* bail out */
729     PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header PPPOE_HEADERLEN failed\n"));
730     LINK_STATS_INC(link.lenerr);
731     goto drop;
732   } 
733
734   PPPDEBUG((LOG_DEBUG, "pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n",
735         sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num,
736         pb->len, plen));
737
738   if (pb->len < plen) {
739     goto drop;
740   }
741
742   pppInProcOverEthernet(sc->sc_pd, pb);
743
744   return;
745
746 drop:
747   pbuf_free(pb);
748 }
749
750 static err_t
751 pppoe_output(struct pppoe_softc *sc, struct pbuf *pb)
752 {
753   struct eth_hdr *ethhdr;
754   u16_t etype;
755   err_t res;
756
757   if (!sc->sc_ethif) {
758     pbuf_free(pb);
759     return ERR_IF;
760   }
761
762   ethhdr = (struct eth_hdr *)pb->payload;
763   etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC;
764   ethhdr->type = htons(etype);
765   MEMCPY(ethhdr->dest.addr, sc->sc_dest.addr, sizeof(ethhdr->dest.addr));
766   MEMCPY(ethhdr->src.addr, ((struct eth_addr *)sc->sc_ethif->hwaddr)->addr, sizeof(ethhdr->src.addr));
767
768   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",
769       sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype,
770       sc->sc_state, sc->sc_session,
771       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],
772       pb->tot_len));
773
774   res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb);
775
776   pbuf_free(pb);
777
778   return res;
779 }
780
781 static err_t
782 pppoe_send_padi(struct pppoe_softc *sc)
783 {
784   struct pbuf *pb;
785   u8_t *p;
786   int len, l1 = 0, l2 = 0; /* XXX: gcc */
787
788   if (sc->sc_state >PPPOE_STATE_PADI_SENT) {
789     PPPDEBUG((LOG_ERR, "ERROR: pppoe_send_padi in state %d", sc->sc_state));
790   }
791
792   /* calculate length of frame (excluding ethernet header + pppoe header) */
793   len = 2 + 2 + 2 + 2 + sizeof sc;  /* service name tag is required, host unique is send too */
794   if (sc->sc_service_name != NULL) {
795     l1 = strlen(sc->sc_service_name);
796     len += l1;
797   }
798   if (sc->sc_concentrator_name != NULL) {
799     l2 = strlen(sc->sc_concentrator_name);
800     len += 2 + 2 + l2;
801   }
802
803   /* allocate a buffer */
804   pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);
805   if (!pb) {
806     return ERR_MEM;
807   }
808
809   p = (u8_t*)pb->payload + sizeof (struct eth_hdr);
810   /* fill in pkt */
811   PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, len);
812   PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
813   if (sc->sc_service_name != NULL) {
814     PPPOE_ADD_16(p, l1);
815     MEMCPY(p, sc->sc_service_name, l1);
816     p += l1;
817   } else {
818     PPPOE_ADD_16(p, 0);
819   }
820   if (sc->sc_concentrator_name != NULL) {
821     PPPOE_ADD_16(p, PPPOE_TAG_ACNAME);
822     PPPOE_ADD_16(p, l2);
823     MEMCPY(p, sc->sc_concentrator_name, l2);
824     p += l2;
825   }
826   PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
827   PPPOE_ADD_16(p, sizeof(sc));
828   MEMCPY(p, &sc, sizeof sc);
829
830   /* send pkt */
831   return pppoe_output(sc, pb);
832 }
833
834 static void
835 pppoe_timeout(void *arg)
836 {
837   int retry_wait, err;
838   struct pppoe_softc *sc = (struct pppoe_softc*)arg;
839
840   PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
841
842   switch (sc->sc_state) {
843     case PPPOE_STATE_PADI_SENT:
844       /*
845        * We have two basic ways of retrying:
846        *  - Quick retry mode: try a few times in short sequence
847        *  - Slow retry mode: we already had a connection successfully
848        *    established and will try infinitely (without user
849        *    intervention)
850        * We only enter slow retry mode if IFF_LINK1 (aka autodial)
851        * is not set.
852        */
853
854       /* initialize for quick retry mode */
855       retry_wait = PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried);
856
857       sc->sc_padi_retried++;
858       if (sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) {
859 #if 0
860         if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) {
861           /* slow retry mode */
862           retry_wait = PPPOE_SLOW_RETRY;
863         } else
864 #endif
865         {
866           pppoe_abort_connect(sc);
867           return;
868         }
869       }
870       if ((err = pppoe_send_padi(sc)) != 0) {
871         sc->sc_padi_retried--;
872         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));
873       }
874       tcpip_timeout(retry_wait, pppoe_timeout, sc);
875       break;
876
877     case PPPOE_STATE_PADR_SENT:
878       sc->sc_padr_retried++;
879       if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) {
880         MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
881         sc->sc_state = PPPOE_STATE_PADI_SENT;
882         sc->sc_padr_retried = 0;
883         if ((err = pppoe_send_padi(sc)) != 0) {
884           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));
885         }
886         tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc);
887         return;
888       }
889       if ((err = pppoe_send_padr(sc)) != 0) {
890         sc->sc_padr_retried--;
891         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));
892       }
893       tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc);
894       break;
895     case PPPOE_STATE_CLOSING:
896       pppoe_do_disconnect(sc);
897       break;
898     default:
899       return;  /* all done, work in peace */
900   }
901 }
902
903 /* Start a connection (i.e. initiate discovery phase) */
904 int
905 pppoe_connect(struct pppoe_softc *sc)
906 {
907   int err;
908
909   if (sc->sc_state != PPPOE_STATE_INITIAL) {
910     return EBUSY;
911   }
912
913 #ifdef PPPOE_SERVER
914   /* wait PADI if IFF_PASSIVE */
915   if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {
916     return 0;
917   }
918 #endif
919   /* save state, in case we fail to send PADI */
920   sc->sc_state = PPPOE_STATE_PADI_SENT;
921   sc->sc_padr_retried = 0;
922   err = pppoe_send_padi(sc);
923   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));
924   tcpip_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc);
925   return err;
926 }
927
928 /* disconnect */
929 void
930 pppoe_disconnect(struct pppoe_softc *sc)
931 {
932   if (sc->sc_state < PPPOE_STATE_SESSION) {
933     return;
934   }
935   /*
936    * Do not call pppoe_disconnect here, the upper layer state
937    * machine gets confused by this. We must return from this
938    * function and defer disconnecting to the timeout handler.
939    */
940   sc->sc_state = PPPOE_STATE_CLOSING;
941   tcpip_timeout(20, pppoe_timeout, sc);
942 }
943
944 static int
945 pppoe_do_disconnect(struct pppoe_softc *sc)
946 {
947   int err;
948
949   if (sc->sc_state < PPPOE_STATE_SESSION) {
950     err = EBUSY;
951   } else {
952     PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
953     err = pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest);
954   }
955
956   /* cleanup softc */
957   sc->sc_state = PPPOE_STATE_INITIAL;
958   MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
959   if (sc->sc_ac_cookie) {
960     mem_free(sc->sc_ac_cookie);
961     sc->sc_ac_cookie = NULL;
962   }
963   sc->sc_ac_cookie_len = 0;
964 #ifdef PPPOE_SERVER
965   if (sc->sc_hunique) {
966     mem_free(sc->sc_hunique);
967     sc->sc_hunique = NULL;
968   }
969   sc->sc_hunique_len = 0;
970 #endif
971   sc->sc_session = 0;
972
973   sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */
974
975   return err;
976 }
977
978 /* Connection attempt aborted */
979 static void
980 pppoe_abort_connect(struct pppoe_softc *sc)
981 {
982   printf("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
983   sc->sc_state = PPPOE_STATE_CLOSING;
984
985   sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */
986
987   /* clear connection state */
988   MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
989   sc->sc_state = PPPOE_STATE_INITIAL;
990 }
991
992 /* Send a PADR packet */
993 static err_t
994 pppoe_send_padr(struct pppoe_softc *sc)
995 {
996   struct pbuf *pb;
997   u8_t *p;
998   size_t len, l1 = 0; /* XXX: gcc */
999
1000   if (sc->sc_state != PPPOE_STATE_PADR_SENT) {
1001     return ERR_CONN;
1002   }
1003
1004   len = 2 + 2 + 2 + 2 + sizeof(sc);    /* service name, host unique */
1005   if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */
1006     l1 = strlen(sc->sc_service_name);
1007     len += l1;
1008   }
1009   if (sc->sc_ac_cookie_len > 0) {
1010     len += 2 + 2 + sc->sc_ac_cookie_len;  /* AC cookie */
1011   }
1012   pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);
1013   if (!pb) {
1014     return ERR_MEM;
1015   }
1016   p = (u8_t*)pb->payload + sizeof (struct eth_hdr);
1017   PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len);
1018   PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
1019   if (sc->sc_service_name != NULL) {
1020     PPPOE_ADD_16(p, l1);
1021     MEMCPY(p, sc->sc_service_name, l1);
1022     p += l1;
1023   } else {
1024     PPPOE_ADD_16(p, 0);
1025   }
1026   if (sc->sc_ac_cookie_len > 0) {
1027     PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);
1028     PPPOE_ADD_16(p, sc->sc_ac_cookie_len);
1029     MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len);
1030     p += sc->sc_ac_cookie_len;
1031   }
1032   PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
1033   PPPOE_ADD_16(p, sizeof(sc));
1034   MEMCPY(p, &sc, sizeof sc);
1035
1036   return pppoe_output(sc, pb);
1037 }
1038
1039 /* send a PADT packet */
1040 static err_t
1041 pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest)
1042 {
1043   struct pbuf *pb;
1044   struct eth_hdr *ethhdr;
1045   err_t res;
1046   u8_t *p;
1047
1048   pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN, PBUF_RAM);
1049   if (!pb) {
1050     return ERR_MEM;
1051   }
1052
1053   ethhdr = (struct eth_hdr *)pb->payload;
1054   ethhdr->type = htons(ETHTYPE_PPPOEDISC);
1055   MEMCPY(ethhdr->dest.addr, dest, sizeof(ethhdr->dest.addr));
1056   MEMCPY(ethhdr->src.addr, ((struct eth_addr *)outgoing_if->hwaddr)->addr, sizeof(ethhdr->src.addr));
1057
1058   p = (u8_t*)(ethhdr + 1);
1059   PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0);
1060
1061   res = outgoing_if->linkoutput(outgoing_if, pb);
1062
1063   pbuf_free(pb);
1064
1065   return res;
1066 }
1067
1068 #ifdef PPPOE_SERVER
1069 static err_t
1070 pppoe_send_pado(struct pppoe_softc *sc)
1071 {
1072   struct pbuf *pb;
1073   u8_t *p;
1074   size_t len;
1075
1076   if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
1077     return ERR_CONN;
1078   }
1079
1080   /* calc length */
1081   len = 0;
1082   /* include ac_cookie */
1083   len += 2 + 2 + sizeof(sc);
1084   /* include hunique */
1085   len += 2 + 2 + sc->sc_hunique_len;
1086   pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);
1087   if (!pb) {
1088     return ERR_MEM;
1089   }
1090   p = (u8_t*)pb->payload + sizeof (struct eth_hdr);
1091   PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len);
1092   PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);
1093   PPPOE_ADD_16(p, sizeof(sc));
1094   MEMCPY(p, &sc, sizeof(sc));
1095   p += sizeof(sc);
1096   PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
1097   PPPOE_ADD_16(p, sc->sc_hunique_len);
1098   MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len);
1099   return pppoe_output(sc, pb);
1100 }
1101
1102 static err_t
1103 pppoe_send_pads(struct pppoe_softc *sc)
1104 {
1105   struct pbuf *pb;
1106   u8_t *p;
1107   size_t len, l1 = 0;  /* XXX: gcc */
1108
1109   if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
1110     return ERR_CONN;
1111   }
1112
1113   sc->sc_session = mono_time.tv_sec % 0xff + 1;
1114   /* calc length */
1115   len = 0;
1116   /* include hunique */
1117   len += 2 + 2 + 2 + 2 + sc->sc_hunique_len;  /* service name, host unique*/
1118   if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */
1119     l1 = strlen(sc->sc_service_name);
1120     len += l1;
1121   }
1122   pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);
1123   if (!pb) {
1124     return ERR_MEM;
1125   }
1126   p = (u8_t*)pb->payload + sizeof (struct eth_hdr);
1127   PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len);
1128   PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
1129   if (sc->sc_service_name != NULL) {
1130     PPPOE_ADD_16(p, l1);
1131     MEMCPY(p, sc->sc_service_name, l1);
1132     p += l1;
1133   } else {
1134     PPPOE_ADD_16(p, 0);
1135   }
1136   PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
1137   PPPOE_ADD_16(p, sc->sc_hunique_len);
1138   MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len);
1139   return pppoe_output(sc, pb);
1140 }
1141 #endif
1142
1143 err_t
1144 pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb)
1145 {
1146   u8_t *p;
1147   size_t len;
1148
1149   /* are we ready to process data yet? */
1150   if (sc->sc_state < PPPOE_STATE_SESSION) {
1151     /*sppp_flush(&sc->sc_sppp.pp_if);*/
1152     pbuf_free(pb);
1153     return ERR_CONN;
1154   }
1155
1156   len = pb->tot_len;
1157
1158   /* make room for Ethernet header - should not fail */
1159   if (pbuf_header(pb, sizeof(struct eth_hdr) + PPPOE_HEADERLEN) != 0) {
1160     /* bail out */
1161     PPPDEBUG((LOG_ERR, "pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
1162     LINK_STATS_INC(link.lenerr);
1163     pbuf_free(pb);
1164     return ERR_BUF;
1165   } 
1166
1167   p = (u8_t*)pb->payload + sizeof(struct eth_hdr);
1168   PPPOE_ADD_HEADER(p, 0, sc->sc_session, len);
1169
1170   return pppoe_output(sc, pb);
1171 }
1172
1173 #if 0 /*def PFIL_HOOKS*/
1174 static int
1175 pppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir)
1176 {
1177   struct pppoe_softc *sc;
1178   int s;
1179
1180   if (mp != (struct pbuf **)PFIL_IFNET_DETACH) {
1181     return 0;
1182   }
1183
1184   LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
1185     if (sc->sc_ethif != ifp) {
1186       continue;
1187     }
1188     if (sc->sc_sppp.pp_if.if_flags & IFF_UP) {
1189       sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
1190       printf("%c%c%"U16_F": ethernet interface detached, going down\n",
1191           sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
1192     }
1193     sc->sc_ethif = NULL;
1194     pppoe_clear_softc(sc, "ethernet interface detached");
1195   }
1196
1197   return 0;
1198 }
1199 #endif
1200
1201 static void
1202 pppoe_clear_softc(struct pppoe_softc *sc, const char *message)
1203 {
1204   LWIP_UNUSED_ARG(message);
1205
1206   /* stop timer */
1207   tcpip_untimeout(pppoe_timeout, sc);
1208   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));
1209
1210   /* fix our state */
1211   sc->sc_state = PPPOE_STATE_INITIAL;
1212
1213   /* notify upper layers */
1214   sc->sc_linkStatusCB(sc->sc_pd, 0);
1215
1216   /* clean up softc */
1217   MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
1218   if (sc->sc_ac_cookie) {
1219     mem_free(sc->sc_ac_cookie);
1220     sc->sc_ac_cookie = NULL;
1221   }
1222   sc->sc_ac_cookie_len = 0;
1223   sc->sc_session = 0;
1224 }
1225
1226 #endif /* PPPOE_SUPPORT */
1227