📄 icmplib.c
字号:
/* icmpLib.c - VxWorks library for ICMP routines *//* Copyright 1984 - 1999 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01o,17mar99,spm added support for identical unit numbers (SPR #20913)01n,17nov98,n_s fixed icmpMaskGet for non-END devices. spr 23005.01m,08dec97,gnn END code review fixes.01l,05oct97,vin added header file ip_var.h01k,03oct97,gnn removed necessity for endDriver global01j,25sep97,gnn SENS beta feedback fixes01i,12aug97,gnn changes necessitated by MUX/END update.01h,20jan97,vin added icmpLibInit for scaling.01g,17dec96,gnn added code to handle the new etherHooks and END stuff.01f,05aug94,dzb set IP address of interface in arpcom struct (SPR #2706).01e,30jun92,jmm moved checksum() to vxLib01d,11jun92,elh changed parameters to ipHeaderCreate.01c,26may92,rrr the tree shuffle -changed includes to have absolute path from h/01b,16apr92,elh moved routines shared by bootpLib here.01a,11mar91,elh written.*//*DESCRIPTIONicmpLib contains routines that use ICMP. icmpMaskGet is currently the only routine in this library. icmpMaskGet generates and sendsan ICMP address mask request to obtain the subnet mask of the network.It gets called during boot time to find the mask of the boot interface.The routine icmpLibInit() is responsible for configuring the ICMP protocolwith various parameters.*//* includes */#include "vxWorks.h"#include "net/protosw.h"#include "net/domain.h"#include "netinet/in.h"#include "netinet/in_systm.h"#include "netinet/in_pcb.h"#include "netinet/ip_var.h"#include "netinet/ip.h"#include "netinet/ip_icmp.h"#include "netLib.h"#include "etherLib.h"#include "errno.h"#include "icmpLib.h"#include "sysLib.h"#include "string.h"#include "taskLib.h"#include "stdio.h"#include "tickLib.h"#include "inetLib.h"#include "vxLib.h"#include "end.h"#include "ipProto.h"#include "muxLib.h"/* externs */IMPORT int _protoSwIndex;IMPORT struct protosw inetsw [IP_PROTO_NUM_MAX]; IMPORT int icmpmaskrepl;/* defines */#define ICMP_REXMT_DELAY 1 /* retransmit delay (secs) */#define ICMP_MAX_SEND 2 /* maximum requests *//* locals */LOCAL BOOL maskReplyReceived; /* recv mask reply */LOCAL char inputBuffer [ETHERMTU]; /* input buffer */LOCAL struct icmp *pIcmpReply; /* pointer to reply */LOCAL struct { struct ip ih; /* IP header */ struct icmp icmph; /* ICMP header */ } icmpMsg;/* forward declarations */LOCAL BOOL icmpMaskInputHook (struct ifnet * pIf, char * pBuffer, int length);extern in_broadcast ();STATUS icmpLibInit ( ICMP_CFG_PARAMS * icmpCfg /* icmp configuration parameters */ ) { FAST struct protosw * pProtoSwitch; if (_protoSwIndex >= sizeof(inetsw)/sizeof(inetsw[0])) return (ERROR) ; pProtoSwitch = &inetsw [_protoSwIndex]; if (pProtoSwitch->pr_domain != NULL) return (OK); /* already initialized */ pProtoSwitch->pr_type = SOCK_RAW; pProtoSwitch->pr_domain = &inetdomain; pProtoSwitch->pr_protocol = IPPROTO_ICMP; pProtoSwitch->pr_flags = PR_ATOMIC | PR_ADDR; pProtoSwitch->pr_input = icmp_input; pProtoSwitch->pr_output = rip_output; pProtoSwitch->pr_ctlinput = 0; pProtoSwitch->pr_ctloutput = rip_ctloutput; pProtoSwitch->pr_usrreq = rip_usrreq; pProtoSwitch->pr_init = icmp_init; pProtoSwitch->pr_fasttimo = 0; pProtoSwitch->pr_slowtimo = 0; pProtoSwitch->pr_drain = 0; pProtoSwitch->pr_sysctl = 0; _protoSwIndex++; /* initialize icmp configuration parameters */ icmpmaskrepl = (icmpCfg->icmpCfgFlags & ICMP_DO_MASK_REPLY) ? TRUE : FALSE; return (OK); }/******************************************************************************** icmpMaskGet - obtain the subnet mask ** icmpMask broadcasts an ICMP Address Mask Request over the network* interface specified by <ifName> to obtain the subnet mask of that network.* This interface, must have been previously attached, but not necessarily* initialized. <src> specifies the source IP address, which is required* if the interface has not already been initialized, and is optional* otherwise. A NULL value for <src> results in the reply being broadcasted.* <dst> specifies and optional destination. A NULL value for <dst> results* in the request being broadcasted.** The subnet mask gets returned in <pSubnet> in host byte order.** INTERNAL* icmpMaskGet uses etherhooks to access the network, because at boot* time the network is not initialized (it doesn't know its IP address).** RETURNS: OK if successful, otherwise ERROR.** ERRNO* S_icmpLib_NO_BROADCAST* S_icmpLib_INVALID_INTERFACE** NOMANUAL*/STATUS icmpMaskGet ( char * ifName, /* network interface name */ char * src, /* optional src address */ char * dst, /* optional dst address */ int * pSubnet /* return subnet mask */ ) { FAST int retransmitSecs; /* retransmit time */ FAST int tickCount; int ix; /* index */ struct in_addr srcAddr; /* source address */ struct in_addr dstAddr; /* destination address */ struct ifnet * pIf; /* pointer to interface */ END_OBJ * pEnd; if ((pIf = ifunit (ifName)) == NULL) { errno = S_icmpLib_INVALID_INTERFACE; return (ERROR); /* interface not attached */ } pEnd = endFindByName (pIf->if_name, pIf->if_unit); if (src == NULL) srcAddr.s_addr = htonl (INADDR_ANY); else /* bind IP address to ac */ { srcAddr.s_addr = inet_addr (src); ((struct arpcom *) pIf)->ac_ipaddr.s_addr = srcAddr.s_addr; } if (dst == NULL) { if ((pIf->if_flags & IFF_BROADCAST) == 0) { errno = S_icmpLib_NO_BROADCAST; return (ERROR); /* no broadcasts */ } dstAddr.s_addr = htonl (INADDR_BROADCAST); } else dstAddr.s_addr = inet_addr (dst); pIf->if_flags |= (IFF_UP | IFF_RUNNING); retransmitSecs = ICMP_REXMT_DELAY; /* set delay value */ maskReplyReceived = FALSE; /* fill in icmp message */ bzero ((char *) &icmpMsg, sizeof (icmpMsg)); icmpMsg.icmph.icmp_type = ICMP_MASKREQ; icmpMsg.icmph.icmp_code = 0; icmpMsg.icmph.icmp_cksum = 0; icmpMsg.icmph.icmp_cksum = checksum ((u_short *) &icmpMsg.icmph, ICMP_MASKLEN); ipHeaderCreate (IPPROTO_ICMP, &srcAddr, &dstAddr, &icmpMsg.ih, sizeof (struct ip) + ICMP_MASKLEN); if (pEnd) { etherInputHookAdd (icmpMaskInputHook, pIf->if_name, pIf->if_unit); } else { (void) etherInputHookAdd (icmpMaskInputHook, NULL, 0); } for (ix = 0; ix < ICMP_MAX_SEND; ix++) { /* send message */ if (etherSend (pIf, &icmpMsg.ih, sizeof (struct ip) + ICMP_MASKLEN) == ERROR) { if (pEnd) etherInputHookDelete (icmpMaskInputHook, pIf->if_name, pIf->if_unit); else etherInputHookDelete (icmpMaskInputHook); return (ERROR); } /* wait for reply */ tickCount = retransmitSecs * sysClkRateGet (); while (tickCount-- > 0) { if (maskReplyReceived) { if (pEnd) etherInputHookDelete (icmpMaskInputHook, pIf->if_name, pIf->if_unit); else etherInputHookDelete (icmpMaskInputHook); *pSubnet = ntohl (pIcmpReply->icmp_mask); return (OK); } taskDelay (1); } } if (pEnd) etherInputHookDelete (icmpMaskInputHook, pIf->if_name, pIf->if_unit); else etherInputHookDelete (icmpMaskInputHook); errno = S_icmpLib_TIMEOUT; return (ERROR); /* no subnet */ }/******************************************************************************** icmpMaskInputHook - input hook to filter ICMP Address Mask Reply** This routine filters out the ICMP Address Mask Reply message from incoming* ethernet traffic. This function is called by the network interface* driver when a new input frame comes in from the network. It is* hooked into the driver via etherHook routines.** RETURNS:* TRUE indicating the ethernet frame is handled by this routine and* no further processing need be done by the network interface driver.* FALSE indicating the ethernet frame is to be handled by the network* interface driver.*/LOCAL BOOL icmpMaskInputHook ( struct ifnet * pIf, /* network interface */ FAST char * pBuffer, /* input data frame */ FAST int length /* input data length */ ) { struct ether_header * pEh; /* ethernet header */ int bufLen; /* buffer length */ if (maskReplyReceived) /* already got a reply */ return (FALSE); pEh = (struct ether_header *) pBuffer; if ((length <= SIZEOF_ETHERHEADER) || (ntohs (pEh->ether_type) != ETHERTYPE_IP)) return (FALSE); /* copy into local buffer */ bufLen = length - SIZEOF_ETHERHEADER; bcopyBytes ((char *) ((u_char *) pBuffer + SIZEOF_ETHERHEADER), inputBuffer, bufLen); pIcmpReply = (struct icmp *) ipHeaderVerify ((struct ip *) inputBuffer, bufLen, IPPROTO_ICMP); if ((pIcmpReply == NULL) || (checksum ((u_short *) pIcmpReply, ICMP_MASKLEN) != 0) || (pIcmpReply->icmp_type != ICMP_MASKREPLY)) return (FALSE); maskReplyReceived = TRUE; return (TRUE); }/******************************************************************************** ipHeaderCreate - create a simple IP header** This generates a simple IP header (with no options) and checksums it.* <proto> specifies the protocol type. <pSrcAddr> and <pDstAddr> define* the source and destination internet addresses, respectively. Both should* be specified in network byte order. <pih> is a pointer to an internet* datagram whose length is <length>.** RETURNS: N/A** NOMANUAL*/void ipHeaderCreate ( int proto, /* protocol number */ struct in_addr * pSrcAddr, /* source ip address */ struct in_addr * pDstAddr, /* dest ip address */ struct ip * pih, /* internet header */ int length /* datagram size */ ) { /* fill in the IP header */ pih->ip_v = IPVERSION; pih->ip_hl = (sizeof (struct ip) >> 2) & 0xf; pih->ip_len = htons ((u_short) length); pih->ip_id = (u_short) (tickGet () & 0xffff); pih->ip_ttl = MAXTTL; pih->ip_p = (u_char) proto; pih->ip_src.s_addr = pSrcAddr->s_addr; pih->ip_dst.s_addr = pDstAddr->s_addr; pih->ip_sum = 0; /* zero out the checksum while computing it */ pih->ip_sum = checksum ((u_short *) pih, (pih->ip_hl << 2)); }/********************************************************************************* ipHeaderVerify - simple IP header verification** ipHeaderVerify performs simple IP header verification. It does* sanity checks and verifies the checksum. <pih> points to an internet* datagram of length <length>. <proto> is the expected protocol.** RETURNS: a pointer to the IP data, or NULL if not a valid IP datagram.** NOMANUAL*/u_char * ipHeaderVerify ( struct ip * pih, /* internet header */ int length, /* length of datagram */ int proto /* protocol */ ) { FAST int options; /* options offset */ /* if not minimum size, or right protocol bail */ if ((length < sizeof (struct ip)) || (pih->ip_p != (u_char) proto)) return (NULL); /* verify checksum */ if (checksum ((u_short *) pih, (pih->ip_hl << 2)) != 0) return (NULL); if ((pih->ip_v != IPVERSION) || (ntohs ((u_short) pih->ip_off) & 0x3FFF)) return (NULL); /* ip_hl is in words */ options = (pih->ip_hl << 2) - sizeof (struct ip); return ((u_char *) pih + sizeof (struct ip) + options); }/********************************************************************************* etherSend - send an IP datagram over ether hooks.** etherSend uses etherOutput to send an IP datagram whose header is* pointed to by <pDatagram> and whose length is <length> over the network* interface specified by <pIf>. The destination must reside on the local* network associated with <pIf> since it may try to resolve this address* via ARP.** RETURNS: OK if successful, otherwise ERROR.** NOMANUAL*/STATUS etherSend ( struct ifnet * pIf, /* network interface */ struct ip * pDatagram, /* buffer pointer */ int length /* buffer size */ ) { struct ether_header eh; /* ethernet header */ char ipDestAscii [ INET_ADDR_LEN ]; bzero ((char *) &eh, sizeof (struct ether_header)); /* if IP broadcast, then use the ethernet broadcast address */ if (in_broadcast (pDatagram->ip_dst, pIf)) bcopy ((char *) etherbroadcastaddr, (char *) eh.ether_dhost, sizeof (etherbroadcastaddr)); else { /* else use ARP to find dest */ inet_ntoa_b (pDatagram->ip_dst, ipDestAscii); if (etherAddrResolve (pIf, ipDestAscii, (char *) eh.ether_dhost, 5, 2 * sysClkRateGet()) == ERROR) return (ERROR); } eh.ether_type = ETHERTYPE_IP; /* htons is in ether_output */ if (etherOutput (pIf, &eh, (char *) pDatagram, length) == ERROR) return (ERROR); return (OK); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -