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

📄 arp.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * INET		An implementation of the TCP/IP protocol suite for the LINUX *		operating system.  INET is implemented using the  BSD Socket *		interface as the means of communication with the user level. * *		This file implements the Address Resolution Protocol (ARP), *		which is used by TCP/IP to map the IP addresses from a host *		to a low-level hardware address (like an Ethernet address) *		which it can use to talk to that host. * * NOTE:	This module will be rewritten completely in the near future, *		because I want it to become a multi-address-family address *		resolver, like it should be.  It will be put in a separate *		directory under 'net', being a protocol of its own. -FvK * * Version:	@(#)arp.c	1.0.15	05/25/93 * * Authors:	Ross Biro, <bir7@leland.Stanford.Edu> *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> *		Arnt Gulbrandsen, <agulbra@pvv.unit.no> * * Fixes: *		Stephen A. Wood	:	arp problems *		'Mr Linux'	:	arp problems. *		Alan Cox	:	arp_ioctl now checks memory areas with verify_area. *		Alan Cox	:	Non IP arp message now only appears with debugging on. *		Alan Cox	: 	arp queue is volatile (may be altered by arp messages while doing sends)  *					Generic queue code is urgently needed! *		Alan Cox	:	Deleting your own ip addr now gives EINVAL not a printk message. *		Alan Cox	:	Fix to arp linked list error *		Alan Cox	:	Ignore broadcast arp (Linus' idea 8-)) *		Alan Cox	:	arp_send memory leak removed *		Alan Cox	:	generic skbuff code fixes. *		Alan Cox	:	'Bad Packet' only reported on debugging *		Alan Cox	:	Proxy arp. *		Alan Cox	:	skb->link3 maintained by letting the other xmit queue kill the packet. *		Alan Cox	:	Knows about type 3 devices (AX.25) using an AX.25 protocol ID not the ethernet *					one. *		Dominik Kubla	:	Better checking *		Tegge		:	Assorted corrections on cross port stuff *		Alan Cox	:	ATF_PERM was backwards! - might be useful now (sigh) *		Alan Cox	:	Arp timer added. * * To Fix: *				:	arp response allocates an skbuff to send. However there is a perfectly *					good spare skbuff the right size about to be freed (the query). Use the *					query for the reply. This avoids an out of memory case _and_ speeds arp *					up. *				:	FREE_READ v FREE_WRITE errors. Not critical as loopback arps don't occur * * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. */#include <linux/types.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/config.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/timer.h>#include <linux/errno.h>#include <linux/if_arp.h>#include <linux/in.h>#include <asm/system.h>#include <asm/segment.h>#include <stdarg.h>#include "inet.h"#include "dev.h"#include "eth.h"#include "ip.h"#include "route.h"#include "protocol.h"#include "tcp.h"#include "skbuff.h"#include "sock.h"#include "arp.h"#define ARP_MAX_TRIES	3static char *unk_print(unsigned char *, int);static char *eth_aprint(unsigned char *, int);static char *arp_cmds[] = {  "0x%04X",  "REQUEST",  "REPLY",  "REVERSE REQUEST",  "REVERSE REPLY",  NULL};#define	ARP_MAX_CMDS	(sizeof(arp_cmds) / sizeof(arp_cmds[0]))static struct {  char	*name;  char	*(*print)(unsigned char *ptr, int len);} arp_types[] = {  { "0x%04X",			unk_print	},  { "10 Mbps Ethernet", 	eth_aprint	},  { "3 Mbps Ethernet",		eth_aprint	},  { "AX.25",			unk_print	},  { "Pronet",			unk_print	},  { "Chaos",			unk_print	},  { "IEEE 802.2 Ethernet (?)",	eth_aprint	},  { "Arcnet",			unk_print	},  { "AppleTalk",		unk_print	},  { NULL,			NULL		}};#define	ARP_MAX_TYPE	(sizeof(arp_types) / sizeof(arp_types[0]))struct arp_table *arp_tables[ARP_TABLE_SIZE] = {  NULL,};static int arp_proxies=0;	/* So we can avoid the proxy arp 				   overhead with the usual case of				   no proxy arps */struct sk_buff * volatile arp_q = NULL;static struct arp_table *arp_lookup(unsigned long addr);static struct arp_table *arp_lookup_proxy(unsigned long addr);/* Dump the ADDRESS bytes of an unknown hardware type. */static char *unk_print(unsigned char *ptr, int len){  static char buff[32];  char *bufp = buff;  int i;  for (i = 0; i < len; i++)	bufp += sprintf(bufp, "%02X ", (*ptr++ & 0377));  return(buff);}/* Dump the ADDRESS bytes of an Ethernet hardware type. */static char *eth_aprint(unsigned char *ptr, int len){  if (len != ETH_ALEN) return("");  return(eth_print(ptr));}/* Dump an ARP packet. Not complete yet for non-Ethernet packets. */static voidarp_print(struct arphdr *arp){  int len, idx;  unsigned char *ptr;  if (inet_debug != DBG_ARP) return;  printk("ARP: ");  if (arp == NULL) {	printk("(null)\n");	return;  }  /* Print the opcode name. */  len = htons(arp->ar_op);  if (len < ARP_MAX_CMDS) idx = len;    else idx = 0;  printk("op ");  printk(arp_cmds[idx], len);  /* Print the ARP header. */  len = htons(arp->ar_hrd);  if (len < ARP_MAX_TYPE) idx = len;    else idx = 0;  printk("   hrd = "); printk(arp_types[idx].name, len);  printk("   pro = 0x%04X\n", htons(arp->ar_pro));  printk("   hlen = %d plen = %d\n", arp->ar_hln, arp->ar_pln);  /*   * Print the variable data.   * When ARP gets redone (after the formal introduction of NET-2),   * this part will be redone.  ARP will then be a multi-family address   * resolver, and the code below will be made more general. -FvK   */  ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);  printk("   sender HA = %s ", arp_types[idx].print(ptr, arp->ar_hln));  ptr += arp->ar_hln;  printk("  PA = %s\n", in_ntoa(*(unsigned long *) ptr));  ptr += arp->ar_pln;  printk("   target HA = %s ", arp_types[idx].print(ptr, arp->ar_hln));  ptr += arp->ar_hln;  printk("  PA = %s\n", in_ntoa(*(unsigned long *) ptr));}/* This will try to retransmit everything on the queue. */static voidarp_send_q(void){  struct sk_buff *skb;  struct sk_buff *volatile work_q;  cli();  work_q = arp_q;  skb_new_list_head(&work_q);  arp_q = NULL;  sti();  while((skb=skb_dequeue(&work_q))!=NULL)  {  	IS_SKB(skb);	skb->magic = 0;	skb->next = NULL;	skb->prev = NULL;	/* Decrement the 'tries' counter. */	cli();	skb->tries--;	if (skb->tries == 0) {		/*		 * Grmpf.		 * We have tried ARP_MAX_TRIES to resolve the IP address		 * from this datagram.  This means that the machine does		 * not listen to our ARP requests.  Perhaps someone tur-		 * ned off the thing?		 * In any case, trying further is useless.  So, we kill		 * this packet from the queue.  (grinnik) -FvK		 */		skb->sk = NULL;		if(skb->free)			kfree_skb(skb, FREE_WRITE);			/* If free was 0, magic is now 0, next is 0 and 			   the write queue will notice and kill */		sti();		continue;	}	/* Can we now complete this packet? */	sti();	if (skb->arp || !skb->dev->rebuild_header(skb->data, skb->dev)) {		skb->arp  = 1;		skb->dev->queue_xmit(skb, skb->dev, 0);	} else {		/* Alas.  Re-queue it... */		skb->magic = ARP_QUEUE_MAGIC;      		skb_queue_head(&arp_q,skb);	}  }}static struct timer_list arp_timer;static void arp_queue_ticker(unsigned long data);static void arp_queue_kick(void){	arp_timer.expires = 500;	/* 5 seconds */	arp_timer.data = 0;	arp_timer.function = arp_queue_ticker;	del_timer(&arp_timer);	add_timer(&arp_timer);}static void arp_queue_ticker(unsigned long data/*UNUSED*/){	arp_send_q();	if (skb_peek(&arp_q))		arp_queue_kick();}/* Create and send our response to an ARP request. */static intarp_response(struct arphdr *arp1, struct device *dev,  int addrtype){  struct arphdr *arp2;  struct sk_buff *skb;  unsigned long src, dst;  unsigned char *ptr1, *ptr2;  int hlen;  struct arp_table *apt = NULL;/* =NULL otherwise the compiler gives warnings */  /* Decode the source (REQUEST) message. */  ptr1 = ((unsigned char *) &arp1->ar_op) + sizeof(u_short);  src = *((unsigned long *) (ptr1 + arp1->ar_hln));  dst = *((unsigned long *) (ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln));    if(addrtype!=IS_MYADDR)  {  	apt=arp_lookup_proxy(dst);  	if(apt==NULL)  		return(1);  }  /* Get some mem and initialize it for the return trip. */  skb = alloc_skb(sizeof(struct sk_buff) +  		sizeof(struct arphdr) +		(2 * arp1->ar_hln) + (2 * arp1->ar_pln) +		dev->hard_header_len, GFP_ATOMIC);  if (skb == NULL) {	printk("ARP: no memory available for ARP REPLY!\n");	return(1);  }  skb->mem_addr = skb;  skb->len      = sizeof(struct arphdr) + (2 * arp1->ar_hln) + 		  (2 * arp1->ar_pln) + dev->hard_header_len;  skb->mem_len  = sizeof(struct sk_buff) + skb->len;  hlen = dev->hard_header(skb->data, dev, ETH_P_ARP, src, dst, skb->len);  if (hlen < 0) {	printk("ARP: cannot create HW frame header for REPLY !\n");	kfree_skb(skb, FREE_WRITE);	return(1);  }  /*   * Fill in the ARP REPLY packet.   * This looks ugly, but we have to deal with the variable-length   * ARP packets and such.  It is not as bad as it looks- FvK   */  arp2 = (struct arphdr *) (skb->data + hlen);  ptr2 = ((unsigned char *) &arp2->ar_op) + sizeof(u_short);  arp2->ar_hrd = arp1->ar_hrd;  arp2->ar_pro = arp1->ar_pro;  arp2->ar_hln = arp1->ar_hln;  arp2->ar_pln = arp1->ar_pln;  arp2->ar_op = htons(ARPOP_REPLY);  if(addrtype==IS_MYADDR)	  memcpy(ptr2, dev->dev_addr, arp2->ar_hln);  else		/* Proxy arp, so pull from the table */  	  memcpy(ptr2, apt->ha, arp2->ar_hln);  ptr2 += arp2->ar_hln;  memcpy(ptr2, ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln, arp2->ar_pln);  ptr2 += arp2->ar_pln;  memcpy(ptr2, ptr1, arp2->ar_hln);  ptr2 += arp2->ar_hln;  memcpy(ptr2, ptr1 + arp1->ar_hln, arp2->ar_pln);  skb->free = 1;  skb->arp = 1;  skb->sk = NULL;  skb->next = NULL;  DPRINTF((DBG_ARP, ">>"));  arp_print(arp2);  /* Queue the packet for transmission. */  dev->queue_xmit(skb, dev, 0);  return(0);}/* This will find an entry in the ARP table by looking at the IP address. */static struct arp_table *arp_lookup(unsigned long paddr){  struct arp_table *apt;  unsigned long hash;  DPRINTF((DBG_ARP, "ARP: lookup(%s)\n", in_ntoa(paddr)));  /* We don't want to ARP ourselves. */  if (chk_addr(paddr) == IS_MYADDR) {	printk("ARP: ARPing my own IP address %s !\n", in_ntoa(paddr));	return(NULL);  }  /* Loop through the table for the desired address. */  hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);  cli();  apt = arp_tables[hash];  while(apt != NULL) {	if (apt->ip == paddr) {		sti();		return(apt);	}	apt = apt->next;  }  sti();  return(NULL);}/* This will find a proxy in the ARP table by looking at the IP address. */static struct arp_table *arp_lookup_proxy(unsigned long paddr){  struct arp_table *apt;  unsigned long hash;  DPRINTF((DBG_ARP, "ARP: lookup proxy(%s)\n", in_ntoa(paddr)));  /* Loop through the table for the desired address. */  hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);  cli();  apt = arp_tables[hash];  while(apt != NULL) {	if (apt->ip == paddr && (apt->flags & ATF_PUBL) ) {		sti();		return(apt);	}	apt = apt->next;  }  sti();  return(NULL);}/* Delete an ARP mapping entry in the cache. */voidarp_destructor(unsigned long paddr, int force){  struct arp_table *apt;  struct arp_table **lapt;  unsigned long hash;  DPRINTF((DBG_ARP, "ARP: destroy(%s)\n", in_ntoa(paddr)));  /* We cannot destroy our own ARP entry. */  if (chk_addr(paddr) == IS_MYADDR) {	DPRINTF((DBG_ARP, "ARP: Destroying my own IP address %s !\n",							in_ntoa(paddr)));	return;  }  hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);  cli();  lapt = &arp_tables[hash];  while ((apt = *lapt) != NULL) {	if (apt->ip == paddr) {		if((apt->flags&ATF_PERM) && !force)			return;		*lapt = apt->next;		if(apt->flags&ATF_PUBL)			arp_proxies--;					kfree_s(apt, sizeof(struct arp_table));		sti();		return;	}	lapt = &apt->next;  }  sti();}/* *	Kill an entry - eg for ioctl() */void arp_destroy(unsigned long paddr){		arp_destructor(paddr,1);}/* *	Delete a possibly invalid entry (see timer.c) */void arp_destroy_maybe(unsigned long paddr){	arp_destructor(paddr,0);}/* Create an ARP entry.  The caller should check for duplicates! */static struct arp_table *arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype){  struct arp_table *apt;  unsigned long hash;  DPRINTF((DBG_ARP, "ARP: create(%s, ", in_ntoa(paddr)));  DPRINTF((DBG_ARP, "%s, ", eth_print(addr)));  DPRINTF((DBG_ARP, "%d, %d)\n", hlen, htype));  apt = (struct arp_table *) kmalloc(sizeof(struct arp_table), GFP_ATOMIC);  if (apt == NULL) {	printk("ARP: no memory available for new ARP entry!\n");	return(NULL);  }  /* Fill in the allocated ARP cache entry. */  hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);  apt->ip = paddr;  apt->hlen = hlen;  apt->htype = htype;  apt->flags = (ATF_INUSE | ATF_COM);		/* USED and COMPLETED entry */

⌨️ 快捷键说明

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