icmpLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:16k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* icmpLib.c - VxWorks library for ICMP routines */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01q,29jan02,vvv  fixed icmpMaskGet to use unfreed mblk when retransmitting
  8.  (SPR #72867)
  9. 01p,15oct01,rae  merge from truestack ver 01t, base 01o (no ether hooks)
  10. 01o,17mar99,spm  added support for identical unit numbers (SPR #20913)
  11. 01n,17nov98,n_s  fixed icmpMaskGet for non-END devices. spr 23005.
  12. 01m,08dec97,gnn  END code review fixes.
  13. 01l,05oct97,vin  added header file ip_var.h
  14. 01k,03oct97,gnn  removed necessity for endDriver global
  15. 01j,25sep97,gnn  SENS beta feedback fixes
  16. 01i,12aug97,gnn  changes necessitated by MUX/END update.
  17. 01h,20jan97,vin  added icmpLibInit for scaling.
  18. 01g,17dec96,gnn  added code to handle the new etherHooks and END stuff.
  19. 01f,05aug94,dzb  set IP address of interface in arpcom struct (SPR #2706).
  20. 01e,30jun92,jmm  moved checksum() to vxLib
  21. 01d,11jun92,elh  changed parameters to ipHeaderCreate.
  22. 01c,26may92,rrr  the tree shuffle
  23.   -changed includes to have absolute path from h/
  24. 01b,16apr92,elh  moved routines shared by bootpLib here.
  25. 01a,11mar91,elh  written.
  26. */
  27. /*
  28. DESCRIPTION
  29. icmpLib contains routines that use ICMP.  icmpMaskGet is currently the only 
  30. routine in this library.  icmpMaskGet generates and sends an ICMP address
  31. mask request to obtain the subnet mask of the network.
  32. The routine icmpLibInit() is responsible for configuring the ICMP protocol
  33. with various parameters.
  34. To use this feature, include the following component:
  35. INCLUDE_ICMP
  36. */
  37. /* includes */
  38. #include "vxWorks.h"
  39. #include "net/protosw.h"
  40. #include "net/domain.h"
  41. #include "netinet/in.h"
  42. #include "netinet/in_systm.h"
  43. #include "netinet/in_pcb.h"
  44. #include "netinet/ip_var.h"
  45. #include "netinet/ip.h"
  46. #include "netinet/ip_icmp.h"
  47. #include "netLib.h"
  48. #include "errno.h"
  49. #include "icmpLib.h"
  50. #include "sysLib.h"
  51. #include "string.h"
  52. #include "taskLib.h"
  53. #include "stdio.h"
  54. #include "tickLib.h"
  55. #include "inetLib.h"
  56. #include "vxLib.h"
  57. #include "end.h"
  58. #include "ipProto.h"
  59. #include "muxLib.h"
  60. #include "muxTkLib.h"
  61. #include "private/muxLibP.h"
  62. #ifdef VIRTUAL_STACK
  63. #include "netinet/vsLib.h"
  64. #endif
  65. /* externs */
  66. #ifndef VIRTUAL_STACK
  67. IMPORT int _protoSwIndex;
  68. IMPORT struct protosw  inetsw [IP_PROTO_NUM_MAX]; 
  69. IMPORT int icmpmaskrepl;
  70. #endif
  71. /* defines */
  72. #define ICMP_REXMT_DELAY 1 /* retransmit delay (secs) */
  73. #define ICMP_MAX_SEND 2 /* maximum requests */
  74. /* locals */
  75. #ifndef VIRTUAL_STACK
  76. LOCAL BOOL       maskReplyReceived = FALSE; /* recv mask reply  */
  77. LOCAL int       icmpMask = 0; /* replied icmp mask    */
  78. LOCAL struct
  79.     {
  80.     struct ip ih; /* IP header */
  81.     struct icmp icmph; /* ICMP header */
  82.     } icmpMsg;
  83. #endif
  84. LOCAL BOOL icmpMaskEndInput (void * pCookie, long type, M_BLK_ID pBuff,
  85.      LL_HDR_INFO * pLinkHdrInfo, void * pSpare);
  86. LOCAL BOOL icmpMaskNptInput (void * callbackId ,long type, M_BLK_ID pBuff,
  87.      void * pSpareData);
  88. /* forward declarations */
  89. IMPORT int in_broadcast ();
  90. /******************************************************************************
  91.  *
  92.  * icmpLibInit - initialize icmpLib 
  93.  *
  94.  * This routine initializes icmpLib.
  95.  *
  96.  * RETURNS: OK if successful, otherwise ERROR.
  97.  *
  98.  * NOMANUAL
  99.  */
  100. STATUS icmpLibInit 
  101.     (
  102.     ICMP_CFG_PARAMS *  icmpCfg /* icmp configuration parameters */
  103.     )
  104.     {
  105.     FAST struct protosw * pProtoSwitch; 
  106.     if (_protoSwIndex >= sizeof(inetsw)/sizeof(inetsw[0]))
  107. return (ERROR) ;
  108.     pProtoSwitch = &inetsw [_protoSwIndex]; 
  109.     if (pProtoSwitch->pr_domain != NULL)
  110. return (OK);  /* already initialized */
  111.     pProtoSwitch->pr_type    =  SOCK_RAW;
  112.     pProtoSwitch->pr_domain    =  &inetdomain;
  113.     pProtoSwitch->pr_protocol   =  IPPROTO_ICMP;
  114.     pProtoSwitch->pr_flags =  PR_ATOMIC | PR_ADDR;
  115.     pProtoSwitch->pr_input =  icmp_input;
  116.     pProtoSwitch->pr_output =  rip_output;
  117.     pProtoSwitch->pr_ctlinput =  0;
  118.     pProtoSwitch->pr_ctloutput =  rip_ctloutput;
  119.     pProtoSwitch->pr_usrreq =  rip_usrreq;
  120.     pProtoSwitch->pr_init =  icmp_init;
  121.     pProtoSwitch->pr_fasttimo =  0;
  122.     pProtoSwitch->pr_slowtimo =  0;
  123.     pProtoSwitch->pr_drain =  0;
  124.     pProtoSwitch->pr_sysctl =  0;
  125.     _protoSwIndex++; 
  126.     /* initialize icmp configuration parameters */
  127.     icmpmaskrepl = (icmpCfg->icmpCfgFlags & ICMP_DO_MASK_REPLY) ? TRUE : FALSE;
  128.     return (OK); 
  129.     }
  130. /******************************************************************************
  131. *
  132. * icmpMaskGet - obtain the subnet mask 
  133. *
  134. * icmpMask broadcasts an ICMP Address Mask Request over the network
  135. * interface specified by <ifName> to obtain the subnet mask of that
  136. * network.
  137. * This interface must have been previously attached and initialized.
  138. *
  139. * <src> specifies the source IP address, which must be set.
  140. *
  141. * <dst> specifies destination of ICMP request.  A NULL value for
  142. * <dst> results in the request being broadcasted.  However, because
  143. * ICMP mask request/reply behaves differently on each ICMP
  144. * implementation, thus the ICMP mask reply by broadcasting ICMP mask
  145. * request is not guranteed.
  146. *
  147. * The subnet mask gets returned in <pSubnet> in host byte order.
  148. *
  149. * NOTE: This routine can be used for END or NPT driver only.
  150. *
  151. * RETURNS: OK if successful, otherwise ERROR.
  152. *
  153. * ERRNO
  154. *   S_icmpLib_NO_BROADCAST
  155. *   S_icmpLib_INVALID_INTERFACE
  156. *   S_icmpLib_TIMEOUT
  157. *
  158. */
  159. STATUS icmpMaskGet
  160.     (
  161.     char * ifName, /* network interface name */
  162.     char *  src, /* optional src address */
  163.     char * dst, /* optional dst address */
  164.     int  * pSubnet /* return subnet mask  */
  165.     )
  166.     {
  167.     FAST int  retransmitSecs; /* retransmit time  */
  168.     FAST int tickCount;
  169.     int ix; /* index  */
  170.     struct in_addr srcAddr; /* source address  */
  171.     struct sockaddr_in dstAddr; /* destination address */
  172.     struct ifnet * pIf; /* pointer to interface */
  173.     IP_DRV_CTRL * pDrvCtrl;
  174.     struct mbuf * pMbuf;
  175.     void * pCookie = NULL;
  176.     FUNCPTR pBoundRtn = NULL;
  177.     int  level;
  178.     int  result;
  179.     /* reset flags */
  180.     maskReplyReceived = FALSE;
  181.     icmpMask = 0;
  182.     /* verify arguments and the I/F if attached END/NPT */
  183.     if (pSubnet == NULL                                      ||
  184.         (pIf = ifunit (ifName)) == NULL                      ||
  185. pIf->if_output == NULL                               ||
  186. (endFindByName (pIf->if_name, pIf->if_unit)) == NULL ||
  187. (pDrvCtrl = (IP_DRV_CTRL *)pIf->pCookie) == NULL)
  188. {
  189. errno = S_icmpLib_INVALID_INTERFACE;
  190. goto icmpMaskGetError;
  191. }
  192.     /* build IP address */
  193.     if (src == NULL)
  194.         {
  195.         errno = S_icmpLib_INVALID_ARGUMENT;
  196. goto icmpMaskGetError;
  197.         }
  198.     /* bind IP address to ac */
  199.     srcAddr.s_addr = inet_addr (src);
  200.     ((struct arpcom *) pIf)->ac_ipaddr.s_addr = srcAddr.s_addr;
  201.     bzero ((char *)&dstAddr, sizeof (struct sockaddr_in));
  202.     if (dst == NULL)
  203. {
  204.         if ((pIf->if_flags & IFF_BROADCAST) == 0)
  205.     {
  206.     errno = S_icmpLib_NO_BROADCAST; /* no broadcasts */
  207.     goto icmpMaskGetError;
  208.     }
  209. dstAddr.sin_addr.s_addr = htonl (INADDR_BROADCAST);
  210. }
  211.     else
  212. dstAddr.sin_addr.s_addr = inet_addr (dst);
  213.     dstAddr.sin_len = sizeof (struct sockaddr_in);
  214.     dstAddr.sin_family = AF_INET;
  215.     pIf->if_flags |= (IFF_UP | IFF_RUNNING);
  216.     retransmitSecs = ICMP_REXMT_DELAY;  /* set delay value */
  217.     maskReplyReceived = FALSE;
  218.     /* fill in ICMP message and put it in an mbuf */
  219.     bzero ((char *) &icmpMsg, sizeof (icmpMsg));
  220.     icmpMsg.icmph.icmp_type  = ICMP_MASKREQ;
  221.     icmpMsg.icmph.icmp_code  = 0;
  222.     icmpMsg.icmph.icmp_cksum = 0;
  223.     icmpMsg.icmph.icmp_cksum = checksum ((u_short *) &icmpMsg.icmph, 
  224.  ICMP_MASKLEN);
  225.     ipHeaderCreate (IPPROTO_ICMP, &srcAddr, &dstAddr.sin_addr,
  226.     &icmpMsg.ih, sizeof (struct ip) + ICMP_MASKLEN);
  227.     /* bind icmpMaskHook as SNARF */
  228.     if (muxTkDrvCheck (pIf->if_name))
  229. {
  230. pCookie = muxTkBind (pIf->if_name, pIf->if_unit,
  231.      (FUNCPTR)icmpMaskNptInput, NULL, NULL, NULL,
  232.      MUX_PROTO_SNARF, "ICMP HOOK NPT",
  233.      pDrvCtrl, NULL, NULL);
  234. pBoundRtn = (FUNCPTR) icmpMaskNptInput;
  235. }
  236.     else
  237. {
  238. pCookie = muxBind (pIf->if_name, pIf->if_unit,
  239.    (FUNCPTR)icmpMaskEndInput, NULL, NULL, NULL,
  240.    MUX_PROTO_SNARF, "ICMP HOOK END",
  241.    pDrvCtrl);
  242. pBoundRtn = (FUNCPTR) icmpMaskEndInput;
  243. }
  244.     if (pCookie == NULL)
  245. goto icmpMaskGetError;
  246.     for (ix = 0; ix < ICMP_MAX_SEND;  ix++)
  247. {
  248.         if ((pMbuf = bcopy_to_mbufs ((u_char *) &icmpMsg, sizeof (icmpMsg),
  249.      0, pIf, NONE)) == NULL)
  250.             goto icmpMaskGetError;
  251.         if (dst == NULL)    /* if broadcasting */
  252.     pMbuf->mBlkHdr.mFlags |= M_BCAST;
  253. /* send message */
  254.         level = splnet ();
  255. result = (* pIf->if_output) ( (struct ifnet *)&pDrvCtrl->idr, pMbuf,
  256.              (struct sockaddr *)&dstAddr, NULL);
  257.         splx (level);
  258. if (result)
  259.     goto icmpMaskGetError;
  260. /* wait for reply */
  261. tickCount = retransmitSecs * sysClkRateGet ();
  262. while (tickCount-- > 0)
  263.     {
  264.     if (maskReplyReceived)
  265. {
  266. *pSubnet = icmpMask;
  267. muxUnbind (pCookie, MUX_PROTO_SNARF, pBoundRtn);
  268. return (OK);
  269. }
  270.     taskDelay (1);
  271.     }
  272. }
  273.     errno = S_icmpLib_TIMEOUT;
  274.     icmpMaskGetError:
  275.         if (pCookie != NULL && pBoundRtn != NULL)
  276.     muxUnbind (pCookie, MUX_PROTO_SNARF, pBoundRtn);
  277.     return (ERROR); /* no subnet */
  278.     }
  279. /******************************************************************************
  280. *
  281. * icmpMaskEndInput - END version of input filter for ICMP Mask Reply
  282. *
  283. * This routine filters out the ICMP Address Mask Reply message from
  284. * incoming link frame.  It is bound to MUX by muxBind as a SNARF
  285. * protocol.
  286. *
  287. * RETURNS:
  288. * TRUE indicating the packet was consumed by this routine and no further
  289. * processing needs to be done.
  290. * FALSE indicating the packet was not consumed by this routine and
  291. * further processing needs to be done.
  292. */
  293. LOCAL BOOL icmpMaskEndInput
  294.     (
  295.     void *              pCookie,        /* device identifier from driver */
  296.     long                type,           /* Protocol type.  */
  297.     M_BLK_ID            pMblk,          /* The whole packet. */
  298.     LL_HDR_INFO *       pLinkHdrInfo,   /* pointer to link level header info */
  299.     void *              pSpare          /* pointer to IP_DRV_CTRL */
  300.     )
  301.     {
  302.     IP_DRV_CTRL * pDrvCtrl = (IP_DRV_CTRL *) pSpare;
  303.     struct ifnet *      pIf = NULL;
  304.     struct icmp * pIcmp;
  305.     M_BLK_ID            pMblkOrig;
  306.     M_BLK tmpM;
  307.     /* already got a reply, or unknown device */
  308.     if (maskReplyReceived || pDrvCtrl == NULL || pMblk == NULL ||
  309. (pIf = (struct ifnet *)&pDrvCtrl->idr) == NULL)
  310. return (FALSE);
  311.     if ((pIf->if_flags & IFF_UP) == 0)
  312.         {
  313.         pIf->if_ierrors++;
  314.         return (FALSE);
  315.         }
  316.     /* Make sure the entire Link Hdr is in the first M_BLK */
  317.  
  318.     pMblkOrig = pMblk;
  319.     if (pMblk->mBlkHdr.mLen < pLinkHdrInfo->dataOffset
  320.         && (pMblk = m_pullup (pMblk, pLinkHdrInfo->dataOffset)) == NULL)
  321.         {
  322.         pMblk = pMblkOrig;
  323.         return (FALSE);
  324. }
  325.  
  326.     /* point to the ip header, and adjust the length */
  327.     bzero ((char *)&tmpM, sizeof (M_BLK));
  328.     bcopy ((char *)pMblk, (char *)&tmpM, sizeof (M_BLK));
  329.     tmpM.mBlkHdr.mData        += pLinkHdrInfo->dataOffset;
  330.     tmpM.mBlkHdr.mLen         -= pLinkHdrInfo->dataOffset;
  331.     tmpM.mBlkPktHdr.len       -= pLinkHdrInfo->dataOffset;
  332.     tmpM.mBlkPktHdr.rcvif     = &pDrvCtrl->idr.ac_if;
  333.  
  334.     /* get and verify icmp */
  335.     pIcmp = (struct icmp *)
  336.     ipHeaderVerify ((struct ip *) tmpM.mBlkHdr.mData,
  337.     tmpM.mBlkHdr.mLen, IPPROTO_ICMP);
  338.     if ((pIcmp == NULL) ||
  339.         (checksum ((u_short *) pIcmp, ICMP_MASKLEN) != 0) ||
  340.         (pIcmp->icmp_type != ICMP_MASKREPLY))
  341.         return (FALSE);
  342.     pIf->if_ipackets++;          /* bump statistic */
  343.     pIf->if_lastchange = tickGet();
  344.     pIf->if_ibytes += pMblk->mBlkPktHdr.len;
  345.   
  346.     maskReplyReceived = TRUE;
  347.     icmpMask = ntohl (pIcmp->icmp_mask);
  348.     netMblkClChainFree (pMblk);
  349.     return (TRUE);
  350.     }
  351. /******************************************************************************
  352. *
  353. * icmpMaskNptInput - NPT version of input filter for ICMP Mask Reply
  354. *
  355. * This routine filters out the ICMP Address Mask Reply message from
  356. * incoming link frame.  It is bound to MUX by muxBind as a SNARF
  357. * protocol.
  358. *
  359. * RETURNS:
  360. * TRUE indicating the packet was consumed by this routine and no further
  361. * processing needs to be done.
  362. * FALSE indicating the packet was not consumed by this routine and
  363. * further processing needs to be done.
  364. */
  365. LOCAL BOOL icmpMaskNptInput
  366.     (
  367.     void *    ipCallbackId,  /* Sent down in muxTkBind call. */
  368.     long      type,          /* Protocol type.  */
  369.     M_BLK_ID  pMblk,         /* The whole packet. */
  370.     void *    pSpareData     /* out of band data */
  371.     )
  372.     {
  373.     IP_DRV_CTRL * pDrvCtrl = (IP_DRV_CTRL *)ipCallbackId;
  374.     struct ifnet * pIf = NULL;
  375.     struct icmp * pIcmp;
  376.     M_BLK_ID            pMblkOrig;
  377.     M_BLK tmpM;
  378.     /* already got a reply, or unknown device */
  379.     if (maskReplyReceived || pDrvCtrl == NULL || pMblk == NULL ||
  380. (pIf = (struct ifnet *)&pDrvCtrl->idr) == NULL)
  381. return (FALSE);
  382.     if ((pIf->if_flags & IFF_UP) == 0)
  383.         {
  384.         pIf->if_ierrors++;
  385.         return (FALSE);
  386.         }
  387.     /* Make sure the entire interface header is in the first M_BLK */
  388.  
  389.     pMblkOrig = pMblk;
  390.     if (pMblk->mBlkHdr.mLen < pIf->if_hdrlen
  391.         && (pMblk = m_pullup (pMblk, pIf->if_hdrlen)) == NULL)
  392.         {
  393.         pMblk = pMblkOrig;
  394.         return (FALSE);
  395. }
  396.  
  397.     /* point to the network service header, and adjust the length */
  398.     bzero ((char *)&tmpM, sizeof (M_BLK));
  399.     bcopy ((char *)pMblk, (char *)&tmpM, sizeof (M_BLK));
  400.     tmpM.mBlkHdr.mData        += pIf->if_hdrlen;
  401.     tmpM.mBlkHdr.mLen         -= pIf->if_hdrlen;
  402.     tmpM.mBlkPktHdr.len       -= pIf->if_hdrlen;
  403.     tmpM.mBlkPktHdr.rcvif     = &pDrvCtrl->idr.ac_if;
  404.     /* get and verify icmp */
  405.     pIcmp = (struct icmp *)
  406.     ipHeaderVerify ((struct ip *) tmpM.mBlkHdr.mData,
  407.     tmpM.mBlkHdr.mLen, IPPROTO_ICMP);
  408.     if (pIcmp == NULL ||
  409.         (checksum ((u_short *) pIcmp, ICMP_MASKLEN) != 0) ||
  410.         (pIcmp->icmp_type != ICMP_MASKREPLY))
  411.         return (FALSE);
  412.     pIf->if_ipackets++;          /* bump statistic */
  413.     pIf->if_lastchange = tickGet();
  414.     pIf->if_ibytes += pMblk->mBlkPktHdr.len;
  415.   
  416.     maskReplyReceived = TRUE; 
  417.     icmpMask = ntohl (pIcmp->icmp_mask);
  418.     netMblkClChainFree (pMblk);
  419.     return (TRUE);
  420.     }
  421. /******************************************************************************
  422. *
  423. * ipHeaderCreate - create a simple IP header
  424. *
  425. * This generates a simple IP header (with no options) and checksums it.
  426. * <proto> specifies the protocol type. <pSrcAddr> and <pDstAddr> define
  427. * the source and destination internet addresses, respectively.  Both should
  428. * be specified in network byte order.  <pih> is a pointer to an internet
  429. * datagram whose length is <length>.
  430. *
  431. * RETURNS: N/A
  432. *
  433. * NOMANUAL
  434. */
  435. void ipHeaderCreate
  436.     (
  437.     int proto, /* protocol number */
  438.     struct in_addr * pSrcAddr, /* source ip address  */
  439.     struct in_addr * pDstAddr, /* dest ip address */
  440.     struct ip * pih, /* internet header  */
  441.     int length /* datagram size  */
  442.     )
  443.     {
  444.      /* fill in the IP header */
  445.     pih->ip_v = IPVERSION;
  446.     pih->ip_hl = (sizeof (struct ip) >> 2) & 0xf;  
  447.     pih->ip_len = htons ((u_short) length);
  448.     pih->ip_id = (u_short) (tickGet () & 0xffff);
  449.     pih->ip_ttl = MAXTTL;
  450.     pih->ip_p = (u_char) proto;
  451.     pih->ip_src.s_addr = pSrcAddr->s_addr;
  452.     pih->ip_dst.s_addr = pDstAddr->s_addr;
  453.     pih->ip_sum = 0; /* zero out the checksum while computing it */
  454.     pih->ip_sum = checksum ((u_short *) pih, (pih->ip_hl << 2));
  455.     }
  456. /*******************************************************************************
  457. *
  458. * ipHeaderVerify - simple IP header verification
  459. *
  460. * ipHeaderVerify performs simple IP header verification.  It does
  461. * sanity checks and verifies the checksum.  <pih> points to an internet
  462. * datagram of length <length>.  <proto> is the expected protocol.
  463. *
  464. * RETURNS: a pointer to the IP data, or NULL if not a valid IP datagram.
  465. *
  466. * NOMANUAL
  467. */
  468. u_char * ipHeaderVerify
  469.     (
  470.     struct ip * pih,  /* internet header */
  471.     int length, /* length of datagram  */
  472.     int proto   /* protocol */
  473.     )
  474.     {
  475.     FAST int options; /* options offset  */
  476.     /* if not minimum size, or right protocol bail */
  477.     if ((length < sizeof (struct ip)) || (pih->ip_p != (u_char) proto))
  478. return (NULL);
  479. /* verify checksum */
  480.     if (checksum ((u_short *) pih, (pih->ip_hl << 2)) != 0)
  481. return (NULL);
  482.     if ((pih->ip_v != IPVERSION) ||
  483. (ntohs ((u_short) pih->ip_off) & 0x3FFF))
  484. return (NULL);
  485. /* ip_hl is in words */
  486.     options = (pih->ip_hl << 2) - sizeof (struct ip);
  487.     return ((u_char *) pih + sizeof (struct ip) + options);
  488.     }