Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.

Dependencies:   mbed

Committer:
iva2k
Date:
Sat Jun 12 06:01:50 2010 +0000
Revision:
0:e614f7875b60

        

Who changed what in which revision?

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