1195972f6Sopenharmony_ci/***************************************************************************** 2195972f6Sopenharmony_ci* pppoe.c - PPP Over Ethernet implementation for lwIP. 3195972f6Sopenharmony_ci* 4195972f6Sopenharmony_ci* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. 5195972f6Sopenharmony_ci* 6195972f6Sopenharmony_ci* The authors hereby grant permission to use, copy, modify, distribute, 7195972f6Sopenharmony_ci* and license this software and its documentation for any purpose, provided 8195972f6Sopenharmony_ci* that existing copyright notices are retained in all copies and that this 9195972f6Sopenharmony_ci* notice and the following disclaimer are included verbatim in any 10195972f6Sopenharmony_ci* distributions. No written agreement, license, or royalty fee is required 11195972f6Sopenharmony_ci* for any of the authorized uses. 12195972f6Sopenharmony_ci* 13195972f6Sopenharmony_ci* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR 14195972f6Sopenharmony_ci* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15195972f6Sopenharmony_ci* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16195972f6Sopenharmony_ci* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 17195972f6Sopenharmony_ci* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18195972f6Sopenharmony_ci* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19195972f6Sopenharmony_ci* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20195972f6Sopenharmony_ci* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21195972f6Sopenharmony_ci* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22195972f6Sopenharmony_ci* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23195972f6Sopenharmony_ci* 24195972f6Sopenharmony_ci****************************************************************************** 25195972f6Sopenharmony_ci* REVISION HISTORY 26195972f6Sopenharmony_ci* 27195972f6Sopenharmony_ci* 06-01-01 Marc Boucher <marc@mbsi.ca> 28195972f6Sopenharmony_ci* Ported to lwIP. 29195972f6Sopenharmony_ci*****************************************************************************/ 30195972f6Sopenharmony_ci 31195972f6Sopenharmony_ci 32195972f6Sopenharmony_ci 33195972f6Sopenharmony_ci/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ 34195972f6Sopenharmony_ci 35195972f6Sopenharmony_ci/*- 36195972f6Sopenharmony_ci * Copyright (c) 2002 The NetBSD Foundation, Inc. 37195972f6Sopenharmony_ci * All rights reserved. 38195972f6Sopenharmony_ci * 39195972f6Sopenharmony_ci * This code is derived from software contributed to The NetBSD Foundation 40195972f6Sopenharmony_ci * by Martin Husemann <martin@NetBSD.org>. 41195972f6Sopenharmony_ci * 42195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 43195972f6Sopenharmony_ci * modification, are permitted provided that the following conditions 44195972f6Sopenharmony_ci * are met: 45195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 46195972f6Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 47195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 48195972f6Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 49195972f6Sopenharmony_ci * documentation and/or other materials provided with the distribution. 50195972f6Sopenharmony_ci * 3. All advertising materials mentioning features or use of this software 51195972f6Sopenharmony_ci * must display the following acknowledgement: 52195972f6Sopenharmony_ci * This product includes software developed by the NetBSD 53195972f6Sopenharmony_ci * Foundation, Inc. and its contributors. 54195972f6Sopenharmony_ci * 4. Neither the name of The NetBSD Foundation nor the names of its 55195972f6Sopenharmony_ci * contributors may be used to endorse or promote products derived 56195972f6Sopenharmony_ci * from this software without specific prior written permission. 57195972f6Sopenharmony_ci * 58195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 59195972f6Sopenharmony_ci * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 60195972f6Sopenharmony_ci * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 61195972f6Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 62195972f6Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 63195972f6Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 64195972f6Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 65195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 66195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 67195972f6Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 68195972f6Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 69195972f6Sopenharmony_ci */ 70195972f6Sopenharmony_ci 71195972f6Sopenharmony_ci#include "netif/ppp/ppp_opts.h" 72195972f6Sopenharmony_ci#if PPP_SUPPORT && PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ 73195972f6Sopenharmony_ci 74195972f6Sopenharmony_ci#if 0 /* UNUSED */ 75195972f6Sopenharmony_ci#include <string.h> 76195972f6Sopenharmony_ci#include <stdio.h> 77195972f6Sopenharmony_ci#endif /* UNUSED */ 78195972f6Sopenharmony_ci 79195972f6Sopenharmony_ci#include "lwip/timeouts.h" 80195972f6Sopenharmony_ci#include "lwip/memp.h" 81195972f6Sopenharmony_ci#include "lwip/stats.h" 82195972f6Sopenharmony_ci#include "lwip/snmp.h" 83195972f6Sopenharmony_ci 84195972f6Sopenharmony_ci#include "netif/ethernet.h" 85195972f6Sopenharmony_ci#include "netif/ppp/ppp_impl.h" 86195972f6Sopenharmony_ci#include "netif/ppp/lcp.h" 87195972f6Sopenharmony_ci#include "netif/ppp/ipcp.h" 88195972f6Sopenharmony_ci#include "netif/ppp/pppoe.h" 89195972f6Sopenharmony_ci 90195972f6Sopenharmony_ci/* Memory pool */ 91195972f6Sopenharmony_ciLWIP_MEMPOOL_DECLARE(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF") 92195972f6Sopenharmony_ci 93195972f6Sopenharmony_ci/* Add a 16 bit unsigned value to a buffer pointed to by PTR */ 94195972f6Sopenharmony_ci#define PPPOE_ADD_16(PTR, VAL) \ 95195972f6Sopenharmony_ci *(PTR)++ = (u8_t)((VAL) / 256); \ 96195972f6Sopenharmony_ci *(PTR)++ = (u8_t)((VAL) % 256) 97195972f6Sopenharmony_ci 98195972f6Sopenharmony_ci/* Add a complete PPPoE header to the buffer pointed to by PTR */ 99195972f6Sopenharmony_ci#define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN) \ 100195972f6Sopenharmony_ci *(PTR)++ = PPPOE_VERTYPE; \ 101195972f6Sopenharmony_ci *(PTR)++ = (CODE); \ 102195972f6Sopenharmony_ci PPPOE_ADD_16(PTR, SESS); \ 103195972f6Sopenharmony_ci PPPOE_ADD_16(PTR, LEN) 104195972f6Sopenharmony_ci 105195972f6Sopenharmony_ci#define PPPOE_DISC_TIMEOUT (5*1000) /* base for quick timeout calculation */ 106195972f6Sopenharmony_ci#define PPPOE_SLOW_RETRY (60*1000) /* persistent retry interval */ 107195972f6Sopenharmony_ci#define PPPOE_DISC_MAXPADI 4 /* retry PADI four times (quickly) */ 108195972f6Sopenharmony_ci#define PPPOE_DISC_MAXPADR 2 /* retry PADR twice */ 109195972f6Sopenharmony_ci 110195972f6Sopenharmony_ci#ifdef PPPOE_SERVER 111195972f6Sopenharmony_ci#error "PPPOE_SERVER is not yet supported under lwIP!" 112195972f6Sopenharmony_ci/* from if_spppsubr.c */ 113195972f6Sopenharmony_ci#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ 114195972f6Sopenharmony_ci#endif 115195972f6Sopenharmony_ci 116195972f6Sopenharmony_ci#define PPPOE_ERRORSTRING_LEN 64 117195972f6Sopenharmony_ci 118195972f6Sopenharmony_ci 119195972f6Sopenharmony_ci/* callbacks called from PPP core */ 120195972f6Sopenharmony_cistatic err_t pppoe_write(ppp_pcb *ppp, void *ctx, struct pbuf *p); 121195972f6Sopenharmony_cistatic err_t pppoe_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol); 122195972f6Sopenharmony_cistatic void pppoe_connect(ppp_pcb *ppp, void *ctx); 123195972f6Sopenharmony_cistatic void pppoe_disconnect(ppp_pcb *ppp, void *ctx); 124195972f6Sopenharmony_cistatic err_t pppoe_destroy(ppp_pcb *ppp, void *ctx); 125195972f6Sopenharmony_ci 126195972f6Sopenharmony_ci/* management routines */ 127195972f6Sopenharmony_cistatic void pppoe_abort_connect(struct pppoe_softc *); 128195972f6Sopenharmony_ci#if 0 /* UNUSED */ 129195972f6Sopenharmony_cistatic void pppoe_clear_softc(struct pppoe_softc *, const char *); 130195972f6Sopenharmony_ci#endif /* UNUSED */ 131195972f6Sopenharmony_ci 132195972f6Sopenharmony_ci/* internal timeout handling */ 133195972f6Sopenharmony_cistatic void pppoe_timeout(void *); 134195972f6Sopenharmony_ci 135195972f6Sopenharmony_ci/* sending actual protocol controll packets */ 136195972f6Sopenharmony_cistatic err_t pppoe_send_padi(struct pppoe_softc *); 137195972f6Sopenharmony_cistatic err_t pppoe_send_padr(struct pppoe_softc *); 138195972f6Sopenharmony_ci#ifdef PPPOE_SERVER 139195972f6Sopenharmony_cistatic err_t pppoe_send_pado(struct pppoe_softc *); 140195972f6Sopenharmony_cistatic err_t pppoe_send_pads(struct pppoe_softc *); 141195972f6Sopenharmony_ci#endif 142195972f6Sopenharmony_cistatic err_t pppoe_send_padt(struct netif *, u_int, const u8_t *); 143195972f6Sopenharmony_ci 144195972f6Sopenharmony_ci/* internal helper functions */ 145195972f6Sopenharmony_cistatic err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb); 146195972f6Sopenharmony_cistatic struct pppoe_softc* pppoe_find_softc_by_session(u_int session, struct netif *rcvif); 147195972f6Sopenharmony_cistatic struct pppoe_softc* pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif); 148195972f6Sopenharmony_ci 149195972f6Sopenharmony_ci/** linked list of created pppoe interfaces */ 150195972f6Sopenharmony_cistatic struct pppoe_softc *pppoe_softc_list; 151195972f6Sopenharmony_ci 152195972f6Sopenharmony_ci/* Callbacks structure for PPP core */ 153195972f6Sopenharmony_cistatic const struct link_callbacks pppoe_callbacks = { 154195972f6Sopenharmony_ci pppoe_connect, 155195972f6Sopenharmony_ci#if PPP_SERVER 156195972f6Sopenharmony_ci NULL, 157195972f6Sopenharmony_ci#endif /* PPP_SERVER */ 158195972f6Sopenharmony_ci pppoe_disconnect, 159195972f6Sopenharmony_ci pppoe_destroy, 160195972f6Sopenharmony_ci pppoe_write, 161195972f6Sopenharmony_ci pppoe_netif_output, 162195972f6Sopenharmony_ci NULL, 163195972f6Sopenharmony_ci NULL 164195972f6Sopenharmony_ci}; 165195972f6Sopenharmony_ci 166195972f6Sopenharmony_ci/* 167195972f6Sopenharmony_ci * Create a new PPP Over Ethernet (PPPoE) connection. 168195972f6Sopenharmony_ci * 169195972f6Sopenharmony_ci * Return 0 on success, an error code on failure. 170195972f6Sopenharmony_ci */ 171195972f6Sopenharmony_cippp_pcb *pppoe_create(struct netif *pppif, 172195972f6Sopenharmony_ci struct netif *ethif, 173195972f6Sopenharmony_ci const char *service_name, const char *concentrator_name, 174195972f6Sopenharmony_ci ppp_link_status_cb_fn link_status_cb, void *ctx_cb) 175195972f6Sopenharmony_ci{ 176195972f6Sopenharmony_ci ppp_pcb *ppp; 177195972f6Sopenharmony_ci struct pppoe_softc *sc; 178195972f6Sopenharmony_ci#if !PPPOE_SCNAME_SUPPORT 179195972f6Sopenharmony_ci LWIP_UNUSED_ARG(service_name); 180195972f6Sopenharmony_ci LWIP_UNUSED_ARG(concentrator_name); 181195972f6Sopenharmony_ci#endif /* !PPPOE_SCNAME_SUPPORT */ 182195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 183195972f6Sopenharmony_ci 184195972f6Sopenharmony_ci sc = (struct pppoe_softc *)LWIP_MEMPOOL_ALLOC(PPPOE_IF); 185195972f6Sopenharmony_ci if (sc == NULL) { 186195972f6Sopenharmony_ci return NULL; 187195972f6Sopenharmony_ci } 188195972f6Sopenharmony_ci 189195972f6Sopenharmony_ci ppp = ppp_new(pppif, &pppoe_callbacks, sc, link_status_cb, ctx_cb); 190195972f6Sopenharmony_ci if (ppp == NULL) { 191195972f6Sopenharmony_ci LWIP_MEMPOOL_FREE(PPPOE_IF, sc); 192195972f6Sopenharmony_ci return NULL; 193195972f6Sopenharmony_ci } 194195972f6Sopenharmony_ci 195195972f6Sopenharmony_ci memset(sc, 0, sizeof(struct pppoe_softc)); 196195972f6Sopenharmony_ci sc->pcb = ppp; 197195972f6Sopenharmony_ci sc->sc_ethif = ethif; 198195972f6Sopenharmony_ci#if PPPOE_SCNAME_SUPPORT 199195972f6Sopenharmony_ci sc->sc_service_name = service_name; 200195972f6Sopenharmony_ci sc->sc_concentrator_name = concentrator_name; 201195972f6Sopenharmony_ci#endif /* PPPOE_SCNAME_SUPPORT */ 202195972f6Sopenharmony_ci /* put the new interface at the head of the list */ 203195972f6Sopenharmony_ci sc->next = pppoe_softc_list; 204195972f6Sopenharmony_ci pppoe_softc_list = sc; 205195972f6Sopenharmony_ci return ppp; 206195972f6Sopenharmony_ci} 207195972f6Sopenharmony_ci 208195972f6Sopenharmony_ci/* Called by PPP core */ 209195972f6Sopenharmony_cistatic err_t pppoe_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) { 210195972f6Sopenharmony_ci struct pppoe_softc *sc = (struct pppoe_softc *)ctx; 211195972f6Sopenharmony_ci struct pbuf *ph; /* Ethernet + PPPoE header */ 212195972f6Sopenharmony_ci err_t ret; 213195972f6Sopenharmony_ci#if MIB2_STATS 214195972f6Sopenharmony_ci u16_t tot_len; 215195972f6Sopenharmony_ci#else /* MIB2_STATS */ 216195972f6Sopenharmony_ci LWIP_UNUSED_ARG(ppp); 217195972f6Sopenharmony_ci#endif /* MIB2_STATS */ 218195972f6Sopenharmony_ci 219195972f6Sopenharmony_ci /* skip address & flags */ 220195972f6Sopenharmony_ci pbuf_remove_header(p, 2); 221195972f6Sopenharmony_ci 222195972f6Sopenharmony_ci ph = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN), PBUF_RAM); 223195972f6Sopenharmony_ci if(!ph) { 224195972f6Sopenharmony_ci LINK_STATS_INC(link.memerr); 225195972f6Sopenharmony_ci LINK_STATS_INC(link.proterr); 226195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); 227195972f6Sopenharmony_ci pbuf_free(p); 228195972f6Sopenharmony_ci return ERR_MEM; 229195972f6Sopenharmony_ci } 230195972f6Sopenharmony_ci 231195972f6Sopenharmony_ci pbuf_remove_header(ph, PPPOE_HEADERLEN); /* hide PPPoE header */ 232195972f6Sopenharmony_ci pbuf_cat(ph, p); 233195972f6Sopenharmony_ci#if MIB2_STATS 234195972f6Sopenharmony_ci tot_len = ph->tot_len; 235195972f6Sopenharmony_ci#endif /* MIB2_STATS */ 236195972f6Sopenharmony_ci 237195972f6Sopenharmony_ci ret = pppoe_xmit(sc, ph); 238195972f6Sopenharmony_ci if (ret != ERR_OK) { 239195972f6Sopenharmony_ci LINK_STATS_INC(link.err); 240195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); 241195972f6Sopenharmony_ci return ret; 242195972f6Sopenharmony_ci } 243195972f6Sopenharmony_ci 244195972f6Sopenharmony_ci MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, (u16_t)tot_len); 245195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); 246195972f6Sopenharmony_ci LINK_STATS_INC(link.xmit); 247195972f6Sopenharmony_ci return ERR_OK; 248195972f6Sopenharmony_ci} 249195972f6Sopenharmony_ci 250195972f6Sopenharmony_ci/* Called by PPP core */ 251195972f6Sopenharmony_cistatic err_t pppoe_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol) { 252195972f6Sopenharmony_ci struct pppoe_softc *sc = (struct pppoe_softc *)ctx; 253195972f6Sopenharmony_ci struct pbuf *pb; 254195972f6Sopenharmony_ci u8_t *pl; 255195972f6Sopenharmony_ci err_t err; 256195972f6Sopenharmony_ci#if MIB2_STATS 257195972f6Sopenharmony_ci u16_t tot_len; 258195972f6Sopenharmony_ci#else /* MIB2_STATS */ 259195972f6Sopenharmony_ci LWIP_UNUSED_ARG(ppp); 260195972f6Sopenharmony_ci#endif /* MIB2_STATS */ 261195972f6Sopenharmony_ci 262195972f6Sopenharmony_ci /* @todo: try to use pbuf_header() here! */ 263195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_LINK, PPPOE_HEADERLEN + sizeof(protocol), PBUF_RAM); 264195972f6Sopenharmony_ci if(!pb) { 265195972f6Sopenharmony_ci LINK_STATS_INC(link.memerr); 266195972f6Sopenharmony_ci LINK_STATS_INC(link.proterr); 267195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); 268195972f6Sopenharmony_ci return ERR_MEM; 269195972f6Sopenharmony_ci } 270195972f6Sopenharmony_ci 271195972f6Sopenharmony_ci pbuf_remove_header(pb, PPPOE_HEADERLEN); 272195972f6Sopenharmony_ci 273195972f6Sopenharmony_ci pl = (u8_t*)pb->payload; 274195972f6Sopenharmony_ci PUTSHORT(protocol, pl); 275195972f6Sopenharmony_ci 276195972f6Sopenharmony_ci pbuf_chain(pb, p); 277195972f6Sopenharmony_ci#if MIB2_STATS 278195972f6Sopenharmony_ci tot_len = pb->tot_len; 279195972f6Sopenharmony_ci#endif /* MIB2_STATS */ 280195972f6Sopenharmony_ci 281195972f6Sopenharmony_ci if( (err = pppoe_xmit(sc, pb)) != ERR_OK) { 282195972f6Sopenharmony_ci LINK_STATS_INC(link.err); 283195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); 284195972f6Sopenharmony_ci return err; 285195972f6Sopenharmony_ci } 286195972f6Sopenharmony_ci 287195972f6Sopenharmony_ci MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, tot_len); 288195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); 289195972f6Sopenharmony_ci LINK_STATS_INC(link.xmit); 290195972f6Sopenharmony_ci return ERR_OK; 291195972f6Sopenharmony_ci} 292195972f6Sopenharmony_ci 293195972f6Sopenharmony_cistatic err_t 294195972f6Sopenharmony_cipppoe_destroy(ppp_pcb *ppp, void *ctx) 295195972f6Sopenharmony_ci{ 296195972f6Sopenharmony_ci struct pppoe_softc *sc = (struct pppoe_softc *)ctx; 297195972f6Sopenharmony_ci struct pppoe_softc **copp, *freep; 298195972f6Sopenharmony_ci LWIP_UNUSED_ARG(ppp); 299195972f6Sopenharmony_ci 300195972f6Sopenharmony_ci sys_untimeout(pppoe_timeout, sc); 301195972f6Sopenharmony_ci 302195972f6Sopenharmony_ci /* remove interface from list */ 303195972f6Sopenharmony_ci for (copp = &pppoe_softc_list; (freep = *copp); copp = &freep->next) { 304195972f6Sopenharmony_ci if (freep == sc) { 305195972f6Sopenharmony_ci *copp = freep->next; 306195972f6Sopenharmony_ci break; 307195972f6Sopenharmony_ci } 308195972f6Sopenharmony_ci } 309195972f6Sopenharmony_ci LWIP_MEMPOOL_FREE(PPPOE_IF, sc); 310195972f6Sopenharmony_ci 311195972f6Sopenharmony_ci return ERR_OK; 312195972f6Sopenharmony_ci} 313195972f6Sopenharmony_ci 314195972f6Sopenharmony_ci/* 315195972f6Sopenharmony_ci * Find the interface handling the specified session. 316195972f6Sopenharmony_ci * Note: O(number of sessions open), this is a client-side only, mean 317195972f6Sopenharmony_ci * and lean implementation, so number of open sessions typically should 318195972f6Sopenharmony_ci * be 1. 319195972f6Sopenharmony_ci */ 320195972f6Sopenharmony_cistatic struct pppoe_softc* pppoe_find_softc_by_session(u_int session, struct netif *rcvif) { 321195972f6Sopenharmony_ci struct pppoe_softc *sc; 322195972f6Sopenharmony_ci 323195972f6Sopenharmony_ci for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { 324195972f6Sopenharmony_ci if (sc->sc_state == PPPOE_STATE_SESSION 325195972f6Sopenharmony_ci && sc->sc_session == session 326195972f6Sopenharmony_ci && sc->sc_ethif == rcvif) { 327195972f6Sopenharmony_ci return sc; 328195972f6Sopenharmony_ci } 329195972f6Sopenharmony_ci } 330195972f6Sopenharmony_ci return NULL; 331195972f6Sopenharmony_ci} 332195972f6Sopenharmony_ci 333195972f6Sopenharmony_ci/* Check host unique token passed and return appropriate softc pointer, 334195972f6Sopenharmony_ci * or NULL if token is bogus. */ 335195972f6Sopenharmony_cistatic struct pppoe_softc* pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif) { 336195972f6Sopenharmony_ci struct pppoe_softc *sc, *t; 337195972f6Sopenharmony_ci 338195972f6Sopenharmony_ci if (len != sizeof sc) { 339195972f6Sopenharmony_ci return NULL; 340195972f6Sopenharmony_ci } 341195972f6Sopenharmony_ci MEMCPY(&t, token, len); 342195972f6Sopenharmony_ci 343195972f6Sopenharmony_ci for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { 344195972f6Sopenharmony_ci if (sc == t) { 345195972f6Sopenharmony_ci break; 346195972f6Sopenharmony_ci } 347195972f6Sopenharmony_ci } 348195972f6Sopenharmony_ci 349195972f6Sopenharmony_ci if (sc == NULL) { 350195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: alien host unique tag, no session found\n")); 351195972f6Sopenharmony_ci return NULL; 352195972f6Sopenharmony_ci } 353195972f6Sopenharmony_ci 354195972f6Sopenharmony_ci /* should be safe to access *sc now */ 355195972f6Sopenharmony_ci if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) { 356195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": host unique tag found, but it belongs to a connection in state %d\n", 357195972f6Sopenharmony_ci sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_state)); 358195972f6Sopenharmony_ci return NULL; 359195972f6Sopenharmony_ci } 360195972f6Sopenharmony_ci if (sc->sc_ethif != rcvif) { 361195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": wrong interface, not accepting host unique\n", 362195972f6Sopenharmony_ci sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); 363195972f6Sopenharmony_ci return NULL; 364195972f6Sopenharmony_ci } 365195972f6Sopenharmony_ci return sc; 366195972f6Sopenharmony_ci} 367195972f6Sopenharmony_ci 368195972f6Sopenharmony_ci/* analyze and handle a single received packet while not in session state */ 369195972f6Sopenharmony_civoid 370195972f6Sopenharmony_cipppoe_disc_input(struct netif *netif, struct pbuf *pb) 371195972f6Sopenharmony_ci{ 372195972f6Sopenharmony_ci u16_t tag, len, off; 373195972f6Sopenharmony_ci u16_t session, plen; 374195972f6Sopenharmony_ci struct pppoe_softc *sc; 375195972f6Sopenharmony_ci#if PPP_DEBUG 376195972f6Sopenharmony_ci const char *err_msg = NULL; 377195972f6Sopenharmony_ci#endif /* PPP_DEBUG */ 378195972f6Sopenharmony_ci u8_t *ac_cookie; 379195972f6Sopenharmony_ci u16_t ac_cookie_len; 380195972f6Sopenharmony_ci#ifdef PPPOE_SERVER 381195972f6Sopenharmony_ci u8_t *hunique; 382195972f6Sopenharmony_ci size_t hunique_len; 383195972f6Sopenharmony_ci#endif 384195972f6Sopenharmony_ci struct pppoehdr *ph; 385195972f6Sopenharmony_ci struct pppoetag pt; 386195972f6Sopenharmony_ci int err; 387195972f6Sopenharmony_ci struct eth_hdr *ethhdr; 388195972f6Sopenharmony_ci 389195972f6Sopenharmony_ci /* don't do anything if there is not a single PPPoE instance */ 390195972f6Sopenharmony_ci if (pppoe_softc_list == NULL) { 391195972f6Sopenharmony_ci pbuf_free(pb); 392195972f6Sopenharmony_ci return; 393195972f6Sopenharmony_ci } 394195972f6Sopenharmony_ci 395195972f6Sopenharmony_ci pb = pbuf_coalesce(pb, PBUF_RAW); 396195972f6Sopenharmony_ci 397195972f6Sopenharmony_ci ethhdr = (struct eth_hdr *)pb->payload; 398195972f6Sopenharmony_ci 399195972f6Sopenharmony_ci ac_cookie = NULL; 400195972f6Sopenharmony_ci ac_cookie_len = 0; 401195972f6Sopenharmony_ci#ifdef PPPOE_SERVER 402195972f6Sopenharmony_ci hunique = NULL; 403195972f6Sopenharmony_ci hunique_len = 0; 404195972f6Sopenharmony_ci#endif 405195972f6Sopenharmony_ci session = 0; 406195972f6Sopenharmony_ci off = sizeof(struct eth_hdr) + sizeof(struct pppoehdr); 407195972f6Sopenharmony_ci if (pb->len < off) { 408195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: packet too short: %d\n", pb->len)); 409195972f6Sopenharmony_ci goto done; 410195972f6Sopenharmony_ci } 411195972f6Sopenharmony_ci 412195972f6Sopenharmony_ci ph = (struct pppoehdr *) (ethhdr + 1); 413195972f6Sopenharmony_ci if (ph->vertype != PPPOE_VERTYPE) { 414195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: unknown version/type packet: 0x%x\n", ph->vertype)); 415195972f6Sopenharmony_ci goto done; 416195972f6Sopenharmony_ci } 417195972f6Sopenharmony_ci session = lwip_ntohs(ph->session); 418195972f6Sopenharmony_ci plen = lwip_ntohs(ph->plen); 419195972f6Sopenharmony_ci 420195972f6Sopenharmony_ci if (plen > (pb->len - off)) { 421195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: packet content does not fit: data available = %d, packet size = %u\n", 422195972f6Sopenharmony_ci pb->len - off, plen)); 423195972f6Sopenharmony_ci goto done; 424195972f6Sopenharmony_ci } 425195972f6Sopenharmony_ci if(pb->tot_len == pb->len) { 426195972f6Sopenharmony_ci u16_t framelen = off + plen; 427195972f6Sopenharmony_ci if (framelen < pb->len) { 428195972f6Sopenharmony_ci /* ignore trailing garbage */ 429195972f6Sopenharmony_ci pb->tot_len = pb->len = framelen; 430195972f6Sopenharmony_ci } 431195972f6Sopenharmony_ci } 432195972f6Sopenharmony_ci tag = 0; 433195972f6Sopenharmony_ci len = 0; 434195972f6Sopenharmony_ci sc = NULL; 435195972f6Sopenharmony_ci while (off + sizeof(pt) <= pb->len) { 436195972f6Sopenharmony_ci MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt)); 437195972f6Sopenharmony_ci tag = lwip_ntohs(pt.tag); 438195972f6Sopenharmony_ci len = lwip_ntohs(pt.len); 439195972f6Sopenharmony_ci if (off + sizeof(pt) + len > pb->len) { 440195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: tag 0x%x len 0x%x is too long\n", tag, len)); 441195972f6Sopenharmony_ci goto done; 442195972f6Sopenharmony_ci } 443195972f6Sopenharmony_ci switch (tag) { 444195972f6Sopenharmony_ci case PPPOE_TAG_EOL: 445195972f6Sopenharmony_ci goto breakbreak; 446195972f6Sopenharmony_ci case PPPOE_TAG_SNAME: 447195972f6Sopenharmony_ci break; /* ignored */ 448195972f6Sopenharmony_ci case PPPOE_TAG_ACNAME: 449195972f6Sopenharmony_ci break; /* ignored */ 450195972f6Sopenharmony_ci case PPPOE_TAG_HUNIQUE: 451195972f6Sopenharmony_ci if (sc != NULL) { 452195972f6Sopenharmony_ci break; 453195972f6Sopenharmony_ci } 454195972f6Sopenharmony_ci#ifdef PPPOE_SERVER 455195972f6Sopenharmony_ci hunique = (u8_t*)pb->payload + off + sizeof(pt); 456195972f6Sopenharmony_ci hunique_len = len; 457195972f6Sopenharmony_ci#endif 458195972f6Sopenharmony_ci sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif); 459195972f6Sopenharmony_ci break; 460195972f6Sopenharmony_ci case PPPOE_TAG_ACCOOKIE: 461195972f6Sopenharmony_ci if (ac_cookie == NULL) { 462195972f6Sopenharmony_ci if (len > PPPOE_MAX_AC_COOKIE_LEN) { 463195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: AC cookie is too long: len = %d, max = %d\n", len, PPPOE_MAX_AC_COOKIE_LEN)); 464195972f6Sopenharmony_ci goto done; 465195972f6Sopenharmony_ci } 466195972f6Sopenharmony_ci ac_cookie = (u8_t*)pb->payload + off + sizeof(pt); 467195972f6Sopenharmony_ci ac_cookie_len = len; 468195972f6Sopenharmony_ci } 469195972f6Sopenharmony_ci break; 470195972f6Sopenharmony_ci#if PPP_DEBUG 471195972f6Sopenharmony_ci case PPPOE_TAG_SNAME_ERR: 472195972f6Sopenharmony_ci err_msg = "SERVICE NAME ERROR"; 473195972f6Sopenharmony_ci break; 474195972f6Sopenharmony_ci case PPPOE_TAG_ACSYS_ERR: 475195972f6Sopenharmony_ci err_msg = "AC SYSTEM ERROR"; 476195972f6Sopenharmony_ci break; 477195972f6Sopenharmony_ci case PPPOE_TAG_GENERIC_ERR: 478195972f6Sopenharmony_ci err_msg = "GENERIC ERROR"; 479195972f6Sopenharmony_ci break; 480195972f6Sopenharmony_ci#endif /* PPP_DEBUG */ 481195972f6Sopenharmony_ci default: 482195972f6Sopenharmony_ci break; 483195972f6Sopenharmony_ci } 484195972f6Sopenharmony_ci#if PPP_DEBUG 485195972f6Sopenharmony_ci if (err_msg != NULL) { 486195972f6Sopenharmony_ci char error_tmp[PPPOE_ERRORSTRING_LEN]; 487195972f6Sopenharmony_ci u16_t error_len = LWIP_MIN(len, sizeof(error_tmp)-1); 488195972f6Sopenharmony_ci strncpy(error_tmp, (char*)pb->payload + off + sizeof(pt), error_len); 489195972f6Sopenharmony_ci error_tmp[error_len] = '\0'; 490195972f6Sopenharmony_ci if (sc) { 491195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": %s: %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err_msg, error_tmp)); 492195972f6Sopenharmony_ci } else { 493195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: %s: %s\n", err_msg, error_tmp)); 494195972f6Sopenharmony_ci } 495195972f6Sopenharmony_ci } 496195972f6Sopenharmony_ci#endif /* PPP_DEBUG */ 497195972f6Sopenharmony_ci off += sizeof(pt) + len; 498195972f6Sopenharmony_ci } 499195972f6Sopenharmony_ci 500195972f6Sopenharmony_cibreakbreak:; 501195972f6Sopenharmony_ci switch (ph->code) { 502195972f6Sopenharmony_ci case PPPOE_CODE_PADI: 503195972f6Sopenharmony_ci#ifdef PPPOE_SERVER 504195972f6Sopenharmony_ci /* 505195972f6Sopenharmony_ci * got service name, concentrator name, and/or host unique. 506195972f6Sopenharmony_ci * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP. 507195972f6Sopenharmony_ci */ 508195972f6Sopenharmony_ci if (LIST_EMPTY(&pppoe_softc_list)) { 509195972f6Sopenharmony_ci goto done; 510195972f6Sopenharmony_ci } 511195972f6Sopenharmony_ci LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { 512195972f6Sopenharmony_ci if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) { 513195972f6Sopenharmony_ci continue; 514195972f6Sopenharmony_ci } 515195972f6Sopenharmony_ci if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { 516195972f6Sopenharmony_ci continue; 517195972f6Sopenharmony_ci } 518195972f6Sopenharmony_ci if (sc->sc_state == PPPOE_STATE_INITIAL) { 519195972f6Sopenharmony_ci break; 520195972f6Sopenharmony_ci } 521195972f6Sopenharmony_ci } 522195972f6Sopenharmony_ci if (sc == NULL) { 523195972f6Sopenharmony_ci /* PPPDEBUG(LOG_DEBUG, ("pppoe: free passive interface is not found\n")); */ 524195972f6Sopenharmony_ci goto done; 525195972f6Sopenharmony_ci } 526195972f6Sopenharmony_ci if (hunique) { 527195972f6Sopenharmony_ci if (sc->sc_hunique) { 528195972f6Sopenharmony_ci mem_free(sc->sc_hunique); 529195972f6Sopenharmony_ci } 530195972f6Sopenharmony_ci sc->sc_hunique = mem_malloc(hunique_len); 531195972f6Sopenharmony_ci if (sc->sc_hunique == NULL) { 532195972f6Sopenharmony_ci goto done; 533195972f6Sopenharmony_ci } 534195972f6Sopenharmony_ci sc->sc_hunique_len = hunique_len; 535195972f6Sopenharmony_ci MEMCPY(sc->sc_hunique, hunique, hunique_len); 536195972f6Sopenharmony_ci } 537195972f6Sopenharmony_ci MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest); 538195972f6Sopenharmony_ci sc->sc_state = PPPOE_STATE_PADO_SENT; 539195972f6Sopenharmony_ci pppoe_send_pado(sc); 540195972f6Sopenharmony_ci break; 541195972f6Sopenharmony_ci#endif /* PPPOE_SERVER */ 542195972f6Sopenharmony_ci case PPPOE_CODE_PADR: 543195972f6Sopenharmony_ci#ifdef PPPOE_SERVER 544195972f6Sopenharmony_ci /* 545195972f6Sopenharmony_ci * get sc from ac_cookie if IFF_PASSIVE 546195972f6Sopenharmony_ci */ 547195972f6Sopenharmony_ci if (ac_cookie == NULL) { 548195972f6Sopenharmony_ci /* be quiet if there is not a single pppoe instance */ 549195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: received PADR but not includes ac_cookie\n")); 550195972f6Sopenharmony_ci goto done; 551195972f6Sopenharmony_ci } 552195972f6Sopenharmony_ci sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif); 553195972f6Sopenharmony_ci if (sc == NULL) { 554195972f6Sopenharmony_ci /* be quiet if there is not a single pppoe instance */ 555195972f6Sopenharmony_ci if (!LIST_EMPTY(&pppoe_softc_list)) { 556195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: received PADR but could not find request for it\n")); 557195972f6Sopenharmony_ci } 558195972f6Sopenharmony_ci goto done; 559195972f6Sopenharmony_ci } 560195972f6Sopenharmony_ci if (sc->sc_state != PPPOE_STATE_PADO_SENT) { 561195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); 562195972f6Sopenharmony_ci goto done; 563195972f6Sopenharmony_ci } 564195972f6Sopenharmony_ci if (hunique) { 565195972f6Sopenharmony_ci if (sc->sc_hunique) { 566195972f6Sopenharmony_ci mem_free(sc->sc_hunique); 567195972f6Sopenharmony_ci } 568195972f6Sopenharmony_ci sc->sc_hunique = mem_malloc(hunique_len); 569195972f6Sopenharmony_ci if (sc->sc_hunique == NULL) { 570195972f6Sopenharmony_ci goto done; 571195972f6Sopenharmony_ci } 572195972f6Sopenharmony_ci sc->sc_hunique_len = hunique_len; 573195972f6Sopenharmony_ci MEMCPY(sc->sc_hunique, hunique, hunique_len); 574195972f6Sopenharmony_ci } 575195972f6Sopenharmony_ci pppoe_send_pads(sc); 576195972f6Sopenharmony_ci sc->sc_state = PPPOE_STATE_SESSION; 577195972f6Sopenharmony_ci ppp_start(sc->pcb); /* notify upper layers */ 578195972f6Sopenharmony_ci break; 579195972f6Sopenharmony_ci#else 580195972f6Sopenharmony_ci /* ignore, we are no access concentrator */ 581195972f6Sopenharmony_ci goto done; 582195972f6Sopenharmony_ci#endif /* PPPOE_SERVER */ 583195972f6Sopenharmony_ci case PPPOE_CODE_PADO: 584195972f6Sopenharmony_ci if (sc == NULL) { 585195972f6Sopenharmony_ci /* be quiet if there is not a single pppoe instance */ 586195972f6Sopenharmony_ci if (pppoe_softc_list != NULL) { 587195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: received PADO but could not find request for it\n")); 588195972f6Sopenharmony_ci } 589195972f6Sopenharmony_ci goto done; 590195972f6Sopenharmony_ci } 591195972f6Sopenharmony_ci if (sc->sc_state != PPPOE_STATE_PADI_SENT) { 592195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); 593195972f6Sopenharmony_ci goto done; 594195972f6Sopenharmony_ci } 595195972f6Sopenharmony_ci if (ac_cookie) { 596195972f6Sopenharmony_ci sc->sc_ac_cookie_len = ac_cookie_len; 597195972f6Sopenharmony_ci MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len); 598195972f6Sopenharmony_ci } 599195972f6Sopenharmony_ci MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr)); 600195972f6Sopenharmony_ci sys_untimeout(pppoe_timeout, sc); 601195972f6Sopenharmony_ci sc->sc_padr_retried = 0; 602195972f6Sopenharmony_ci sc->sc_state = PPPOE_STATE_PADR_SENT; 603195972f6Sopenharmony_ci if ((err = pppoe_send_padr(sc)) != 0) { 604195972f6Sopenharmony_ci 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)); 605195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ 606195972f6Sopenharmony_ci } 607195972f6Sopenharmony_ci sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); 608195972f6Sopenharmony_ci break; 609195972f6Sopenharmony_ci case PPPOE_CODE_PADS: 610195972f6Sopenharmony_ci if (sc == NULL) { 611195972f6Sopenharmony_ci goto done; 612195972f6Sopenharmony_ci } 613195972f6Sopenharmony_ci sc->sc_session = session; 614195972f6Sopenharmony_ci sys_untimeout(pppoe_timeout, sc); 615195972f6Sopenharmony_ci 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)); 616195972f6Sopenharmony_ci sc->sc_state = PPPOE_STATE_SESSION; 617195972f6Sopenharmony_ci ppp_start(sc->pcb); /* notify upper layers */ 618195972f6Sopenharmony_ci break; 619195972f6Sopenharmony_ci case PPPOE_CODE_PADT: 620195972f6Sopenharmony_ci /* Don't disconnect here, we let the LCP Echo/Reply find the fact 621195972f6Sopenharmony_ci * that PPP session is down. Asking the PPP stack to end the session 622195972f6Sopenharmony_ci * require strict checking about the PPP phase to prevent endless 623195972f6Sopenharmony_ci * disconnection loops. 624195972f6Sopenharmony_ci */ 625195972f6Sopenharmony_ci#if 0 /* UNUSED */ 626195972f6Sopenharmony_ci if (sc == NULL) { /* PADT frames are rarely sent with a hunique tag, this is actually almost always true */ 627195972f6Sopenharmony_ci goto done; 628195972f6Sopenharmony_ci } 629195972f6Sopenharmony_ci pppoe_clear_softc(sc, "received PADT"); 630195972f6Sopenharmony_ci#endif /* UNUSED */ 631195972f6Sopenharmony_ci break; 632195972f6Sopenharmony_ci default: 633195972f6Sopenharmony_ci if(sc) { 634195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": unknown code (0x%"X16_F") session = 0x%"X16_F"\n", 635195972f6Sopenharmony_ci sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, 636195972f6Sopenharmony_ci (u16_t)ph->code, session)); 637195972f6Sopenharmony_ci } else { 638195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: unknown code (0x%"X16_F") session = 0x%"X16_F"\n", (u16_t)ph->code, session)); 639195972f6Sopenharmony_ci } 640195972f6Sopenharmony_ci break; 641195972f6Sopenharmony_ci } 642195972f6Sopenharmony_ci 643195972f6Sopenharmony_cidone: 644195972f6Sopenharmony_ci pbuf_free(pb); 645195972f6Sopenharmony_ci return; 646195972f6Sopenharmony_ci} 647195972f6Sopenharmony_ci 648195972f6Sopenharmony_civoid 649195972f6Sopenharmony_cipppoe_data_input(struct netif *netif, struct pbuf *pb) 650195972f6Sopenharmony_ci{ 651195972f6Sopenharmony_ci u16_t session, plen; 652195972f6Sopenharmony_ci struct pppoe_softc *sc; 653195972f6Sopenharmony_ci struct pppoehdr *ph; 654195972f6Sopenharmony_ci#ifdef PPPOE_TERM_UNKNOWN_SESSIONS 655195972f6Sopenharmony_ci u8_t shost[ETHER_ADDR_LEN]; 656195972f6Sopenharmony_ci#endif 657195972f6Sopenharmony_ci 658195972f6Sopenharmony_ci#ifdef PPPOE_TERM_UNKNOWN_SESSIONS 659195972f6Sopenharmony_ci MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost)); 660195972f6Sopenharmony_ci#endif 661195972f6Sopenharmony_ci if (pbuf_remove_header(pb, sizeof(struct eth_hdr)) != 0) { 662195972f6Sopenharmony_ci /* bail out */ 663195972f6Sopenharmony_ci PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_remove_header failed\n")); 664195972f6Sopenharmony_ci LINK_STATS_INC(link.lenerr); 665195972f6Sopenharmony_ci goto drop; 666195972f6Sopenharmony_ci } 667195972f6Sopenharmony_ci 668195972f6Sopenharmony_ci if (pb->len < sizeof(*ph)) { 669195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: could not get PPPoE header\n")); 670195972f6Sopenharmony_ci goto drop; 671195972f6Sopenharmony_ci } 672195972f6Sopenharmony_ci ph = (struct pppoehdr *)pb->payload; 673195972f6Sopenharmony_ci 674195972f6Sopenharmony_ci if (ph->vertype != PPPOE_VERTYPE) { 675195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype)); 676195972f6Sopenharmony_ci goto drop; 677195972f6Sopenharmony_ci } 678195972f6Sopenharmony_ci if (ph->code != 0) { 679195972f6Sopenharmony_ci goto drop; 680195972f6Sopenharmony_ci } 681195972f6Sopenharmony_ci 682195972f6Sopenharmony_ci session = lwip_ntohs(ph->session); 683195972f6Sopenharmony_ci sc = pppoe_find_softc_by_session(session, netif); 684195972f6Sopenharmony_ci if (sc == NULL) { 685195972f6Sopenharmony_ci#ifdef PPPOE_TERM_UNKNOWN_SESSIONS 686195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: input for unknown session 0x%x, sending PADT\n", session)); 687195972f6Sopenharmony_ci pppoe_send_padt(netif, session, shost); 688195972f6Sopenharmony_ci#endif 689195972f6Sopenharmony_ci goto drop; 690195972f6Sopenharmony_ci } 691195972f6Sopenharmony_ci 692195972f6Sopenharmony_ci plen = lwip_ntohs(ph->plen); 693195972f6Sopenharmony_ci 694195972f6Sopenharmony_ci if (pbuf_remove_header(pb, PPPOE_HEADERLEN) != 0) { 695195972f6Sopenharmony_ci /* bail out */ 696195972f6Sopenharmony_ci PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_remove_header PPPOE_HEADERLEN failed\n")); 697195972f6Sopenharmony_ci LINK_STATS_INC(link.lenerr); 698195972f6Sopenharmony_ci goto drop; 699195972f6Sopenharmony_ci } 700195972f6Sopenharmony_ci 701195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n", 702195972f6Sopenharmony_ci sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, 703195972f6Sopenharmony_ci pb->len, plen)); 704195972f6Sopenharmony_ci 705195972f6Sopenharmony_ci if (pb->tot_len < plen) { 706195972f6Sopenharmony_ci goto drop; 707195972f6Sopenharmony_ci } 708195972f6Sopenharmony_ci 709195972f6Sopenharmony_ci /* Dispatch the packet thereby consuming it. */ 710195972f6Sopenharmony_ci ppp_input(sc->pcb, pb); 711195972f6Sopenharmony_ci return; 712195972f6Sopenharmony_ci 713195972f6Sopenharmony_cidrop: 714195972f6Sopenharmony_ci pbuf_free(pb); 715195972f6Sopenharmony_ci} 716195972f6Sopenharmony_ci 717195972f6Sopenharmony_cistatic err_t 718195972f6Sopenharmony_cipppoe_output(struct pppoe_softc *sc, struct pbuf *pb) 719195972f6Sopenharmony_ci{ 720195972f6Sopenharmony_ci struct eth_hdr *ethhdr; 721195972f6Sopenharmony_ci u16_t etype; 722195972f6Sopenharmony_ci err_t res; 723195972f6Sopenharmony_ci 724195972f6Sopenharmony_ci /* make room for Ethernet header - should not fail */ 725195972f6Sopenharmony_ci if (pbuf_add_header(pb, sizeof(struct eth_hdr)) != 0) { 726195972f6Sopenharmony_ci /* bail out */ 727195972f6Sopenharmony_ci PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_output: could not allocate room for Ethernet header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); 728195972f6Sopenharmony_ci LINK_STATS_INC(link.lenerr); 729195972f6Sopenharmony_ci pbuf_free(pb); 730195972f6Sopenharmony_ci return ERR_BUF; 731195972f6Sopenharmony_ci } 732195972f6Sopenharmony_ci ethhdr = (struct eth_hdr *)pb->payload; 733195972f6Sopenharmony_ci etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC; 734195972f6Sopenharmony_ci ethhdr->type = lwip_htons(etype); 735195972f6Sopenharmony_ci MEMCPY(ðhdr->dest.addr, &sc->sc_dest.addr, sizeof(ethhdr->dest.addr)); 736195972f6Sopenharmony_ci MEMCPY(ðhdr->src.addr, &sc->sc_ethif->hwaddr, sizeof(ethhdr->src.addr)); 737195972f6Sopenharmony_ci 738195972f6Sopenharmony_ci 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", 739195972f6Sopenharmony_ci sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype, 740195972f6Sopenharmony_ci sc->sc_state, sc->sc_session, 741195972f6Sopenharmony_ci 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], 742195972f6Sopenharmony_ci pb->tot_len)); 743195972f6Sopenharmony_ci 744195972f6Sopenharmony_ci res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb); 745195972f6Sopenharmony_ci 746195972f6Sopenharmony_ci pbuf_free(pb); 747195972f6Sopenharmony_ci 748195972f6Sopenharmony_ci return res; 749195972f6Sopenharmony_ci} 750195972f6Sopenharmony_ci 751195972f6Sopenharmony_cistatic err_t 752195972f6Sopenharmony_cipppoe_send_padi(struct pppoe_softc *sc) 753195972f6Sopenharmony_ci{ 754195972f6Sopenharmony_ci struct pbuf *pb; 755195972f6Sopenharmony_ci u8_t *p; 756195972f6Sopenharmony_ci int len; 757195972f6Sopenharmony_ci#if PPPOE_SCNAME_SUPPORT 758195972f6Sopenharmony_ci int l1 = 0, l2 = 0; /* XXX: gcc */ 759195972f6Sopenharmony_ci#endif /* PPPOE_SCNAME_SUPPORT */ 760195972f6Sopenharmony_ci 761195972f6Sopenharmony_ci /* calculate length of frame (excluding ethernet header + pppoe header) */ 762195972f6Sopenharmony_ci len = 2 + 2 + 2 + 2 + sizeof sc; /* service name tag is required, host unique is send too */ 763195972f6Sopenharmony_ci#if PPPOE_SCNAME_SUPPORT 764195972f6Sopenharmony_ci if (sc->sc_service_name != NULL) { 765195972f6Sopenharmony_ci l1 = (int)strlen(sc->sc_service_name); 766195972f6Sopenharmony_ci len += l1; 767195972f6Sopenharmony_ci } 768195972f6Sopenharmony_ci if (sc->sc_concentrator_name != NULL) { 769195972f6Sopenharmony_ci l2 = (int)strlen(sc->sc_concentrator_name); 770195972f6Sopenharmony_ci len += 2 + 2 + l2; 771195972f6Sopenharmony_ci } 772195972f6Sopenharmony_ci#endif /* PPPOE_SCNAME_SUPPORT */ 773195972f6Sopenharmony_ci LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", 774195972f6Sopenharmony_ci sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); 775195972f6Sopenharmony_ci 776195972f6Sopenharmony_ci /* allocate a buffer */ 777195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); 778195972f6Sopenharmony_ci if (!pb) { 779195972f6Sopenharmony_ci return ERR_MEM; 780195972f6Sopenharmony_ci } 781195972f6Sopenharmony_ci LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); 782195972f6Sopenharmony_ci 783195972f6Sopenharmony_ci p = (u8_t*)pb->payload; 784195972f6Sopenharmony_ci /* fill in pkt */ 785195972f6Sopenharmony_ci PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, (u16_t)len); 786195972f6Sopenharmony_ci PPPOE_ADD_16(p, PPPOE_TAG_SNAME); 787195972f6Sopenharmony_ci#if PPPOE_SCNAME_SUPPORT 788195972f6Sopenharmony_ci if (sc->sc_service_name != NULL) { 789195972f6Sopenharmony_ci PPPOE_ADD_16(p, l1); 790195972f6Sopenharmony_ci MEMCPY(p, sc->sc_service_name, l1); 791195972f6Sopenharmony_ci p += l1; 792195972f6Sopenharmony_ci } else 793195972f6Sopenharmony_ci#endif /* PPPOE_SCNAME_SUPPORT */ 794195972f6Sopenharmony_ci { 795195972f6Sopenharmony_ci PPPOE_ADD_16(p, 0); 796195972f6Sopenharmony_ci } 797195972f6Sopenharmony_ci#if PPPOE_SCNAME_SUPPORT 798195972f6Sopenharmony_ci if (sc->sc_concentrator_name != NULL) { 799195972f6Sopenharmony_ci PPPOE_ADD_16(p, PPPOE_TAG_ACNAME); 800195972f6Sopenharmony_ci PPPOE_ADD_16(p, l2); 801195972f6Sopenharmony_ci MEMCPY(p, sc->sc_concentrator_name, l2); 802195972f6Sopenharmony_ci p += l2; 803195972f6Sopenharmony_ci } 804195972f6Sopenharmony_ci#endif /* PPPOE_SCNAME_SUPPORT */ 805195972f6Sopenharmony_ci PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); 806195972f6Sopenharmony_ci PPPOE_ADD_16(p, sizeof(sc)); 807195972f6Sopenharmony_ci MEMCPY(p, &sc, sizeof sc); 808195972f6Sopenharmony_ci 809195972f6Sopenharmony_ci /* send pkt */ 810195972f6Sopenharmony_ci return pppoe_output(sc, pb); 811195972f6Sopenharmony_ci} 812195972f6Sopenharmony_ci 813195972f6Sopenharmony_cistatic void 814195972f6Sopenharmony_cipppoe_timeout(void *arg) 815195972f6Sopenharmony_ci{ 816195972f6Sopenharmony_ci u32_t retry_wait; 817195972f6Sopenharmony_ci int err; 818195972f6Sopenharmony_ci struct pppoe_softc *sc = (struct pppoe_softc*)arg; 819195972f6Sopenharmony_ci 820195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); 821195972f6Sopenharmony_ci 822195972f6Sopenharmony_ci switch (sc->sc_state) { 823195972f6Sopenharmony_ci case PPPOE_STATE_PADI_SENT: 824195972f6Sopenharmony_ci /* 825195972f6Sopenharmony_ci * We have two basic ways of retrying: 826195972f6Sopenharmony_ci * - Quick retry mode: try a few times in short sequence 827195972f6Sopenharmony_ci * - Slow retry mode: we already had a connection successfully 828195972f6Sopenharmony_ci * established and will try infinitely (without user 829195972f6Sopenharmony_ci * intervention) 830195972f6Sopenharmony_ci * We only enter slow retry mode if IFF_LINK1 (aka autodial) 831195972f6Sopenharmony_ci * is not set. 832195972f6Sopenharmony_ci */ 833195972f6Sopenharmony_ci if (sc->sc_padi_retried < 0xff) { 834195972f6Sopenharmony_ci sc->sc_padi_retried++; 835195972f6Sopenharmony_ci } 836195972f6Sopenharmony_ci if (!sc->pcb->settings.persist && sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) { 837195972f6Sopenharmony_ci#if 0 838195972f6Sopenharmony_ci if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) { 839195972f6Sopenharmony_ci /* slow retry mode */ 840195972f6Sopenharmony_ci retry_wait = PPPOE_SLOW_RETRY; 841195972f6Sopenharmony_ci } else 842195972f6Sopenharmony_ci#endif 843195972f6Sopenharmony_ci { 844195972f6Sopenharmony_ci pppoe_abort_connect(sc); 845195972f6Sopenharmony_ci return; 846195972f6Sopenharmony_ci } 847195972f6Sopenharmony_ci } 848195972f6Sopenharmony_ci /* initialize for quick retry mode */ 849195972f6Sopenharmony_ci retry_wait = LWIP_MIN(PPPOE_DISC_TIMEOUT * sc->sc_padi_retried, PPPOE_SLOW_RETRY); 850195972f6Sopenharmony_ci if ((err = pppoe_send_padi(sc)) != 0) { 851195972f6Sopenharmony_ci sc->sc_padi_retried--; 852195972f6Sopenharmony_ci 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)); 853195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ 854195972f6Sopenharmony_ci } 855195972f6Sopenharmony_ci sys_timeout(retry_wait, pppoe_timeout, sc); 856195972f6Sopenharmony_ci break; 857195972f6Sopenharmony_ci 858195972f6Sopenharmony_ci case PPPOE_STATE_PADR_SENT: 859195972f6Sopenharmony_ci sc->sc_padr_retried++; 860195972f6Sopenharmony_ci if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) { 861195972f6Sopenharmony_ci MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); 862195972f6Sopenharmony_ci sc->sc_state = PPPOE_STATE_PADI_SENT; 863195972f6Sopenharmony_ci sc->sc_padr_retried = 0; 864195972f6Sopenharmony_ci if ((err = pppoe_send_padi(sc)) != 0) { 865195972f6Sopenharmony_ci 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)); 866195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ 867195972f6Sopenharmony_ci } 868195972f6Sopenharmony_ci sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc); 869195972f6Sopenharmony_ci return; 870195972f6Sopenharmony_ci } 871195972f6Sopenharmony_ci if ((err = pppoe_send_padr(sc)) != 0) { 872195972f6Sopenharmony_ci sc->sc_padr_retried--; 873195972f6Sopenharmony_ci 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)); 874195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ 875195972f6Sopenharmony_ci } 876195972f6Sopenharmony_ci sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); 877195972f6Sopenharmony_ci break; 878195972f6Sopenharmony_ci default: 879195972f6Sopenharmony_ci return; /* all done, work in peace */ 880195972f6Sopenharmony_ci } 881195972f6Sopenharmony_ci} 882195972f6Sopenharmony_ci 883195972f6Sopenharmony_ci/* Start a connection (i.e. initiate discovery phase) */ 884195972f6Sopenharmony_cistatic void 885195972f6Sopenharmony_cipppoe_connect(ppp_pcb *ppp, void *ctx) 886195972f6Sopenharmony_ci{ 887195972f6Sopenharmony_ci err_t err; 888195972f6Sopenharmony_ci struct pppoe_softc *sc = (struct pppoe_softc *)ctx; 889195972f6Sopenharmony_ci lcp_options *lcp_wo; 890195972f6Sopenharmony_ci lcp_options *lcp_ao; 891195972f6Sopenharmony_ci#if PPP_IPV4_SUPPORT && VJ_SUPPORT 892195972f6Sopenharmony_ci ipcp_options *ipcp_wo; 893195972f6Sopenharmony_ci ipcp_options *ipcp_ao; 894195972f6Sopenharmony_ci#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ 895195972f6Sopenharmony_ci 896195972f6Sopenharmony_ci sc->sc_session = 0; 897195972f6Sopenharmony_ci sc->sc_ac_cookie_len = 0; 898195972f6Sopenharmony_ci sc->sc_padi_retried = 0; 899195972f6Sopenharmony_ci sc->sc_padr_retried = 0; 900195972f6Sopenharmony_ci /* changed to real address later */ 901195972f6Sopenharmony_ci MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); 902195972f6Sopenharmony_ci#ifdef PPPOE_SERVER 903195972f6Sopenharmony_ci /* wait PADI if IFF_PASSIVE */ 904195972f6Sopenharmony_ci if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { 905195972f6Sopenharmony_ci return 0; 906195972f6Sopenharmony_ci } 907195972f6Sopenharmony_ci#endif 908195972f6Sopenharmony_ci 909195972f6Sopenharmony_ci lcp_wo = &ppp->lcp_wantoptions; 910195972f6Sopenharmony_ci lcp_wo->mru = sc->sc_ethif->mtu-PPPOE_HEADERLEN-2; /* two byte PPP protocol discriminator, then IP data */ 911195972f6Sopenharmony_ci lcp_wo->neg_asyncmap = 0; 912195972f6Sopenharmony_ci lcp_wo->neg_pcompression = 0; 913195972f6Sopenharmony_ci lcp_wo->neg_accompression = 0; 914195972f6Sopenharmony_ci lcp_wo->passive = 0; 915195972f6Sopenharmony_ci lcp_wo->silent = 0; 916195972f6Sopenharmony_ci 917195972f6Sopenharmony_ci lcp_ao = &ppp->lcp_allowoptions; 918195972f6Sopenharmony_ci lcp_ao->mru = sc->sc_ethif->mtu-PPPOE_HEADERLEN-2; /* two byte PPP protocol discriminator, then IP data */ 919195972f6Sopenharmony_ci lcp_ao->neg_asyncmap = 0; 920195972f6Sopenharmony_ci lcp_ao->neg_pcompression = 0; 921195972f6Sopenharmony_ci lcp_ao->neg_accompression = 0; 922195972f6Sopenharmony_ci 923195972f6Sopenharmony_ci#if PPP_IPV4_SUPPORT && VJ_SUPPORT 924195972f6Sopenharmony_ci ipcp_wo = &ppp->ipcp_wantoptions; 925195972f6Sopenharmony_ci ipcp_wo->neg_vj = 0; 926195972f6Sopenharmony_ci ipcp_wo->old_vj = 0; 927195972f6Sopenharmony_ci 928195972f6Sopenharmony_ci ipcp_ao = &ppp->ipcp_allowoptions; 929195972f6Sopenharmony_ci ipcp_ao->neg_vj = 0; 930195972f6Sopenharmony_ci ipcp_ao->old_vj = 0; 931195972f6Sopenharmony_ci#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ 932195972f6Sopenharmony_ci 933195972f6Sopenharmony_ci /* save state, in case we fail to send PADI */ 934195972f6Sopenharmony_ci sc->sc_state = PPPOE_STATE_PADI_SENT; 935195972f6Sopenharmony_ci if ((err = pppoe_send_padi(sc)) != 0) { 936195972f6Sopenharmony_ci 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)); 937195972f6Sopenharmony_ci } 938195972f6Sopenharmony_ci sys_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc); 939195972f6Sopenharmony_ci} 940195972f6Sopenharmony_ci 941195972f6Sopenharmony_ci/* disconnect */ 942195972f6Sopenharmony_cistatic void 943195972f6Sopenharmony_cipppoe_disconnect(ppp_pcb *ppp, void *ctx) 944195972f6Sopenharmony_ci{ 945195972f6Sopenharmony_ci struct pppoe_softc *sc = (struct pppoe_softc *)ctx; 946195972f6Sopenharmony_ci 947195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); 948195972f6Sopenharmony_ci if (sc->sc_state == PPPOE_STATE_SESSION) { 949195972f6Sopenharmony_ci pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest); 950195972f6Sopenharmony_ci } 951195972f6Sopenharmony_ci 952195972f6Sopenharmony_ci /* stop any timer, disconnect can be called while initiating is in progress */ 953195972f6Sopenharmony_ci sys_untimeout(pppoe_timeout, sc); 954195972f6Sopenharmony_ci sc->sc_state = PPPOE_STATE_INITIAL; 955195972f6Sopenharmony_ci#ifdef PPPOE_SERVER 956195972f6Sopenharmony_ci if (sc->sc_hunique) { 957195972f6Sopenharmony_ci mem_free(sc->sc_hunique); 958195972f6Sopenharmony_ci sc->sc_hunique = NULL; /* probably not necessary, if state is initial we shouldn't have to access hunique anyway */ 959195972f6Sopenharmony_ci } 960195972f6Sopenharmony_ci sc->sc_hunique_len = 0; /* probably not necessary, if state is initial we shouldn't have to access hunique anyway */ 961195972f6Sopenharmony_ci#endif 962195972f6Sopenharmony_ci ppp_link_end(ppp); /* notify upper layers */ 963195972f6Sopenharmony_ci return; 964195972f6Sopenharmony_ci} 965195972f6Sopenharmony_ci 966195972f6Sopenharmony_ci/* Connection attempt aborted */ 967195972f6Sopenharmony_cistatic void 968195972f6Sopenharmony_cipppoe_abort_connect(struct pppoe_softc *sc) 969195972f6Sopenharmony_ci{ 970195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); 971195972f6Sopenharmony_ci sc->sc_state = PPPOE_STATE_INITIAL; 972195972f6Sopenharmony_ci ppp_link_failed(sc->pcb); /* notify upper layers */ 973195972f6Sopenharmony_ci} 974195972f6Sopenharmony_ci 975195972f6Sopenharmony_ci/* Send a PADR packet */ 976195972f6Sopenharmony_cistatic err_t 977195972f6Sopenharmony_cipppoe_send_padr(struct pppoe_softc *sc) 978195972f6Sopenharmony_ci{ 979195972f6Sopenharmony_ci struct pbuf *pb; 980195972f6Sopenharmony_ci u8_t *p; 981195972f6Sopenharmony_ci size_t len; 982195972f6Sopenharmony_ci#if PPPOE_SCNAME_SUPPORT 983195972f6Sopenharmony_ci size_t l1 = 0; /* XXX: gcc */ 984195972f6Sopenharmony_ci#endif /* PPPOE_SCNAME_SUPPORT */ 985195972f6Sopenharmony_ci 986195972f6Sopenharmony_ci len = 2 + 2 + 2 + 2 + sizeof(sc); /* service name, host unique */ 987195972f6Sopenharmony_ci#if PPPOE_SCNAME_SUPPORT 988195972f6Sopenharmony_ci if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ 989195972f6Sopenharmony_ci l1 = strlen(sc->sc_service_name); 990195972f6Sopenharmony_ci len += l1; 991195972f6Sopenharmony_ci } 992195972f6Sopenharmony_ci#endif /* PPPOE_SCNAME_SUPPORT */ 993195972f6Sopenharmony_ci if (sc->sc_ac_cookie_len > 0) { 994195972f6Sopenharmony_ci len += 2 + 2 + sc->sc_ac_cookie_len; /* AC cookie */ 995195972f6Sopenharmony_ci } 996195972f6Sopenharmony_ci LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", 997195972f6Sopenharmony_ci sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); 998195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); 999195972f6Sopenharmony_ci if (!pb) { 1000195972f6Sopenharmony_ci return ERR_MEM; 1001195972f6Sopenharmony_ci } 1002195972f6Sopenharmony_ci LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); 1003195972f6Sopenharmony_ci p = (u8_t*)pb->payload; 1004195972f6Sopenharmony_ci PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len); 1005195972f6Sopenharmony_ci PPPOE_ADD_16(p, PPPOE_TAG_SNAME); 1006195972f6Sopenharmony_ci#if PPPOE_SCNAME_SUPPORT 1007195972f6Sopenharmony_ci if (sc->sc_service_name != NULL) { 1008195972f6Sopenharmony_ci PPPOE_ADD_16(p, l1); 1009195972f6Sopenharmony_ci MEMCPY(p, sc->sc_service_name, l1); 1010195972f6Sopenharmony_ci p += l1; 1011195972f6Sopenharmony_ci } else 1012195972f6Sopenharmony_ci#endif /* PPPOE_SCNAME_SUPPORT */ 1013195972f6Sopenharmony_ci { 1014195972f6Sopenharmony_ci PPPOE_ADD_16(p, 0); 1015195972f6Sopenharmony_ci } 1016195972f6Sopenharmony_ci if (sc->sc_ac_cookie_len > 0) { 1017195972f6Sopenharmony_ci PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); 1018195972f6Sopenharmony_ci PPPOE_ADD_16(p, sc->sc_ac_cookie_len); 1019195972f6Sopenharmony_ci MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len); 1020195972f6Sopenharmony_ci p += sc->sc_ac_cookie_len; 1021195972f6Sopenharmony_ci } 1022195972f6Sopenharmony_ci PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); 1023195972f6Sopenharmony_ci PPPOE_ADD_16(p, sizeof(sc)); 1024195972f6Sopenharmony_ci MEMCPY(p, &sc, sizeof sc); 1025195972f6Sopenharmony_ci 1026195972f6Sopenharmony_ci return pppoe_output(sc, pb); 1027195972f6Sopenharmony_ci} 1028195972f6Sopenharmony_ci 1029195972f6Sopenharmony_ci/* send a PADT packet */ 1030195972f6Sopenharmony_cistatic err_t 1031195972f6Sopenharmony_cipppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest) 1032195972f6Sopenharmony_ci{ 1033195972f6Sopenharmony_ci struct pbuf *pb; 1034195972f6Sopenharmony_ci struct eth_hdr *ethhdr; 1035195972f6Sopenharmony_ci err_t res; 1036195972f6Sopenharmony_ci u8_t *p; 1037195972f6Sopenharmony_ci 1038195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN), PBUF_RAM); 1039195972f6Sopenharmony_ci if (!pb) { 1040195972f6Sopenharmony_ci return ERR_MEM; 1041195972f6Sopenharmony_ci } 1042195972f6Sopenharmony_ci LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); 1043195972f6Sopenharmony_ci 1044195972f6Sopenharmony_ci if (pbuf_add_header(pb, sizeof(struct eth_hdr))) { 1045195972f6Sopenharmony_ci PPPDEBUG(LOG_ERR, ("pppoe: pppoe_send_padt: could not allocate room for PPPoE header\n")); 1046195972f6Sopenharmony_ci LINK_STATS_INC(link.lenerr); 1047195972f6Sopenharmony_ci pbuf_free(pb); 1048195972f6Sopenharmony_ci return ERR_BUF; 1049195972f6Sopenharmony_ci } 1050195972f6Sopenharmony_ci ethhdr = (struct eth_hdr *)pb->payload; 1051195972f6Sopenharmony_ci ethhdr->type = PP_HTONS(ETHTYPE_PPPOEDISC); 1052195972f6Sopenharmony_ci MEMCPY(ðhdr->dest.addr, dest, sizeof(ethhdr->dest.addr)); 1053195972f6Sopenharmony_ci MEMCPY(ðhdr->src.addr, &outgoing_if->hwaddr, sizeof(ethhdr->src.addr)); 1054195972f6Sopenharmony_ci 1055195972f6Sopenharmony_ci p = (u8_t*)(ethhdr + 1); 1056195972f6Sopenharmony_ci PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0); 1057195972f6Sopenharmony_ci 1058195972f6Sopenharmony_ci res = outgoing_if->linkoutput(outgoing_if, pb); 1059195972f6Sopenharmony_ci 1060195972f6Sopenharmony_ci pbuf_free(pb); 1061195972f6Sopenharmony_ci 1062195972f6Sopenharmony_ci return res; 1063195972f6Sopenharmony_ci} 1064195972f6Sopenharmony_ci 1065195972f6Sopenharmony_ci#ifdef PPPOE_SERVER 1066195972f6Sopenharmony_cistatic err_t 1067195972f6Sopenharmony_cipppoe_send_pado(struct pppoe_softc *sc) 1068195972f6Sopenharmony_ci{ 1069195972f6Sopenharmony_ci struct pbuf *pb; 1070195972f6Sopenharmony_ci u8_t *p; 1071195972f6Sopenharmony_ci size_t len; 1072195972f6Sopenharmony_ci 1073195972f6Sopenharmony_ci /* calc length */ 1074195972f6Sopenharmony_ci len = 0; 1075195972f6Sopenharmony_ci /* include ac_cookie */ 1076195972f6Sopenharmony_ci len += 2 + 2 + sizeof(sc); 1077195972f6Sopenharmony_ci /* include hunique */ 1078195972f6Sopenharmony_ci len += 2 + 2 + sc->sc_hunique_len; 1079195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); 1080195972f6Sopenharmony_ci if (!pb) { 1081195972f6Sopenharmony_ci return ERR_MEM; 1082195972f6Sopenharmony_ci } 1083195972f6Sopenharmony_ci LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); 1084195972f6Sopenharmony_ci p = (u8_t*)pb->payload; 1085195972f6Sopenharmony_ci PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len); 1086195972f6Sopenharmony_ci PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); 1087195972f6Sopenharmony_ci PPPOE_ADD_16(p, sizeof(sc)); 1088195972f6Sopenharmony_ci MEMCPY(p, &sc, sizeof(sc)); 1089195972f6Sopenharmony_ci p += sizeof(sc); 1090195972f6Sopenharmony_ci PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); 1091195972f6Sopenharmony_ci PPPOE_ADD_16(p, sc->sc_hunique_len); 1092195972f6Sopenharmony_ci MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); 1093195972f6Sopenharmony_ci return pppoe_output(sc, pb); 1094195972f6Sopenharmony_ci} 1095195972f6Sopenharmony_ci 1096195972f6Sopenharmony_cistatic err_t 1097195972f6Sopenharmony_cipppoe_send_pads(struct pppoe_softc *sc) 1098195972f6Sopenharmony_ci{ 1099195972f6Sopenharmony_ci struct pbuf *pb; 1100195972f6Sopenharmony_ci u8_t *p; 1101195972f6Sopenharmony_ci size_t len, l1 = 0; /* XXX: gcc */ 1102195972f6Sopenharmony_ci 1103195972f6Sopenharmony_ci sc->sc_session = mono_time.tv_sec % 0xff + 1; 1104195972f6Sopenharmony_ci /* calc length */ 1105195972f6Sopenharmony_ci len = 0; 1106195972f6Sopenharmony_ci /* include hunique */ 1107195972f6Sopenharmony_ci len += 2 + 2 + 2 + 2 + sc->sc_hunique_len; /* service name, host unique*/ 1108195972f6Sopenharmony_ci if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ 1109195972f6Sopenharmony_ci l1 = strlen(sc->sc_service_name); 1110195972f6Sopenharmony_ci len += l1; 1111195972f6Sopenharmony_ci } 1112195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); 1113195972f6Sopenharmony_ci if (!pb) { 1114195972f6Sopenharmony_ci return ERR_MEM; 1115195972f6Sopenharmony_ci } 1116195972f6Sopenharmony_ci LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); 1117195972f6Sopenharmony_ci p = (u8_t*)pb->payload; 1118195972f6Sopenharmony_ci PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len); 1119195972f6Sopenharmony_ci PPPOE_ADD_16(p, PPPOE_TAG_SNAME); 1120195972f6Sopenharmony_ci if (sc->sc_service_name != NULL) { 1121195972f6Sopenharmony_ci PPPOE_ADD_16(p, l1); 1122195972f6Sopenharmony_ci MEMCPY(p, sc->sc_service_name, l1); 1123195972f6Sopenharmony_ci p += l1; 1124195972f6Sopenharmony_ci } else { 1125195972f6Sopenharmony_ci PPPOE_ADD_16(p, 0); 1126195972f6Sopenharmony_ci } 1127195972f6Sopenharmony_ci PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); 1128195972f6Sopenharmony_ci PPPOE_ADD_16(p, sc->sc_hunique_len); 1129195972f6Sopenharmony_ci MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); 1130195972f6Sopenharmony_ci return pppoe_output(sc, pb); 1131195972f6Sopenharmony_ci} 1132195972f6Sopenharmony_ci#endif 1133195972f6Sopenharmony_ci 1134195972f6Sopenharmony_cistatic err_t 1135195972f6Sopenharmony_cipppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb) 1136195972f6Sopenharmony_ci{ 1137195972f6Sopenharmony_ci u8_t *p; 1138195972f6Sopenharmony_ci size_t len; 1139195972f6Sopenharmony_ci 1140195972f6Sopenharmony_ci len = pb->tot_len; 1141195972f6Sopenharmony_ci 1142195972f6Sopenharmony_ci /* make room for PPPoE header - should not fail */ 1143195972f6Sopenharmony_ci if (pbuf_add_header(pb, PPPOE_HEADERLEN) != 0) { 1144195972f6Sopenharmony_ci /* bail out */ 1145195972f6Sopenharmony_ci PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for PPPoE header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); 1146195972f6Sopenharmony_ci LINK_STATS_INC(link.lenerr); 1147195972f6Sopenharmony_ci pbuf_free(pb); 1148195972f6Sopenharmony_ci return ERR_BUF; 1149195972f6Sopenharmony_ci } 1150195972f6Sopenharmony_ci 1151195972f6Sopenharmony_ci p = (u8_t*)pb->payload; 1152195972f6Sopenharmony_ci PPPOE_ADD_HEADER(p, 0, sc->sc_session, len); 1153195972f6Sopenharmony_ci 1154195972f6Sopenharmony_ci return pppoe_output(sc, pb); 1155195972f6Sopenharmony_ci} 1156195972f6Sopenharmony_ci 1157195972f6Sopenharmony_ci#if 0 /*def PFIL_HOOKS*/ 1158195972f6Sopenharmony_cistatic int 1159195972f6Sopenharmony_cipppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir) 1160195972f6Sopenharmony_ci{ 1161195972f6Sopenharmony_ci struct pppoe_softc *sc; 1162195972f6Sopenharmony_ci int s; 1163195972f6Sopenharmony_ci 1164195972f6Sopenharmony_ci if (mp != (struct pbuf **)PFIL_IFNET_DETACH) { 1165195972f6Sopenharmony_ci return 0; 1166195972f6Sopenharmony_ci } 1167195972f6Sopenharmony_ci 1168195972f6Sopenharmony_ci LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { 1169195972f6Sopenharmony_ci if (sc->sc_ethif != ifp) { 1170195972f6Sopenharmony_ci continue; 1171195972f6Sopenharmony_ci } 1172195972f6Sopenharmony_ci if (sc->sc_sppp.pp_if.if_flags & IFF_UP) { 1173195972f6Sopenharmony_ci sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 1174195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": ethernet interface detached, going down\n", 1175195972f6Sopenharmony_ci sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); 1176195972f6Sopenharmony_ci } 1177195972f6Sopenharmony_ci sc->sc_ethif = NULL; 1178195972f6Sopenharmony_ci pppoe_clear_softc(sc, "ethernet interface detached"); 1179195972f6Sopenharmony_ci } 1180195972f6Sopenharmony_ci 1181195972f6Sopenharmony_ci return 0; 1182195972f6Sopenharmony_ci} 1183195972f6Sopenharmony_ci#endif 1184195972f6Sopenharmony_ci 1185195972f6Sopenharmony_ci#if 0 /* UNUSED */ 1186195972f6Sopenharmony_cistatic void 1187195972f6Sopenharmony_cipppoe_clear_softc(struct pppoe_softc *sc, const char *message) 1188195972f6Sopenharmony_ci{ 1189195972f6Sopenharmony_ci LWIP_UNUSED_ARG(message); 1190195972f6Sopenharmony_ci 1191195972f6Sopenharmony_ci /* stop timer */ 1192195972f6Sopenharmony_ci sys_untimeout(pppoe_timeout, sc); 1193195972f6Sopenharmony_ci 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)); 1194195972f6Sopenharmony_ci sc->sc_state = PPPOE_STATE_INITIAL; 1195195972f6Sopenharmony_ci ppp_link_end(sc->pcb); /* notify upper layers - /!\ dangerous /!\ - see pppoe_disc_input() */ 1196195972f6Sopenharmony_ci} 1197195972f6Sopenharmony_ci#endif /* UNUSED */ 1198195972f6Sopenharmony_ci#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ 1199