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: TYBLE16_simple_data_logger TYBLE16_MP3_Air
pppos.cpp
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 */
Generated on Tue Jul 12 2022 13:54:43 by
