1/** 2 * @file 3 * Network Point to Point Protocol over Serial file. 4 * 5 */ 6 7/* 8 * Redistribution and use in source and binary forms, with or without modification, 9 * are permitted provided that the following conditions are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 22 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 24 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 28 * OF SUCH DAMAGE. 29 * 30 * This file is part of the lwIP TCP/IP stack. 31 * 32 */ 33 34#include "netif/ppp/ppp_opts.h" 35#if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */ 36 37#include <string.h> 38 39#include "lwip/arch.h" 40#include "lwip/err.h" 41#include "lwip/pbuf.h" 42#include "lwip/sys.h" 43#include "lwip/memp.h" 44#include "lwip/netif.h" 45#include "lwip/snmp.h" 46#include "lwip/priv/tcpip_priv.h" 47#include "lwip/api.h" 48#include "lwip/ip4.h" /* for ip4_input() */ 49 50#include "netif/ppp/ppp_impl.h" 51#include "netif/ppp/pppos.h" 52#include "netif/ppp/vj.h" 53 54/* Memory pool */ 55LWIP_MEMPOOL_DECLARE(PPPOS_PCB, MEMP_NUM_PPPOS_INTERFACES, sizeof(pppos_pcb), "PPPOS_PCB") 56 57/* callbacks called from PPP core */ 58static err_t pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p); 59static err_t pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol); 60static void pppos_connect(ppp_pcb *ppp, void *ctx); 61#if PPP_SERVER 62static void pppos_listen(ppp_pcb *ppp, void *ctx); 63#endif /* PPP_SERVER */ 64static void pppos_disconnect(ppp_pcb *ppp, void *ctx); 65static err_t pppos_destroy(ppp_pcb *ppp, void *ctx); 66static void pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp); 67static void pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp); 68 69/* Prototypes for procedures local to this file. */ 70#if PPP_INPROC_IRQ_SAFE 71static void pppos_input_callback(void *arg); 72#endif /* PPP_INPROC_IRQ_SAFE */ 73static void pppos_input_free_current_packet(pppos_pcb *pppos); 74static void pppos_input_drop(pppos_pcb *pppos); 75static err_t pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs); 76static err_t pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs); 77 78/* Callbacks structure for PPP core */ 79static const struct link_callbacks pppos_callbacks = { 80 pppos_connect, 81#if PPP_SERVER 82 pppos_listen, 83#endif /* PPP_SERVER */ 84 pppos_disconnect, 85 pppos_destroy, 86 pppos_write, 87 pppos_netif_output, 88 pppos_send_config, 89 pppos_recv_config 90}; 91 92/* PPP's Asynchronous-Control-Character-Map. The mask array is used 93 * to select the specific bit for a character. */ 94#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & 1 << (c & 0x07)) 95 96#if PPP_FCS_TABLE 97/* 98 * FCS lookup table as calculated by genfcstab. 99 */ 100static const u16_t fcstab[256] = { 101 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 102 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 103 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 104 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 105 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 106 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 107 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 108 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 109 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 110 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 111 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 112 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 113 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 114 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 115 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 116 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 117 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 118 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 119 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 120 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 121 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 122 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 123 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 124 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 125 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 126 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 127 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 128 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 129 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 130 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 131 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 132 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 133}; 134#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) 135#else /* PPP_FCS_TABLE */ 136/* The HDLC polynomial: X**0 + X**5 + X**12 + X**16 (0x8408) */ 137#define PPP_FCS_POLYNOMIAL 0x8408 138static u16_t 139ppp_get_fcs(u8_t byte) 140{ 141 unsigned int octet; 142 int bit; 143 octet = byte; 144 for (bit = 8; bit-- > 0; ) { 145 octet = (octet & 0x01) ? ((octet >> 1) ^ PPP_FCS_POLYNOMIAL) : (octet >> 1); 146 } 147 return octet & 0xffff; 148} 149#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_get_fcs(((fcs) ^ (c)) & 0xff)) 150#endif /* PPP_FCS_TABLE */ 151 152/* 153 * Values for FCS calculations. 154 */ 155#define PPP_INITFCS 0xffff /* Initial FCS value */ 156#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ 157 158#if PPP_INPROC_IRQ_SAFE 159#define PPPOS_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev) 160#define PPPOS_PROTECT(lev) SYS_ARCH_PROTECT(lev) 161#define PPPOS_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev) 162#else 163#define PPPOS_DECL_PROTECT(lev) 164#define PPPOS_PROTECT(lev) 165#define PPPOS_UNPROTECT(lev) 166#endif /* PPP_INPROC_IRQ_SAFE */ 167 168 169/* 170 * Create a new PPP connection using the given serial I/O device. 171 * 172 * Return 0 on success, an error code on failure. 173 */ 174ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, 175 ppp_link_status_cb_fn link_status_cb, void *ctx_cb) 176{ 177 pppos_pcb *pppos; 178 ppp_pcb *ppp; 179 LWIP_ASSERT_CORE_LOCKED(); 180 181 pppos = (pppos_pcb *)LWIP_MEMPOOL_ALLOC(PPPOS_PCB); 182 if (pppos == NULL) { 183 return NULL; 184 } 185 186 ppp = ppp_new(pppif, &pppos_callbacks, pppos, link_status_cb, ctx_cb); 187 if (ppp == NULL) { 188 LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos); 189 return NULL; 190 } 191 192 memset(pppos, 0, sizeof(pppos_pcb)); 193 pppos->ppp = ppp; 194 pppos->output_cb = output_cb; 195 return ppp; 196} 197 198/* Called by PPP core */ 199static err_t 200pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) 201{ 202 pppos_pcb *pppos = (pppos_pcb *)ctx; 203 u8_t *s; 204 struct pbuf *nb; 205 u16_t n; 206 u16_t fcs_out; 207 err_t err; 208 LWIP_UNUSED_ARG(ppp); 209 210 /* Grab an output buffer. Using PBUF_POOL here for tx is ok since the pbuf 211 gets freed by 'pppos_output_last' before this function returns and thus 212 cannot starve rx. */ 213 nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); 214 if (nb == NULL) { 215 PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: alloc fail\n", ppp->netif->num)); 216 LINK_STATS_INC(link.memerr); 217 LINK_STATS_INC(link.drop); 218 MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); 219 pbuf_free(p); 220 return ERR_MEM; 221 } 222 223 /* Set nb->tot_len to actual payload length */ 224 nb->tot_len = p->len; 225 226 /* If the link has been idle, we'll send a fresh flag character to 227 * flush any noise. */ 228 err = ERR_OK; 229 if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) { 230 err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL); 231 } 232 233 /* Load output buffer. */ 234 fcs_out = PPP_INITFCS; 235 s = (u8_t*)p->payload; 236 n = p->len; 237 while (n-- > 0) { 238 err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out); 239 } 240 241 err = pppos_output_last(pppos, err, nb, &fcs_out); 242 if (err == ERR_OK) { 243 PPPDEBUG(LOG_INFO, ("pppos_write[%d]: len=%d\n", ppp->netif->num, p->len)); 244 } else { 245 PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: output failed len=%d\n", ppp->netif->num, p->len)); 246 } 247 pbuf_free(p); 248 return err; 249} 250 251/* Called by PPP core */ 252static err_t 253pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol) 254{ 255 pppos_pcb *pppos = (pppos_pcb *)ctx; 256 struct pbuf *nb, *p; 257 u16_t fcs_out; 258 err_t err; 259 LWIP_UNUSED_ARG(ppp); 260 261 /* Grab an output buffer. Using PBUF_POOL here for tx is ok since the pbuf 262 gets freed by 'pppos_output_last' before this function returns and thus 263 cannot starve rx. */ 264 nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); 265 if (nb == NULL) { 266 PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: alloc fail\n", ppp->netif->num)); 267 LINK_STATS_INC(link.memerr); 268 LINK_STATS_INC(link.drop); 269 MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); 270 return ERR_MEM; 271 } 272 273 /* Set nb->tot_len to actual payload length */ 274 nb->tot_len = pb->tot_len; 275 276 /* If the link has been idle, we'll send a fresh flag character to 277 * flush any noise. */ 278 err = ERR_OK; 279 if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) { 280 err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL); 281 } 282 283 fcs_out = PPP_INITFCS; 284 if (!pppos->accomp) { 285 err = pppos_output_append(pppos, err, nb, PPP_ALLSTATIONS, 1, &fcs_out); 286 err = pppos_output_append(pppos, err, nb, PPP_UI, 1, &fcs_out); 287 } 288 if (!pppos->pcomp || protocol > 0xFF) { 289 err = pppos_output_append(pppos, err, nb, (protocol >> 8) & 0xFF, 1, &fcs_out); 290 } 291 err = pppos_output_append(pppos, err, nb, protocol & 0xFF, 1, &fcs_out); 292 293 /* Load packet. */ 294 for(p = pb; p; p = p->next) { 295 u16_t n = p->len; 296 u8_t *s = (u8_t*)p->payload; 297 298 while (n-- > 0) { 299 err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out); 300 } 301 } 302 303 err = pppos_output_last(pppos, err, nb, &fcs_out); 304 if (err == ERR_OK) { 305 PPPDEBUG(LOG_INFO, ("pppos_netif_output[%d]: proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len)); 306 } else { 307 PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: output failed proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len)); 308 } 309 return err; 310} 311 312static void 313pppos_connect(ppp_pcb *ppp, void *ctx) 314{ 315 pppos_pcb *pppos = (pppos_pcb *)ctx; 316 PPPOS_DECL_PROTECT(lev); 317 318#if PPP_INPROC_IRQ_SAFE 319 /* input pbuf left over from last session? */ 320 pppos_input_free_current_packet(pppos); 321#endif /* PPP_INPROC_IRQ_SAFE */ 322 323 /* reset PPPoS control block to its initial state */ 324 memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit)); 325 326 /* 327 * Default the in and out accm so that escape and flag characters 328 * are always escaped. 329 */ 330 pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */ 331 pppos->out_accm[15] = 0x60; 332 PPPOS_PROTECT(lev); 333 pppos->open = 1; 334 PPPOS_UNPROTECT(lev); 335 336 /* 337 * Start the connection and handle incoming events (packet or timeout). 338 */ 339 PPPDEBUG(LOG_INFO, ("pppos_connect: unit %d: connecting\n", ppp->netif->num)); 340 ppp_start(ppp); /* notify upper layers */ 341} 342 343#if PPP_SERVER 344static void 345pppos_listen(ppp_pcb *ppp, void *ctx) 346{ 347 pppos_pcb *pppos = (pppos_pcb *)ctx; 348 PPPOS_DECL_PROTECT(lev); 349 350#if PPP_INPROC_IRQ_SAFE 351 /* input pbuf left over from last session? */ 352 pppos_input_free_current_packet(pppos); 353#endif /* PPP_INPROC_IRQ_SAFE */ 354 355 /* reset PPPoS control block to its initial state */ 356 memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit)); 357 358 /* 359 * Default the in and out accm so that escape and flag characters 360 * are always escaped. 361 */ 362 pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */ 363 pppos->out_accm[15] = 0x60; 364 PPPOS_PROTECT(lev); 365 pppos->open = 1; 366 PPPOS_UNPROTECT(lev); 367 368 /* 369 * Wait for something to happen. 370 */ 371 PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num)); 372 ppp_start(ppp); /* notify upper layers */ 373} 374#endif /* PPP_SERVER */ 375 376static void 377pppos_disconnect(ppp_pcb *ppp, void *ctx) 378{ 379 pppos_pcb *pppos = (pppos_pcb *)ctx; 380 PPPOS_DECL_PROTECT(lev); 381 382 PPPOS_PROTECT(lev); 383 pppos->open = 0; 384 PPPOS_UNPROTECT(lev); 385 386 /* If PPP_INPROC_IRQ_SAFE is used we cannot call 387 * pppos_input_free_current_packet() here because 388 * rx IRQ might still call pppos_input(). 389 */ 390#if !PPP_INPROC_IRQ_SAFE 391 /* input pbuf left ? */ 392 pppos_input_free_current_packet(pppos); 393#endif /* !PPP_INPROC_IRQ_SAFE */ 394 395 ppp_link_end(ppp); /* notify upper layers */ 396} 397 398static err_t 399pppos_destroy(ppp_pcb *ppp, void *ctx) 400{ 401 pppos_pcb *pppos = (pppos_pcb *)ctx; 402 LWIP_UNUSED_ARG(ppp); 403 404#if PPP_INPROC_IRQ_SAFE 405 /* input pbuf left ? */ 406 pppos_input_free_current_packet(pppos); 407#endif /* PPP_INPROC_IRQ_SAFE */ 408 409 LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos); 410 return ERR_OK; 411} 412 413#if !NO_SYS && !PPP_INPROC_IRQ_SAFE 414/** Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread. 415 * 416 * This is one of the only functions that may be called outside of the TCPIP thread! 417 * 418 * @param ppp PPP descriptor index, returned by pppos_create() 419 * @param s received data 420 * @param l length of received data 421 */ 422err_t 423pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l) 424{ 425 struct pbuf *p; 426 err_t err; 427 428 p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL); 429 if (!p) { 430 return ERR_MEM; 431 } 432 pbuf_take(p, s, l); 433 434 err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys); 435 if (err != ERR_OK) { 436 pbuf_free(p); 437 } 438 return err; 439} 440 441/* called from TCPIP thread */ 442err_t pppos_input_sys(struct pbuf *p, struct netif *inp) { 443 ppp_pcb *ppp = (ppp_pcb*)inp->state; 444 struct pbuf *n; 445 LWIP_ASSERT_CORE_LOCKED(); 446 447 for (n = p; n; n = n->next) { 448 pppos_input(ppp, (u8_t*)n->payload, n->len); 449 } 450 pbuf_free(p); 451 return ERR_OK; 452} 453#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ 454 455/** PPPoS input helper struct, must be packed since it is stored 456 * to pbuf->payload, which might be unaligned. */ 457#if PPP_INPROC_IRQ_SAFE 458#ifdef PACK_STRUCT_USE_INCLUDES 459# include "arch/bpstruct.h" 460#endif 461PACK_STRUCT_BEGIN 462struct pppos_input_header { 463 PACK_STRUCT_FIELD(ppp_pcb *ppp); 464} PACK_STRUCT_STRUCT; 465PACK_STRUCT_END 466#ifdef PACK_STRUCT_USE_INCLUDES 467# include "arch/epstruct.h" 468#endif 469#endif /* PPP_INPROC_IRQ_SAFE */ 470 471/** Pass received raw characters to PPPoS to be decoded. 472 * 473 * @param ppp PPP descriptor index, returned by pppos_create() 474 * @param s received data 475 * @param l length of received data 476 */ 477void 478pppos_input(ppp_pcb *ppp, u8_t *s, int l) 479{ 480 pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb; 481 struct pbuf *next_pbuf; 482 u8_t cur_char; 483 u8_t escaped; 484 PPPOS_DECL_PROTECT(lev); 485#if !PPP_INPROC_IRQ_SAFE 486 LWIP_ASSERT_CORE_LOCKED(); 487#endif 488 489 PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l)); 490 while (l-- > 0) { 491 cur_char = *s++; 492 493 PPPOS_PROTECT(lev); 494 /* ppp_input can disconnect the interface, we need to abort to prevent a memory 495 * leak if there are remaining bytes because pppos_connect and pppos_listen 496 * functions expect input buffer to be free. Furthermore there are no real 497 * reason to continue reading bytes if we are disconnected. 498 */ 499 if (!pppos->open) { 500 PPPOS_UNPROTECT(lev); 501 return; 502 } 503 escaped = ESCAPE_P(pppos->in_accm, cur_char); 504 PPPOS_UNPROTECT(lev); 505 /* Handle special characters. */ 506 if (escaped) { 507 /* Check for escape sequences. */ 508 /* XXX Note that this does not handle an escaped 0x5d character which 509 * would appear as an escape character. Since this is an ASCII ']' 510 * and there is no reason that I know of to escape it, I won't complicate 511 * the code to handle this case. GLL */ 512 if (cur_char == PPP_ESCAPE) { 513 pppos->in_escaped = 1; 514 /* Check for the flag character. */ 515 } else if (cur_char == PPP_FLAG) { 516 /* If this is just an extra flag character, ignore it. */ 517 if (pppos->in_state <= PDADDRESS) { 518 /* ignore it */; 519 /* If we haven't received the packet header, drop what has come in. */ 520 } else if (pppos->in_state < PDDATA) { 521 PPPDEBUG(LOG_WARNING, 522 ("pppos_input[%d]: Dropping incomplete packet %d\n", 523 ppp->netif->num, pppos->in_state)); 524 LINK_STATS_INC(link.lenerr); 525 pppos_input_drop(pppos); 526 /* If the fcs is invalid, drop the packet. */ 527 } else if (pppos->in_fcs != PPP_GOODFCS) { 528 PPPDEBUG(LOG_INFO, 529 ("pppos_input[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n", 530 ppp->netif->num, pppos->in_fcs, pppos->in_protocol)); 531 /* Note: If you get lots of these, check for UART frame errors or try different baud rate */ 532 LINK_STATS_INC(link.chkerr); 533 pppos_input_drop(pppos); 534 /* Otherwise it's a good packet so pass it on. */ 535 } else { 536 struct pbuf *inp; 537 /* Trim off the checksum. */ 538 if(pppos->in_tail->len > 2) { 539 pppos->in_tail->len -= 2; 540 541 pppos->in_tail->tot_len = pppos->in_tail->len; 542 if (pppos->in_tail != pppos->in_head) { 543 pbuf_cat(pppos->in_head, pppos->in_tail); 544 } 545 } else { 546 pppos->in_tail->tot_len = pppos->in_tail->len; 547 if (pppos->in_tail != pppos->in_head) { 548 pbuf_cat(pppos->in_head, pppos->in_tail); 549 } 550 551 pbuf_realloc(pppos->in_head, pppos->in_head->tot_len - 2); 552 } 553 554 /* Dispatch the packet thereby consuming it. */ 555 inp = pppos->in_head; 556 /* Packet consumed, release our references. */ 557 pppos->in_head = NULL; 558 pppos->in_tail = NULL; 559#if IP_FORWARD || LWIP_IPV6_FORWARD 560 /* hide the room for Ethernet forwarding header */ 561 pbuf_remove_header(inp, PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN); 562#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */ 563#if PPP_INPROC_IRQ_SAFE 564 if(tcpip_try_callback(pppos_input_callback, inp) != ERR_OK) { 565 PPPDEBUG(LOG_ERR, ("pppos_input[%d]: tcpip_callback() failed, dropping packet\n", ppp->netif->num)); 566 pbuf_free(inp); 567 LINK_STATS_INC(link.drop); 568 MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards); 569 } 570#else /* PPP_INPROC_IRQ_SAFE */ 571 ppp_input(ppp, inp); 572#endif /* PPP_INPROC_IRQ_SAFE */ 573 } 574 575 /* Prepare for a new packet. */ 576 pppos->in_fcs = PPP_INITFCS; 577 pppos->in_state = PDADDRESS; 578 pppos->in_escaped = 0; 579 /* Other characters are usually control characters that may have 580 * been inserted by the physical layer so here we just drop them. */ 581 } else { 582 PPPDEBUG(LOG_WARNING, 583 ("pppos_input[%d]: Dropping ACCM char <%d>\n", ppp->netif->num, cur_char)); 584 } 585 /* Process other characters. */ 586 } else { 587 /* Unencode escaped characters. */ 588 if (pppos->in_escaped) { 589 pppos->in_escaped = 0; 590 cur_char ^= PPP_TRANS; 591 } 592 593 /* Process character relative to current state. */ 594 switch(pppos->in_state) { 595 case PDIDLE: /* Idle state - waiting. */ 596 /* Drop the character if it's not 0xff 597 * we would have processed a flag character above. */ 598 if (cur_char != PPP_ALLSTATIONS) { 599 break; 600 } 601 /* no break */ 602 /* Fall through */ 603 604 case PDSTART: /* Process start flag. */ 605 /* Prepare for a new packet. */ 606 pppos->in_fcs = PPP_INITFCS; 607 /* no break */ 608 /* Fall through */ 609 610 case PDADDRESS: /* Process address field. */ 611 if (cur_char == PPP_ALLSTATIONS) { 612 pppos->in_state = PDCONTROL; 613 break; 614 } 615 /* no break */ 616 617 /* Else assume compressed address and control fields so 618 * fall through to get the protocol... */ 619 /* Fall through */ 620 case PDCONTROL: /* Process control field. */ 621 /* If we don't get a valid control code, restart. */ 622 if (cur_char == PPP_UI) { 623 pppos->in_state = PDPROTOCOL1; 624 break; 625 } 626 /* no break */ 627 628#if 0 629 else { 630 PPPDEBUG(LOG_WARNING, 631 ("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char)); 632 pppos->in_state = PDSTART; 633 } 634#endif 635 /* Fall through */ 636 637 case PDPROTOCOL1: /* Process protocol field 1. */ 638 /* If the lower bit is set, this is the end of the protocol 639 * field. */ 640 if (cur_char & 1) { 641 pppos->in_protocol = cur_char; 642 pppos->in_state = PDDATA; 643 } else { 644 pppos->in_protocol = (u16_t)cur_char << 8; 645 pppos->in_state = PDPROTOCOL2; 646 } 647 break; 648 case PDPROTOCOL2: /* Process protocol field 2. */ 649 pppos->in_protocol |= cur_char; 650 pppos->in_state = PDDATA; 651 break; 652 case PDDATA: /* Process data byte. */ 653 /* Make space to receive processed data. */ 654 if (pppos->in_tail == NULL || pppos->in_tail->len == PBUF_POOL_BUFSIZE) { 655 u16_t pbuf_alloc_len; 656 if (pppos->in_tail != NULL) { 657 pppos->in_tail->tot_len = pppos->in_tail->len; 658 if (pppos->in_tail != pppos->in_head) { 659 pbuf_cat(pppos->in_head, pppos->in_tail); 660 /* give up the in_tail reference now */ 661 pppos->in_tail = NULL; 662 } 663 } 664 /* If we haven't started a packet, we need a packet header. */ 665 pbuf_alloc_len = 0; 666#if IP_FORWARD || LWIP_IPV6_FORWARD 667 /* If IP forwarding is enabled we are reserving PBUF_LINK_ENCAPSULATION_HLEN 668 * + PBUF_LINK_HLEN bytes so the packet is being allocated with enough header 669 * space to be forwarded (to Ethernet for example). 670 */ 671 if (pppos->in_head == NULL) { 672 pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN; 673 } 674#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */ 675 next_pbuf = pbuf_alloc(PBUF_RAW, pbuf_alloc_len, PBUF_POOL); 676 if (next_pbuf == NULL) { 677 /* No free buffers. Drop the input packet and let the 678 * higher layers deal with it. Continue processing 679 * the received pbuf chain in case a new packet starts. */ 680 PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE PBUFS!\n", ppp->netif->num)); 681 LINK_STATS_INC(link.memerr); 682 pppos_input_drop(pppos); 683 pppos->in_state = PDSTART; /* Wait for flag sequence. */ 684 break; 685 } 686 if (pppos->in_head == NULL) { 687 u8_t *payload = ((u8_t*)next_pbuf->payload) + pbuf_alloc_len; 688#if PPP_INPROC_IRQ_SAFE 689 ((struct pppos_input_header*)payload)->ppp = ppp; 690 payload += sizeof(struct pppos_input_header); 691 next_pbuf->len += sizeof(struct pppos_input_header); 692#endif /* PPP_INPROC_IRQ_SAFE */ 693 next_pbuf->len += sizeof(pppos->in_protocol); 694 *(payload++) = pppos->in_protocol >> 8; 695 *(payload) = pppos->in_protocol & 0xFF; 696 pppos->in_head = next_pbuf; 697 } 698 pppos->in_tail = next_pbuf; 699 } 700 /* Load character into buffer. */ 701 ((u8_t*)pppos->in_tail->payload)[pppos->in_tail->len++] = cur_char; 702 break; 703 default: 704 break; 705 } 706 707 /* update the frame check sequence number. */ 708 pppos->in_fcs = PPP_FCS(pppos->in_fcs, cur_char); 709 } 710 } /* while (l-- > 0), all bytes processed */ 711} 712 713#if PPP_INPROC_IRQ_SAFE 714/* PPPoS input callback using one input pointer 715 */ 716static void pppos_input_callback(void *arg) { 717 struct pbuf *pb = (struct pbuf*)arg; 718 ppp_pcb *ppp; 719 720 ppp = ((struct pppos_input_header*)pb->payload)->ppp; 721 if(pbuf_remove_header(pb, sizeof(struct pppos_input_header))) { 722 LWIP_ASSERT("pbuf_remove_header failed\n", 0); 723 goto drop; 724 } 725 726 /* Dispatch the packet thereby consuming it. */ 727 ppp_input(ppp, pb); 728 return; 729 730drop: 731 LINK_STATS_INC(link.drop); 732 MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards); 733 pbuf_free(pb); 734} 735#endif /* PPP_INPROC_IRQ_SAFE */ 736 737static void 738pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp) 739{ 740 int i; 741 pppos_pcb *pppos = (pppos_pcb *)ctx; 742 LWIP_UNUSED_ARG(ppp); 743 744 pppos->pcomp = pcomp; 745 pppos->accomp = accomp; 746 747 /* Load the ACCM bits for the 32 control codes. */ 748 for (i = 0; i < 32/8; i++) { 749 pppos->out_accm[i] = (u8_t)((accm >> (8 * i)) & 0xFF); 750 } 751 752 PPPDEBUG(LOG_INFO, ("pppos_send_config[%d]: out_accm=%X %X %X %X\n", 753 pppos->ppp->netif->num, 754 pppos->out_accm[0], pppos->out_accm[1], pppos->out_accm[2], pppos->out_accm[3])); 755} 756 757static void 758pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp) 759{ 760 int i; 761 pppos_pcb *pppos = (pppos_pcb *)ctx; 762 PPPOS_DECL_PROTECT(lev); 763 LWIP_UNUSED_ARG(ppp); 764 LWIP_UNUSED_ARG(pcomp); 765 LWIP_UNUSED_ARG(accomp); 766 767 /* Load the ACCM bits for the 32 control codes. */ 768 PPPOS_PROTECT(lev); 769 for (i = 0; i < 32 / 8; i++) { 770 pppos->in_accm[i] = (u8_t)(accm >> (i * 8)); 771 } 772 PPPOS_UNPROTECT(lev); 773 774 PPPDEBUG(LOG_INFO, ("pppos_recv_config[%d]: in_accm=%X %X %X %X\n", 775 pppos->ppp->netif->num, 776 pppos->in_accm[0], pppos->in_accm[1], pppos->in_accm[2], pppos->in_accm[3])); 777} 778 779/* 780 * Drop the input packet. 781 */ 782static void 783pppos_input_free_current_packet(pppos_pcb *pppos) 784{ 785 if (pppos->in_head != NULL) { 786 if (pppos->in_tail && (pppos->in_tail != pppos->in_head)) { 787 pbuf_free(pppos->in_tail); 788 } 789 pbuf_free(pppos->in_head); 790 pppos->in_head = NULL; 791 } 792 pppos->in_tail = NULL; 793} 794 795/* 796 * Drop the input packet and increase error counters. 797 */ 798static void 799pppos_input_drop(pppos_pcb *pppos) 800{ 801 if (pppos->in_head != NULL) { 802#if 0 803 PPPDEBUG(LOG_INFO, ("pppos_input_drop: %d:%.*H\n", pppos->in_head->len, min(60, pppos->in_head->len * 2), pppos->in_head->payload)); 804#endif 805 PPPDEBUG(LOG_INFO, ("pppos_input_drop: pbuf len=%d, addr %p\n", pppos->in_head->len, (void*)pppos->in_head)); 806 } 807 pppos_input_free_current_packet(pppos); 808#if VJ_SUPPORT 809 vj_uncompress_err(&pppos->ppp->vj_comp); 810#endif /* VJ_SUPPORT */ 811 812 LINK_STATS_INC(link.drop); 813 MIB2_STATS_NETIF_INC(pppos->ppp->netif, ifindiscards); 814} 815 816/* 817 * pppos_output_append - append given character to end of given pbuf. 818 * If out_accm is not 0 and the character needs to be escaped, do so. 819 * If pbuf is full, send the pbuf and reuse it. 820 * Return the current pbuf. 821 */ 822static err_t 823pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs) 824{ 825 if (err != ERR_OK) { 826 return err; 827 } 828 829 /* Make sure there is room for the character and an escape code. 830 * Sure we don't quite fill the buffer if the character doesn't 831 * get escaped but is one character worth complicating this? */ 832 if ((PBUF_POOL_BUFSIZE - nb->len) < 2) { 833 u32_t l = pppos->output_cb(pppos->ppp, (u8_t*)nb->payload, nb->len, pppos->ppp->ctx_cb); 834 if (l != nb->len) { 835 return ERR_IF; 836 } 837 nb->len = 0; 838 } 839 840 /* Update FCS before checking for special characters. */ 841 if (fcs) { 842 *fcs = PPP_FCS(*fcs, c); 843 } 844 845 /* Copy to output buffer escaping special characters. */ 846 if (accm && ESCAPE_P(pppos->out_accm, c)) { 847 *((u8_t*)nb->payload + nb->len++) = PPP_ESCAPE; 848 *((u8_t*)nb->payload + nb->len++) = c ^ PPP_TRANS; 849 } else { 850 *((u8_t*)nb->payload + nb->len++) = c; 851 } 852 853 return ERR_OK; 854} 855 856static err_t 857pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs) 858{ 859 ppp_pcb *ppp = pppos->ppp; 860 861 /* Add FCS and trailing flag. */ 862 err = pppos_output_append(pppos, err, nb, ~(*fcs) & 0xFF, 1, NULL); 863 err = pppos_output_append(pppos, err, nb, (~(*fcs) >> 8) & 0xFF, 1, NULL); 864 err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL); 865 866 if (err != ERR_OK) { 867 goto failed; 868 } 869 870 /* Send remaining buffer if not empty */ 871 if (nb->len > 0) { 872 u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb); 873 if (l != nb->len) { 874 err = ERR_IF; 875 goto failed; 876 } 877 } 878 879 pppos->last_xmit = sys_now(); 880 MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, nb->tot_len); 881 MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); 882 LINK_STATS_INC(link.xmit); 883 pbuf_free(nb); 884 return ERR_OK; 885 886failed: 887 pppos->last_xmit = 0; /* prepend PPP_FLAG to next packet */ 888 LINK_STATS_INC(link.err); 889 LINK_STATS_INC(link.drop); 890 MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); 891 pbuf_free(nb); 892 return err; 893} 894 895#endif /* PPP_SUPPORT && PPPOS_SUPPORT */ 896