From 3ce6dd166c3c022a3549d95014a8abf8417ff9e8 Mon Sep 17 00:00:00 2001 From: Sylvain Rochet Date: Sun, 1 Mar 2015 22:04:24 +0100 Subject: [PATCH] PPP, L2TP, added link-level IPv6 support --- src/api/pppapi.c | 46 +++++++++++ src/include/lwip/pppapi.h | 19 +++++ src/include/netif/ppp/pppol2tp.h | 12 ++- src/netif/ppp/pppol2tp.c | 129 ++++++++++++++++++++++++++----- 4 files changed, 184 insertions(+), 22 deletions(-) diff --git a/src/api/pppapi.c b/src/api/pppapi.c index 5b7940d1..5ba190ec 100644 --- a/src/api/pppapi.c +++ b/src/api/pppapi.c @@ -232,6 +232,52 @@ pppapi_pppol2tp_create(struct netif *pppif, struct netif *netif, ip_addr_t *ipad TCPIP_PPPAPI(&msg); return msg.msg.ppp; } + + +#if LWIP_IPV6 +/** + * Call pppol2tp_create_ip6() inside the tcpip_thread context. + */ +static void +pppapi_do_pppol2tp_create_ip6(struct pppapi_msg_msg *msg) +{ + msg->ppp = pppol2tp_create_ip6(msg->msg.l2tpcreateip6.pppif, + msg->msg.l2tpcreateip6.netif, msg->msg.l2tpcreateip6.ip6addr, msg->msg.l2tpcreateip6.port, +#if PPPOL2TP_AUTH_SUPPORT + msg->msg.l2tpcreateip6.secret, + msg->msg.l2tpcreateip6.secret_len, +#else /* PPPOL2TP_AUTH_SUPPORT */ + NULL, +#endif /* PPPOL2TP_AUTH_SUPPORT */ + msg->msg.l2tpcreateip6.link_status_cb, msg->msg.l2tpcreateip6.ctx_cb); + TCPIP_PPPAPI_ACK(msg); +} + +/** + * Call pppol2tp_create_ip6() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +ppp_pcb* +pppapi_pppol2tp_create_ip6(struct netif *pppif, struct netif *netif, ip6_addr_t *ip6addr, u16_t port, + u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb) +{ + struct pppapi_msg msg; + msg.function = pppapi_do_pppol2tp_create_ip6; + msg.msg.msg.l2tpcreateip6.pppif = pppif; + msg.msg.msg.l2tpcreateip6.netif = netif; + msg.msg.msg.l2tpcreateip6.ip6addr = ip6addr; + msg.msg.msg.l2tpcreateip6.port = port; +#if PPPOL2TP_AUTH_SUPPORT + msg.msg.msg.l2tpcreateip6.secret = secret; + msg.msg.msg.l2tpcreateip6.secret_len = secret_len; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + msg.msg.msg.l2tpcreateip6.link_status_cb = link_status_cb; + msg.msg.msg.l2tpcreateip6.ctx_cb = ctx_cb; + TCPIP_PPPAPI(&msg); + return msg.msg.ppp; +} +#endif /* LWIP_IPV6 */ #endif /* PPPOL2TP_SUPPORT */ diff --git a/src/include/lwip/pppapi.h b/src/include/lwip/pppapi.h index 270c5fc7..b82cc8dd 100644 --- a/src/include/lwip/pppapi.h +++ b/src/include/lwip/pppapi.h @@ -88,6 +88,20 @@ struct pppapi_msg_msg { ppp_link_status_cb_fn link_status_cb; void *ctx_cb; } l2tpcreate; +#if LWIP_IPV6 + struct { + struct netif *pppif; + struct netif *netif; + ip6_addr_t *ip6addr; + u16_t port; +#if PPPOL2TP_AUTH_SUPPORT + u8_t *secret; + u8_t secret_len; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + ppp_link_status_cb_fn link_status_cb; + void *ctx_cb; + } l2tpcreateip6; +#endif /* LWIP_IPV6 */ #endif /* PPPOL2TP_SUPPORT */ struct { u16_t holdoff; @@ -130,6 +144,11 @@ ppp_pcb *pppapi_pppoe_create(struct netif *pppif, struct netif *ethif, const cha ppp_pcb *pppapi_pppol2tp_create(struct netif *pppif, struct netif *netif, ip_addr_t *ipaddr, u16_t port, u8_t *secret, u8_t secret_len, ppp_link_status_cb_fn link_status_cb, void *ctx_cb); +#if LWIP_IPV6 +ppp_pcb *pppapi_pppol2tp_create_ip6(struct netif *pppif, struct netif *netif, ip6_addr_t *ip6addr, u16_t port, + u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); +#endif /* LWIP_IPV6 */ #endif /* PPPOL2TP_SUPPORT */ err_t pppapi_connect(ppp_pcb *pcb, u16_t holdoff); #if PPP_SERVER diff --git a/src/include/netif/ppp/pppol2tp.h b/src/include/netif/ppp/pppol2tp.h index df57c189..064b7766 100644 --- a/src/include/netif/ppp/pppol2tp.h +++ b/src/include/netif/ppp/pppol2tp.h @@ -166,7 +166,7 @@ struct pppol2tp_pcb_s { u8_t phase; /* L2TP phase */ struct udp_pcb *udp; /* UDP L2TP Socket */ struct netif *netif; /* Output interface, used as a default route */ - ip_addr_t remote_ip; /* LNS IP Address */ + ipX_addr_t remote_ip; /* LNS IP Address */ u16_t remote_port; /* LNS port */ #if PPPOL2TP_AUTH_SUPPORT u8_t *secret; /* Secret string */ @@ -191,11 +191,19 @@ struct pppol2tp_pcb_s { }; -/* Create a new L2TP session. */ +/* Create a new L2TP session over IPv4. */ ppp_pcb *pppol2tp_create(struct netif *pppif, struct netif *netif, ip_addr_t *ipaddr, u16_t port, u8_t *secret, u8_t secret_len, ppp_link_status_cb_fn link_status_cb, void *ctx_cb); +#if LWIP_IPV6 +/* Create a new L2TP session over IPv6. */ +ppp_pcb *pppol2tp_create_ip6(struct netif *pppif, + struct netif *netif, ip6_addr_t *ip6addr, u16_t port, + u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); +#endif /* LWIP_IPV6 */ + #endif /* PPPOL2TP_H_ */ #endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/src/netif/ppp/pppol2tp.c b/src/netif/ppp/pppol2tp.c index 3e4935f2..737e0677 100644 --- a/src/netif/ppp/pppol2tp.c +++ b/src/netif/ppp/pppol2tp.c @@ -82,9 +82,12 @@ static err_t pppol2tp_connect(ppp_pcb *ppp, void *ctx); /* Be a LAC, connect static void pppol2tp_disconnect(ppp_pcb *ppp, void *ctx); /* Disconnect */ /* Prototypes for procedures local to this file. */ -static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const struct ip_addr *addr, u16_t port); -static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, const struct ip_addr *addr, u16_t port, - struct pbuf *p, u16_t len, u16_t tunnel_id, u16_t session_id, u16_t ns, u16_t nr); +static void pppol2tp_input_ip4(void *arg, struct udp_pcb *pcb, struct pbuf *p, const struct ip_addr *addr, u16_t port); +#if LWIP_IPV6 +static void pppol2tp_input_ip6(void *arg, struct udp_pcb *pcb, struct pbuf *p, const struct ip6_addr *addr, u16_t port); +#endif /* LWIP_IPV6 */ +static void pppol2tp_input(pppol2tp_pcb *l2tp, struct pbuf *p, u16_t port); +static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, u16_t port, struct pbuf *p, u16_t ns, u16_t nr); static void pppol2tp_timeout(void *arg); static void pppol2tp_abort_connect(pppol2tp_pcb *l2tp); static void pppol2tp_clear(pppol2tp_pcb *l2tp); @@ -143,16 +146,16 @@ ppp_pcb *pppol2tp_create(struct netif *pppif, ppp_free(ppp); return NULL; } - udp_recv(udp, pppol2tp_input, l2tp); + udp_recv(udp, pppol2tp_input_ip4, l2tp); memset(l2tp, 0, sizeof(pppol2tp_pcb)); l2tp->phase = PPPOL2TP_STATE_INITIAL; l2tp->ppp = ppp; l2tp->udp = udp; l2tp->netif = netif; - ip_addr_set(&l2tp->remote_ip, ipaddr); + ip_addr_set(&l2tp->remote_ip.ip4, ipaddr); l2tp->remote_port = port; - #if PPPOL2TP_AUTH_SUPPORT +#if PPPOL2TP_AUTH_SUPPORT l2tp->secret = secret; l2tp->secret_len = secret_len; #endif /* PPPOL2TP_AUTH_SUPPORT */ @@ -161,6 +164,52 @@ ppp_pcb *pppol2tp_create(struct netif *pppif, return ppp; } +#if LWIP_IPV6 +/* Create a new L2TP session over IPv6. */ +ppp_pcb *pppol2tp_create_ip6(struct netif *pppif, + struct netif *netif, ip6_addr_t *ip6addr, u16_t port, + u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb) { + ppp_pcb *ppp; + pppol2tp_pcb *l2tp; + struct udp_pcb *udp; + + ppp = ppp_new(pppif, link_status_cb, ctx_cb); + if (ppp == NULL) { + return NULL; + } + + l2tp = (pppol2tp_pcb *)memp_malloc(MEMP_PPPOL2TP_PCB); + if (l2tp == NULL) { + ppp_free(ppp); + return NULL; + } + + udp = udp_new_ip6(); + if (udp == NULL) { + memp_free(MEMP_PPPOL2TP_PCB, l2tp); + ppp_free(ppp); + return NULL; + } + udp_recv_ip6(udp, pppol2tp_input_ip6, l2tp); + + memset(l2tp, 0, sizeof(pppol2tp_pcb)); + l2tp->phase = PPPOL2TP_STATE_INITIAL; + l2tp->ppp = ppp; + l2tp->udp = udp; + l2tp->netif = netif; + ip6_addr_set(&l2tp->remote_ip.ip6, ip6addr); + l2tp->remote_port = port; +#if PPPOL2TP_AUTH_SUPPORT + l2tp->secret = secret; + l2tp->secret_len = secret_len; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + ppp_link_set_callbacks(ppp, &pppol2tp_callbacks, l2tp); + return ppp; +} +#endif /* LWIP_IPV6 */ + /* Called by PPP core */ static err_t pppol2tp_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) { pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; @@ -302,6 +351,11 @@ static err_t pppol2tp_connect(ppp_pcb *ppp, void *ctx) { /* Listen to a random source port, we need to do that instead of using udp_connect() * because the L2TP LNS might answer with its own random source port (!= 1701) */ +#if LWIP_IPV6 + if (PCB_ISIPV6(l2tp->udp)) { + udp_bind_ip6(l2tp->udp, IP6_ADDR_ANY, 0); + } else +#endif /* LWIP_IPV6 */ udp_bind(l2tp->udp, IP_ADDR_ANY, 0); #if PPPOL2TP_AUTH_SUPPORT @@ -339,21 +393,52 @@ static void pppol2tp_disconnect(ppp_pcb *ppp, void *ctx) { ppp_link_end(ppp); /* notify upper layers */ } -/* UDP Callback for incoming L2TP frames */ -static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const struct ip_addr *addr, u16_t port) { +/* UDP Callback for incoming IPv4 L2TP frames */ +static void pppol2tp_input_ip4(void *arg, struct udp_pcb *pcb, struct pbuf *p, const struct ip_addr *addr, u16_t port) { pppol2tp_pcb *l2tp = (pppol2tp_pcb*)arg; - u16_t hflags, hlen, len=0, tunnel_id=0, session_id=0, ns=0, nr=0, offset=0; - u8_t *inp; LWIP_UNUSED_ARG(pcb); if (l2tp->phase < PPPOL2TP_STATE_SCCRQ_SENT) { goto free_and_return; } - if (!ip_addr_cmp(&l2tp->remote_ip, addr)) { + if (!ip_addr_cmp(&l2tp->remote_ip.ip4, addr)) { goto free_and_return; } + pppol2tp_input(l2tp, p, port); + return; + +free_and_return: + pbuf_free(p); +} + +#if LWIP_IPV6 +/* UDP Callback for incoming IPv6 L2TP frames */ +static void pppol2tp_input_ip6(void *arg, struct udp_pcb *pcb, struct pbuf *p, const struct ip6_addr *addr, u16_t port) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb*)arg; + LWIP_UNUSED_ARG(pcb); + + if (l2tp->phase < PPPOL2TP_STATE_SCCRQ_SENT) { + goto free_and_return; + } + + if (!ip6_addr_cmp(&l2tp->remote_ip.ip6, addr)) { + goto free_and_return; + } + + pppol2tp_input(l2tp, p, port); + return; + +free_and_return: + pbuf_free(p); +} +#endif /* LWIP_IPV6 */ + +static void pppol2tp_input(pppol2tp_pcb *l2tp, struct pbuf *p, u16_t port) { + u16_t hflags, hlen, len=0, tunnel_id=0, session_id=0, ns=0, nr=0, offset=0; + u8_t *inp; + /* discard packet if port mismatch, but only if we received a SCCRP */ if (l2tp->phase > PPPOL2TP_STATE_SCCRQ_SENT && l2tp->tunnel_port != port) { goto free_and_return; @@ -442,7 +527,7 @@ static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const /* Control packet */ if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) { - pppol2tp_dispatch_control_packet(l2tp, addr, port, p, len, tunnel_id, session_id, ns, nr); + pppol2tp_dispatch_control_packet(l2tp, port, p, ns, nr); goto free_and_return; } @@ -479,8 +564,7 @@ free_and_return: } /* L2TP Control packet entry point */ -static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, const struct ip_addr *addr, u16_t port, - struct pbuf *p, u16_t len, u16_t tunnel_id, u16_t session_id, u16_t ns, u16_t nr) { +static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, u16_t port, struct pbuf *p, u16_t ns, u16_t nr) { u8_t *inp; u16_t avplen, avpflags, vendorid, attributetype, messagetype=0; err_t err; @@ -489,10 +573,6 @@ static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, const struct ip u8_t md5_hash[16]; u8_t challenge_id = 0; #endif /* PPPOL2TP_AUTH_SUPPORT */ - LWIP_UNUSED_ARG(addr); - LWIP_UNUSED_ARG(len); - LWIP_UNUSED_ARG(tunnel_id); - LWIP_UNUSED_ARG(session_id); l2tp->peer_nr = nr; l2tp->peer_ns = ns; @@ -1137,10 +1217,19 @@ static err_t pppol2tp_xmit(pppol2tp_pcb *l2tp, struct pbuf *pb) { static err_t pppol2tp_udp_send(pppol2tp_pcb *l2tp, struct pbuf *pb) { err_t err; +#if LWIP_IPV6 + if (PCB_ISIPV6(l2tp->udp)) { + if (l2tp->netif) { + udp_sendto_if_ip6(l2tp->udp, pb, &l2tp->remote_ip.ip6, l2tp->tunnel_port, l2tp->netif); + } else { + udp_sendto_ip6(l2tp->udp, pb, &l2tp->remote_ip.ip6, l2tp->tunnel_port); + } + } else +#endif /* LWIP_IPV6 */ if (l2tp->netif) { - err = udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip, l2tp->tunnel_port, l2tp->netif); + err = udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip.ip4, l2tp->tunnel_port, l2tp->netif); } else { - err = udp_sendto(l2tp->udp, pb, &l2tp->remote_ip, l2tp->tunnel_port); + err = udp_sendto(l2tp->udp, pb, &l2tp->remote_ip.ip4, l2tp->tunnel_port); } pbuf_free(pb); return err;