📄 ahdlc.c
字号:
chr ^= PPP_ESCAPE_BIT; } else if (chr == PPP_FRAME) { /* End of frame. */ if (as->sbdpt && as->rx_sbdptr > 0) { /* * If we're handling seven-bit data path transparency, then * finish out this decode. */ as->rx_sbdptr--; if (as->rx_sbdptr == 0 || as->rx_octets+as->rx_sbdptr > MAXIMUM_MRU) goto notify_error; as->rx_octets += as->rx_sbdptr; chr = as->rx_sbdbuf[as->rx_sbdptr] << (7-as->rx_sbdptr); for (i = 0; i < as->rx_sbdptr; i++) { chr <<= 1; chr2 = as->rx_sbdbuf[i] | (chr & 0x80); as->rx_crc = (as->rx_crc >> 8) ^ fcstab_16[(as->rx_crc ^ chr2) & 0xFF]; as->rx_crcl = (as->rx_crcl >> 8) ^ fcstab_32[(as->rx_crcl ^ chr2) & 0xFF]; *as->rx_bufp++ = (char)chr2; } } if (as->userrcv != NULL && ((as->usecrc32 && as->rx_crcl == PPPGOODFCS32) || (!as->usecrc32 && as->rx_crc == PPPGOODFCS16))) { (*as->userrcv)(as->userstate,as->rx_buffer, as->rx_octets - (as->usecrc32 ? 4 : 2)); as->rx_buffer = buffer_fetch(MAXIMUM_MRU); } else if (as->rx_octets > 3) goto notify_error; goto reset_buffer; } else if (chr == PPP_ESCAPE) { as->escaped = 1; continue; } /* Handle seven-bit data path transparency mode. */ if (as->sbdpt) { if (as->rx_sbdptr < 7) { as->rx_sbdbuf[as->rx_sbdptr++] = chr; continue; } if (as->rx_octets+7 > MAXIMUM_MRU) goto notify_error; as->rx_octets += 7; for (i = 0; i < 7; i++) { chr <<= 1; chr2 = as->rx_sbdbuf[i] | (chr & 0x80); as->rx_crc = (as->rx_crc >> 8) ^ fcstab_16[(as->rx_crc ^ chr2) & 0xFF]; as->rx_crcl = (as->rx_crcl >> 8) ^ fcstab_32[(as->rx_crcl ^ chr2) & 0xFF]; *as->rx_bufp++ = (char)chr2; } as->rx_sbdptr = 0; continue; } /* If we're here, then we have an input data octet. */ if (as->rx_octets >= MAXIMUM_MRU) { notify_error: /* * Notify PPP of receive error here! Some protocols, like VJ * compressed TCP/IP, work much better when receive errors are * caught and reported by the driver. */ reset_buffer: as->rx_bufp = as->rx_buffer; as->rx_crc = PPPINITFCS16; as->rx_crcl = PPPINITFCS32; as->rx_octets = 0; as->rx_sbdptr = 0; } else { /* * On most systems, it's faster to just calculate both of these * than to attempt to conditionally calculate one based on the * type of CRC negotiated. */ as->rx_crc = (as->rx_crc >> 8) ^ fcstab_16[(as->rx_crc ^ chr) & 0xFF]; as->rx_crcl = (as->rx_crcl >> 8) ^ fcstab_32[(as->rx_crcl ^ chr) & 0xFF]; *as->rx_bufp++ = (char)chr; as->rx_octets++; } }}/* * This routine will place up to 'maxcount' characters for * transmission on the serial link in the given buffer. It should be * called by a FIFO-empty interrupt on the serial link. It returns a * count of the actual number of characters written to the buffer, * which may be less than the maximum given if no more data from PPP * is ready to be sent. * * When PPP places a message on the output queue, it must determine if * the queue was empty when it did this. If so, then the PPP output * routine should arrange to have the serial driver call this routine * once to get the ball rolling. */intahdlc_transmit(void *statep, char *buffer, int maxcount){ struct ahdlc_state *as = (struct ahdlc_state *)statep; int omaxcount = maxcount; octet chr; while (--maxcount >= 0) { if (as->escaping) { as->escaping = 0; *buffer = as->tx_savechr ^ PPP_ESCAPE_BIT;#ifndef TRANSMIT_TO_HARDWARE buffer++;#endif continue; } /* If we need a new buffer to transmit, then go get one from PPP. */ if (as->tx_buffer == NULL) { /* If the user is trying to synchronize, then break out here. */ if (as->outputsync) break; if (as->userxmt != NULL) (*as->userxmt)(as->userstate,&as->tx_buffer,&as->tx_octets); if (as->tx_buffer == NULL || as->tx_octets == 0) { /* Nothing left in queue; will need PPP frame marker next time. */ as->needstart = 1; break; } as->tx_bufp = as->tx_buffer; as->tx_crc = PPPINITFCS16; as->tx_crcl = PPPINITFCS32; /* If we need a frame marker at the beginning, then insert it now. */ if (as->needstart) { as->needstart = 0; *buffer = (char)PPP_FRAME;#ifndef TRANSMIT_TO_HARDWARE buffer++;#endif continue; } } if (as->tx_octets == 0) { /* If no more octets of data left, then set up to send the CRC. */ if (as->usecrc32) { as->tx_crcl = ~as->tx_crcl; as->localfcs[0] = as->tx_crcl & 0xFF; as->localfcs[1] = (as->tx_crcl >> 8) & 0xFF; as->localfcs[2] = (as->tx_crcl >> 16) & 0xFF; as->localfcs[3] = (as->tx_crcl >> 24) & 0xFF; } else { as->tx_crc = ~as->tx_crc; as->localfcs[0] = as->tx_crc & 0xFF; as->localfcs[1] = (as->tx_crc >> 8) & 0xFF; as->tx_octets = -2; } /* * Note that the CRC is sent as though it were data -- we have * to escape characters in the CRC also! Neglecting this is a * common AHDLC implementation bug. */ as->tx_bufp = as->localfcs; } else if (as->tx_octets == -4 && (!as->sbdpt || as->tx_sbdcnt == 0)) { /* All out of CRC octets; give back the buffer and end the frame. */ /* buffer_release(as->tx_buffer); */ as->tx_buffer = NULL; *buffer = (char)PPP_FRAME;#ifndef TRANSMIT_TO_HARDWARE buffer++;#endif continue; } if (as->sbdpt) { if (as->tx_sbdcnt < 7 && as->tx_octets != -4) { as->tx_sbdcnt++; as->tx_octets--; chr = (int)*as->tx_bufp++; as->tx_crc = (as->tx_crc >> 8) ^ fcstab_16[(as->tx_crc ^ chr) & 0xFF]; as->tx_crcl = (as->tx_crcl >> 8) ^ fcstab_32[(as->tx_crcl ^ chr) & 0xFF]; as->tx_sbdval = (as->tx_sbdval<<1) | ((chr&0x80)?1:0); chr &= 0x7F; } else { as->tx_sbdcnt = 0; chr = as->tx_sbdval; as->tx_sbdval = 0; } } else { as->tx_octets--; chr = 0xFF&(int)*as->tx_bufp++; as->tx_crc = (as->tx_crc >> 8) ^ fcstab_16[(as->tx_crc ^ chr) & 0xFF]; as->tx_crcl = (as->tx_crcl >> 8) ^ fcstab_32[(as->tx_crcl ^ chr) & 0xFF]; } if (as->tx_accm[chr/8] & (1 << (chr&7))) { as->tx_savechr = chr; chr = PPP_ESCAPE; as->escaping = 1; } *buffer = (char)chr;#ifndef TRANSMIT_TO_HARDWARE buffer++;#endif } /* * This block is only here to support the optional synchronization * routine below. It is not necessary for proper operation. It * relies on the BSD kernel sleep/wakeup() mechanism to operate. */ if (as->tx_buffer == NULL && as->outputsync) { as->needstart = 1; as->outputsync = 0; wakeup(as); } /* Calculate number of bytes in buffer and return. */ return omaxcount-maxcount-1;}/* * This is an optional routine which achieves synchronization with the * output function. This can be necessary to change some variables, * such as the ACCM. It relies on the BSD kernel sleep()/wakeup() * mechanism. If you are programming at the normal user level, these * functions do not exist. */voidahdlc_sync_wait(void *statep){ struct ahdlc_state *as = (struct ahdlc_state *)statep; as->outputsync = 1; while (as->outputsync) sleep(as,0);}/* * This routine sets the standard PPP receive and transmit ACCM. It * should be called by LCP. Again, like the sync routine above, it * assumes a number of BSD kernel functions. */voidahdlc_set_accm(void *statep, uint32 rx_accm, uint32 tx_accm){ struct ahdlc_state *as = (struct ahdlc_state *)statep; interrupts_off(); ahdlc_sync_wait(statep); as->rx_accm[0] = rx_accm & 0xFF; as->rx_accm[1] = (rx_accm >> 8) & 0xFF; as->rx_accm[2] = (rx_accm >> 16) & 0xFF; as->rx_accm[3] = (rx_accm >> 24) & 0xFF; as->tx_accm[0] = tx_accm & 0xFF; as->tx_accm[1] = (tx_accm >> 8) & 0xFF; as->tx_accm[2] = (tx_accm >> 16) & 0xFF; as->tx_accm[3] = (tx_accm >> 24) & 0xFF; interrupts_on();}/* * This is an example of a wrapper routine to change the CRC mode * flag. Note that because both CRCs are always calculated, no * synchronization is necessary. */voidahdlc_set_crc_mode(void *statep, int mode){ struct ahdlc_state *as = (struct ahdlc_state *)statep; as->usecrc32 = mode;}/* * This is in ISO/IEC 3309:1993(E), but is not part of RFC 1662. * Enabling this option will allow operation over seven bit data * paths, but is not compliant with the RFC. */voidahdlc_set_sbdpt(void *statep, int onoff){ struct ahdlc_state *as = (struct ahdlc_state *)statep; as->sbdpt = onoff;}/* * This is an example routine to report physical-layer * misconfiguration to the user. You'll probably need to modify this * routine. */voidahdlc_report_on_failure(void *statep){ struct ahdlc_state *as = (struct ahdlc_state *)statep; if (as->magicvar & MCT_NODATA) syslog(LOG_ERR,"no data was received from the peer."); else if (as->magicvar & MCT_ZEROPAR) { syslog(LOG_ERR,"all bytes received from peer had bit 8 cleared;"); syslog(LOG_ERR,"7 bit data path with no parity suspected."); } else if (as->magicvar & MCT_ONEPAR) { syslog(LOG_ERR,"all bytes received from peer had bit 8 set;"); syslog(LOG_ERR,"7 bit data path with mark parity suspected."); } else if (as->magicvar & MCT_ODDPAR) { syslog(LOG_ERR,"all bytes received from peer had odd parity;"); syslog(LOG_ERR,"7 bit data path with odd parity suspected."); } else if (as->magicvar & MCT_EVENPAR) { syslog(LOG_ERR,"all bytes received from peer had even parity;"); syslog(LOG_ERR,"7 bit data path with even parity suspected."); } else if (as->magicvar & MCT_NOTCTL) { syslog(LOG_INFO,"no bytes in 00-1f or 80-9f received;"); syslog(LOG_INFO,"control transparency left enabled"); } else if (as->magicvar & MCT_NOTLOW) { syslog(LOG_INFO,"no bytes in 00-1f received;"); syslog(LOG_INFO,"control transparency left enabled"); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -