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