Daiki Kato / mbed-os-lychee

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

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 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   /* 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   return ERR_OK;
00331 }
00332 
00333 #if PPP_SERVER
00334 static err_t
00335 pppos_listen(ppp_pcb *ppp, void *ctx)
00336 {
00337   pppos_pcb *pppos = (pppos_pcb *)ctx;
00338   PPPOS_DECL_PROTECT(lev);
00339 
00340 #if PPP_INPROC_IRQ_SAFE
00341   /* input pbuf left over from last session? */
00342   pppos_input_free_current_packet(pppos);
00343 #endif /* PPP_INPROC_IRQ_SAFE */
00344 
00345   /* reset PPPoS control block to its initial state */
00346   memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
00347 
00348   /*
00349    * Default the in and out accm so that escape and flag characters
00350    * are always escaped.
00351    */
00352   pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
00353   pppos->out_accm[15] = 0x60;
00354   PPPOS_PROTECT(lev);
00355   pppos->open = 1;
00356   PPPOS_UNPROTECT(lev);
00357 
00358   /*
00359    * Wait for something to happen.
00360    */
00361   PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num));
00362   ppp_start(ppp); /* notify upper layers */
00363   return ERR_OK;
00364 }
00365 #endif /* PPP_SERVER */
00366 
00367 static void
00368 pppos_disconnect(ppp_pcb *ppp, void *ctx)
00369 {
00370   pppos_pcb *pppos = (pppos_pcb *)ctx;
00371   PPPOS_DECL_PROTECT(lev);
00372 
00373   PPPOS_PROTECT(lev);
00374   pppos->open = 0;
00375   PPPOS_UNPROTECT(lev);
00376 
00377   /* If PPP_INPROC_IRQ_SAFE is used we cannot call
00378    * pppos_input_free_current_packet() here because
00379    * rx IRQ might still call pppos_input().
00380    */
00381 #if !PPP_INPROC_IRQ_SAFE
00382   /* input pbuf left ? */
00383   pppos_input_free_current_packet(pppos);
00384 #endif /* !PPP_INPROC_IRQ_SAFE */
00385 
00386   ppp_link_end(ppp); /* notify upper layers */
00387 }
00388 
00389 static err_t
00390 pppos_destroy(ppp_pcb *ppp, void *ctx)
00391 {
00392   pppos_pcb *pppos = (pppos_pcb *)ctx;
00393   LWIP_UNUSED_ARG(ppp);
00394 
00395 #if PPP_INPROC_IRQ_SAFE
00396   /* input pbuf left ? */
00397   pppos_input_free_current_packet(pppos);
00398 #endif /* PPP_INPROC_IRQ_SAFE */
00399 
00400   LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
00401   return ERR_OK;
00402 }
00403 
00404 #if !NO_SYS && !PPP_INPROC_IRQ_SAFE
00405 /** Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread.
00406  *
00407  * @param ppp PPP descriptor index, returned by pppos_create()
00408  * @param s received data
00409  * @param l length of received data
00410  */
00411 err_t
00412 pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l)
00413 {
00414   struct pbuf *p;
00415   err_t err;
00416 
00417   p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL);
00418   if (!p) {
00419     return ERR_MEM;
00420   }
00421   pbuf_take(p, s, l);
00422 
00423   err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys);
00424   if (err != ERR_OK) {
00425      pbuf_free(p);
00426   }
00427   return err;
00428 }
00429 
00430 /* called from TCPIP thread */
00431 err_t pppos_input_sys(struct pbuf *p, struct netif *inp) {
00432   ppp_pcb *ppp = (ppp_pcb*)inp->state;
00433   struct pbuf *n;
00434 
00435   for (n = p; n; n = n->next) {
00436     pppos_input(ppp, (u8_t*)n->payload, n->len);
00437   }
00438   pbuf_free(p);
00439   return ERR_OK;
00440 }
00441 #endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */
00442 
00443 /** PPPoS input helper struct, must be packed since it is stored
00444  * to pbuf->payload, which might be unaligned. */
00445 #if PPP_INPROC_IRQ_SAFE
00446 #ifdef PACK_STRUCT_USE_INCLUDES
00447 #  include "arch/bpstruct.h"
00448 #endif
00449 PACK_STRUCT_BEGIN
00450 struct pppos_input_header {
00451   PACK_STRUCT_FIELD(ppp_pcb *ppp);
00452 } PACK_STRUCT_STRUCT;
00453 PACK_STRUCT_END
00454 #ifdef PACK_STRUCT_USE_INCLUDES
00455 #  include "arch/epstruct.h"
00456 #endif
00457 #endif /* PPP_INPROC_IRQ_SAFE */
00458 
00459 /** Pass received raw characters to PPPoS to be decoded.
00460  *
00461  * @param ppp PPP descriptor index, returned by pppos_create()
00462  * @param s received data
00463  * @param l length of received data
00464  */
00465 void
00466 pppos_input(ppp_pcb *ppp, u8_t *s, int l)
00467 {
00468   pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb;
00469   struct pbuf *next_pbuf;
00470   u8_t cur_char;
00471   u8_t escaped;
00472   PPPOS_DECL_PROTECT(lev);
00473 
00474   PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l));
00475   while (l-- > 0) {
00476     cur_char = *s++;
00477 
00478     PPPOS_PROTECT(lev);
00479     /* ppp_input can disconnect the interface, we need to abort to prevent a memory
00480      * leak if there are remaining bytes because pppos_connect and pppos_listen
00481      * functions expect input buffer to be free. Furthermore there are no real
00482      * reason to continue reading bytes if we are disconnected.
00483      */
00484     if (!pppos->open) {
00485       PPPOS_UNPROTECT(lev);
00486       return;
00487     }
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
00791   vj_uncompress_err(&pppos->ppp->vj_comp);
00792 #endif /* VJ_SUPPORT */
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 */