wdbSlipPktDrv.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:14k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* wdbSlipPktDrv.c - a serial line packetizer for the WDB agent */
  2. /* Copyright 1994-2001 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01g,18oct01,jhw  Fixed documentation build errors.
  7. 01f,18sep01,jhw  Fixed compiler warnings from gnu -pedantic option.
  8.  Added Copyright.
  9. 01e,16jan98,dbt  modified overflow test in wdbCharRcv() (SPR #8625).
  10. 01d,14oct95,jdi  doc: cleanup.
  11. 01c,26sep95,ms   docs
  12. 01b,15jun95,ms  updated for new serial device interface
  13. 01a,02dec94,ms   written.
  14. */
  15. /*
  16. DESCRIPTION
  17. This is a lightweight SLIP driver that interfaces with the WDB agents
  18. UDP/IP interpreter.  It is the lightweight equivalent of the VxWorks
  19. SLIP netif driver, and uses the same protocol to assemble serial
  20. characters into IP datagrams (namely the SLIP protocol).
  21. SLIP is a simple protocol that uses four token characters
  22. to delimit each packet:
  23.     - FRAME_END (0300)
  24.     - FRAME_ESC (0333)
  25.     - FRAME_TRANS_END (0334)
  26.     - FRAME_TRANS_ESC (0335)
  27. The END character denotes the end of an IP packet.  The ESC character is used
  28. with TRANS_END and TRANS_ESC to circumvent potential occurrences of END or ESC
  29. within a packet.  If the END character is to be embedded, SLIP sends
  30. "ESC TRANS_END" to avoid confusion between a SLIP-specific END and actual
  31. data whose value is END.  If the ESC character is to be embedded, then
  32. SLIP sends "ESC TRANS_ESC" to avoid confusion.  (Note that the SLIP ESC is
  33. not the same as the ASCII ESC.)
  34. On the receiving side of the connection, SLIP uses the opposite actions to
  35. decode the SLIP packets.  Whenever an END character is received, SLIP
  36. assumes a full packet has been received and sends on.
  37. This driver has an MTU of 1006 bytes.  If the host is using a real SLIP
  38. driver with a smaller MTU, then you will need to lower the definition
  39. of WDB_MTU in configAll.h so that the host and target MTU match.
  40. If you are not using a SLIP driver on the host, but instead are using
  41. the target server's wdbserial backend to connect to the agent, then you do not
  42. need to worry about incompatabilities between the host and target MTUs.
  43. INTERNAL
  44. The END character is also sent at the begining of a packet. Although
  45. this is not part of the SLIP spec, it helps remove any "noise characters"
  46. that may have accumulated.
  47. Only a single input packet can arrive at a time. Once that packet has
  48. arrived, the input buffer is marked "locked", and any further
  49. characters received are dropped.  When the buffer is finally read
  50. by the agent, then it is marked "unlocked" again.
  51. */
  52. #include "string.h"
  53. #include "errno.h"
  54. #include "sioLib.h"
  55. #include "intLib.h"
  56. #include "wdb/wdbMbufLib.h"
  57. #include "drv/wdb/wdbSlipPktDrv.h"
  58. #if 0
  59. /*
  60.  * SLMTU is now a hard limit on input packet size.
  61.  * SLMTU must be <= MCLBYTES - sizeof(struct ifnet *).
  62.  */
  63. #define SLMTU           1006    /* be compatible with BSD 4.3 SLIP */
  64. #endif
  65. /* SLIP protocol characters */
  66. #define FRAME_END          (char)0300 /* Frame End */
  67. #define FRAME_ESCAPE       (char)0333 /* Frame Esc */
  68. #define TRANS_FRAME_END    (char)0334 /* transposed frame end */
  69. #define TRANS_FRAME_ESCAPE (char)0335 /* transposed frame esc */
  70. /* states of the input/ouput buffers (bitwise or'ed together) */
  71. #define STATE_BUSY 1 /* I/O is being performed */
  72. #define STATE_ESC 2 /* in the middle of a SLIP escape seq */
  73. #define STATE_START 4 /* output just started */
  74. /* some handy macros */
  75. #define RESET_INPUT(pPktDev) {pPktDev->inBufPtr = pPktDev->inBufBase; 
  76.  pPktDev->inputState = 0;}
  77. /* forward declarations */
  78. static STATUS wdbCharRcv (void *pPktDev, char thisChar);
  79. static STATUS wdbCharTx  (void *pPktDev, char *thisChar);
  80. static STATUS wdbPktPoll (void *pPktDev);
  81. static STATUS wdbPktTx   (void *pPktDev, struct mbuf *pMbuf);
  82. static void wdbPktFree (void *pPktDev);
  83. static STATUS wdbPktModeSet (void *pPktDev, uint_t newMode);
  84. static STATUS mbufChainCharGet (struct mbuf *, int, char *);
  85. static void mbufChainFree  (struct mbuf *);
  86. /******************************************************************************
  87. *
  88. * wdbPktResetOutput - reset the output packet state machine
  89. */ 
  90. static void wdbPktResetOutput
  91.     (
  92.     WDB_SLIP_PKT_DEV * pPktDev
  93.     )
  94.     {
  95.     struct mbuf * pMbuf;
  96.     pPktDev->outputIx  = 0;
  97.     pPktDev->outputState = 0;
  98.     while (pPktDev->pMbuf != NULL)
  99. {
  100. pMbuf = pPktDev->pMbuf->m_act;
  101. mbufChainFree (pPktDev->pMbuf);
  102. pPktDev->pMbuf = pMbuf;
  103. }
  104.     }
  105. /******************************************************************************
  106. *
  107. * wdbSlipPktDevInit - initialize a SLIP packet device for a WDB agent
  108. *
  109. * This routine initializes a SLIP packet device on one of the BSP's
  110. * serial channels.  It is typically called from usrWdb.c when the WDB
  111. * agent's lightweight SLIP communication path is selected.
  112. *
  113. * RETURNS: N/A
  114. */
  115. void wdbSlipPktDevInit
  116.     (
  117.     WDB_SLIP_PKT_DEV *pPktDev, /* SLIP packetizer device */
  118.     SIO_CHAN * pSioChan, /* underlying serial channel */
  119.     void (*stackRcv)() /* callback when a packet arrives */
  120.     )
  121.     {
  122.     pPktDev->wdbDrvIf.mode = WDB_COMM_MODE_POLL | WDB_COMM_MODE_INT;
  123.     pPktDev->wdbDrvIf.mtu = SLMTU;
  124.     pPktDev->wdbDrvIf.stackRcv = stackRcv;
  125.     pPktDev->wdbDrvIf.devId = (WDB_SLIP_PKT_DEV *)pPktDev;
  126.     pPktDev->wdbDrvIf.pollRtn = wdbPktPoll;
  127.     pPktDev->wdbDrvIf.pktTxRtn  = wdbPktTx;
  128.     pPktDev->wdbDrvIf.modeSetRtn = wdbPktModeSet;
  129.     pPktDev->pSioChan  = pSioChan;
  130.     pPktDev->inBufEnd = pPktDev->inBufBase + SLMTU;
  131.     pPktDev->pMbuf = 0;
  132.     sioCallbackInstall (pSioChan, SIO_CALLBACK_GET_TX_CHAR,
  133. (FUNCPTR) wdbCharTx, (void *)pPktDev);
  134.     sioCallbackInstall (pSioChan, SIO_CALLBACK_PUT_RCV_CHAR,
  135. (FUNCPTR) wdbCharRcv, (void *)pPktDev);
  136.     wdbPktModeSet (pPktDev, WDB_COMM_MODE_INT);
  137.     }
  138. /******************************************************************************
  139. *
  140. * wdbCharRcv - input a character
  141. *
  142. * This routine is called by the driver's input ISR (or poll routine) to
  143. * give the next character for the input packet.
  144. * If this is the "FRAME_END" character, then a whole packet has arrived,
  145. * and we call the "pktRcvRtn" routine to hand off the packet.
  146. *
  147. * RETURNS: OK, or ERROR if input is locked or the input buffer overflows.
  148. */
  149. static STATUS wdbCharRcv
  150.     (
  151.     void * pDev,
  152.     char  thisChar
  153.     )
  154.     {
  155.     WDB_SLIP_PKT_DEV * pPktDev = (WDB_SLIP_PKT_DEV *)pDev;
  156.     /* input buffer already in use by another packet - just return */
  157.     if (pPktDev->inputState & STATE_BUSY)
  158. {
  159. return (ERROR);
  160. }
  161.     switch (thisChar)
  162. {
  163. case FRAME_END:
  164.     /* don't process zero byte packets */
  165.     if (pPktDev->inBufPtr == pPktDev->inBufBase)
  166. {
  167. RESET_INPUT(pPktDev);
  168. return (OK);
  169. }
  170.     else /* hand off the packet */
  171. {
  172. /* grab an mbuf and use it as a cluster pointer */
  173. struct mbuf * pMbuf = wdbMbufAlloc();
  174. if (pMbuf == NULL)
  175.     {
  176.     RESET_INPUT(pPktDev);
  177.     return (ERROR);
  178.     }
  179. wdbMbufClusterInit (pMbuf, pPktDev->inBufBase,
  180. pPktDev->inBufPtr - pPktDev->inBufBase,
  181. (int (*)())wdbPktFree, (int)pPktDev);
  182. pPktDev->inputState |= STATE_BUSY;
  183. (*pPktDev->wdbDrvIf.stackRcv) (pMbuf);
  184. return (OK);
  185. }
  186. case FRAME_ESCAPE:
  187.     pPktDev->inputState |= STATE_ESC;
  188.     return (OK);
  189. default:
  190.     if (pPktDev->inputState & STATE_ESC)
  191. {
  192. pPktDev->inputState &= (~STATE_ESC);
  193. switch (thisChar)
  194.     {
  195.     case TRANS_FRAME_ESCAPE:
  196. thisChar = FRAME_ESCAPE;
  197. break;
  198.     case TRANS_FRAME_END:
  199. thisChar = FRAME_END;
  200. break;
  201.     default:
  202. return (ERROR);
  203.     }
  204. }
  205.     /* If overflow, reset the input buffer */
  206.     if (pPktDev->inBufPtr >= pPktDev->inBufEnd)
  207. {
  208. RESET_INPUT(pPktDev);
  209. return (ERROR);
  210. }
  211.     /* put the character in the input buffer */
  212.     *pPktDev->inBufPtr = thisChar;
  213.     pPktDev->inBufPtr++;
  214.     break;
  215. }
  216.     return (OK);
  217.     }
  218. /******************************************************************************
  219. *
  220. * wdbCharTx - transmit a character
  221. *
  222. * This routine is called by a driver's output ISR to get the next character
  223. * for transmition.
  224. *
  225. * RETURNS: OK, or ERROR if there are no more characters in the buffer.
  226. */
  227. static STATUS wdbCharTx
  228.     (
  229.     void * pDev,
  230.     caddr_t thisChar
  231.     )
  232.     {
  233.     WDB_SLIP_PKT_DEV * pPktDev = (WDB_SLIP_PKT_DEV *)pDev;
  234.     /* Return ERROR if there are no characters left to output */
  235.     if (!(pPktDev->outputState & STATE_BUSY))
  236. {
  237. return (ERROR);
  238. }
  239.     /* transmit a FRAME_END at the end of a packet */
  240.     if (mbufChainCharGet (pPktDev->pMbuf, pPktDev->outputIx, thisChar) == ERROR)
  241. {
  242. struct mbuf * pNextMbuf = pPktDev->pMbuf->m_act;
  243. *thisChar = FRAME_END; /* output end-of-frame */
  244. mbufChainFree (pPktDev->pMbuf); /* free the mbuf chain */
  245. pPktDev->pMbuf = pNextMbuf; /* queue up the next chain */
  246. pPktDev->outputIx = 0;
  247. pPktDev->outputState = STATE_START | STATE_BUSY;
  248. if (pNextMbuf == NULL) /* reset if no more packets */
  249.     wdbPktResetOutput(pPktDev);
  250. }
  251.     /* transmit a FRAME_END at the start of a packet */
  252.     else if (pPktDev->outputState & STATE_START)
  253. {
  254. *thisChar = FRAME_END;
  255. pPktDev->outputState &= ~STATE_START;
  256. }
  257.     /* transpose the character if we are in the middle of an escape sequence */
  258.     else if (pPktDev->outputState & STATE_ESC)
  259. {
  260. pPktDev->outputState &= (~STATE_ESC);
  261. switch (*thisChar)
  262.     {
  263.     case FRAME_END:
  264. *thisChar = TRANS_FRAME_END;
  265. break;
  266.     case FRAME_ESCAPE:
  267. *thisChar = TRANS_FRAME_ESCAPE;
  268. break;
  269.     default: /* this can't happen! */
  270. wdbPktResetOutput (pPktDev);
  271. return (ERROR);
  272. }
  273. pPktDev->outputIx++;
  274. }
  275.     /* else output the next character in the buffer */
  276.     else switch (*thisChar)
  277. {
  278. case FRAME_END:
  279. case FRAME_ESCAPE:
  280.     *thisChar = FRAME_ESCAPE;
  281.     pPktDev->outputState |= STATE_ESC;
  282.     break;
  283. default:
  284.     pPktDev->outputIx++;
  285.     break;
  286. }
  287.     return (OK);
  288.     }
  289. /******************************************************************************
  290. *
  291. * wdbPktTx - transmit a packet
  292. *
  293. * This routine can only be called by the WDB agent.
  294. *
  295. * RETURNS: OK, or ERROR if a packet is currently being transmitted, or
  296. * the packet is too large to send.
  297. */
  298. static STATUS wdbPktTx
  299.     (
  300.     void * pDev,
  301.     struct mbuf * pMbuf
  302.     )
  303.     {
  304.     WDB_SLIP_PKT_DEV *pPktDev = pDev;
  305.     int  lockKey;
  306.     /* if we are in polled mode, transmit the packet in a loop */
  307.     if (pPktDev->mode == WDB_COMM_MODE_POLL)
  308. {
  309. char thisChar;
  310. pPktDev->outputState = STATE_BUSY | STATE_START;
  311. pPktDev->pMbuf      = pMbuf;
  312. pPktDev->outputIx    = 0;
  313. while (wdbCharTx (pPktDev, &thisChar) != ERROR)
  314.     {
  315.     while (sioPollOutput (pPktDev->pSioChan, thisChar) == EAGAIN)
  316. ;
  317.     }
  318. return (OK);
  319. }
  320.     lockKey = intLock();
  321.     /* if no mbufs are queued for output, queue this one and start trasnmit */
  322.     if (pPktDev->pMbuf == NULL)
  323. {
  324. pPktDev->outputState = STATE_BUSY | STATE_START;
  325. pPktDev->pMbuf      = pMbuf;
  326. pPktDev->outputIx    = 0;
  327. sioTxStartup (pPktDev->pSioChan);
  328. intUnlock (lockKey);
  329. return (OK);
  330. }
  331.     /* queue up to one packet - no more */
  332.     if (pPktDev->pMbuf->m_act == NULL)
  333. {
  334. pPktDev->pMbuf->m_act = pMbuf;
  335. intUnlock (lockKey);
  336. return (OK);
  337. }
  338.     intUnlock (lockKey);
  339.     mbufChainFree (pMbuf);
  340.     return (ERROR);
  341.     }
  342. /******************************************************************************
  343. *
  344. * wdbPktFree - free the input buffer
  345. *
  346. * This routine is called after the agent has read in the packet to indicate
  347. * that the input buffer can be used again to receive a new packet.
  348. */
  349. static void wdbPktFree
  350.     (
  351.     void * pDev
  352.     )
  353.     {
  354.     WDB_SLIP_PKT_DEV * pPktDev = pDev;
  355.     RESET_INPUT(pPktDev);
  356.     }
  357. /******************************************************************************
  358. *
  359. * wdbPktModeSet - set the communications mode to INT or POLL
  360. */
  361. static STATUS wdbPktModeSet
  362.     (
  363.     void * pDev,
  364.     uint_t newMode
  365.     )
  366.     {
  367.     u_int   sioMode;
  368.     WDB_SLIP_PKT_DEV * pPktDev = pDev;
  369.     RESET_INPUT  (pPktDev);
  370.     wdbPktResetOutput (pPktDev);
  371.     if (newMode == WDB_COMM_MODE_INT)
  372. sioMode = SIO_MODE_INT;
  373.     else if (newMode == WDB_COMM_MODE_POLL)
  374. sioMode = SIO_MODE_POLL;
  375.     else
  376. return (ERROR);
  377.     if (sioIoctl (pPktDev->pSioChan, SIO_MODE_SET, (void *)sioMode) == OK)
  378. {
  379. pPktDev->mode = newMode;
  380. return (OK);
  381. }
  382.     return (ERROR);
  383.     }
  384. /******************************************************************************
  385. *
  386. * wdbPktPoll - poll for a packet
  387. *
  388. * RETURNS: OK if a character has arrived; otherwise ERROR.
  389. */ 
  390. static STATUS wdbPktPoll
  391.     (
  392.     void * pDev
  393.     )
  394.     {
  395.     char thisChar;
  396.     WDB_SLIP_PKT_DEV * pPktDev = pDev;
  397.     if (sioPollInput (pPktDev->pSioChan, &thisChar) == OK)
  398. {
  399. wdbCharRcv ((void *)pPktDev, thisChar);
  400. return (OK);
  401. }
  402.     return (ERROR);
  403.     }
  404. /******************************************************************************
  405. *
  406. * mbufChainFree - free a chain of mbufs
  407. */ 
  408. static void mbufChainFree
  409.     (
  410.     struct mbuf * pMbuf /* mbuf chain to free */
  411.     )
  412.     {
  413.     struct mbuf * pNextMbuf;
  414.     while (pMbuf != NULL)
  415. {
  416. pNextMbuf = pMbuf->m_next;
  417. wdbMbufFree (pMbuf);
  418. pMbuf = pNextMbuf;
  419. }
  420.     }
  421. /******************************************************************************
  422. *
  423. * mbufChainCharGet - get a character from an mbuf chain
  424. *
  425. * This routine makes a chain of mbufs apprear as a contingurous block
  426. * of memory, and fetches character number <charNum>.
  427. *
  428. * RETURNS: OK, or ERROR if the <charNum> is outside the buffer range.
  429. */ 
  430. static STATUS mbufChainCharGet
  431.     (
  432.     struct mbuf * pMbuf, /* mbuf chain */
  433.     int   charNum, /* character index */
  434.     char *   pChar /* where to put character */
  435.     )
  436.     {
  437.     int bytesRead = 0;
  438.     struct mbuf * pThisMbuf;
  439.     if (charNum < 0)
  440. return (ERROR);
  441.     for (pThisMbuf = pMbuf; pThisMbuf != NULL; pThisMbuf = pThisMbuf->m_next)
  442. {
  443. if (bytesRead + pThisMbuf->m_len > charNum)
  444.     {
  445.     *pChar = *(mtod (pThisMbuf, char *) + charNum - bytesRead);
  446.     return (OK);
  447.     }
  448. bytesRead += pThisMbuf->m_len;
  449. }
  450.     return (ERROR);
  451.     }