Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pppos.cpp Source File

pppos.cpp

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