1195972f6Sopenharmony_ci/** 2195972f6Sopenharmony_ci * @file 3195972f6Sopenharmony_ci * Network Point to Point Protocol over Layer 2 Tunneling Protocol program file. 4195972f6Sopenharmony_ci * 5195972f6Sopenharmony_ci */ 6195972f6Sopenharmony_ci 7195972f6Sopenharmony_ci/* 8195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 9195972f6Sopenharmony_ci * are permitted provided that the following conditions are met: 10195972f6Sopenharmony_ci * 11195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 12195972f6Sopenharmony_ci * this list of conditions and the following disclaimer. 13195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 14195972f6Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 15195972f6Sopenharmony_ci * and/or other materials provided with the distribution. 16195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 17195972f6Sopenharmony_ci * derived from this software without specific prior written permission. 18195972f6Sopenharmony_ci * 19195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 20195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 22195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 24195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 28195972f6Sopenharmony_ci * OF SUCH DAMAGE. 29195972f6Sopenharmony_ci * 30195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack. 31195972f6Sopenharmony_ci * 32195972f6Sopenharmony_ci */ 33195972f6Sopenharmony_ci 34195972f6Sopenharmony_ci/* 35195972f6Sopenharmony_ci * L2TP Support status: 36195972f6Sopenharmony_ci * 37195972f6Sopenharmony_ci * Supported: 38195972f6Sopenharmony_ci * - L2TPv2 (PPP over L2TP, a.k.a. UDP tunnels) 39195972f6Sopenharmony_ci * - LAC 40195972f6Sopenharmony_ci * 41195972f6Sopenharmony_ci * Not supported: 42195972f6Sopenharmony_ci * - LNS (require PPP server support) 43195972f6Sopenharmony_ci * - L2TPv3 ethernet pseudowires 44195972f6Sopenharmony_ci * - L2TPv3 VLAN pseudowire 45195972f6Sopenharmony_ci * - L2TPv3 PPP pseudowires 46195972f6Sopenharmony_ci * - L2TPv3 IP encapsulation 47195972f6Sopenharmony_ci * - L2TPv3 IP pseudowire 48195972f6Sopenharmony_ci * - L2TP tunnel switching - http://tools.ietf.org/html/draft-ietf-l2tpext-tunnel-switching-08 49195972f6Sopenharmony_ci * - Multiple tunnels per UDP socket, as well as multiple sessions per tunnel 50195972f6Sopenharmony_ci * - Hidden AVPs 51195972f6Sopenharmony_ci */ 52195972f6Sopenharmony_ci 53195972f6Sopenharmony_ci#include "netif/ppp/ppp_opts.h" 54195972f6Sopenharmony_ci#if PPP_SUPPORT && PPPOL2TP_SUPPORT /* don't build if not configured for use in lwipopts.h */ 55195972f6Sopenharmony_ci 56195972f6Sopenharmony_ci#include "lwip/err.h" 57195972f6Sopenharmony_ci#include "lwip/memp.h" 58195972f6Sopenharmony_ci#include "lwip/netif.h" 59195972f6Sopenharmony_ci#include "lwip/udp.h" 60195972f6Sopenharmony_ci#include "lwip/snmp.h" 61195972f6Sopenharmony_ci 62195972f6Sopenharmony_ci#include "netif/ppp/ppp_impl.h" 63195972f6Sopenharmony_ci#include "netif/ppp/lcp.h" 64195972f6Sopenharmony_ci#include "netif/ppp/ipcp.h" 65195972f6Sopenharmony_ci#include "netif/ppp/pppol2tp.h" 66195972f6Sopenharmony_ci#include "netif/ppp/pppcrypt.h" 67195972f6Sopenharmony_ci#include "netif/ppp/magic.h" 68195972f6Sopenharmony_ci 69195972f6Sopenharmony_ci/* Memory pool */ 70195972f6Sopenharmony_ciLWIP_MEMPOOL_DECLARE(PPPOL2TP_PCB, MEMP_NUM_PPPOL2TP_INTERFACES, sizeof(pppol2tp_pcb), "PPPOL2TP_PCB") 71195972f6Sopenharmony_ci 72195972f6Sopenharmony_ci/* callbacks called from PPP core */ 73195972f6Sopenharmony_cistatic err_t pppol2tp_write(ppp_pcb *ppp, void *ctx, struct pbuf *p); 74195972f6Sopenharmony_cistatic err_t pppol2tp_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol); 75195972f6Sopenharmony_cistatic err_t pppol2tp_destroy(ppp_pcb *ppp, void *ctx); /* Destroy a L2TP control block */ 76195972f6Sopenharmony_cistatic void pppol2tp_connect(ppp_pcb *ppp, void *ctx); /* Be a LAC, connect to a LNS. */ 77195972f6Sopenharmony_cistatic void pppol2tp_disconnect(ppp_pcb *ppp, void *ctx); /* Disconnect */ 78195972f6Sopenharmony_ci 79195972f6Sopenharmony_ci /* Prototypes for procedures local to this file. */ 80195972f6Sopenharmony_cistatic void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); 81195972f6Sopenharmony_cistatic void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, u16_t port, struct pbuf *p, u16_t ns, u16_t nr); 82195972f6Sopenharmony_cistatic void pppol2tp_timeout(void *arg); 83195972f6Sopenharmony_cistatic void pppol2tp_abort_connect(pppol2tp_pcb *l2tp); 84195972f6Sopenharmony_cistatic err_t pppol2tp_send_sccrq(pppol2tp_pcb *l2tp); 85195972f6Sopenharmony_cistatic err_t pppol2tp_send_scccn(pppol2tp_pcb *l2tp, u16_t ns); 86195972f6Sopenharmony_cistatic err_t pppol2tp_send_icrq(pppol2tp_pcb *l2tp, u16_t ns); 87195972f6Sopenharmony_cistatic err_t pppol2tp_send_iccn(pppol2tp_pcb *l2tp, u16_t ns); 88195972f6Sopenharmony_cistatic err_t pppol2tp_send_zlb(pppol2tp_pcb *l2tp, u16_t ns, u16_t nr); 89195972f6Sopenharmony_cistatic err_t pppol2tp_send_stopccn(pppol2tp_pcb *l2tp, u16_t ns); 90195972f6Sopenharmony_cistatic err_t pppol2tp_xmit(pppol2tp_pcb *l2tp, struct pbuf *pb); 91195972f6Sopenharmony_cistatic err_t pppol2tp_udp_send(pppol2tp_pcb *l2tp, struct pbuf *pb); 92195972f6Sopenharmony_ci 93195972f6Sopenharmony_ci/* Callbacks structure for PPP core */ 94195972f6Sopenharmony_cistatic const struct link_callbacks pppol2tp_callbacks = { 95195972f6Sopenharmony_ci pppol2tp_connect, 96195972f6Sopenharmony_ci#if PPP_SERVER 97195972f6Sopenharmony_ci NULL, 98195972f6Sopenharmony_ci#endif /* PPP_SERVER */ 99195972f6Sopenharmony_ci pppol2tp_disconnect, 100195972f6Sopenharmony_ci pppol2tp_destroy, 101195972f6Sopenharmony_ci pppol2tp_write, 102195972f6Sopenharmony_ci pppol2tp_netif_output, 103195972f6Sopenharmony_ci NULL, 104195972f6Sopenharmony_ci NULL 105195972f6Sopenharmony_ci}; 106195972f6Sopenharmony_ci 107195972f6Sopenharmony_ci 108195972f6Sopenharmony_ci/* Create a new L2TP session. */ 109195972f6Sopenharmony_cippp_pcb *pppol2tp_create(struct netif *pppif, 110195972f6Sopenharmony_ci struct netif *netif, const ip_addr_t *ipaddr, u16_t port, 111195972f6Sopenharmony_ci const u8_t *secret, u8_t secret_len, 112195972f6Sopenharmony_ci ppp_link_status_cb_fn link_status_cb, void *ctx_cb) { 113195972f6Sopenharmony_ci ppp_pcb *ppp; 114195972f6Sopenharmony_ci pppol2tp_pcb *l2tp; 115195972f6Sopenharmony_ci struct udp_pcb *udp; 116195972f6Sopenharmony_ci#if !PPPOL2TP_AUTH_SUPPORT 117195972f6Sopenharmony_ci LWIP_UNUSED_ARG(secret); 118195972f6Sopenharmony_ci LWIP_UNUSED_ARG(secret_len); 119195972f6Sopenharmony_ci#endif /* !PPPOL2TP_AUTH_SUPPORT */ 120195972f6Sopenharmony_ci 121195972f6Sopenharmony_ci if (ipaddr == NULL) { 122195972f6Sopenharmony_ci goto ipaddr_check_failed; 123195972f6Sopenharmony_ci } 124195972f6Sopenharmony_ci 125195972f6Sopenharmony_ci l2tp = (pppol2tp_pcb *)LWIP_MEMPOOL_ALLOC(PPPOL2TP_PCB); 126195972f6Sopenharmony_ci if (l2tp == NULL) { 127195972f6Sopenharmony_ci goto memp_malloc_l2tp_failed; 128195972f6Sopenharmony_ci } 129195972f6Sopenharmony_ci 130195972f6Sopenharmony_ci udp = udp_new_ip_type(IP_GET_TYPE(ipaddr)); 131195972f6Sopenharmony_ci if (udp == NULL) { 132195972f6Sopenharmony_ci goto udp_new_failed; 133195972f6Sopenharmony_ci } 134195972f6Sopenharmony_ci udp_recv(udp, pppol2tp_input, l2tp); 135195972f6Sopenharmony_ci 136195972f6Sopenharmony_ci ppp = ppp_new(pppif, &pppol2tp_callbacks, l2tp, link_status_cb, ctx_cb); 137195972f6Sopenharmony_ci if (ppp == NULL) { 138195972f6Sopenharmony_ci goto ppp_new_failed; 139195972f6Sopenharmony_ci } 140195972f6Sopenharmony_ci 141195972f6Sopenharmony_ci memset(l2tp, 0, sizeof(pppol2tp_pcb)); 142195972f6Sopenharmony_ci l2tp->phase = PPPOL2TP_STATE_INITIAL; 143195972f6Sopenharmony_ci l2tp->ppp = ppp; 144195972f6Sopenharmony_ci l2tp->udp = udp; 145195972f6Sopenharmony_ci l2tp->netif = netif; 146195972f6Sopenharmony_ci ip_addr_copy(l2tp->remote_ip, *ipaddr); 147195972f6Sopenharmony_ci l2tp->remote_port = port; 148195972f6Sopenharmony_ci#if PPPOL2TP_AUTH_SUPPORT 149195972f6Sopenharmony_ci l2tp->secret = secret; 150195972f6Sopenharmony_ci l2tp->secret_len = secret_len; 151195972f6Sopenharmony_ci#endif /* PPPOL2TP_AUTH_SUPPORT */ 152195972f6Sopenharmony_ci 153195972f6Sopenharmony_ci return ppp; 154195972f6Sopenharmony_ci 155195972f6Sopenharmony_cippp_new_failed: 156195972f6Sopenharmony_ci udp_remove(udp); 157195972f6Sopenharmony_ciudp_new_failed: 158195972f6Sopenharmony_ci LWIP_MEMPOOL_FREE(PPPOL2TP_PCB, l2tp); 159195972f6Sopenharmony_cimemp_malloc_l2tp_failed: 160195972f6Sopenharmony_ciipaddr_check_failed: 161195972f6Sopenharmony_ci return NULL; 162195972f6Sopenharmony_ci} 163195972f6Sopenharmony_ci 164195972f6Sopenharmony_ci/* Called by PPP core */ 165195972f6Sopenharmony_cistatic err_t pppol2tp_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) { 166195972f6Sopenharmony_ci pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; 167195972f6Sopenharmony_ci struct pbuf *ph; /* UDP + L2TP header */ 168195972f6Sopenharmony_ci err_t ret; 169195972f6Sopenharmony_ci#if MIB2_STATS 170195972f6Sopenharmony_ci u16_t tot_len; 171195972f6Sopenharmony_ci#else /* MIB2_STATS */ 172195972f6Sopenharmony_ci LWIP_UNUSED_ARG(ppp); 173195972f6Sopenharmony_ci#endif /* MIB2_STATS */ 174195972f6Sopenharmony_ci 175195972f6Sopenharmony_ci ph = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(PPPOL2TP_OUTPUT_DATA_HEADER_LEN), PBUF_RAM); 176195972f6Sopenharmony_ci if(!ph) { 177195972f6Sopenharmony_ci LINK_STATS_INC(link.memerr); 178195972f6Sopenharmony_ci LINK_STATS_INC(link.proterr); 179195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); 180195972f6Sopenharmony_ci pbuf_free(p); 181195972f6Sopenharmony_ci return ERR_MEM; 182195972f6Sopenharmony_ci } 183195972f6Sopenharmony_ci 184195972f6Sopenharmony_ci pbuf_remove_header(ph, PPPOL2TP_OUTPUT_DATA_HEADER_LEN); /* hide L2TP header */ 185195972f6Sopenharmony_ci pbuf_cat(ph, p); 186195972f6Sopenharmony_ci#if MIB2_STATS 187195972f6Sopenharmony_ci tot_len = ph->tot_len; 188195972f6Sopenharmony_ci#endif /* MIB2_STATS */ 189195972f6Sopenharmony_ci 190195972f6Sopenharmony_ci ret = pppol2tp_xmit(l2tp, ph); 191195972f6Sopenharmony_ci if (ret != ERR_OK) { 192195972f6Sopenharmony_ci LINK_STATS_INC(link.err); 193195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); 194195972f6Sopenharmony_ci return ret; 195195972f6Sopenharmony_ci } 196195972f6Sopenharmony_ci 197195972f6Sopenharmony_ci MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, (u16_t)tot_len); 198195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); 199195972f6Sopenharmony_ci LINK_STATS_INC(link.xmit); 200195972f6Sopenharmony_ci return ERR_OK; 201195972f6Sopenharmony_ci} 202195972f6Sopenharmony_ci 203195972f6Sopenharmony_ci/* Called by PPP core */ 204195972f6Sopenharmony_cistatic err_t pppol2tp_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol) { 205195972f6Sopenharmony_ci pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; 206195972f6Sopenharmony_ci struct pbuf *pb; 207195972f6Sopenharmony_ci u8_t *pl; 208195972f6Sopenharmony_ci err_t err; 209195972f6Sopenharmony_ci#if MIB2_STATS 210195972f6Sopenharmony_ci u16_t tot_len; 211195972f6Sopenharmony_ci#else /* MIB2_STATS */ 212195972f6Sopenharmony_ci LWIP_UNUSED_ARG(ppp); 213195972f6Sopenharmony_ci#endif /* MIB2_STATS */ 214195972f6Sopenharmony_ci 215195972f6Sopenharmony_ci /* @todo: try to use pbuf_header() here! */ 216195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_TRANSPORT, PPPOL2TP_OUTPUT_DATA_HEADER_LEN + sizeof(protocol), PBUF_RAM); 217195972f6Sopenharmony_ci if(!pb) { 218195972f6Sopenharmony_ci LINK_STATS_INC(link.memerr); 219195972f6Sopenharmony_ci LINK_STATS_INC(link.proterr); 220195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); 221195972f6Sopenharmony_ci return ERR_MEM; 222195972f6Sopenharmony_ci } 223195972f6Sopenharmony_ci 224195972f6Sopenharmony_ci pbuf_remove_header(pb, PPPOL2TP_OUTPUT_DATA_HEADER_LEN); 225195972f6Sopenharmony_ci 226195972f6Sopenharmony_ci pl = (u8_t*)pb->payload; 227195972f6Sopenharmony_ci PUTSHORT(protocol, pl); 228195972f6Sopenharmony_ci 229195972f6Sopenharmony_ci pbuf_chain(pb, p); 230195972f6Sopenharmony_ci#if MIB2_STATS 231195972f6Sopenharmony_ci tot_len = pb->tot_len; 232195972f6Sopenharmony_ci#endif /* MIB2_STATS */ 233195972f6Sopenharmony_ci 234195972f6Sopenharmony_ci if( (err = pppol2tp_xmit(l2tp, pb)) != ERR_OK) { 235195972f6Sopenharmony_ci LINK_STATS_INC(link.err); 236195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); 237195972f6Sopenharmony_ci return err; 238195972f6Sopenharmony_ci } 239195972f6Sopenharmony_ci 240195972f6Sopenharmony_ci MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, tot_len); 241195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); 242195972f6Sopenharmony_ci LINK_STATS_INC(link.xmit); 243195972f6Sopenharmony_ci return ERR_OK; 244195972f6Sopenharmony_ci} 245195972f6Sopenharmony_ci 246195972f6Sopenharmony_ci/* Destroy a L2TP control block */ 247195972f6Sopenharmony_cistatic err_t pppol2tp_destroy(ppp_pcb *ppp, void *ctx) { 248195972f6Sopenharmony_ci pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; 249195972f6Sopenharmony_ci LWIP_UNUSED_ARG(ppp); 250195972f6Sopenharmony_ci 251195972f6Sopenharmony_ci sys_untimeout(pppol2tp_timeout, l2tp); 252195972f6Sopenharmony_ci udp_remove(l2tp->udp); 253195972f6Sopenharmony_ci LWIP_MEMPOOL_FREE(PPPOL2TP_PCB, l2tp); 254195972f6Sopenharmony_ci return ERR_OK; 255195972f6Sopenharmony_ci} 256195972f6Sopenharmony_ci 257195972f6Sopenharmony_ci/* Be a LAC, connect to a LNS. */ 258195972f6Sopenharmony_cistatic void pppol2tp_connect(ppp_pcb *ppp, void *ctx) { 259195972f6Sopenharmony_ci err_t err; 260195972f6Sopenharmony_ci pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; 261195972f6Sopenharmony_ci lcp_options *lcp_wo; 262195972f6Sopenharmony_ci lcp_options *lcp_ao; 263195972f6Sopenharmony_ci#if PPP_IPV4_SUPPORT && VJ_SUPPORT 264195972f6Sopenharmony_ci ipcp_options *ipcp_wo; 265195972f6Sopenharmony_ci ipcp_options *ipcp_ao; 266195972f6Sopenharmony_ci#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ 267195972f6Sopenharmony_ci 268195972f6Sopenharmony_ci l2tp->tunnel_port = l2tp->remote_port; 269195972f6Sopenharmony_ci l2tp->our_ns = 0; 270195972f6Sopenharmony_ci l2tp->peer_nr = 0; 271195972f6Sopenharmony_ci l2tp->peer_ns = 0; 272195972f6Sopenharmony_ci l2tp->source_tunnel_id = 0; 273195972f6Sopenharmony_ci l2tp->remote_tunnel_id = 0; 274195972f6Sopenharmony_ci l2tp->source_session_id = 0; 275195972f6Sopenharmony_ci l2tp->remote_session_id = 0; 276195972f6Sopenharmony_ci /* l2tp->*_retried are cleared when used */ 277195972f6Sopenharmony_ci 278195972f6Sopenharmony_ci lcp_wo = &ppp->lcp_wantoptions; 279195972f6Sopenharmony_ci lcp_wo->mru = PPPOL2TP_DEFMRU; 280195972f6Sopenharmony_ci lcp_wo->neg_asyncmap = 0; 281195972f6Sopenharmony_ci lcp_wo->neg_pcompression = 0; 282195972f6Sopenharmony_ci lcp_wo->neg_accompression = 0; 283195972f6Sopenharmony_ci lcp_wo->passive = 0; 284195972f6Sopenharmony_ci lcp_wo->silent = 0; 285195972f6Sopenharmony_ci 286195972f6Sopenharmony_ci lcp_ao = &ppp->lcp_allowoptions; 287195972f6Sopenharmony_ci lcp_ao->mru = PPPOL2TP_DEFMRU; 288195972f6Sopenharmony_ci lcp_ao->neg_asyncmap = 0; 289195972f6Sopenharmony_ci lcp_ao->neg_pcompression = 0; 290195972f6Sopenharmony_ci lcp_ao->neg_accompression = 0; 291195972f6Sopenharmony_ci 292195972f6Sopenharmony_ci#if PPP_IPV4_SUPPORT && VJ_SUPPORT 293195972f6Sopenharmony_ci ipcp_wo = &ppp->ipcp_wantoptions; 294195972f6Sopenharmony_ci ipcp_wo->neg_vj = 0; 295195972f6Sopenharmony_ci ipcp_wo->old_vj = 0; 296195972f6Sopenharmony_ci 297195972f6Sopenharmony_ci ipcp_ao = &ppp->ipcp_allowoptions; 298195972f6Sopenharmony_ci ipcp_ao->neg_vj = 0; 299195972f6Sopenharmony_ci ipcp_ao->old_vj = 0; 300195972f6Sopenharmony_ci#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ 301195972f6Sopenharmony_ci 302195972f6Sopenharmony_ci /* Listen to a random source port, we need to do that instead of using udp_connect() 303195972f6Sopenharmony_ci * because the L2TP LNS might answer with its own random source port (!= 1701) 304195972f6Sopenharmony_ci */ 305195972f6Sopenharmony_ci#if LWIP_IPV6 306195972f6Sopenharmony_ci if (IP_IS_V6_VAL(l2tp->udp->local_ip)) { 307195972f6Sopenharmony_ci udp_bind(l2tp->udp, IP6_ADDR_ANY, 0); 308195972f6Sopenharmony_ci } else 309195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 310195972f6Sopenharmony_ci udp_bind(l2tp->udp, IP_ADDR_ANY, 0); 311195972f6Sopenharmony_ci 312195972f6Sopenharmony_ci#if PPPOL2TP_AUTH_SUPPORT 313195972f6Sopenharmony_ci /* Generate random vector */ 314195972f6Sopenharmony_ci if (l2tp->secret != NULL) { 315195972f6Sopenharmony_ci magic_random_bytes(l2tp->secret_rv, sizeof(l2tp->secret_rv)); 316195972f6Sopenharmony_ci } 317195972f6Sopenharmony_ci#endif /* PPPOL2TP_AUTH_SUPPORT */ 318195972f6Sopenharmony_ci 319195972f6Sopenharmony_ci do { 320195972f6Sopenharmony_ci l2tp->remote_tunnel_id = magic(); 321195972f6Sopenharmony_ci } while(l2tp->remote_tunnel_id == 0); 322195972f6Sopenharmony_ci /* save state, in case we fail to send SCCRQ */ 323195972f6Sopenharmony_ci l2tp->sccrq_retried = 0; 324195972f6Sopenharmony_ci l2tp->phase = PPPOL2TP_STATE_SCCRQ_SENT; 325195972f6Sopenharmony_ci if ((err = pppol2tp_send_sccrq(l2tp)) != 0) { 326195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCRQ, error=%d\n", err)); 327195972f6Sopenharmony_ci } 328195972f6Sopenharmony_ci sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); 329195972f6Sopenharmony_ci} 330195972f6Sopenharmony_ci 331195972f6Sopenharmony_ci/* Disconnect */ 332195972f6Sopenharmony_cistatic void pppol2tp_disconnect(ppp_pcb *ppp, void *ctx) { 333195972f6Sopenharmony_ci pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; 334195972f6Sopenharmony_ci 335195972f6Sopenharmony_ci l2tp->our_ns++; 336195972f6Sopenharmony_ci pppol2tp_send_stopccn(l2tp, l2tp->our_ns); 337195972f6Sopenharmony_ci 338195972f6Sopenharmony_ci /* stop any timer, disconnect can be called while initiating is in progress */ 339195972f6Sopenharmony_ci sys_untimeout(pppol2tp_timeout, l2tp); 340195972f6Sopenharmony_ci l2tp->phase = PPPOL2TP_STATE_INITIAL; 341195972f6Sopenharmony_ci ppp_link_end(ppp); /* notify upper layers */ 342195972f6Sopenharmony_ci} 343195972f6Sopenharmony_ci 344195972f6Sopenharmony_ci/* UDP Callback for incoming IPv4 L2TP frames */ 345195972f6Sopenharmony_cistatic void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { 346195972f6Sopenharmony_ci pppol2tp_pcb *l2tp = (pppol2tp_pcb*)arg; 347195972f6Sopenharmony_ci u16_t hflags, hlen, len=0, tunnel_id=0, session_id=0, ns=0, nr=0, offset=0; 348195972f6Sopenharmony_ci u8_t *inp; 349195972f6Sopenharmony_ci LWIP_UNUSED_ARG(pcb); 350195972f6Sopenharmony_ci 351195972f6Sopenharmony_ci /* we can't unbound a UDP pcb, thus we can still receive UDP frames after the link is closed */ 352195972f6Sopenharmony_ci if (l2tp->phase < PPPOL2TP_STATE_SCCRQ_SENT) { 353195972f6Sopenharmony_ci goto free_and_return; 354195972f6Sopenharmony_ci } 355195972f6Sopenharmony_ci 356195972f6Sopenharmony_ci if (!ip_addr_cmp(&l2tp->remote_ip, addr)) { 357195972f6Sopenharmony_ci goto free_and_return; 358195972f6Sopenharmony_ci } 359195972f6Sopenharmony_ci 360195972f6Sopenharmony_ci /* discard packet if port mismatch, but only if we received a SCCRP */ 361195972f6Sopenharmony_ci if (l2tp->phase > PPPOL2TP_STATE_SCCRQ_SENT && l2tp->tunnel_port != port) { 362195972f6Sopenharmony_ci goto free_and_return; 363195972f6Sopenharmony_ci } 364195972f6Sopenharmony_ci 365195972f6Sopenharmony_ci /* printf("-----------\nL2TP INPUT, %d\n", p->len); */ 366195972f6Sopenharmony_ci 367195972f6Sopenharmony_ci /* L2TP header */ 368195972f6Sopenharmony_ci if (p->len < sizeof(hflags) + sizeof(tunnel_id) + sizeof(session_id) ) { 369195972f6Sopenharmony_ci goto packet_too_short; 370195972f6Sopenharmony_ci } 371195972f6Sopenharmony_ci 372195972f6Sopenharmony_ci inp = (u8_t*)p->payload; 373195972f6Sopenharmony_ci GETSHORT(hflags, inp); 374195972f6Sopenharmony_ci 375195972f6Sopenharmony_ci if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) { 376195972f6Sopenharmony_ci /* check mandatory flags for a control packet */ 377195972f6Sopenharmony_ci if ( (hflags & PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY) != PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY ) { 378195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: mandatory header flags for control packet not set\n")); 379195972f6Sopenharmony_ci goto free_and_return; 380195972f6Sopenharmony_ci } 381195972f6Sopenharmony_ci /* check forbidden flags for a control packet */ 382195972f6Sopenharmony_ci if (hflags & PPPOL2TP_HEADERFLAG_CONTROL_FORBIDDEN) { 383195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: forbidden header flags for control packet found\n")); 384195972f6Sopenharmony_ci goto free_and_return; 385195972f6Sopenharmony_ci } 386195972f6Sopenharmony_ci } else { 387195972f6Sopenharmony_ci /* check mandatory flags for a data packet */ 388195972f6Sopenharmony_ci if ( (hflags & PPPOL2TP_HEADERFLAG_DATA_MANDATORY) != PPPOL2TP_HEADERFLAG_DATA_MANDATORY) { 389195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: mandatory header flags for data packet not set\n")); 390195972f6Sopenharmony_ci goto free_and_return; 391195972f6Sopenharmony_ci } 392195972f6Sopenharmony_ci } 393195972f6Sopenharmony_ci 394195972f6Sopenharmony_ci /* Expected header size */ 395195972f6Sopenharmony_ci hlen = sizeof(hflags) + sizeof(tunnel_id) + sizeof(session_id); 396195972f6Sopenharmony_ci if (hflags & PPPOL2TP_HEADERFLAG_LENGTH) { 397195972f6Sopenharmony_ci hlen += sizeof(len); 398195972f6Sopenharmony_ci } 399195972f6Sopenharmony_ci if (hflags & PPPOL2TP_HEADERFLAG_SEQUENCE) { 400195972f6Sopenharmony_ci hlen += sizeof(ns) + sizeof(nr); 401195972f6Sopenharmony_ci } 402195972f6Sopenharmony_ci if (hflags & PPPOL2TP_HEADERFLAG_OFFSET) { 403195972f6Sopenharmony_ci hlen += sizeof(offset); 404195972f6Sopenharmony_ci } 405195972f6Sopenharmony_ci if (p->len < hlen) { 406195972f6Sopenharmony_ci goto packet_too_short; 407195972f6Sopenharmony_ci } 408195972f6Sopenharmony_ci 409195972f6Sopenharmony_ci if (hflags & PPPOL2TP_HEADERFLAG_LENGTH) { 410195972f6Sopenharmony_ci GETSHORT(len, inp); 411195972f6Sopenharmony_ci if (p->len < len || len < hlen) { 412195972f6Sopenharmony_ci goto packet_too_short; 413195972f6Sopenharmony_ci } 414195972f6Sopenharmony_ci } 415195972f6Sopenharmony_ci GETSHORT(tunnel_id, inp); 416195972f6Sopenharmony_ci GETSHORT(session_id, inp); 417195972f6Sopenharmony_ci if (hflags & PPPOL2TP_HEADERFLAG_SEQUENCE) { 418195972f6Sopenharmony_ci GETSHORT(ns, inp); 419195972f6Sopenharmony_ci GETSHORT(nr, inp); 420195972f6Sopenharmony_ci } 421195972f6Sopenharmony_ci if (hflags & PPPOL2TP_HEADERFLAG_OFFSET) { 422195972f6Sopenharmony_ci GETSHORT(offset, inp) 423195972f6Sopenharmony_ci if (offset > 4096) { /* don't be fooled with large offset which might overflow hlen */ 424195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: strange packet received, offset=%d\n", offset)); 425195972f6Sopenharmony_ci goto free_and_return; 426195972f6Sopenharmony_ci } 427195972f6Sopenharmony_ci hlen += offset; 428195972f6Sopenharmony_ci if (p->len < hlen) { 429195972f6Sopenharmony_ci goto packet_too_short; 430195972f6Sopenharmony_ci } 431195972f6Sopenharmony_ci INCPTR(offset, inp); 432195972f6Sopenharmony_ci } 433195972f6Sopenharmony_ci 434195972f6Sopenharmony_ci /* printf("HLEN = %d\n", hlen); */ 435195972f6Sopenharmony_ci 436195972f6Sopenharmony_ci /* skip L2TP header */ 437195972f6Sopenharmony_ci if (pbuf_remove_header(p, hlen) != 0) { 438195972f6Sopenharmony_ci goto free_and_return; 439195972f6Sopenharmony_ci } 440195972f6Sopenharmony_ci 441195972f6Sopenharmony_ci /* printf("LEN=%d, TUNNEL_ID=%d, SESSION_ID=%d, NS=%d, NR=%d, OFFSET=%d\n", len, tunnel_id, session_id, ns, nr, offset); */ 442195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: input packet, len=%"U16_F", tunnel=%"U16_F", session=%"U16_F", ns=%"U16_F", nr=%"U16_F"\n", 443195972f6Sopenharmony_ci len, tunnel_id, session_id, ns, nr)); 444195972f6Sopenharmony_ci 445195972f6Sopenharmony_ci /* Control packet */ 446195972f6Sopenharmony_ci if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) { 447195972f6Sopenharmony_ci pppol2tp_dispatch_control_packet(l2tp, port, p, ns, nr); 448195972f6Sopenharmony_ci goto free_and_return; 449195972f6Sopenharmony_ci } 450195972f6Sopenharmony_ci 451195972f6Sopenharmony_ci /* Data packet */ 452195972f6Sopenharmony_ci if(l2tp->phase != PPPOL2TP_STATE_DATA) { 453195972f6Sopenharmony_ci goto free_and_return; 454195972f6Sopenharmony_ci } 455195972f6Sopenharmony_ci if(tunnel_id != l2tp->remote_tunnel_id) { 456195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: tunnel ID mismatch, assigned=%d, received=%d\n", l2tp->remote_tunnel_id, tunnel_id)); 457195972f6Sopenharmony_ci goto free_and_return; 458195972f6Sopenharmony_ci } 459195972f6Sopenharmony_ci if(session_id != l2tp->remote_session_id) { 460195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: session ID mismatch, assigned=%d, received=%d\n", l2tp->remote_session_id, session_id)); 461195972f6Sopenharmony_ci goto free_and_return; 462195972f6Sopenharmony_ci } 463195972f6Sopenharmony_ci /* 464195972f6Sopenharmony_ci * skip address & flags if necessary 465195972f6Sopenharmony_ci * 466195972f6Sopenharmony_ci * RFC 2661 does not specify whether the PPP frame in the L2TP payload should 467195972f6Sopenharmony_ci * have a HDLC header or not. We handle both cases for compatibility. 468195972f6Sopenharmony_ci */ 469195972f6Sopenharmony_ci if (p->len >= 2) { 470195972f6Sopenharmony_ci GETSHORT(hflags, inp); 471195972f6Sopenharmony_ci if (hflags == 0xff03) { 472195972f6Sopenharmony_ci pbuf_remove_header(p, 2); 473195972f6Sopenharmony_ci } 474195972f6Sopenharmony_ci } 475195972f6Sopenharmony_ci /* Dispatch the packet thereby consuming it. */ 476195972f6Sopenharmony_ci ppp_input(l2tp->ppp, p); 477195972f6Sopenharmony_ci return; 478195972f6Sopenharmony_ci 479195972f6Sopenharmony_cipacket_too_short: 480195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: packet too short: %d\n", p->len)); 481195972f6Sopenharmony_cifree_and_return: 482195972f6Sopenharmony_ci pbuf_free(p); 483195972f6Sopenharmony_ci} 484195972f6Sopenharmony_ci 485195972f6Sopenharmony_ci/* L2TP Control packet entry point */ 486195972f6Sopenharmony_cistatic void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, u16_t port, struct pbuf *p, u16_t ns, u16_t nr) { 487195972f6Sopenharmony_ci u8_t *inp; 488195972f6Sopenharmony_ci u16_t avplen, avpflags, vendorid, attributetype, messagetype=0; 489195972f6Sopenharmony_ci err_t err; 490195972f6Sopenharmony_ci#if PPPOL2TP_AUTH_SUPPORT 491195972f6Sopenharmony_ci lwip_md5_context md5_ctx; 492195972f6Sopenharmony_ci u8_t md5_hash[16]; 493195972f6Sopenharmony_ci u8_t challenge_id = 0; 494195972f6Sopenharmony_ci#endif /* PPPOL2TP_AUTH_SUPPORT */ 495195972f6Sopenharmony_ci 496195972f6Sopenharmony_ci /* printf("L2TP CTRL INPUT, ns=%d, nr=%d, len=%d\n", ns, nr, p->len); */ 497195972f6Sopenharmony_ci 498195972f6Sopenharmony_ci /* Drop unexpected packet */ 499195972f6Sopenharmony_ci if (ns != l2tp->peer_ns) { 500195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: drop unexpected packet: received NS=%d, expected NS=%d\n", ns, l2tp->peer_ns)); 501195972f6Sopenharmony_ci /* 502195972f6Sopenharmony_ci * In order to ensure that all messages are acknowledged properly 503195972f6Sopenharmony_ci * (particularly in the case of a lost ZLB ACK message), receipt 504195972f6Sopenharmony_ci * of duplicate messages MUST be acknowledged. 505195972f6Sopenharmony_ci * 506195972f6Sopenharmony_ci * In this very special case we Ack a packet we previously received. 507195972f6Sopenharmony_ci * Therefore our NS is the NR we just received. And our NR is the 508195972f6Sopenharmony_ci * NS we just received plus one. 509195972f6Sopenharmony_ci */ 510195972f6Sopenharmony_ci if ((s16_t)(ns - l2tp->peer_ns) < 0) { 511195972f6Sopenharmony_ci pppol2tp_send_zlb(l2tp, nr, ns+1); 512195972f6Sopenharmony_ci } 513195972f6Sopenharmony_ci return; 514195972f6Sopenharmony_ci } 515195972f6Sopenharmony_ci 516195972f6Sopenharmony_ci l2tp->peer_nr = nr; 517195972f6Sopenharmony_ci 518195972f6Sopenharmony_ci /* Handle the special case of the ICCN acknowledge */ 519195972f6Sopenharmony_ci if (l2tp->phase == PPPOL2TP_STATE_ICCN_SENT && (s16_t)(l2tp->peer_nr - l2tp->our_ns) > 0) { 520195972f6Sopenharmony_ci l2tp->phase = PPPOL2TP_STATE_DATA; 521195972f6Sopenharmony_ci sys_untimeout(pppol2tp_timeout, l2tp); 522195972f6Sopenharmony_ci ppp_start(l2tp->ppp); /* notify upper layers */ 523195972f6Sopenharmony_ci } 524195972f6Sopenharmony_ci 525195972f6Sopenharmony_ci /* ZLB packets */ 526195972f6Sopenharmony_ci if (p->tot_len == 0) { 527195972f6Sopenharmony_ci return; 528195972f6Sopenharmony_ci } 529195972f6Sopenharmony_ci /* A ZLB packet does not consume a NS slot thus we don't record the NS value for ZLB packets */ 530195972f6Sopenharmony_ci l2tp->peer_ns = ns+1; 531195972f6Sopenharmony_ci 532195972f6Sopenharmony_ci p = pbuf_coalesce(p, PBUF_RAW); 533195972f6Sopenharmony_ci inp = (u8_t*)p->payload; 534195972f6Sopenharmony_ci /* Decode AVPs */ 535195972f6Sopenharmony_ci while (p->len > 0) { 536195972f6Sopenharmony_ci if (p->len < sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype) ) { 537195972f6Sopenharmony_ci goto packet_too_short; 538195972f6Sopenharmony_ci } 539195972f6Sopenharmony_ci GETSHORT(avpflags, inp); 540195972f6Sopenharmony_ci avplen = avpflags & PPPOL2TP_AVPHEADERFLAG_LENGTHMASK; 541195972f6Sopenharmony_ci /* printf("AVPLEN = %d\n", avplen); */ 542195972f6Sopenharmony_ci if (p->len < avplen || avplen < sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype)) { 543195972f6Sopenharmony_ci goto packet_too_short; 544195972f6Sopenharmony_ci } 545195972f6Sopenharmony_ci GETSHORT(vendorid, inp); 546195972f6Sopenharmony_ci GETSHORT(attributetype, inp); 547195972f6Sopenharmony_ci avplen -= sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype); 548195972f6Sopenharmony_ci 549195972f6Sopenharmony_ci /* Message type must be the first AVP */ 550195972f6Sopenharmony_ci if (messagetype == 0) { 551195972f6Sopenharmony_ci if (attributetype != 0 || vendorid != 0 || avplen != sizeof(messagetype) ) { 552195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: message type must be the first AVP\n")); 553195972f6Sopenharmony_ci return; 554195972f6Sopenharmony_ci } 555195972f6Sopenharmony_ci GETSHORT(messagetype, inp); 556195972f6Sopenharmony_ci /* printf("Message type = %d\n", messagetype); */ 557195972f6Sopenharmony_ci switch(messagetype) { 558195972f6Sopenharmony_ci /* Start Control Connection Reply */ 559195972f6Sopenharmony_ci case PPPOL2TP_MESSAGETYPE_SCCRP: 560195972f6Sopenharmony_ci /* Only accept SCCRP packet if we sent a SCCRQ */ 561195972f6Sopenharmony_ci if (l2tp->phase != PPPOL2TP_STATE_SCCRQ_SENT) { 562195972f6Sopenharmony_ci goto send_zlb; 563195972f6Sopenharmony_ci } 564195972f6Sopenharmony_ci break; 565195972f6Sopenharmony_ci /* Incoming Call Reply */ 566195972f6Sopenharmony_ci case PPPOL2TP_MESSAGETYPE_ICRP: 567195972f6Sopenharmony_ci /* Only accept ICRP packet if we sent a IRCQ */ 568195972f6Sopenharmony_ci if (l2tp->phase != PPPOL2TP_STATE_ICRQ_SENT) { 569195972f6Sopenharmony_ci goto send_zlb; 570195972f6Sopenharmony_ci } 571195972f6Sopenharmony_ci break; 572195972f6Sopenharmony_ci /* Stop Control Connection Notification */ 573195972f6Sopenharmony_ci case PPPOL2TP_MESSAGETYPE_STOPCCN: 574195972f6Sopenharmony_ci pppol2tp_send_zlb(l2tp, l2tp->our_ns+1, l2tp->peer_ns); /* Ack the StopCCN before we switch to down state */ 575195972f6Sopenharmony_ci if (l2tp->phase < PPPOL2TP_STATE_DATA) { 576195972f6Sopenharmony_ci pppol2tp_abort_connect(l2tp); 577195972f6Sopenharmony_ci } else if (l2tp->phase == PPPOL2TP_STATE_DATA) { 578195972f6Sopenharmony_ci /* Don't disconnect here, we let the LCP Echo/Reply find the fact 579195972f6Sopenharmony_ci * that PPP session is down. Asking the PPP stack to end the session 580195972f6Sopenharmony_ci * require strict checking about the PPP phase to prevent endless 581195972f6Sopenharmony_ci * disconnection loops. 582195972f6Sopenharmony_ci */ 583195972f6Sopenharmony_ci } 584195972f6Sopenharmony_ci return; 585195972f6Sopenharmony_ci default: 586195972f6Sopenharmony_ci break; 587195972f6Sopenharmony_ci } 588195972f6Sopenharmony_ci goto nextavp; 589195972f6Sopenharmony_ci } 590195972f6Sopenharmony_ci 591195972f6Sopenharmony_ci /* Skip proprietary L2TP extensions */ 592195972f6Sopenharmony_ci if (vendorid != 0) { 593195972f6Sopenharmony_ci goto skipavp; 594195972f6Sopenharmony_ci } 595195972f6Sopenharmony_ci 596195972f6Sopenharmony_ci switch (messagetype) { 597195972f6Sopenharmony_ci /* Start Control Connection Reply */ 598195972f6Sopenharmony_ci case PPPOL2TP_MESSAGETYPE_SCCRP: 599195972f6Sopenharmony_ci switch (attributetype) { 600195972f6Sopenharmony_ci case PPPOL2TP_AVPTYPE_TUNNELID: 601195972f6Sopenharmony_ci if (avplen != sizeof(l2tp->source_tunnel_id) ) { 602195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Assign tunnel ID length check failed\n")); 603195972f6Sopenharmony_ci return; 604195972f6Sopenharmony_ci } 605195972f6Sopenharmony_ci GETSHORT(l2tp->source_tunnel_id, inp); 606195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: Assigned tunnel ID %"U16_F"\n", l2tp->source_tunnel_id)); 607195972f6Sopenharmony_ci goto nextavp; 608195972f6Sopenharmony_ci#if PPPOL2TP_AUTH_SUPPORT 609195972f6Sopenharmony_ci case PPPOL2TP_AVPTYPE_CHALLENGE: 610195972f6Sopenharmony_ci if (avplen == 0) { 611195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: Challenge length check failed\n")); 612195972f6Sopenharmony_ci return; 613195972f6Sopenharmony_ci } 614195972f6Sopenharmony_ci if (l2tp->secret == NULL) { 615195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: Received challenge from peer and no secret key available\n")); 616195972f6Sopenharmony_ci pppol2tp_abort_connect(l2tp); 617195972f6Sopenharmony_ci return; 618195972f6Sopenharmony_ci } 619195972f6Sopenharmony_ci /* Generate hash of ID, secret, challenge */ 620195972f6Sopenharmony_ci lwip_md5_init(&md5_ctx); 621195972f6Sopenharmony_ci lwip_md5_starts(&md5_ctx); 622195972f6Sopenharmony_ci challenge_id = PPPOL2TP_MESSAGETYPE_SCCCN; 623195972f6Sopenharmony_ci lwip_md5_update(&md5_ctx, &challenge_id, 1); 624195972f6Sopenharmony_ci lwip_md5_update(&md5_ctx, l2tp->secret, l2tp->secret_len); 625195972f6Sopenharmony_ci lwip_md5_update(&md5_ctx, inp, avplen); 626195972f6Sopenharmony_ci lwip_md5_finish(&md5_ctx, l2tp->challenge_hash); 627195972f6Sopenharmony_ci lwip_md5_free(&md5_ctx); 628195972f6Sopenharmony_ci l2tp->send_challenge = 1; 629195972f6Sopenharmony_ci goto skipavp; 630195972f6Sopenharmony_ci case PPPOL2TP_AVPTYPE_CHALLENGERESPONSE: 631195972f6Sopenharmony_ci if (avplen != PPPOL2TP_AVPTYPE_CHALLENGERESPONSE_SIZE) { 632195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Challenge Response length check failed\n")); 633195972f6Sopenharmony_ci return; 634195972f6Sopenharmony_ci } 635195972f6Sopenharmony_ci /* Generate hash of ID, secret, challenge */ 636195972f6Sopenharmony_ci lwip_md5_init(&md5_ctx); 637195972f6Sopenharmony_ci lwip_md5_starts(&md5_ctx); 638195972f6Sopenharmony_ci challenge_id = PPPOL2TP_MESSAGETYPE_SCCRP; 639195972f6Sopenharmony_ci lwip_md5_update(&md5_ctx, &challenge_id, 1); 640195972f6Sopenharmony_ci lwip_md5_update(&md5_ctx, l2tp->secret, l2tp->secret_len); 641195972f6Sopenharmony_ci lwip_md5_update(&md5_ctx, l2tp->secret_rv, sizeof(l2tp->secret_rv)); 642195972f6Sopenharmony_ci lwip_md5_finish(&md5_ctx, md5_hash); 643195972f6Sopenharmony_ci lwip_md5_free(&md5_ctx); 644195972f6Sopenharmony_ci if ( memcmp(inp, md5_hash, sizeof(md5_hash)) ) { 645195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: Received challenge response from peer and secret key do not match\n")); 646195972f6Sopenharmony_ci pppol2tp_abort_connect(l2tp); 647195972f6Sopenharmony_ci return; 648195972f6Sopenharmony_ci } 649195972f6Sopenharmony_ci goto skipavp; 650195972f6Sopenharmony_ci#endif /* PPPOL2TP_AUTH_SUPPORT */ 651195972f6Sopenharmony_ci default: 652195972f6Sopenharmony_ci break; 653195972f6Sopenharmony_ci } 654195972f6Sopenharmony_ci break; 655195972f6Sopenharmony_ci /* Incoming Call Reply */ 656195972f6Sopenharmony_ci case PPPOL2TP_MESSAGETYPE_ICRP: 657195972f6Sopenharmony_ci switch (attributetype) { 658195972f6Sopenharmony_ci case PPPOL2TP_AVPTYPE_SESSIONID: 659195972f6Sopenharmony_ci if (avplen != sizeof(l2tp->source_session_id) ) { 660195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Assign session ID length check failed\n")); 661195972f6Sopenharmony_ci return; 662195972f6Sopenharmony_ci } 663195972f6Sopenharmony_ci GETSHORT(l2tp->source_session_id, inp); 664195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: Assigned session ID %"U16_F"\n", l2tp->source_session_id)); 665195972f6Sopenharmony_ci goto nextavp; 666195972f6Sopenharmony_ci default: 667195972f6Sopenharmony_ci break; 668195972f6Sopenharmony_ci } 669195972f6Sopenharmony_ci break; 670195972f6Sopenharmony_ci default: 671195972f6Sopenharmony_ci break; 672195972f6Sopenharmony_ci } 673195972f6Sopenharmony_ci 674195972f6Sopenharmony_ciskipavp: 675195972f6Sopenharmony_ci INCPTR(avplen, inp); 676195972f6Sopenharmony_cinextavp: 677195972f6Sopenharmony_ci /* printf("AVP Found, vendor=%d, attribute=%d, len=%d\n", vendorid, attributetype, avplen); */ 678195972f6Sopenharmony_ci /* next AVP */ 679195972f6Sopenharmony_ci if (pbuf_remove_header(p, avplen + sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype)) != 0) { 680195972f6Sopenharmony_ci return; 681195972f6Sopenharmony_ci } 682195972f6Sopenharmony_ci } 683195972f6Sopenharmony_ci 684195972f6Sopenharmony_ci switch(messagetype) { 685195972f6Sopenharmony_ci /* Start Control Connection Reply */ 686195972f6Sopenharmony_ci case PPPOL2TP_MESSAGETYPE_SCCRP: 687195972f6Sopenharmony_ci do { 688195972f6Sopenharmony_ci l2tp->remote_session_id = magic(); 689195972f6Sopenharmony_ci } while(l2tp->remote_session_id == 0); 690195972f6Sopenharmony_ci l2tp->tunnel_port = port; /* LNS server might have chosen its own local port */ 691195972f6Sopenharmony_ci l2tp->icrq_retried = 0; 692195972f6Sopenharmony_ci l2tp->phase = PPPOL2TP_STATE_ICRQ_SENT; 693195972f6Sopenharmony_ci l2tp->our_ns++; 694195972f6Sopenharmony_ci if ((err = pppol2tp_send_scccn(l2tp, l2tp->our_ns)) != 0) { 695195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCCN, error=%d\n", err)); 696195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ 697195972f6Sopenharmony_ci } 698195972f6Sopenharmony_ci l2tp->our_ns++; 699195972f6Sopenharmony_ci if ((err = pppol2tp_send_icrq(l2tp, l2tp->our_ns)) != 0) { 700195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICRQ, error=%d\n", err)); 701195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ 702195972f6Sopenharmony_ci } 703195972f6Sopenharmony_ci sys_untimeout(pppol2tp_timeout, l2tp); 704195972f6Sopenharmony_ci sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); 705195972f6Sopenharmony_ci break; 706195972f6Sopenharmony_ci /* Incoming Call Reply */ 707195972f6Sopenharmony_ci case PPPOL2TP_MESSAGETYPE_ICRP: 708195972f6Sopenharmony_ci l2tp->iccn_retried = 0; 709195972f6Sopenharmony_ci l2tp->phase = PPPOL2TP_STATE_ICCN_SENT; 710195972f6Sopenharmony_ci l2tp->our_ns++; 711195972f6Sopenharmony_ci if ((err = pppol2tp_send_iccn(l2tp, l2tp->our_ns)) != 0) { 712195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICCN, error=%d\n", err)); 713195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ 714195972f6Sopenharmony_ci } 715195972f6Sopenharmony_ci sys_untimeout(pppol2tp_timeout, l2tp); 716195972f6Sopenharmony_ci sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); 717195972f6Sopenharmony_ci break; 718195972f6Sopenharmony_ci /* Unhandled packet, send ZLB ACK */ 719195972f6Sopenharmony_ci default: 720195972f6Sopenharmony_ci goto send_zlb; 721195972f6Sopenharmony_ci } 722195972f6Sopenharmony_ci return; 723195972f6Sopenharmony_ci 724195972f6Sopenharmony_cisend_zlb: 725195972f6Sopenharmony_ci pppol2tp_send_zlb(l2tp, l2tp->our_ns+1, l2tp->peer_ns); 726195972f6Sopenharmony_ci return; 727195972f6Sopenharmony_cipacket_too_short: 728195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: packet too short: %d\n", p->len)); 729195972f6Sopenharmony_ci} 730195972f6Sopenharmony_ci 731195972f6Sopenharmony_ci/* L2TP Timeout handler */ 732195972f6Sopenharmony_cistatic void pppol2tp_timeout(void *arg) { 733195972f6Sopenharmony_ci pppol2tp_pcb *l2tp = (pppol2tp_pcb*)arg; 734195972f6Sopenharmony_ci err_t err; 735195972f6Sopenharmony_ci u32_t retry_wait; 736195972f6Sopenharmony_ci 737195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: timeout\n")); 738195972f6Sopenharmony_ci 739195972f6Sopenharmony_ci switch (l2tp->phase) { 740195972f6Sopenharmony_ci case PPPOL2TP_STATE_SCCRQ_SENT: 741195972f6Sopenharmony_ci /* backoff wait */ 742195972f6Sopenharmony_ci if (l2tp->sccrq_retried < 0xff) { 743195972f6Sopenharmony_ci l2tp->sccrq_retried++; 744195972f6Sopenharmony_ci } 745195972f6Sopenharmony_ci if (!l2tp->ppp->settings.persist && l2tp->sccrq_retried >= PPPOL2TP_MAXSCCRQ) { 746195972f6Sopenharmony_ci pppol2tp_abort_connect(l2tp); 747195972f6Sopenharmony_ci return; 748195972f6Sopenharmony_ci } 749195972f6Sopenharmony_ci retry_wait = LWIP_MIN(PPPOL2TP_CONTROL_TIMEOUT * l2tp->sccrq_retried, PPPOL2TP_SLOW_RETRY); 750195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: sccrq_retried=%d\n", l2tp->sccrq_retried)); 751195972f6Sopenharmony_ci if ((err = pppol2tp_send_sccrq(l2tp)) != 0) { 752195972f6Sopenharmony_ci l2tp->sccrq_retried--; 753195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCRQ, error=%d\n", err)); 754195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ 755195972f6Sopenharmony_ci } 756195972f6Sopenharmony_ci sys_timeout(retry_wait, pppol2tp_timeout, l2tp); 757195972f6Sopenharmony_ci break; 758195972f6Sopenharmony_ci 759195972f6Sopenharmony_ci case PPPOL2TP_STATE_ICRQ_SENT: 760195972f6Sopenharmony_ci l2tp->icrq_retried++; 761195972f6Sopenharmony_ci if (l2tp->icrq_retried >= PPPOL2TP_MAXICRQ) { 762195972f6Sopenharmony_ci pppol2tp_abort_connect(l2tp); 763195972f6Sopenharmony_ci return; 764195972f6Sopenharmony_ci } 765195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: icrq_retried=%d\n", l2tp->icrq_retried)); 766195972f6Sopenharmony_ci if ((s16_t)(l2tp->peer_nr - l2tp->our_ns) < 0) { /* the SCCCN was not acknowledged */ 767195972f6Sopenharmony_ci if ((err = pppol2tp_send_scccn(l2tp, l2tp->our_ns -1)) != 0) { 768195972f6Sopenharmony_ci l2tp->icrq_retried--; 769195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCCN, error=%d\n", err)); 770195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ 771195972f6Sopenharmony_ci sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); 772195972f6Sopenharmony_ci break; 773195972f6Sopenharmony_ci } 774195972f6Sopenharmony_ci } 775195972f6Sopenharmony_ci if ((err = pppol2tp_send_icrq(l2tp, l2tp->our_ns)) != 0) { 776195972f6Sopenharmony_ci l2tp->icrq_retried--; 777195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICRQ, error=%d\n", err)); 778195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ 779195972f6Sopenharmony_ci } 780195972f6Sopenharmony_ci sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); 781195972f6Sopenharmony_ci break; 782195972f6Sopenharmony_ci 783195972f6Sopenharmony_ci case PPPOL2TP_STATE_ICCN_SENT: 784195972f6Sopenharmony_ci l2tp->iccn_retried++; 785195972f6Sopenharmony_ci if (l2tp->iccn_retried >= PPPOL2TP_MAXICCN) { 786195972f6Sopenharmony_ci pppol2tp_abort_connect(l2tp); 787195972f6Sopenharmony_ci return; 788195972f6Sopenharmony_ci } 789195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: iccn_retried=%d\n", l2tp->iccn_retried)); 790195972f6Sopenharmony_ci if ((err = pppol2tp_send_iccn(l2tp, l2tp->our_ns)) != 0) { 791195972f6Sopenharmony_ci l2tp->iccn_retried--; 792195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICCN, error=%d\n", err)); 793195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */ 794195972f6Sopenharmony_ci } 795195972f6Sopenharmony_ci sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); 796195972f6Sopenharmony_ci break; 797195972f6Sopenharmony_ci 798195972f6Sopenharmony_ci default: 799195972f6Sopenharmony_ci return; /* all done, work in peace */ 800195972f6Sopenharmony_ci } 801195972f6Sopenharmony_ci} 802195972f6Sopenharmony_ci 803195972f6Sopenharmony_ci/* Connection attempt aborted */ 804195972f6Sopenharmony_cistatic void pppol2tp_abort_connect(pppol2tp_pcb *l2tp) { 805195972f6Sopenharmony_ci PPPDEBUG(LOG_DEBUG, ("pppol2tp: could not establish connection\n")); 806195972f6Sopenharmony_ci l2tp->phase = PPPOL2TP_STATE_INITIAL; 807195972f6Sopenharmony_ci ppp_link_failed(l2tp->ppp); /* notify upper layers */ 808195972f6Sopenharmony_ci} 809195972f6Sopenharmony_ci 810195972f6Sopenharmony_ci/* Initiate a new tunnel */ 811195972f6Sopenharmony_cistatic err_t pppol2tp_send_sccrq(pppol2tp_pcb *l2tp) { 812195972f6Sopenharmony_ci struct pbuf *pb; 813195972f6Sopenharmony_ci u8_t *p; 814195972f6Sopenharmony_ci u16_t len; 815195972f6Sopenharmony_ci 816195972f6Sopenharmony_ci /* calculate UDP packet length */ 817195972f6Sopenharmony_ci len = 12 +8 +8 +10 +10 +6+sizeof(PPPOL2TP_HOSTNAME)-1 +6+sizeof(PPPOL2TP_VENDORNAME)-1 +8 +8; 818195972f6Sopenharmony_ci#if PPPOL2TP_AUTH_SUPPORT 819195972f6Sopenharmony_ci if (l2tp->secret != NULL) { 820195972f6Sopenharmony_ci len += 6 + sizeof(l2tp->secret_rv); 821195972f6Sopenharmony_ci } 822195972f6Sopenharmony_ci#endif /* PPPOL2TP_AUTH_SUPPORT */ 823195972f6Sopenharmony_ci 824195972f6Sopenharmony_ci /* allocate a buffer */ 825195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); 826195972f6Sopenharmony_ci if (pb == NULL) { 827195972f6Sopenharmony_ci return ERR_MEM; 828195972f6Sopenharmony_ci } 829195972f6Sopenharmony_ci LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); 830195972f6Sopenharmony_ci 831195972f6Sopenharmony_ci p = (u8_t*)pb->payload; 832195972f6Sopenharmony_ci /* fill in pkt */ 833195972f6Sopenharmony_ci /* L2TP control header */ 834195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); 835195972f6Sopenharmony_ci PUTSHORT(len, p); /* Length */ 836195972f6Sopenharmony_ci PUTSHORT(0, p); /* Tunnel Id */ 837195972f6Sopenharmony_ci PUTSHORT(0, p); /* Session Id */ 838195972f6Sopenharmony_ci PUTSHORT(0, p); /* NS Sequence number - to peer */ 839195972f6Sopenharmony_ci PUTSHORT(0, p); /* NR Sequence number - expected for peer */ 840195972f6Sopenharmony_ci 841195972f6Sopenharmony_ci /* AVP - Message type */ 842195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ 843195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 844195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ 845195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_MESSAGETYPE_SCCRQ, p); /* Attribute value: Message type: SCCRQ */ 846195972f6Sopenharmony_ci 847195972f6Sopenharmony_ci /* AVP - L2TP Version */ 848195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ 849195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 850195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_VERSION, p); /* Attribute type: Version */ 851195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_VERSION, p); /* Attribute value: L2TP Version */ 852195972f6Sopenharmony_ci 853195972f6Sopenharmony_ci /* AVP - Framing capabilities */ 854195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ 855195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 856195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_FRAMINGCAPABILITIES, p); /* Attribute type: Framing capabilities */ 857195972f6Sopenharmony_ci PUTLONG(PPPOL2TP_FRAMINGCAPABILITIES, p); /* Attribute value: Framing capabilities */ 858195972f6Sopenharmony_ci 859195972f6Sopenharmony_ci /* AVP - Bearer capabilities */ 860195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ 861195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 862195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_BEARERCAPABILITIES, p); /* Attribute type: Bearer capabilities */ 863195972f6Sopenharmony_ci PUTLONG(PPPOL2TP_BEARERCAPABILITIES, p); /* Attribute value: Bearer capabilities */ 864195972f6Sopenharmony_ci 865195972f6Sopenharmony_ci /* AVP - Host name */ 866195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6+sizeof(PPPOL2TP_HOSTNAME)-1, p); /* Mandatory flag + len field */ 867195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 868195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_HOSTNAME, p); /* Attribute type: Hostname */ 869195972f6Sopenharmony_ci MEMCPY(p, PPPOL2TP_HOSTNAME, sizeof(PPPOL2TP_HOSTNAME)-1); /* Attribute value: Hostname */ 870195972f6Sopenharmony_ci INCPTR(sizeof(PPPOL2TP_HOSTNAME)-1, p); 871195972f6Sopenharmony_ci 872195972f6Sopenharmony_ci /* AVP - Vendor name */ 873195972f6Sopenharmony_ci PUTSHORT(6+sizeof(PPPOL2TP_VENDORNAME)-1, p); /* len field */ 874195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 875195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_VENDORNAME, p); /* Attribute type: Vendor name */ 876195972f6Sopenharmony_ci MEMCPY(p, PPPOL2TP_VENDORNAME, sizeof(PPPOL2TP_VENDORNAME)-1); /* Attribute value: Vendor name */ 877195972f6Sopenharmony_ci INCPTR(sizeof(PPPOL2TP_VENDORNAME)-1, p); 878195972f6Sopenharmony_ci 879195972f6Sopenharmony_ci /* AVP - Assign tunnel ID */ 880195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ 881195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 882195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_TUNNELID, p); /* Attribute type: Tunnel ID */ 883195972f6Sopenharmony_ci PUTSHORT(l2tp->remote_tunnel_id, p); /* Attribute value: Tunnel ID */ 884195972f6Sopenharmony_ci 885195972f6Sopenharmony_ci /* AVP - Receive window size */ 886195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ 887195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 888195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_RECEIVEWINDOWSIZE, p); /* Attribute type: Receive window size */ 889195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_RECEIVEWINDOWSIZE, p); /* Attribute value: Receive window size */ 890195972f6Sopenharmony_ci 891195972f6Sopenharmony_ci#if PPPOL2TP_AUTH_SUPPORT 892195972f6Sopenharmony_ci /* AVP - Challenge */ 893195972f6Sopenharmony_ci if (l2tp->secret != NULL) { 894195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6 + sizeof(l2tp->secret_rv), p); /* Mandatory flag + len field */ 895195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 896195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_CHALLENGE, p); /* Attribute type: Challenge */ 897195972f6Sopenharmony_ci MEMCPY(p, l2tp->secret_rv, sizeof(l2tp->secret_rv)); /* Attribute value: Random vector */ 898195972f6Sopenharmony_ci INCPTR(sizeof(l2tp->secret_rv), p); 899195972f6Sopenharmony_ci } 900195972f6Sopenharmony_ci#endif /* PPPOL2TP_AUTH_SUPPORT */ 901195972f6Sopenharmony_ci 902195972f6Sopenharmony_ci return pppol2tp_udp_send(l2tp, pb); 903195972f6Sopenharmony_ci} 904195972f6Sopenharmony_ci 905195972f6Sopenharmony_ci/* Complete tunnel establishment */ 906195972f6Sopenharmony_cistatic err_t pppol2tp_send_scccn(pppol2tp_pcb *l2tp, u16_t ns) { 907195972f6Sopenharmony_ci struct pbuf *pb; 908195972f6Sopenharmony_ci u8_t *p; 909195972f6Sopenharmony_ci u16_t len; 910195972f6Sopenharmony_ci 911195972f6Sopenharmony_ci /* calculate UDP packet length */ 912195972f6Sopenharmony_ci len = 12 +8; 913195972f6Sopenharmony_ci#if PPPOL2TP_AUTH_SUPPORT 914195972f6Sopenharmony_ci if (l2tp->send_challenge) { 915195972f6Sopenharmony_ci len += 6 + sizeof(l2tp->challenge_hash); 916195972f6Sopenharmony_ci } 917195972f6Sopenharmony_ci#endif /* PPPOL2TP_AUTH_SUPPORT */ 918195972f6Sopenharmony_ci 919195972f6Sopenharmony_ci /* allocate a buffer */ 920195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); 921195972f6Sopenharmony_ci if (pb == NULL) { 922195972f6Sopenharmony_ci return ERR_MEM; 923195972f6Sopenharmony_ci } 924195972f6Sopenharmony_ci LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); 925195972f6Sopenharmony_ci 926195972f6Sopenharmony_ci p = (u8_t*)pb->payload; 927195972f6Sopenharmony_ci /* fill in pkt */ 928195972f6Sopenharmony_ci /* L2TP control header */ 929195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); 930195972f6Sopenharmony_ci PUTSHORT(len, p); /* Length */ 931195972f6Sopenharmony_ci PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ 932195972f6Sopenharmony_ci PUTSHORT(0, p); /* Session Id */ 933195972f6Sopenharmony_ci PUTSHORT(ns, p); /* NS Sequence number - to peer */ 934195972f6Sopenharmony_ci PUTSHORT(l2tp->peer_ns, p); /* NR Sequence number - expected for peer */ 935195972f6Sopenharmony_ci 936195972f6Sopenharmony_ci /* AVP - Message type */ 937195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ 938195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 939195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ 940195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_MESSAGETYPE_SCCCN, p); /* Attribute value: Message type: SCCCN */ 941195972f6Sopenharmony_ci 942195972f6Sopenharmony_ci#if PPPOL2TP_AUTH_SUPPORT 943195972f6Sopenharmony_ci /* AVP - Challenge response */ 944195972f6Sopenharmony_ci if (l2tp->send_challenge) { 945195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6 + sizeof(l2tp->challenge_hash), p); /* Mandatory flag + len field */ 946195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 947195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_CHALLENGERESPONSE, p); /* Attribute type: Challenge response */ 948195972f6Sopenharmony_ci MEMCPY(p, l2tp->challenge_hash, sizeof(l2tp->challenge_hash)); /* Attribute value: Computed challenge */ 949195972f6Sopenharmony_ci INCPTR(sizeof(l2tp->challenge_hash), p); 950195972f6Sopenharmony_ci } 951195972f6Sopenharmony_ci#endif /* PPPOL2TP_AUTH_SUPPORT */ 952195972f6Sopenharmony_ci 953195972f6Sopenharmony_ci return pppol2tp_udp_send(l2tp, pb); 954195972f6Sopenharmony_ci} 955195972f6Sopenharmony_ci 956195972f6Sopenharmony_ci/* Initiate a new session */ 957195972f6Sopenharmony_cistatic err_t pppol2tp_send_icrq(pppol2tp_pcb *l2tp, u16_t ns) { 958195972f6Sopenharmony_ci struct pbuf *pb; 959195972f6Sopenharmony_ci u8_t *p; 960195972f6Sopenharmony_ci u16_t len; 961195972f6Sopenharmony_ci u32_t serialnumber; 962195972f6Sopenharmony_ci 963195972f6Sopenharmony_ci /* calculate UDP packet length */ 964195972f6Sopenharmony_ci len = 12 +8 +8 +10; 965195972f6Sopenharmony_ci 966195972f6Sopenharmony_ci /* allocate a buffer */ 967195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); 968195972f6Sopenharmony_ci if (pb == NULL) { 969195972f6Sopenharmony_ci return ERR_MEM; 970195972f6Sopenharmony_ci } 971195972f6Sopenharmony_ci LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); 972195972f6Sopenharmony_ci 973195972f6Sopenharmony_ci p = (u8_t*)pb->payload; 974195972f6Sopenharmony_ci /* fill in pkt */ 975195972f6Sopenharmony_ci /* L2TP control header */ 976195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); 977195972f6Sopenharmony_ci PUTSHORT(len, p); /* Length */ 978195972f6Sopenharmony_ci PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ 979195972f6Sopenharmony_ci PUTSHORT(0, p); /* Session Id */ 980195972f6Sopenharmony_ci PUTSHORT(ns, p); /* NS Sequence number - to peer */ 981195972f6Sopenharmony_ci PUTSHORT(l2tp->peer_ns, p); /* NR Sequence number - expected for peer */ 982195972f6Sopenharmony_ci 983195972f6Sopenharmony_ci /* AVP - Message type */ 984195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ 985195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 986195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ 987195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_MESSAGETYPE_ICRQ, p); /* Attribute value: Message type: ICRQ */ 988195972f6Sopenharmony_ci 989195972f6Sopenharmony_ci /* AVP - Assign session ID */ 990195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ 991195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 992195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_SESSIONID, p); /* Attribute type: Session ID */ 993195972f6Sopenharmony_ci PUTSHORT(l2tp->remote_session_id, p); /* Attribute value: Session ID */ 994195972f6Sopenharmony_ci 995195972f6Sopenharmony_ci /* AVP - Call Serial Number */ 996195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ 997195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 998195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_CALLSERIALNUMBER, p); /* Attribute type: Serial number */ 999195972f6Sopenharmony_ci serialnumber = magic(); 1000195972f6Sopenharmony_ci PUTLONG(serialnumber, p); /* Attribute value: Serial number */ 1001195972f6Sopenharmony_ci 1002195972f6Sopenharmony_ci return pppol2tp_udp_send(l2tp, pb); 1003195972f6Sopenharmony_ci} 1004195972f6Sopenharmony_ci 1005195972f6Sopenharmony_ci/* Complete tunnel establishment */ 1006195972f6Sopenharmony_cistatic err_t pppol2tp_send_iccn(pppol2tp_pcb *l2tp, u16_t ns) { 1007195972f6Sopenharmony_ci struct pbuf *pb; 1008195972f6Sopenharmony_ci u8_t *p; 1009195972f6Sopenharmony_ci u16_t len; 1010195972f6Sopenharmony_ci 1011195972f6Sopenharmony_ci /* calculate UDP packet length */ 1012195972f6Sopenharmony_ci len = 12 +8 +10 +10; 1013195972f6Sopenharmony_ci 1014195972f6Sopenharmony_ci /* allocate a buffer */ 1015195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); 1016195972f6Sopenharmony_ci if (pb == NULL) { 1017195972f6Sopenharmony_ci return ERR_MEM; 1018195972f6Sopenharmony_ci } 1019195972f6Sopenharmony_ci LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); 1020195972f6Sopenharmony_ci 1021195972f6Sopenharmony_ci p = (u8_t*)pb->payload; 1022195972f6Sopenharmony_ci /* fill in pkt */ 1023195972f6Sopenharmony_ci /* L2TP control header */ 1024195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); 1025195972f6Sopenharmony_ci PUTSHORT(len, p); /* Length */ 1026195972f6Sopenharmony_ci PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ 1027195972f6Sopenharmony_ci PUTSHORT(l2tp->source_session_id, p); /* Session Id */ 1028195972f6Sopenharmony_ci PUTSHORT(ns, p); /* NS Sequence number - to peer */ 1029195972f6Sopenharmony_ci PUTSHORT(l2tp->peer_ns, p); /* NR Sequence number - expected for peer */ 1030195972f6Sopenharmony_ci 1031195972f6Sopenharmony_ci /* AVP - Message type */ 1032195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ 1033195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 1034195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ 1035195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_MESSAGETYPE_ICCN, p); /* Attribute value: Message type: ICCN */ 1036195972f6Sopenharmony_ci 1037195972f6Sopenharmony_ci /* AVP - Framing type */ 1038195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ 1039195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 1040195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_FRAMINGTYPE, p); /* Attribute type: Framing type */ 1041195972f6Sopenharmony_ci PUTLONG(PPPOL2TP_FRAMINGTYPE, p); /* Attribute value: Framing type */ 1042195972f6Sopenharmony_ci 1043195972f6Sopenharmony_ci /* AVP - TX Connect speed */ 1044195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ 1045195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 1046195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_TXCONNECTSPEED, p); /* Attribute type: TX Connect speed */ 1047195972f6Sopenharmony_ci PUTLONG(PPPOL2TP_TXCONNECTSPEED, p); /* Attribute value: TX Connect speed */ 1048195972f6Sopenharmony_ci 1049195972f6Sopenharmony_ci return pppol2tp_udp_send(l2tp, pb); 1050195972f6Sopenharmony_ci} 1051195972f6Sopenharmony_ci 1052195972f6Sopenharmony_ci/* Send a ZLB ACK packet */ 1053195972f6Sopenharmony_cistatic err_t pppol2tp_send_zlb(pppol2tp_pcb *l2tp, u16_t ns, u16_t nr) { 1054195972f6Sopenharmony_ci struct pbuf *pb; 1055195972f6Sopenharmony_ci u8_t *p; 1056195972f6Sopenharmony_ci u16_t len; 1057195972f6Sopenharmony_ci 1058195972f6Sopenharmony_ci /* calculate UDP packet length */ 1059195972f6Sopenharmony_ci len = 12; 1060195972f6Sopenharmony_ci 1061195972f6Sopenharmony_ci /* allocate a buffer */ 1062195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); 1063195972f6Sopenharmony_ci if (pb == NULL) { 1064195972f6Sopenharmony_ci return ERR_MEM; 1065195972f6Sopenharmony_ci } 1066195972f6Sopenharmony_ci LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); 1067195972f6Sopenharmony_ci 1068195972f6Sopenharmony_ci p = (u8_t*)pb->payload; 1069195972f6Sopenharmony_ci /* fill in pkt */ 1070195972f6Sopenharmony_ci /* L2TP control header */ 1071195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); 1072195972f6Sopenharmony_ci PUTSHORT(len, p); /* Length */ 1073195972f6Sopenharmony_ci PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ 1074195972f6Sopenharmony_ci PUTSHORT(0, p); /* Session Id */ 1075195972f6Sopenharmony_ci PUTSHORT(ns, p); /* NS Sequence number - to peer */ 1076195972f6Sopenharmony_ci PUTSHORT(nr, p); /* NR Sequence number - expected for peer */ 1077195972f6Sopenharmony_ci 1078195972f6Sopenharmony_ci return pppol2tp_udp_send(l2tp, pb); 1079195972f6Sopenharmony_ci} 1080195972f6Sopenharmony_ci 1081195972f6Sopenharmony_ci/* Send a StopCCN packet */ 1082195972f6Sopenharmony_cistatic err_t pppol2tp_send_stopccn(pppol2tp_pcb *l2tp, u16_t ns) { 1083195972f6Sopenharmony_ci struct pbuf *pb; 1084195972f6Sopenharmony_ci u8_t *p; 1085195972f6Sopenharmony_ci u16_t len; 1086195972f6Sopenharmony_ci 1087195972f6Sopenharmony_ci /* calculate UDP packet length */ 1088195972f6Sopenharmony_ci len = 12 +8 +8 +8; 1089195972f6Sopenharmony_ci 1090195972f6Sopenharmony_ci /* allocate a buffer */ 1091195972f6Sopenharmony_ci pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); 1092195972f6Sopenharmony_ci if (pb == NULL) { 1093195972f6Sopenharmony_ci return ERR_MEM; 1094195972f6Sopenharmony_ci } 1095195972f6Sopenharmony_ci LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); 1096195972f6Sopenharmony_ci 1097195972f6Sopenharmony_ci p = (u8_t*)pb->payload; 1098195972f6Sopenharmony_ci /* fill in pkt */ 1099195972f6Sopenharmony_ci /* L2TP control header */ 1100195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); 1101195972f6Sopenharmony_ci PUTSHORT(len, p); /* Length */ 1102195972f6Sopenharmony_ci PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ 1103195972f6Sopenharmony_ci PUTSHORT(0, p); /* Session Id */ 1104195972f6Sopenharmony_ci PUTSHORT(ns, p); /* NS Sequence number - to peer */ 1105195972f6Sopenharmony_ci PUTSHORT(l2tp->peer_ns, p); /* NR Sequence number - expected for peer */ 1106195972f6Sopenharmony_ci 1107195972f6Sopenharmony_ci /* AVP - Message type */ 1108195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ 1109195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 1110195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ 1111195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_MESSAGETYPE_STOPCCN, p); /* Attribute value: Message type: StopCCN */ 1112195972f6Sopenharmony_ci 1113195972f6Sopenharmony_ci /* AVP - Assign tunnel ID */ 1114195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ 1115195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 1116195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_TUNNELID, p); /* Attribute type: Tunnel ID */ 1117195972f6Sopenharmony_ci PUTSHORT(l2tp->remote_tunnel_id, p); /* Attribute value: Tunnel ID */ 1118195972f6Sopenharmony_ci 1119195972f6Sopenharmony_ci /* AVP - Result code */ 1120195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ 1121195972f6Sopenharmony_ci PUTSHORT(0, p); /* Vendor ID */ 1122195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_AVPTYPE_RESULTCODE, p); /* Attribute type: Result code */ 1123195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_RESULTCODE, p); /* Attribute value: Result code */ 1124195972f6Sopenharmony_ci 1125195972f6Sopenharmony_ci return pppol2tp_udp_send(l2tp, pb); 1126195972f6Sopenharmony_ci} 1127195972f6Sopenharmony_ci 1128195972f6Sopenharmony_cistatic err_t pppol2tp_xmit(pppol2tp_pcb *l2tp, struct pbuf *pb) { 1129195972f6Sopenharmony_ci u8_t *p; 1130195972f6Sopenharmony_ci 1131195972f6Sopenharmony_ci /* make room for L2TP header - should not fail */ 1132195972f6Sopenharmony_ci if (pbuf_add_header(pb, PPPOL2TP_OUTPUT_DATA_HEADER_LEN) != 0) { 1133195972f6Sopenharmony_ci /* bail out */ 1134195972f6Sopenharmony_ci PPPDEBUG(LOG_ERR, ("pppol2tp: pppol2tp_pcb: could not allocate room for L2TP header\n")); 1135195972f6Sopenharmony_ci LINK_STATS_INC(link.lenerr); 1136195972f6Sopenharmony_ci pbuf_free(pb); 1137195972f6Sopenharmony_ci return ERR_BUF; 1138195972f6Sopenharmony_ci } 1139195972f6Sopenharmony_ci 1140195972f6Sopenharmony_ci p = (u8_t*)pb->payload; 1141195972f6Sopenharmony_ci PUTSHORT(PPPOL2TP_HEADERFLAG_DATA_MANDATORY, p); 1142195972f6Sopenharmony_ci PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ 1143195972f6Sopenharmony_ci PUTSHORT(l2tp->source_session_id, p); /* Session Id */ 1144195972f6Sopenharmony_ci 1145195972f6Sopenharmony_ci return pppol2tp_udp_send(l2tp, pb); 1146195972f6Sopenharmony_ci} 1147195972f6Sopenharmony_ci 1148195972f6Sopenharmony_cistatic err_t pppol2tp_udp_send(pppol2tp_pcb *l2tp, struct pbuf *pb) { 1149195972f6Sopenharmony_ci err_t err; 1150195972f6Sopenharmony_ci if (l2tp->netif) { 1151195972f6Sopenharmony_ci err = udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip, l2tp->tunnel_port, l2tp->netif); 1152195972f6Sopenharmony_ci } else { 1153195972f6Sopenharmony_ci err = udp_sendto(l2tp->udp, pb, &l2tp->remote_ip, l2tp->tunnel_port); 1154195972f6Sopenharmony_ci } 1155195972f6Sopenharmony_ci pbuf_free(pb); 1156195972f6Sopenharmony_ci return err; 1157195972f6Sopenharmony_ci} 1158195972f6Sopenharmony_ci 1159195972f6Sopenharmony_ci#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ 1160