⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
int arp_find(unsigned char *haddr, struct sk_buff *skb){	struct net_device *dev = skb->dev;	__be32 paddr;	struct neighbour *n;	if (!skb->dst) {		printk(KERN_DEBUG "arp_find is called with dst==NULL\n");		kfree_skb(skb);		return 1;	}	paddr = ((struct rtable*)skb->dst)->rt_gateway;	if (arp_set_predefined(inet_addr_type(paddr), haddr, paddr, dev))		return 0;	n = __neigh_lookup(&arp_tbl, &paddr, dev, 1);	if (n) {		n->used = jiffies;		if (n->nud_state&NUD_VALID || neigh_event_send(n, skb) == 0) {			read_lock_bh(&n->lock);			memcpy(haddr, n->ha, dev->addr_len);			read_unlock_bh(&n->lock);			neigh_release(n);			return 0;		}		neigh_release(n);	} else		kfree_skb(skb);	return 1;}/* END OF OBSOLETE FUNCTIONS */int arp_bind_neighbour(struct dst_entry *dst){	struct net_device *dev = dst->dev;	struct neighbour *n = dst->neighbour;	if (dev == NULL)		return -EINVAL;	if (n == NULL) {		__be32 nexthop = ((struct rtable*)dst)->rt_gateway;		if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))			nexthop = 0;		n = __neigh_lookup_errno(#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)		    dev->type == ARPHRD_ATM ? clip_tbl_hook :#endif		    &arp_tbl, &nexthop, dev);		if (IS_ERR(n))			return PTR_ERR(n);		dst->neighbour = n;	}	return 0;}/* * Check if we can use proxy ARP for this path */static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt){	struct in_device *out_dev;	int imi, omi = -1;	if (!IN_DEV_PROXY_ARP(in_dev))		return 0;	if ((imi = IN_DEV_MEDIUM_ID(in_dev)) == 0)		return 1;	if (imi == -1)		return 0;	/* place to check for proxy_arp for routes */	if ((out_dev = in_dev_get(rt->u.dst.dev)) != NULL) {		omi = IN_DEV_MEDIUM_ID(out_dev);		in_dev_put(out_dev);	}	return (omi != imi && omi != -1);}/* *	Interface to link layer: send routine and receive handler. *//* *	Create an arp packet. If (dest_hw == NULL), we create a broadcast *	message. */struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,			   struct net_device *dev, __be32 src_ip,			   unsigned char *dest_hw, unsigned char *src_hw,			   unsigned char *target_hw){	struct sk_buff *skb;	struct arphdr *arp;	unsigned char *arp_ptr;	/*	 *	Allocate a buffer	 */	skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)				+ LL_RESERVED_SPACE(dev), GFP_ATOMIC);	if (skb == NULL)		return NULL;	skb_reserve(skb, LL_RESERVED_SPACE(dev));	skb_reset_network_header(skb);	arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));	skb->dev = dev;	skb->protocol = htons(ETH_P_ARP);	if (src_hw == NULL)		src_hw = dev->dev_addr;	if (dest_hw == NULL)		dest_hw = dev->broadcast;	/*	 *	Fill the device header for the ARP frame	 */	if (dev_hard_header(skb, dev, ptype, dest_hw, src_hw, skb->len) < 0)		goto out;	/*	 * Fill out the arp protocol part.	 *	 * The arp hardware type should match the device type, except for FDDI,	 * which (according to RFC 1390) should always equal 1 (Ethernet).	 */	/*	 *	Exceptions everywhere. AX.25 uses the AX.25 PID value not the	 *	DIX code for the protocol. Make these device structure fields.	 */	switch (dev->type) {	default:		arp->ar_hrd = htons(dev->type);		arp->ar_pro = htons(ETH_P_IP);		break;#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)	case ARPHRD_AX25:		arp->ar_hrd = htons(ARPHRD_AX25);		arp->ar_pro = htons(AX25_P_IP);		break;#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)	case ARPHRD_NETROM:		arp->ar_hrd = htons(ARPHRD_NETROM);		arp->ar_pro = htons(AX25_P_IP);		break;#endif#endif#ifdef CONFIG_FDDI	case ARPHRD_FDDI:		arp->ar_hrd = htons(ARPHRD_ETHER);		arp->ar_pro = htons(ETH_P_IP);		break;#endif#ifdef CONFIG_TR	case ARPHRD_IEEE802_TR:		arp->ar_hrd = htons(ARPHRD_IEEE802);		arp->ar_pro = htons(ETH_P_IP);		break;#endif	}	arp->ar_hln = dev->addr_len;	arp->ar_pln = 4;	arp->ar_op = htons(type);	arp_ptr=(unsigned char *)(arp+1);	memcpy(arp_ptr, src_hw, dev->addr_len);	arp_ptr+=dev->addr_len;	memcpy(arp_ptr, &src_ip,4);	arp_ptr+=4;	if (target_hw != NULL)		memcpy(arp_ptr, target_hw, dev->addr_len);	else		memset(arp_ptr, 0, dev->addr_len);	arp_ptr+=dev->addr_len;	memcpy(arp_ptr, &dest_ip, 4);	return skb;out:	kfree_skb(skb);	return NULL;}/* *	Send an arp packet. */void arp_xmit(struct sk_buff *skb){	/* Send it off, maybe filter it using firewalling first.  */	NF_HOOK(NF_ARP, NF_ARP_OUT, skb, NULL, skb->dev, dev_queue_xmit);}/* *	Create and send an arp packet. */void arp_send(int type, int ptype, __be32 dest_ip,	      struct net_device *dev, __be32 src_ip,	      unsigned char *dest_hw, unsigned char *src_hw,	      unsigned char *target_hw){	struct sk_buff *skb;	/*	 *	No arp on this interface.	 */	if (dev->flags&IFF_NOARP)		return;	skb = arp_create(type, ptype, dest_ip, dev, src_ip,			 dest_hw, src_hw, target_hw);	if (skb == NULL) {		return;	}	arp_xmit(skb);}/* *	Process an arp request. */static int arp_process(struct sk_buff *skb){	struct net_device *dev = skb->dev;	struct in_device *in_dev = in_dev_get(dev);	struct arphdr *arp;	unsigned char *arp_ptr;	struct rtable *rt;	unsigned char *sha;	__be32 sip, tip;	u16 dev_type = dev->type;	int addr_type;	struct neighbour *n;	/* arp_rcv below verifies the ARP header and verifies the device	 * is ARP'able.	 */	if (in_dev == NULL)		goto out;	arp = arp_hdr(skb);	switch (dev_type) {	default:		if (arp->ar_pro != htons(ETH_P_IP) ||		    htons(dev_type) != arp->ar_hrd)			goto out;		break;	case ARPHRD_ETHER:	case ARPHRD_IEEE802_TR:	case ARPHRD_FDDI:	case ARPHRD_IEEE802:		/*		 * ETHERNET, Token Ring and Fibre Channel (which are IEEE 802		 * devices, according to RFC 2625) devices will accept ARP		 * hardware types of either 1 (Ethernet) or 6 (IEEE 802.2).		 * This is the case also of FDDI, where the RFC 1390 says that		 * FDDI devices should accept ARP hardware of (1) Ethernet,		 * however, to be more robust, we'll accept both 1 (Ethernet)		 * or 6 (IEEE 802.2)		 */		if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&		     arp->ar_hrd != htons(ARPHRD_IEEE802)) ||		    arp->ar_pro != htons(ETH_P_IP))			goto out;		break;	case ARPHRD_AX25:		if (arp->ar_pro != htons(AX25_P_IP) ||		    arp->ar_hrd != htons(ARPHRD_AX25))			goto out;		break;	case ARPHRD_NETROM:		if (arp->ar_pro != htons(AX25_P_IP) ||		    arp->ar_hrd != htons(ARPHRD_NETROM))			goto out;		break;	}	/* Understand only these message types */	if (arp->ar_op != htons(ARPOP_REPLY) &&	    arp->ar_op != htons(ARPOP_REQUEST))		goto out;/* *	Extract fields */	arp_ptr= (unsigned char *)(arp+1);	sha	= arp_ptr;	arp_ptr += dev->addr_len;	memcpy(&sip, arp_ptr, 4);	arp_ptr += 4;	arp_ptr += dev->addr_len;	memcpy(&tip, arp_ptr, 4);/* *	Check for bad requests for 127.x.x.x and requests for multicast *	addresses.  If this is one such, delete it. */	if (LOOPBACK(tip) || MULTICAST(tip))		goto out;/* *     Special case: We must set Frame Relay source Q.922 address */	if (dev_type == ARPHRD_DLCI)		sha = dev->broadcast;/* *  Process entry.  The idea here is we want to send a reply if it is a *  request for us or if it is a request for someone else that we hold *  a proxy for.  We want to add an entry to our cache if it is a reply *  to us or if it is a request for our address. *  (The assumption for this last is that if someone is requesting our *  address, they are probably intending to talk to us, so it saves time *  if we cache their address.  Their address is also probably not in *  our cache, since ours is not in their cache.) * *  Putting this another way, we only care about replies if they are to *  us, in which case we add them to the cache.  For requests, we care *  about those for us and those for our proxies.  We reply to both, *  and in the case of requests for us we add the requester to the arp *  cache. */	/* Special case: IPv4 duplicate address detection packet (RFC2131) */	if (sip == 0) {		if (arp->ar_op == htons(ARPOP_REQUEST) &&		    inet_addr_type(tip) == RTN_LOCAL &&		    !arp_ignore(in_dev,dev,sip,tip))			arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,				 dev->dev_addr, sha);		goto out;	}	if (arp->ar_op == htons(ARPOP_REQUEST) &&	    ip_route_input(skb, tip, sip, 0, dev) == 0) {		rt = (struct rtable*)skb->dst;		addr_type = rt->rt_type;		if (addr_type == RTN_LOCAL) {			n = neigh_event_ns(&arp_tbl, sha, &sip, dev);			if (n) {				int dont_send = 0;				if (!dont_send)					dont_send |= arp_ignore(in_dev,dev,sip,tip);				if (!dont_send && IN_DEV_ARPFILTER(in_dev))					dont_send |= arp_filter(sip,tip,dev);				if (!dont_send)					arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);				neigh_release(n);			}			goto out;		} else if (IN_DEV_FORWARD(in_dev)) {			if ((rt->rt_flags&RTCF_DNAT) ||			    (addr_type == RTN_UNICAST  && rt->u.dst.dev != dev &&			     (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {				n = neigh_event_ns(&arp_tbl, sha, &sip, dev);				if (n)					neigh_release(n);				if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED ||				    skb->pkt_type == PACKET_HOST ||				    in_dev->arp_parms->proxy_delay == 0) {					arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);				} else {					pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb);					in_dev_put(in_dev);					return 0;				}				goto out;			}		}	}	/* Update our ARP tables */	n = __neigh_lookup(&arp_tbl, &sip, dev, 0);	if (IPV4_DEVCONF_ALL(ARP_ACCEPT)) {		/* Unsolicited ARP is not accepted by default.		   It is possible, that this option should be enabled for some		   devices (strip is candidate)		 */		if (n == NULL &&		    arp->ar_op == htons(ARPOP_REPLY) &&		    inet_addr_type(sip) == RTN_UNICAST)			n = __neigh_lookup(&arp_tbl, &sip, dev, 1);	}	if (n) {		int state = NUD_REACHABLE;		int override;		/* If several different ARP replies follows back-to-back,		   use the FIRST one. It is possible, if several proxy		   agents are active. Taking the first reply prevents		   arp trashing and chooses the fastest router.		 */		override = time_after(jiffies, n->updated + n->parms->locktime);		/* Broadcast replies and request packets		   do not assert neighbour reachability.		 */		if (arp->ar_op != htons(ARPOP_REPLY) ||		    skb->pkt_type != PACKET_HOST)			state = NUD_STALE;		neigh_update(n, sha, state, override ? NEIGH_UPDATE_F_OVERRIDE : 0);		neigh_release(n);	}out:	if (in_dev)		in_dev_put(in_dev);	kfree_skb(skb);	return 0;}static void parp_redo(struct sk_buff *skb){	arp_process(skb);}/* *	Receive an arp request from the device layer. */static int arp_rcv(struct sk_buff *skb, struct net_device *dev,		   struct packet_type *pt, struct net_device *orig_dev){	struct arphdr *arp;	if (dev->nd_net != &init_net)		goto freeskb;	/* ARP header, plus 2 device addresses, plus 2 IP addresses.  */	if (!pskb_may_pull(skb, (sizeof(struct arphdr) +				 (2 * dev->addr_len) +				 (2 * sizeof(u32)))))		goto freeskb;	arp = arp_hdr(skb);	if (arp->ar_hln != dev->addr_len ||	    dev->flags & IFF_NOARP ||	    skb->pkt_type == PACKET_OTHERHOST ||	    skb->pkt_type == PACKET_LOOPBACK ||	    arp->ar_pln != 4)		goto freeskb;	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -