Rtos API example

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 
00039 #include "lwip/arch.h"
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 void pppos_connect(ppp_pcb *ppp, void *ctx);
00061 #if PPP_SERVER
00062 static void 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 void
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   /* reset PPPoS control block to its initial state */
00313   memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
00314 
00315   /*
00316    * Default the in and out accm so that escape and flag characters
00317    * are always escaped.
00318    */
00319   pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
00320   pppos->out_accm[15] = 0x60;
00321   PPPOS_PROTECT(lev);
00322   pppos->open = 1;
00323   PPPOS_UNPROTECT(lev);
00324 
00325   /*
00326    * Start the connection and handle incoming events (packet or timeout).
00327    */
00328   PPPDEBUG(LOG_INFO, ("pppos_connect: unit %d: connecting\n", ppp->netif->num));
00329   ppp_start(ppp); /* notify upper layers */
00330 }
00331 
00332 #if PPP_SERVER
00333 static void
00334 pppos_listen(ppp_pcb *ppp, void *ctx)
00335 {
00336   pppos_pcb *pppos = (pppos_pcb *)ctx;
00337   PPPOS_DECL_PROTECT(lev);
00338 
00339 #if PPP_INPROC_IRQ_SAFE
00340   /* input pbuf left over from last session? */
00341   pppos_input_free_current_packet(pppos);
00342 #endif /* PPP_INPROC_IRQ_SAFE */
00343 
00344   /* reset PPPoS control block to its initial state */
00345   memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
00346 
00347   /*
00348    * Default the in and out accm so that escape and flag characters
00349    * are always escaped.
00350    */
00351   pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
00352   pppos->out_accm[15] = 0x60;
00353   PPPOS_PROTECT(lev);
00354   pppos->open = 1;
00355   PPPOS_UNPROTECT(lev);
00356 
00357   /*
00358    * Wait for something to happen.
00359    */
00360   PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num));
00361   ppp_start(ppp); /* notify upper layers */
00362 }
00363 #endif /* PPP_SERVER */
00364 
00365 static void
00366 pppos_disconnect(ppp_pcb *ppp, void *ctx)
00367 {
00368   pppos_pcb *pppos = (pppos_pcb *)ctx;
00369   PPPOS_DECL_PROTECT(lev);
00370 
00371   PPPOS_PROTECT(lev);
00372   pppos->open = 0;
00373   PPPOS_UNPROTECT(lev);
00374 
00375   /* If PPP_INPROC_IRQ_SAFE is used we cannot call
00376    * pppos_input_free_current_packet() here because
00377    * rx IRQ might still call pppos_input().
00378    */
00379 #if !PPP_INPROC_IRQ_SAFE
00380   /* input pbuf left ? */
00381   pppos_input_free_current_packet(pppos);
00382 #endif /* !PPP_INPROC_IRQ_SAFE */
00383 
00384   ppp_link_end(ppp); /* notify upper layers */
00385 }
00386 
00387 static err_t
00388 pppos_destroy(ppp_pcb *ppp, void *ctx)
00389 {
00390   pppos_pcb *pppos = (pppos_pcb *)ctx;
00391   LWIP_UNUSED_ARG(ppp);
00392 
00393 #if PPP_INPROC_IRQ_SAFE
00394   /* input pbuf left ? */
00395   pppos_input_free_current_packet(pppos);
00396 #endif /* PPP_INPROC_IRQ_SAFE */
00397 
00398   LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
00399   return ERR_OK;
00400 }
00401 
00402 #if !NO_SYS && !PPP_INPROC_IRQ_SAFE
00403 /** Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread.
00404  *
00405  * @param ppp PPP descriptor index, returned by pppos_create()
00406  * @param s received data
00407  * @param l length of received data
00408  */
00409 err_t
00410 pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l)
00411 {
00412   struct pbuf *p;
00413   err_t err;
00414 
00415   p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL);
00416   if (!p) {
00417     return ERR_MEM;
00418   }
00419   pbuf_take(p, s, l);
00420 
00421   err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys);
00422   if (err != ERR_OK) {
00423      pbuf_free(p);
00424   }
00425   return err;
00426 }
00427 
00428 /* called from TCPIP thread */
00429 err_t pppos_input_sys(struct pbuf *p, struct netif *inp) {
00430   ppp_pcb *ppp = (ppp_pcb*)inp->state;
00431   struct pbuf *n;
00432 
00433   for (n = p; n; n = n->next) {
00434     pppos_input(ppp, (u8_t*)n->payload, n->len);
00435   }
00436   pbuf_free(p);
00437   return ERR_OK;
00438 }
00439 #endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */
00440 
00441 /** PPPoS input helper struct, must be packed since it is stored
00442  * to pbuf->payload, which might be unaligned. */
00443 #if PPP_INPROC_IRQ_SAFE
00444 #ifdef PACK_STRUCT_USE_INCLUDES
00445 #  include "arch/bpstruct.h"
00446 #endif
00447 PACK_STRUCT_BEGIN
00448 struct pppos_input_header {
00449   PACK_STRUCT_FIELD(ppp_pcb *ppp);
00450 } PACK_STRUCT_STRUCT;
00451 PACK_STRUCT_END
00452 #ifdef PACK_STRUCT_USE_INCLUDES
00453 #  include "arch/epstruct.h"
00454 #endif
00455 #endif /* PPP_INPROC_IRQ_SAFE */
00456 
00457 /** Pass received raw characters to PPPoS to be decoded.
00458  *
00459  * @param ppp PPP descriptor index, returned by pppos_create()
00460  * @param s received data
00461  * @param l length of received data
00462  */
00463 void
00464 pppos_input(ppp_pcb *ppp, u8_t *s, int l)
00465 {
00466   pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb;
00467   struct pbuf *next_pbuf;
00468   u8_t cur_char;
00469   u8_t escaped;
00470   PPPOS_DECL_PROTECT(lev);
00471 
00472   PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l));
00473   while (l-- > 0) {
00474     cur_char = *s++;
00475 
00476     PPPOS_PROTECT(lev);
00477     /* ppp_input can disconnect the interface, we need to abort to prevent a memory
00478      * leak if there are remaining bytes because pppos_connect and pppos_listen
00479      * functions expect input buffer to be free. Furthermore there are no real
00480      * reason to continue reading bytes if we are disconnected.
00481      */
00482     if (!pppos->open) {
00483       PPPOS_UNPROTECT(lev);
00484       return;
00485     }
00486     escaped = ESCAPE_P(pppos->in_accm, cur_char);
00487     PPPOS_UNPROTECT(lev);
00488     /* Handle special characters. */
00489     if (escaped) {
00490       /* Check for escape sequences. */
00491       /* XXX Note that this does not handle an escaped 0x5d character which
00492        * would appear as an escape character.  Since this is an ASCII ']'
00493        * and there is no reason that I know of to escape it, I won't complicate
00494        * the code to handle this case. GLL */
00495       if (cur_char == PPP_ESCAPE) {
00496         pppos->in_escaped = 1;
00497       /* Check for the flag character. */
00498       } else if (cur_char == PPP_FLAG) {
00499         /* If this is just an extra flag character, ignore it. */
00500         if (pppos->in_state <= PDADDRESS) {
00501           /* ignore it */;
00502         /* If we haven't received the packet header, drop what has come in. */
00503         } else if (pppos->in_state < PDDATA) {
00504           PPPDEBUG(LOG_WARNING,
00505                    ("pppos_input[%d]: Dropping incomplete packet %d\n",
00506                     ppp->netif->num, pppos->in_state));
00507           LINK_STATS_INC(link.lenerr);
00508           pppos_input_drop(pppos);
00509         /* If the fcs is invalid, drop the packet. */
00510         } else if (pppos->in_fcs != PPP_GOODFCS) {
00511           PPPDEBUG(LOG_INFO,
00512                    ("pppos_input[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n",
00513                     ppp->netif->num, pppos->in_fcs, pppos->in_protocol));
00514           /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
00515           LINK_STATS_INC(link.chkerr);
00516           pppos_input_drop(pppos);
00517         /* Otherwise it's a good packet so pass it on. */
00518         } else {
00519           struct pbuf *inp;
00520           /* Trim off the checksum. */
00521           if(pppos->in_tail->len > 2) {
00522             pppos->in_tail->len -= 2;
00523 
00524             pppos->in_tail->tot_len = pppos->in_tail->len;
00525             if (pppos->in_tail != pppos->in_head) {
00526               pbuf_cat(pppos->in_head, pppos->in_tail);
00527             }
00528           } else {
00529             pppos->in_tail->tot_len = pppos->in_tail->len;
00530             if (pppos->in_tail != pppos->in_head) {
00531               pbuf_cat(pppos->in_head, pppos->in_tail);
00532             }
00533 
00534             pbuf_realloc(pppos->in_head, pppos->in_head->tot_len - 2);
00535           }
00536 
00537           /* Dispatch the packet thereby consuming it. */
00538           inp = pppos->in_head;
00539           /* Packet consumed, release our references. */
00540           pppos->in_head = NULL;
00541           pppos->in_tail = NULL;
00542 #if IP_FORWARD || LWIP_IPV6_FORWARD
00543           /* hide the room for Ethernet forwarding header */
00544           pbuf_header(inp, -(s16_t)(PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN));
00545 #endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
00546 #if PPP_INPROC_IRQ_SAFE
00547           if(tcpip_callback_with_block(pppos_input_callback, inp, 0) != ERR_OK) {
00548             PPPDEBUG(LOG_ERR, ("pppos_input[%d]: tcpip_callback() failed, dropping packet\n", ppp->netif->num));
00549             pbuf_free(inp);
00550             LINK_STATS_INC(link.drop);
00551             MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
00552           }
00553 #else /* PPP_INPROC_IRQ_SAFE */
00554           ppp_input(ppp, inp);
00555 #endif /* PPP_INPROC_IRQ_SAFE */
00556         }
00557 
00558         /* Prepare for a new packet. */
00559         pppos->in_fcs = PPP_INITFCS;
00560         pppos->in_state = PDADDRESS;
00561         pppos->in_escaped = 0;
00562       /* Other characters are usually control characters that may have
00563        * been inserted by the physical layer so here we just drop them. */
00564       } else {
00565         PPPDEBUG(LOG_WARNING,
00566                  ("pppos_input[%d]: Dropping ACCM char <%d>\n", ppp->netif->num, cur_char));
00567       }
00568     /* Process other characters. */
00569     } else {
00570       /* Unencode escaped characters. */
00571       if (pppos->in_escaped) {
00572         pppos->in_escaped = 0;
00573         cur_char ^= PPP_TRANS;
00574       }
00575 
00576       /* Process character relative to current state. */
00577       switch(pppos->in_state) {
00578         case PDIDLE:                    /* Idle state - waiting. */
00579           /* Drop the character if it's not 0xff
00580            * we would have processed a flag character above. */
00581           if (cur_char != PPP_ALLSTATIONS) {
00582             break;
00583           }
00584           /* no break */
00585           /* Fall through */
00586 
00587         case PDSTART:                   /* Process start flag. */
00588           /* Prepare for a new packet. */
00589           pppos->in_fcs = PPP_INITFCS;
00590           /* no break */
00591           /* Fall through */
00592 
00593         case PDADDRESS:                 /* Process address field. */
00594           if (cur_char == PPP_ALLSTATIONS) {
00595             pppos->in_state = PDCONTROL;
00596             break;
00597           }
00598           /* no break */
00599 
00600           /* Else assume compressed address and control fields so
00601            * fall through to get the protocol... */
00602         case PDCONTROL:                 /* Process control field. */
00603           /* If we don't get a valid control code, restart. */
00604           if (cur_char == PPP_UI) {
00605             pppos->in_state = PDPROTOCOL1;
00606             break;
00607           }
00608           /* no break */
00609 
00610 #if 0
00611           else {
00612             PPPDEBUG(LOG_WARNING,
00613                      ("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char));
00614             pppos->in_state = PDSTART;
00615           }
00616 #endif
00617         case PDPROTOCOL1:               /* Process protocol field 1. */
00618           /* If the lower bit is set, this is the end of the protocol
00619            * field. */
00620           if (cur_char & 1) {
00621             pppos->in_protocol = cur_char;
00622             pppos->in_state = PDDATA;
00623           } else {
00624             pppos->in_protocol = (u16_t)cur_char << 8;
00625             pppos->in_state = PDPROTOCOL2;
00626           }
00627           break;
00628         case PDPROTOCOL2:               /* Process protocol field 2. */
00629           pppos->in_protocol |= cur_char;
00630           pppos->in_state = PDDATA;
00631           break;
00632         case PDDATA:                    /* Process data byte. */
00633           /* Make space to receive processed data. */
00634           if (pppos->in_tail == NULL || pppos->in_tail->len == PBUF_POOL_BUFSIZE) {
00635             u16_t pbuf_alloc_len;
00636             if (pppos->in_tail != NULL) {
00637               pppos->in_tail->tot_len = pppos->in_tail->len;
00638               if (pppos->in_tail != pppos->in_head) {
00639                 pbuf_cat(pppos->in_head, pppos->in_tail);
00640                 /* give up the in_tail reference now */
00641                 pppos->in_tail = NULL;
00642               }
00643             }
00644             /* If we haven't started a packet, we need a packet header. */
00645             pbuf_alloc_len = 0;
00646 #if IP_FORWARD || LWIP_IPV6_FORWARD
00647             /* If IP forwarding is enabled we are reserving PBUF_LINK_ENCAPSULATION_HLEN
00648              * + PBUF_LINK_HLEN bytes so the packet is being allocated with enough header
00649              * space to be forwarded (to Ethernet for example).
00650              */
00651             if (pppos->in_head == NULL) {
00652               pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN;
00653             }
00654 #endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
00655             next_pbuf = pbuf_alloc(PBUF_RAW, pbuf_alloc_len, PBUF_POOL);
00656             if (next_pbuf == NULL) {
00657               /* No free buffers.  Drop the input packet and let the
00658                * higher layers deal with it.  Continue processing
00659                * the received pbuf chain in case a new packet starts. */
00660               PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE PBUFS!\n", ppp->netif->num));
00661               LINK_STATS_INC(link.memerr);
00662               pppos_input_drop(pppos);
00663               pppos->in_state = PDSTART;  /* Wait for flag sequence. */
00664               break;
00665             }
00666             if (pppos->in_head == NULL) {
00667               u8_t *payload = ((u8_t*)next_pbuf->payload) + pbuf_alloc_len;
00668 #if PPP_INPROC_IRQ_SAFE
00669               ((struct pppos_input_header*)payload)->ppp = ppp;
00670               payload += sizeof(struct pppos_input_header);
00671               next_pbuf->len += sizeof(struct pppos_input_header);
00672 #endif /* PPP_INPROC_IRQ_SAFE */
00673               next_pbuf->len += sizeof(pppos->in_protocol);
00674               *(payload++) = pppos->in_protocol >> 8;
00675               *(payload) = pppos->in_protocol & 0xFF;
00676               pppos->in_head = next_pbuf;
00677             }
00678             pppos->in_tail = next_pbuf;
00679           }
00680           /* Load character into buffer. */
00681           ((u8_t*)pppos->in_tail->payload)[pppos->in_tail->len++] = cur_char;
00682           break;
00683         default:
00684           break;
00685       }
00686 
00687       /* update the frame check sequence number. */
00688       pppos->in_fcs = PPP_FCS(pppos->in_fcs, cur_char);
00689     }
00690   } /* while (l-- > 0), all bytes processed */
00691 }
00692 
00693 #if PPP_INPROC_IRQ_SAFE
00694 /* PPPoS input callback using one input pointer
00695  */
00696 static void pppos_input_callback(void *arg) {
00697   struct pbuf *pb = (struct pbuf*)arg;
00698   ppp_pcb *ppp;
00699 
00700   ppp = ((struct pppos_input_header*)pb->payload)->ppp;
00701   if(pbuf_header(pb, -(s16_t)sizeof(struct pppos_input_header))) {
00702     LWIP_ASSERT("pbuf_header failed\n", 0);
00703     goto drop;
00704   }
00705 
00706   /* Dispatch the packet thereby consuming it. */
00707   ppp_input(ppp, pb);
00708   return;
00709 
00710 drop:
00711   LINK_STATS_INC(link.drop);
00712   MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
00713   pbuf_free(pb);
00714 }
00715 #endif /* PPP_INPROC_IRQ_SAFE */
00716 
00717 static void
00718 pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
00719 {
00720   int i;
00721   pppos_pcb *pppos = (pppos_pcb *)ctx;
00722   LWIP_UNUSED_ARG(ppp);
00723 
00724   pppos->pcomp = pcomp;
00725   pppos->accomp = accomp;
00726 
00727   /* Load the ACCM bits for the 32 control codes. */
00728   for (i = 0; i < 32/8; i++) {
00729     pppos->out_accm[i] = (u8_t)((accm >> (8 * i)) & 0xFF);
00730   }
00731 
00732   PPPDEBUG(LOG_INFO, ("pppos_send_config[%d]: out_accm=%X %X %X %X\n",
00733             pppos->ppp->netif->num,
00734             pppos->out_accm[0], pppos->out_accm[1], pppos->out_accm[2], pppos->out_accm[3]));
00735 }
00736 
00737 static void
00738 pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
00739 {
00740   int i;
00741   pppos_pcb *pppos = (pppos_pcb *)ctx;
00742   PPPOS_DECL_PROTECT(lev);
00743   LWIP_UNUSED_ARG(ppp);
00744   LWIP_UNUSED_ARG(pcomp);
00745   LWIP_UNUSED_ARG(accomp);
00746 
00747   /* Load the ACCM bits for the 32 control codes. */
00748   PPPOS_PROTECT(lev);
00749   for (i = 0; i < 32 / 8; i++) {
00750     pppos->in_accm[i] = (u8_t)(accm >> (i * 8));
00751   }
00752   PPPOS_UNPROTECT(lev);
00753 
00754   PPPDEBUG(LOG_INFO, ("pppos_recv_config[%d]: in_accm=%X %X %X %X\n",
00755             pppos->ppp->netif->num,
00756             pppos->in_accm[0], pppos->in_accm[1], pppos->in_accm[2], pppos->in_accm[3]));
00757 }
00758 
00759 /*
00760  * Drop the input packet.
00761  */
00762 static void
00763 pppos_input_free_current_packet(pppos_pcb *pppos)
00764 {
00765   if (pppos->in_head != NULL) {
00766     if (pppos->in_tail && (pppos->in_tail != pppos->in_head)) {
00767       pbuf_free(pppos->in_tail);
00768     }
00769     pbuf_free(pppos->in_head);
00770     pppos->in_head = NULL;
00771   }
00772   pppos->in_tail = NULL;
00773 }
00774 
00775 /*
00776  * Drop the input packet and increase error counters.
00777  */
00778 static void
00779 pppos_input_drop(pppos_pcb *pppos)
00780 {
00781   if (pppos->in_head != NULL) {
00782 #if 0
00783     PPPDEBUG(LOG_INFO, ("pppos_input_drop: %d:%.*H\n", pppos->in_head->len, min(60, pppos->in_head->len * 2), pppos->in_head->payload));
00784 #endif
00785     PPPDEBUG(LOG_INFO, ("pppos_input_drop: pbuf len=%d, addr %p\n", pppos->in_head->len, (void*)pppos->in_head));
00786   }
00787   pppos_input_free_current_packet(pppos);
00788 #if VJ_SUPPORT
00789   vj_uncompress_err(&pppos->ppp->vj_comp);
00790 #endif /* VJ_SUPPORT */
00791 
00792   LINK_STATS_INC(link.drop);
00793   MIB2_STATS_NETIF_INC(pppos->ppp->netif, ifindiscards);
00794 }
00795 
00796 /*
00797  * pppos_output_append - append given character to end of given pbuf.
00798  * If out_accm is not 0 and the character needs to be escaped, do so.
00799  * If pbuf is full, send the pbuf and reuse it.
00800  * Return the current pbuf.
00801  */
00802 static err_t
00803 pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs)
00804 {
00805   if (err != ERR_OK) {
00806     return err;
00807   }
00808 
00809   /* Make sure there is room for the character and an escape code.
00810    * Sure we don't quite fill the buffer if the character doesn't
00811    * get escaped but is one character worth complicating this? */
00812   if ((PBUF_POOL_BUFSIZE - nb->len) < 2) {
00813     u32_t l = pppos->output_cb(pppos->ppp, (u8_t*)nb->payload, nb->len, pppos->ppp->ctx_cb);
00814     if (l != nb->len) {
00815       return ERR_IF;
00816     }
00817     nb->len = 0;
00818   }
00819 
00820   /* Update FCS before checking for special characters. */
00821   if (fcs) {
00822     *fcs = PPP_FCS(*fcs, c);
00823   }
00824 
00825   /* Copy to output buffer escaping special characters. */
00826   if (accm && ESCAPE_P(pppos->out_accm, c)) {
00827     *((u8_t*)nb->payload + nb->len++) = PPP_ESCAPE;
00828     *((u8_t*)nb->payload + nb->len++) = c ^ PPP_TRANS;
00829   } else {
00830     *((u8_t*)nb->payload + nb->len++) = c;
00831   }
00832 
00833   return ERR_OK;
00834 }
00835 
00836 static err_t
00837 pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs)
00838 {
00839   ppp_pcb *ppp = pppos->ppp;
00840 
00841   /* Add FCS and trailing flag. */
00842   err = pppos_output_append(pppos, err,  nb, ~(*fcs) & 0xFF, 1, NULL);
00843   err = pppos_output_append(pppos, err,  nb, (~(*fcs) >> 8) & 0xFF, 1, NULL);
00844   err = pppos_output_append(pppos, err,  nb, PPP_FLAG, 0, NULL);
00845 
00846   if (err != ERR_OK) {
00847     goto failed;
00848   }
00849 
00850   /* Send remaining buffer if not empty */
00851   if (nb->len > 0) {
00852     u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb);
00853     if (l != nb->len) {
00854       err = ERR_IF;
00855       goto failed;
00856     }
00857   }
00858 
00859   pppos->last_xmit = sys_now();
00860   MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, nb->tot_len);
00861   MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts);
00862   LINK_STATS_INC(link.xmit);
00863   pbuf_free(nb);
00864   return ERR_OK;
00865 
00866 failed:
00867   pppos->last_xmit = 0; /* prepend PPP_FLAG to next packet */
00868   LINK_STATS_INC(link.err);
00869   LINK_STATS_INC(link.drop);
00870   MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
00871   pbuf_free(nb);
00872   return err;
00873 }
00874 
00875 #endif /* PPP_SUPPORT && PPPOS_SUPPORT */