Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more
lwip_pppos.c
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 */
Generated on Tue Jul 12 2022 11:02:27 by
1.7.2