Experimental HTTPClient with proxy support

Committer:
igorsk
Date:
Wed Jun 29 16:01:58 2011 +0000
Revision:
0:b56b6a05cad4

        

Who changed what in which revision?

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