ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_pppos.c Source File

lwip_pppos.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Network Point to Point Protocol over Serial file.
00004  *
00005  */
00006 
00007 /*
00008  * Redistribution and use in source and binary forms, with or without modification,
00009  * are permitted provided that the following conditions are met:
00010  *
00011  * 1. Redistributions of source code must retain the above copyright notice,
00012  *    this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright notice,
00014  *    this list of conditions and the following disclaimer in the documentation
00015  *    and/or other materials provided with the distribution.
00016  * 3. The name of the author may not be used to endorse or promote products
00017  *    derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00020  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00021  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00022  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00023  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00024  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00027  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00028  * OF SUCH DAMAGE.
00029  *
00030  * This file is part of the lwIP TCP/IP stack.
00031  *
00032  */
00033 
00034 #include "netif/ppp/ppp_opts.h"
00035 #if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */
00036 
00037 #include <string.h>
00038 #include <stddef.h>
00039 
00040 #include "lwip/err.h"
00041 #include "lwip/pbuf.h"
00042 #include "lwip/sys.h"
00043 #include "lwip/memp.h"
00044 #include "lwip/netif.h"
00045 #include "lwip/snmp.h"
00046 #include "lwip/priv/tcpip_priv.h"
00047 #include "lwip/api.h"
00048 #include "lwip/ip4.h" /* for ip4_input() */
00049 
00050 #include "netif/ppp/ppp_impl.h"
00051 #include "netif/ppp/pppos.h"
00052 #include "netif/ppp/vj.h"
00053 
00054 /* Memory pool */
00055 LWIP_MEMPOOL_DECLARE(PPPOS_PCB, MEMP_NUM_PPPOS_INTERFACES, sizeof(pppos_pcb), "PPPOS_PCB")
00056 
00057 /* callbacks called from PPP core */
00058 static err_t pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p);
00059 static err_t pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol);
00060 static err_t pppos_connect(ppp_pcb *ppp, void *ctx);
00061 #if PPP_SERVER
00062 static err_t pppos_listen(ppp_pcb *ppp, void *ctx);
00063 #endif /* PPP_SERVER */
00064 static void pppos_disconnect(ppp_pcb *ppp, void *ctx);
00065 static err_t pppos_destroy(ppp_pcb *ppp, void *ctx);
00066 static void pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp);
00067 static void pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp);
00068 
00069 /* Prototypes for procedures local to this file. */
00070 #if PPP_INPROC_IRQ_SAFE
00071 static void pppos_input_callback(void *arg);
00072 #endif /* PPP_INPROC_IRQ_SAFE */
00073 static void pppos_input_free_current_packet(pppos_pcb *pppos);
00074 static void pppos_input_drop(pppos_pcb *pppos);
00075 static err_t pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs);
00076 static err_t pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs);
00077 
00078 /* Callbacks structure for PPP core */
00079 static const struct link_callbacks pppos_callbacks = {
00080   pppos_connect,
00081 #if PPP_SERVER
00082   pppos_listen,
00083 #endif /* PPP_SERVER */
00084   pppos_disconnect,
00085   pppos_destroy,
00086   pppos_write,
00087   pppos_netif_output,
00088   pppos_send_config,
00089   pppos_recv_config
00090 };
00091 
00092 /* PPP's Asynchronous-Control-Character-Map.  The mask array is used
00093  * to select the specific bit for a character. */
00094 #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & 1 << (c & 0x07))
00095 
00096 #if PPP_FCS_TABLE
00097 /*
00098  * FCS lookup table as calculated by genfcstab.
00099  */
00100 static const u16_t fcstab[256] = {
00101   0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
00102   0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
00103   0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
00104   0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
00105   0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
00106   0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
00107   0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
00108   0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
00109   0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
00110   0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
00111   0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
00112   0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
00113   0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
00114   0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
00115   0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
00116   0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
00117   0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
00118   0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
00119   0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
00120   0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
00121   0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
00122   0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
00123   0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
00124   0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
00125   0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
00126   0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
00127   0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
00128   0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
00129   0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
00130   0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
00131   0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
00132   0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
00133 };
00134 #define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
00135 #else /* PPP_FCS_TABLE */
00136 /* The HDLC polynomial: X**0 + X**5 + X**12 + X**16 (0x8408) */
00137 #define PPP_FCS_POLYNOMIAL 0x8408
00138 static u16_t
00139 ppp_get_fcs(u8_t byte)
00140 {
00141   unsigned int octet;
00142   int bit;
00143   octet = byte;
00144   for (bit = 8; bit-- > 0; ) {
00145     octet = (octet & 0x01) ? ((octet >> 1) ^ PPP_FCS_POLYNOMIAL) : (octet >> 1);
00146   }
00147   return octet & 0xffff;
00148 }
00149 #define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_get_fcs(((fcs) ^ (c)) & 0xff))
00150 #endif /* PPP_FCS_TABLE */
00151 
00152 /*
00153  * Values for FCS calculations.
00154  */
00155 #define PPP_INITFCS     0xffff  /* Initial FCS value */
00156 #define PPP_GOODFCS     0xf0b8  /* Good final FCS value */
00157 
00158 #if PPP_INPROC_IRQ_SAFE
00159 #define PPPOS_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev)
00160 #define PPPOS_PROTECT(lev) SYS_ARCH_PROTECT(lev)
00161 #define PPPOS_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev)
00162 #else
00163 #define PPPOS_DECL_PROTECT(lev)
00164 #define PPPOS_PROTECT(lev)
00165 #define PPPOS_UNPROTECT(lev)
00166 #endif /* PPP_INPROC_IRQ_SAFE */
00167 
00168 
00169 /*
00170  * Create a new PPP connection using the given serial I/O device.
00171  *
00172  * Return 0 on success, an error code on failure.
00173  */
00174 ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb,
00175        ppp_link_status_cb_fn link_status_cb, void *ctx_cb)
00176 {
00177   pppos_pcb *pppos;
00178   ppp_pcb *ppp;
00179 
00180   pppos = (pppos_pcb *)LWIP_MEMPOOL_ALLOC(PPPOS_PCB);
00181   if (pppos == NULL) {
00182     return NULL;
00183   }
00184 
00185   ppp = ppp_new(pppif, &pppos_callbacks, pppos, link_status_cb, ctx_cb);
00186   if (ppp == NULL) {
00187     LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
00188     return NULL;
00189   }
00190 
00191   memset(pppos, 0, sizeof(pppos_pcb));
00192   pppos->ppp = ppp;
00193   pppos->output_cb = output_cb;
00194   return ppp;
00195 }
00196 
00197 /* Called by PPP core */
00198 static err_t
00199 pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p)
00200 {
00201   pppos_pcb *pppos = (pppos_pcb *)ctx;
00202   u8_t *s;
00203   struct pbuf *nb;
00204   u16_t n;
00205   u16_t fcs_out;
00206   err_t err;
00207   LWIP_UNUSED_ARG(ppp);
00208 
00209   /* Grab an output buffer. */
00210   nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
00211   if (nb == NULL) {
00212     PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: alloc fail\n", ppp->netif->num));
00213     LINK_STATS_INC(link.memerr);
00214     LINK_STATS_INC(link.drop);
00215     MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
00216     pbuf_free(p);
00217     return ERR_MEM;
00218   }
00219 
00220   /* If the link has been idle, we'll send a fresh flag character to
00221    * flush any noise. */
00222   err = ERR_OK;
00223   if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) {
00224     err = pppos_output_append(pppos, err,  nb, PPP_FLAG, 0, NULL);
00225   }
00226 
00227   /* Load output buffer. */
00228   fcs_out = PPP_INITFCS;
00229   s = (u8_t*)p->payload;
00230   n = p->len;
00231   while (n-- > 0) {
00232     err = pppos_output_append(pppos, err,  nb, *s++, 1, &fcs_out);
00233   }
00234 
00235   err = pppos_output_last(pppos, err, nb, &fcs_out);
00236   if (err == ERR_OK) {
00237     PPPDEBUG(LOG_INFO, ("pppos_write[%d]: len=%d\n", ppp->netif->num, p->len));
00238   } else {
00239     PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: output failed len=%d\n", ppp->netif->num, p->len));
00240   }
00241   pbuf_free(p);
00242   return err;
00243 }
00244 
00245 /* Called by PPP core */
00246 static err_t
00247 pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol)
00248 {
00249   pppos_pcb *pppos = (pppos_pcb *)ctx;
00250   struct pbuf *nb, *p;
00251   u16_t fcs_out;
00252   err_t err;
00253   LWIP_UNUSED_ARG(ppp);
00254 
00255   /* Grab an output buffer. */
00256   nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
00257   if (nb == NULL) {
00258     PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: alloc fail\n", ppp->netif->num));
00259     LINK_STATS_INC(link.memerr);
00260     LINK_STATS_INC(link.drop);
00261     MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
00262     return ERR_MEM;
00263   }
00264 
00265   /* If the link has been idle, we'll send a fresh flag character to
00266    * flush any noise. */
00267   err = ERR_OK;
00268   if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) {
00269     err = pppos_output_append(pppos, err,  nb, PPP_FLAG, 0, NULL);
00270   }
00271 
00272   fcs_out = PPP_INITFCS;
00273   if (!pppos->accomp) {
00274     err = pppos_output_append(pppos, err,  nb, PPP_ALLSTATIONS, 1, &fcs_out);
00275     err = pppos_output_append(pppos, err,  nb, PPP_UI, 1, &fcs_out);
00276   }
00277   if (!pppos->pcomp || protocol > 0xFF) {
00278     err = pppos_output_append(pppos, err,  nb, (protocol >> 8) & 0xFF, 1, &fcs_out);
00279   }
00280   err = pppos_output_append(pppos, err,  nb, protocol & 0xFF, 1, &fcs_out);
00281 
00282   /* Load packet. */
00283   for(p = pb; p; p = p->next) {
00284     u16_t n = p->len;
00285     u8_t *s = (u8_t*)p->payload;
00286 
00287     while (n-- > 0) {
00288       err = pppos_output_append(pppos, err,  nb, *s++, 1, &fcs_out);
00289     }
00290   }
00291 
00292   err = pppos_output_last(pppos, err, nb, &fcs_out);
00293   if (err == ERR_OK) {
00294     PPPDEBUG(LOG_INFO, ("pppos_netif_output[%d]: proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len));
00295   } else {
00296     PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: output failed proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len));
00297   }
00298   return err;
00299 }
00300 
00301 static err_t
00302 pppos_connect(ppp_pcb *ppp, void *ctx)
00303 {
00304   pppos_pcb *pppos = (pppos_pcb *)ctx;
00305   PPPOS_DECL_PROTECT(lev);
00306 
00307 #if PPP_INPROC_IRQ_SAFE
00308   /* input pbuf left over from last session? */
00309   pppos_input_free_current_packet(pppos);
00310 #endif /* PPP_INPROC_IRQ_SAFE */
00311 
00312   ppp_link_start(ppp);
00313   /* reset PPPoS control block to its initial state */
00314   memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
00315 
00316   /*
00317    * Default the in and out accm so that escape and flag characters
00318    * are always escaped.
00319    */
00320   pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
00321   pppos->out_accm[15] = 0x60;
00322   PPPOS_PROTECT(lev);
00323   pppos->open = 1;
00324   PPPOS_UNPROTECT(lev);
00325 
00326   /*
00327    * Start the connection and handle incoming events (packet or timeout).
00328    */
00329   PPPDEBUG(LOG_INFO, ("pppos_connect: unit %d: connecting\n", ppp->netif->num));
00330   ppp_start(ppp); /* notify upper layers */
00331   return ERR_OK;
00332 }
00333 
00334 #if PPP_SERVER
00335 static err_t
00336 pppos_listen(ppp_pcb *ppp, void *ctx)
00337 {
00338   pppos_pcb *pppos = (pppos_pcb *)ctx;
00339   PPPOS_DECL_PROTECT(lev);
00340 
00341 #if PPP_INPROC_IRQ_SAFE
00342   /* input pbuf left over from last session? */
00343   pppos_input_free_current_packet(pppos);
00344 #endif /* PPP_INPROC_IRQ_SAFE */
00345 
00346   ppp_link_start(ppp);
00347   /* reset PPPoS control block to its initial state */
00348   memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
00349 
00350   /*
00351    * Default the in and out accm so that escape and flag characters
00352    * are always escaped.
00353    */
00354   pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
00355   pppos->out_accm[15] = 0x60;
00356   PPPOS_PROTECT(lev);
00357   pppos->open = 1;
00358   PPPOS_UNPROTECT(lev);
00359 
00360   /*
00361    * Wait for something to happen.
00362    */
00363   PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num));
00364   ppp_start(ppp); /* notify upper layers */
00365   return ERR_OK;
00366 }
00367 #endif /* PPP_SERVER */
00368 
00369 static void
00370 pppos_disconnect(ppp_pcb *ppp, void *ctx)
00371 {
00372   pppos_pcb *pppos = (pppos_pcb *)ctx;
00373   PPPOS_DECL_PROTECT(lev);
00374 
00375   PPPOS_PROTECT(lev);
00376   pppos->open = 0;
00377   PPPOS_UNPROTECT(lev);
00378 
00379   /* If PPP_INPROC_IRQ_SAFE is used we cannot call
00380    * pppos_input_free_current_packet() here because
00381    * rx IRQ might still call pppos_input().
00382    */
00383 #if !PPP_INPROC_IRQ_SAFE
00384   /* input pbuf left ? */
00385   pppos_input_free_current_packet(pppos);
00386 #endif /* !PPP_INPROC_IRQ_SAFE */
00387 
00388   ppp_link_end(ppp); /* notify upper layers */
00389 }
00390 
00391 static err_t
00392 pppos_destroy(ppp_pcb *ppp, void *ctx)
00393 {
00394   pppos_pcb *pppos = (pppos_pcb *)ctx;
00395   LWIP_UNUSED_ARG(ppp);
00396 
00397 #if PPP_INPROC_IRQ_SAFE
00398   /* input pbuf left ? */
00399   pppos_input_free_current_packet(pppos);
00400 #endif /* PPP_INPROC_IRQ_SAFE */
00401 
00402   LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
00403   return ERR_OK;
00404 }
00405 
00406 #if !NO_SYS && !PPP_INPROC_IRQ_SAFE
00407 /** Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread.
00408  *
00409  * @param pcb PPP descriptor index, returned by pppos_create()
00410  * @param data received data
00411  * @param len length of received data
00412  */
00413 err_t
00414 pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l)
00415 {
00416   struct pbuf *p;
00417   err_t err;
00418 
00419   p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL);
00420   if (!p) {
00421     return ERR_MEM;
00422   }
00423   pbuf_take(p, s, l);
00424 
00425   err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys);
00426   if (err != ERR_OK) {
00427      pbuf_free(p);
00428   }
00429   return err;
00430 }
00431 
00432 /* called from TCPIP thread */
00433 err_t pppos_input_sys(struct pbuf *p, struct netif *inp) {
00434   ppp_pcb *ppp = (ppp_pcb*)inp->state;
00435   struct pbuf *n;
00436 
00437   for (n = p; n; n = n->next) {
00438     pppos_input(ppp, (u8_t*)n->payload, n->len);
00439   }
00440   pbuf_free(p);
00441   return ERR_OK;
00442 }
00443 #endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */
00444 
00445 /** PPPoS input helper struct, must be packed since it is stored
00446  * to pbuf->payload, which might be unaligned. */
00447 #if PPP_INPROC_IRQ_SAFE
00448 #ifdef PACK_STRUCT_USE_INCLUDES
00449 #  include "arch/bpstruct.h"
00450 #endif
00451 PACK_STRUCT_BEGIN
00452 struct pppos_input_header {
00453   PACK_STRUCT_FIELD(ppp_pcb *ppp);
00454 } PACK_STRUCT_STRUCT;
00455 PACK_STRUCT_END
00456 #ifdef PACK_STRUCT_USE_INCLUDES
00457 #  include "arch/epstruct.h"
00458 #endif
00459 #endif /* PPP_INPROC_IRQ_SAFE */
00460 
00461 /** Pass received raw characters to PPPoS to be decoded.
00462  *
00463  * @param pcb PPP descriptor index, returned by pppos_create()
00464  * @param data received data
00465  * @param len length of received data
00466  */
00467 void
00468 pppos_input(ppp_pcb *ppp, u8_t *s, int l)
00469 {
00470   pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb;
00471   struct pbuf *next_pbuf;
00472   u8_t cur_char;
00473   u8_t escaped;
00474   PPPOS_DECL_PROTECT(lev);
00475 
00476   PPPOS_PROTECT(lev);
00477   if (!pppos->open) {
00478     PPPOS_UNPROTECT(lev);
00479     return;
00480   }
00481   PPPOS_UNPROTECT(lev);
00482 
00483   PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l));
00484   while (l-- > 0) {
00485     cur_char = *s++;
00486 
00487     PPPOS_PROTECT(lev);
00488     escaped = ESCAPE_P(pppos->in_accm, cur_char);
00489     PPPOS_UNPROTECT(lev);
00490     /* Handle special characters. */
00491     if (escaped) {
00492       /* Check for escape sequences. */
00493       /* XXX Note that this does not handle an escaped 0x5d character which
00494        * would appear as an escape character.  Since this is an ASCII ']'
00495        * and there is no reason that I know of to escape it, I won't complicate
00496        * the code to handle this case. GLL */
00497       if (cur_char == PPP_ESCAPE) {
00498         pppos->in_escaped = 1;
00499       /* Check for the flag character. */
00500       } else if (cur_char == PPP_FLAG) {
00501         /* If this is just an extra flag character, ignore it. */
00502         if (pppos->in_state <= PDADDRESS) {
00503           /* ignore it */;
00504         /* If we haven't received the packet header, drop what has come in. */
00505         } else if (pppos->in_state < PDDATA) {
00506           PPPDEBUG(LOG_WARNING,
00507                    ("pppos_input[%d]: Dropping incomplete packet %d\n",
00508                     ppp->netif->num, pppos->in_state));
00509           LINK_STATS_INC(link.lenerr);
00510           pppos_input_drop(pppos);
00511         /* If the fcs is invalid, drop the packet. */
00512         } else if (pppos->in_fcs != PPP_GOODFCS) {
00513           PPPDEBUG(LOG_INFO,
00514                    ("pppos_input[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n",
00515                     ppp->netif->num, pppos->in_fcs, pppos->in_protocol));
00516           /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
00517           LINK_STATS_INC(link.chkerr);
00518           pppos_input_drop(pppos);
00519         /* Otherwise it's a good packet so pass it on. */
00520         } else {
00521           struct pbuf *inp;
00522           /* Trim off the checksum. */
00523           if(pppos->in_tail->len > 2) {
00524             pppos->in_tail->len -= 2;
00525 
00526             pppos->in_tail->tot_len = pppos->in_tail->len;
00527             if (pppos->in_tail != pppos->in_head) {
00528               pbuf_cat(pppos->in_head, pppos->in_tail);
00529             }
00530           } else {
00531             pppos->in_tail->tot_len = pppos->in_tail->len;
00532             if (pppos->in_tail != pppos->in_head) {
00533               pbuf_cat(pppos->in_head, pppos->in_tail);
00534             }
00535 
00536             pbuf_realloc(pppos->in_head, pppos->in_head->tot_len - 2);
00537           }
00538 
00539           /* Dispatch the packet thereby consuming it. */
00540           inp = pppos->in_head;
00541           /* Packet consumed, release our references. */
00542           pppos->in_head = NULL;
00543           pppos->in_tail = NULL;
00544 #if IP_FORWARD || LWIP_IPV6_FORWARD
00545           /* hide the room for Ethernet forwarding header */
00546           pbuf_header(inp, -(s16_t)(PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN));
00547 #endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
00548 #if PPP_INPROC_IRQ_SAFE
00549           if(tcpip_callback_with_block(pppos_input_callback, inp, 0) != ERR_OK) {
00550             PPPDEBUG(LOG_ERR, ("pppos_input[%d]: tcpip_callback() failed, dropping packet\n", ppp->netif->num));
00551             pbuf_free(inp);
00552             LINK_STATS_INC(link.drop);
00553             MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
00554           }
00555 #else /* PPP_INPROC_IRQ_SAFE */
00556           ppp_input(ppp, inp);
00557 #endif /* PPP_INPROC_IRQ_SAFE */
00558         }
00559 
00560         /* Prepare for a new packet. */
00561         pppos->in_fcs = PPP_INITFCS;
00562         pppos->in_state = PDADDRESS;
00563         pppos->in_escaped = 0;
00564       /* Other characters are usually control characters that may have
00565        * been inserted by the physical layer so here we just drop them. */
00566       } else {
00567         PPPDEBUG(LOG_WARNING,
00568                  ("pppos_input[%d]: Dropping ACCM char <%d>\n", ppp->netif->num, cur_char));
00569       }
00570     /* Process other characters. */
00571     } else {
00572       /* Unencode escaped characters. */
00573       if (pppos->in_escaped) {
00574         pppos->in_escaped = 0;
00575         cur_char ^= PPP_TRANS;
00576       }
00577 
00578       /* Process character relative to current state. */
00579       switch(pppos->in_state) {
00580         case PDIDLE:                    /* Idle state - waiting. */
00581           /* Drop the character if it's not 0xff
00582            * we would have processed a flag character above. */
00583           if (cur_char != PPP_ALLSTATIONS) {
00584             break;
00585           }
00586           /* no break */
00587           /* Fall through */
00588 
00589         case PDSTART:                   /* Process start flag. */
00590           /* Prepare for a new packet. */
00591           pppos->in_fcs = PPP_INITFCS;
00592           /* no break */
00593           /* Fall through */
00594 
00595         case PDADDRESS:                 /* Process address field. */
00596           if (cur_char == PPP_ALLSTATIONS) {
00597             pppos->in_state = PDCONTROL;
00598             break;
00599           }
00600           /* no break */
00601 
00602           /* Else assume compressed address and control fields so
00603            * fall through to get the protocol... */
00604         case PDCONTROL:                 /* Process control field. */
00605           /* If we don't get a valid control code, restart. */
00606           if (cur_char == PPP_UI) {
00607             pppos->in_state = PDPROTOCOL1;
00608             break;
00609           }
00610           /* no break */
00611 
00612 #if 0
00613           else {
00614             PPPDEBUG(LOG_WARNING,
00615                      ("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char));
00616             pppos->in_state = PDSTART;
00617           }
00618 #endif
00619         case PDPROTOCOL1:               /* Process protocol field 1. */
00620           /* If the lower bit is set, this is the end of the protocol
00621            * field. */
00622           if (cur_char & 1) {
00623             pppos->in_protocol = cur_char;
00624             pppos->in_state = PDDATA;
00625           } else {
00626             pppos->in_protocol = (u16_t)cur_char << 8;
00627             pppos->in_state = PDPROTOCOL2;
00628           }
00629           break;
00630         case PDPROTOCOL2:               /* Process protocol field 2. */
00631           pppos->in_protocol |= cur_char;
00632           pppos->in_state = PDDATA;
00633           break;
00634         case PDDATA:                    /* Process data byte. */
00635           /* Make space to receive processed data. */
00636           if (pppos->in_tail == NULL || pppos->in_tail->len == PBUF_POOL_BUFSIZE) {
00637             u16_t pbuf_alloc_len;
00638             if (pppos->in_tail != NULL) {
00639               pppos->in_tail->tot_len = pppos->in_tail->len;
00640               if (pppos->in_tail != pppos->in_head) {
00641                 pbuf_cat(pppos->in_head, pppos->in_tail);
00642                 /* give up the in_tail reference now */
00643                 pppos->in_tail = NULL;
00644               }
00645             }
00646             /* If we haven't started a packet, we need a packet header. */
00647             pbuf_alloc_len = 0;
00648 #if IP_FORWARD || LWIP_IPV6_FORWARD
00649             /* If IP forwarding is enabled we are reserving PBUF_LINK_ENCAPSULATION_HLEN
00650              * + PBUF_LINK_HLEN bytes so the packet is being allocated with enough header
00651              * space to be forwarded (to Ethernet for example).
00652              */
00653             if (pppos->in_head == NULL) {
00654               pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN;
00655             }
00656 #endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
00657             next_pbuf = pbuf_alloc(PBUF_RAW, pbuf_alloc_len, PBUF_POOL);
00658             if (next_pbuf == NULL) {
00659               /* No free buffers.  Drop the input packet and let the
00660                * higher layers deal with it.  Continue processing
00661                * the received pbuf chain in case a new packet starts. */
00662               PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE PBUFS!\n", ppp->netif->num));
00663               LINK_STATS_INC(link.memerr);
00664               pppos_input_drop(pppos);
00665               pppos->in_state = PDSTART;  /* Wait for flag sequence. */
00666               break;
00667             }
00668             if (pppos->in_head == NULL) {
00669               u8_t *payload = ((u8_t*)next_pbuf->payload) + pbuf_alloc_len;
00670 #if PPP_INPROC_IRQ_SAFE
00671               ((struct pppos_input_header*)payload)->ppp = ppp;
00672               payload += sizeof(struct pppos_input_header);
00673               next_pbuf->len += sizeof(struct pppos_input_header);
00674 #endif /* PPP_INPROC_IRQ_SAFE */
00675               next_pbuf->len += sizeof(pppos->in_protocol);
00676               *(payload++) = pppos->in_protocol >> 8;
00677               *(payload) = pppos->in_protocol & 0xFF;
00678               pppos->in_head = next_pbuf;
00679             }
00680             pppos->in_tail = next_pbuf;
00681           }
00682           /* Load character into buffer. */
00683           ((u8_t*)pppos->in_tail->payload)[pppos->in_tail->len++] = cur_char;
00684           break;
00685         default:
00686           break;
00687       }
00688 
00689       /* update the frame check sequence number. */
00690       pppos->in_fcs = PPP_FCS(pppos->in_fcs, cur_char);
00691     }
00692   } /* while (l-- > 0), all bytes processed */
00693 }
00694 
00695 #if PPP_INPROC_IRQ_SAFE
00696 /* PPPoS input callback using one input pointer
00697  */
00698 static void pppos_input_callback(void *arg) {
00699   struct pbuf *pb = (struct pbuf*)arg;
00700   ppp_pcb *ppp;
00701 
00702   ppp = ((struct pppos_input_header*)pb->payload)->ppp;
00703   if(pbuf_header(pb, -(s16_t)sizeof(struct pppos_input_header))) {
00704     LWIP_ASSERT("pbuf_header failed\n", 0);
00705     goto drop;
00706   }
00707 
00708   /* Dispatch the packet thereby consuming it. */
00709   ppp_input(ppp, pb);
00710   return;
00711 
00712 drop:
00713   LINK_STATS_INC(link.drop);
00714   MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
00715   pbuf_free(pb);
00716 }
00717 #endif /* PPP_INPROC_IRQ_SAFE */
00718 
00719 static void
00720 pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
00721 {
00722   int i;
00723   pppos_pcb *pppos = (pppos_pcb *)ctx;
00724   LWIP_UNUSED_ARG(ppp);
00725 
00726   pppos->pcomp = pcomp;
00727   pppos->accomp = accomp;
00728 
00729   /* Load the ACCM bits for the 32 control codes. */
00730   for (i = 0; i < 32/8; i++) {
00731     pppos->out_accm[i] = (u8_t)((accm >> (8 * i)) & 0xFF);
00732   }
00733 
00734   PPPDEBUG(LOG_INFO, ("pppos_send_config[%d]: out_accm=%X %X %X %X\n",
00735             pppos->ppp->netif->num,
00736             pppos->out_accm[0], pppos->out_accm[1], pppos->out_accm[2], pppos->out_accm[3]));
00737 }
00738 
00739 static void
00740 pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
00741 {
00742   int i;
00743   pppos_pcb *pppos = (pppos_pcb *)ctx;
00744   PPPOS_DECL_PROTECT(lev);
00745   LWIP_UNUSED_ARG(ppp);
00746   LWIP_UNUSED_ARG(pcomp);
00747   LWIP_UNUSED_ARG(accomp);
00748 
00749   /* Load the ACCM bits for the 32 control codes. */
00750   PPPOS_PROTECT(lev);
00751   for (i = 0; i < 32 / 8; i++) {
00752     pppos->in_accm[i] = (u8_t)(accm >> (i * 8));
00753   }
00754   PPPOS_UNPROTECT(lev);
00755 
00756   PPPDEBUG(LOG_INFO, ("pppos_recv_config[%d]: in_accm=%X %X %X %X\n",
00757             pppos->ppp->netif->num,
00758             pppos->in_accm[0], pppos->in_accm[1], pppos->in_accm[2], pppos->in_accm[3]));
00759 }
00760 
00761 /*
00762  * Drop the input packet.
00763  */
00764 static void
00765 pppos_input_free_current_packet(pppos_pcb *pppos)
00766 {
00767   if (pppos->in_head != NULL) {
00768     if (pppos->in_tail && (pppos->in_tail != pppos->in_head)) {
00769       pbuf_free(pppos->in_tail);
00770     }
00771     pbuf_free(pppos->in_head);
00772     pppos->in_head = NULL;
00773   }
00774   pppos->in_tail = NULL;
00775 }
00776 
00777 /*
00778  * Drop the input packet and increase error counters.
00779  */
00780 static void
00781 pppos_input_drop(pppos_pcb *pppos)
00782 {
00783   if (pppos->in_head != NULL) {
00784 #if 0
00785     PPPDEBUG(LOG_INFO, ("pppos_input_drop: %d:%.*H\n", pppos->in_head->len, min(60, pppos->in_head->len * 2), pppos->in_head->payload));
00786 #endif
00787     PPPDEBUG(LOG_INFO, ("pppos_input_drop: pbuf len=%d, addr %p\n", pppos->in_head->len, (void*)pppos->in_head));
00788   }
00789   pppos_input_free_current_packet(pppos);
00790 #if VJ_SUPPORT && LWIP_TCP
00791   vj_uncompress_err(&pppos->ppp->vj_comp);
00792 #endif /* VJ_SUPPORT && LWIP_TCP */
00793 
00794   LINK_STATS_INC(link.drop);
00795   MIB2_STATS_NETIF_INC(pppos->ppp->netif, ifindiscards);
00796 }
00797 
00798 /*
00799  * pppos_output_append - append given character to end of given pbuf.
00800  * If out_accm is not 0 and the character needs to be escaped, do so.
00801  * If pbuf is full, send the pbuf and reuse it.
00802  * Return the current pbuf.
00803  */
00804 static err_t
00805 pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs)
00806 {
00807   if (err != ERR_OK) {
00808     return err;
00809   }
00810 
00811   /* Make sure there is room for the character and an escape code.
00812    * Sure we don't quite fill the buffer if the character doesn't
00813    * get escaped but is one character worth complicating this? */
00814   if ((PBUF_POOL_BUFSIZE - nb->len) < 2) {
00815     u32_t l = pppos->output_cb(pppos->ppp, (u8_t*)nb->payload, nb->len, pppos->ppp->ctx_cb);
00816     if (l != nb->len) {
00817       return ERR_IF;
00818     }
00819     nb->len = 0;
00820   }
00821 
00822   /* Update FCS before checking for special characters. */
00823   if (fcs) {
00824     *fcs = PPP_FCS(*fcs, c);
00825   }
00826 
00827   /* Copy to output buffer escaping special characters. */
00828   if (accm && ESCAPE_P(pppos->out_accm, c)) {
00829     *((u8_t*)nb->payload + nb->len++) = PPP_ESCAPE;
00830     *((u8_t*)nb->payload + nb->len++) = c ^ PPP_TRANS;
00831   } else {
00832     *((u8_t*)nb->payload + nb->len++) = c;
00833   }
00834 
00835   return ERR_OK;
00836 }
00837 
00838 static err_t
00839 pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs)
00840 {
00841   ppp_pcb *ppp = pppos->ppp;
00842 
00843   /* Add FCS and trailing flag. */
00844   err = pppos_output_append(pppos, err,  nb, ~(*fcs) & 0xFF, 1, NULL);
00845   err = pppos_output_append(pppos, err,  nb, (~(*fcs) >> 8) & 0xFF, 1, NULL);
00846   err = pppos_output_append(pppos, err,  nb, PPP_FLAG, 0, NULL);
00847 
00848   if (err != ERR_OK) {
00849     goto failed;
00850   }
00851 
00852   /* Send remaining buffer if not empty */
00853   if (nb->len > 0) {
00854     u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb);
00855     if (l != nb->len) {
00856       err = ERR_IF;
00857       goto failed;
00858     }
00859   }
00860 
00861   pppos->last_xmit = sys_now();
00862   MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, nb->tot_len);
00863   MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts);
00864   LINK_STATS_INC(link.xmit);
00865   pbuf_free(nb);
00866   return ERR_OK;
00867 
00868 failed:
00869   pppos->last_xmit = 0; /* prepend PPP_FLAG to next packet */
00870   LINK_STATS_INC(link.err);
00871   LINK_STATS_INC(link.drop);
00872   MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
00873   pbuf_free(nb);
00874   return err;
00875 }
00876 
00877 #endif /* PPP_SUPPORT && PPPOS_SUPPORT */