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

📄 arp.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 2 页
字号:
  memcpy(apt->ha, addr, hlen);  apt->last_used = jiffies;  cli();  apt->next = arp_tables[hash];  arp_tables[hash] = apt;  sti();  return(apt);}/* * An ARP REQUEST packet has arrived. * We try to be smart here, and fetch the data of the sender of the * packet- we might need it later, so fetching it now can save us a * broadcast later. * Then, if the packet was meant for us (i.e. the TARGET address was * one of our own IP addresses), we set up and send out an ARP REPLY * packet to the sender. */intarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt){  struct arphdr *arp;  struct arp_table *tbl;  unsigned long src, dst;  unsigned char *ptr;  int ret;  int addr_hint;  DPRINTF((DBG_ARP, "<<\n"));  arp = skb->h.arp;  arp_print(arp);  /* If this test doesn't pass, its not IP. Might be DECNET or friends */  if (arp->ar_hln != dev->addr_len || dev->type != NET16(arp->ar_hrd))   {	DPRINTF((DBG_ARP,"ARP: Bad packet received on device \"%s\" !\n", dev->name));	kfree_skb(skb, FREE_READ);	return(0);  }  /* For now we will only deal with IP addresses. */  if (((arp->ar_pro != NET16(0x00CC) && dev->type==3) || (arp->ar_pro != NET16(ETH_P_IP) && dev->type!=3) ) || arp->ar_pln != 4)   {	if (arp->ar_op != NET16(ARPOP_REQUEST))		DPRINTF((DBG_ARP,"ARP: Non-IP request on device \"%s\" !\n", dev->name));	kfree_skb(skb, FREE_READ);	return(0);  }  /*   * As said before, we try to be smart by using the   * info already present in the packet: the sender's   * IP and hardware address.   */  ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);  memcpy(&src, ptr + arp->ar_hln, arp->ar_pln);  tbl = arp_lookup(src);  if (tbl != NULL) {	DPRINTF((DBG_ARP, "ARP: udating entry for %s\n", in_ntoa(src)));	memcpy(tbl->ha, ptr, arp->ar_hln);	tbl->hlen = arp->ar_hln;	tbl->flags |= ATF_COM;	tbl->last_used = jiffies;  } else {	memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);	if (chk_addr(dst) != IS_MYADDR && arp_proxies == 0) {		kfree_skb(skb, FREE_READ);		return(0);	} else {		tbl = arp_create(src, ptr, arp->ar_hln, arp->ar_hrd);		if (tbl == NULL) {			kfree_skb(skb, FREE_READ);			return(0);		}	}  }  /*   * Since we updated the ARP cache, we might have enough   * information to send out some previously queued IP   * datagrams....   */  arp_send_q();  /*   * OK, we used that part of the info.  Now check if the   * request was an ARP REQUEST for one of our own addresses..   */  if (arp->ar_op != NET16(ARPOP_REQUEST)) {	kfree_skb(skb, FREE_READ);	return(0);  }/* * A broadcast arp, ignore it */  if(chk_addr(dst)==IS_BROADCAST)  {	kfree_skb(skb, FREE_READ);	return 0;  }    memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);  if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0) {	DPRINTF((DBG_ARP, "ARP: request was not for me!\n"));	kfree_skb(skb, FREE_READ);	return(0);  }  /*   * Yes, it is for us.   * Allocate, fill in and send an ARP REPLY packet.   */  ret = arp_response(arp, dev, addr_hint);  kfree_skb(skb, FREE_READ);  return(ret);}/* Create and send an ARP REQUEST packet. */voidarp_send(unsigned long paddr, struct device *dev, unsigned long saddr){  struct sk_buff *skb;  struct arphdr *arp;  unsigned char *ptr;  int tmp;  DPRINTF((DBG_ARP, "ARP: send(paddr=%s, ", in_ntoa(paddr)));  DPRINTF((DBG_ARP, "dev=%s, ", dev->name));  DPRINTF((DBG_ARP, "saddr=%s)\n", in_ntoa(saddr)));  skb = alloc_skb(sizeof(struct sk_buff) +  		sizeof(struct arphdr) + (2 * dev->addr_len) +		dev->hard_header_len +		(2 * 4 /* arp->plen */), GFP_ATOMIC);  if (skb == NULL) {	printk("ARP: No memory available for REQUEST %s\n", in_ntoa(paddr));	return;  }    /* Fill in the request. */  skb->sk = NULL;  skb->mem_addr = skb;  skb->len = sizeof(struct arphdr) +	     dev->hard_header_len + (2 * dev->addr_len) + 8;  skb->mem_len = sizeof(struct sk_buff) + skb->len;  skb->arp = 1;  skb->dev = dev;  skb->next = NULL;  skb->free = 1;  tmp = dev->hard_header(skb->data, dev, ETH_P_ARP, 0, saddr, skb->len);  if (tmp < 0) {	kfree_skb(skb,FREE_WRITE);	return;  }  arp = (struct arphdr *) (skb->data + tmp);  arp->ar_hrd = htons(dev->type);  if(dev->type!=3)	/* AX.25 */  	arp->ar_pro = htons(ETH_P_IP);  else  	arp->ar_pro = htons(0xCC);  arp->ar_hln = dev->addr_len;  arp->ar_pln = 4;  arp->ar_op = htons(ARPOP_REQUEST);  ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);  memcpy(ptr, dev->dev_addr, arp->ar_hln);  ptr += arp->ar_hln;  memcpy(ptr, &saddr, arp->ar_pln);  ptr += arp->ar_pln;  /*memcpy(ptr, dev->broadcast, arp->ar_hln);*/  memset(ptr,0,arp->ar_hln);  ptr += arp->ar_hln;  memcpy(ptr, &paddr, arp->ar_pln);  DPRINTF((DBG_ARP, ">>\n"));  arp_print(arp);  dev->queue_xmit(skb, dev, 0);}/* Find an ARP mapping in the cache. If not found, post a REQUEST. */intarp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,	   unsigned long saddr){  struct arp_table *apt;  DPRINTF((DBG_ARP, "ARP: find(haddr=%s, ", eth_print(haddr)));  DPRINTF((DBG_ARP, "paddr=%s, ", in_ntoa(paddr)));  DPRINTF((DBG_ARP, "dev=%s, saddr=%s)\n", dev->name, in_ntoa(saddr)));  switch(chk_addr(paddr)) {	case IS_MYADDR:		memcpy(haddr, dev->dev_addr, dev->addr_len);		return(0);	case IS_BROADCAST:		memcpy(haddr, dev->broadcast, dev->addr_len);		return(0);  }		  apt = arp_lookup(paddr);  if (apt != NULL) {	/*	 * Make sure it's not too old. If it is too old, we will	 * just pretend we did not find it, and then arp_send will	 * verify the address for us.	 */        if ((apt->flags & ATF_PERM) ||	    (apt->last_used < jiffies+ARP_TIMEOUT && apt->hlen != 0)) {		apt->last_used = jiffies;		memcpy(haddr, apt->ha, dev->addr_len);		return(0);	} else {		DPRINTF((DBG_ARP, "ARP: find: found expired entry for %s\n",							in_ntoa(apt->ip)));	}  }  /*   * This assume haddr are at least 4 bytes.   * If this isn't true we can use a lookup table, one for every dev.   * NOTE: this bit of code still looks fishy to me- FvK   */  *(unsigned long *)haddr = paddr;  /* If we didn't find an entry, we will try to send an ARP packet. */  arp_send(paddr, dev, saddr);  return(1);}/* Add an entry to the ARP cache.  Check for dupes! */voidarp_add(unsigned long addr, unsigned char *haddr, struct device *dev){  struct arp_table *apt;  DPRINTF((DBG_ARP, "ARP: add(%s, ", in_ntoa(addr)));  DPRINTF((DBG_ARP, "%s, ", eth_print(haddr)));  DPRINTF((DBG_ARP, "%d, %d)\n", dev->hard_header_len, dev->type));  /* This is probably a good check... */  if (addr == 0) {	printk("ARP: add: will not add entry for 0.0.0.0 !\n");	return;  }  /* First see if the address is already in the table. */  apt = arp_lookup(addr);  if (apt != NULL) {	DPRINTF((DBG_ARP, "ARP: updating entry for %s\n", in_ntoa(addr)));	apt->last_used = jiffies;	memcpy(apt->ha, haddr , dev->addr_len);	return;  }  arp_create(addr, haddr, dev->addr_len, dev->type);}/* Create an ARP entry for a device's broadcast address. */voidarp_add_broad(unsigned long addr, struct device *dev){  struct arp_table *apt;  arp_add(addr, dev->broadcast, dev);  apt = arp_lookup(addr);  if (apt != NULL) {	apt->flags |= ATF_PERM;  }}/* Queue an IP packet, while waiting for the ARP reply packet. */voidarp_queue(struct sk_buff *skb){  cli();  skb->tries = ARP_MAX_TRIES;  if (skb->next != NULL) {	sti();	printk("ARP: arp_queue skb already on queue magic=%X.\n", skb->magic);	return;  }  if(arp_q==NULL)  	arp_queue_kick();  skb_queue_tail(&arp_q,skb);  skb->magic = ARP_QUEUE_MAGIC;  sti();}/* * Write the contents of the ARP cache to a PROCfs file. * This is not by long perfect, as the internal ARP table doesn't * have all the info we would like to have.  Oh well, it works for * now, eh? - FvK * Also note, that due to space limits, we cannot generate more than * 4Kbyte worth of data.  This usually is enough, but I have seen * machines die from under me because of a *very* large ARP cache. * This can be simply tested by doing: * *	# ping 255.255.255.255 *	# arp -a * * Perhaps we should redo PROCfs to handle larger buffers?  Michael? */intarp_get_info(char *buffer){  struct arpreq *req;  struct arp_table *apt;  int i;  char *pos;  /* Loop over the ARP table and copy structures to the buffer. */  pos = buffer;  i = 0;  for (i = 0; i < ARP_TABLE_SIZE; i++) {	cli();	apt = arp_tables[i];	sti();	while (apt != NULL) {		if (pos < (buffer + 4000)) {			req = (struct arpreq *) pos;			memset((char *) req, 0, sizeof(struct arpreq));			req->arp_pa.sa_family = AF_INET;			memcpy((char *) req->arp_pa.sa_data, (char *) &apt->ip, 4);				req->arp_ha.sa_family = apt->htype;			memcpy((char *) req->arp_ha.sa_data,		       		(char *) &apt->ha, apt->hlen);			req->arp_flags = apt->flags;		}		pos += sizeof(struct arpreq);		cli();		apt = apt->next;		sti();	}  }  return(pos - buffer);}/* Set (create) an ARP cache entry. */static intarp_req_set(struct arpreq *req){  struct arpreq r;  struct arp_table *apt;  struct sockaddr_in *si;  int htype, hlen;  /* We only understand about IP addresses... */  memcpy_fromfs(&r, req, sizeof(r));  if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);  /*   * Find out about the hardware type.   * We have to be compatible with BSD UNIX, so we have to   * assume that a "not set" value (i.e. 0) means Ethernet.   */  si = (struct sockaddr_in *) &r.arp_pa;  switch(r.arp_ha.sa_family) {	case 0:	case ARPHRD_ETHER:		htype = ARPHRD_ETHER;		hlen = ETH_ALEN;		break;		case ARPHRD_AX25:			htype = ARPHRD_AX25;			hlen = 7;			break;			default:		return(-EPFNOSUPPORT);  }  /* Is there an existing entry for this address? */  if (si->sin_addr.s_addr == 0) {	printk("ARP: SETARP: requested PA is 0.0.0.0 !\n");	return(-EINVAL);  }  apt = arp_lookup(si->sin_addr.s_addr);  if (apt == NULL) {	apt = arp_create(si->sin_addr.s_addr,		(unsigned char *) r.arp_ha.sa_data, hlen, htype);	if (apt == NULL) return(-ENOMEM);  }  /* We now have a pointer to an ARP entry.  Update it! */  memcpy((char *) &apt->ha, (char *) &r.arp_ha.sa_data, hlen);  apt->last_used = jiffies;  apt->flags = r.arp_flags;  if(apt->flags&ATF_PUBL)  	arp_proxies++;		/* Count proxy arps so we know if to use it */  return(0);}/* Get an ARP cache entry. */static intarp_req_get(struct arpreq *req){  struct arpreq r;  struct arp_table *apt;  struct sockaddr_in *si;  /* We only understand about IP addresses... */  memcpy_fromfs(&r, req, sizeof(r));  if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);  /* Is there an existing entry for this address? */  si = (struct sockaddr_in *) &r.arp_pa;  apt = arp_lookup(si->sin_addr.s_addr);  if (apt == NULL) return(-ENXIO);  /* We found it; copy into structure. */  memcpy((char *) r.arp_ha.sa_data, (char *) &apt->ha, apt->hlen);  r.arp_ha.sa_family = apt->htype;  /* Copy the information back */  memcpy_tofs(req, &r, sizeof(r));  return(0);}/* Delete an ARP cache entry. */static intarp_req_del(struct arpreq *req){  struct arpreq r;  struct sockaddr_in *si;  /* We only understand about IP addresses... */  memcpy_fromfs(&r, req, sizeof(r));  if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);  si = (struct sockaddr_in *) &r.arp_pa;    /* The system cope with this but splats up a nasty kernel message      We trap it beforehand and tell the user off */  if(chk_addr(si->sin_addr.s_addr)==IS_MYADDR)  	return -EINVAL;  	  arp_destroy(si->sin_addr.s_addr);  return(0);}/* Handle an ARP layer I/O control request. */intarp_ioctl(unsigned int cmd, void *arg){  int err;  switch(cmd) {	case DDIOCSDBG:		return(dbg_ioctl(arg, DBG_ARP));	case SIOCDARP:		if (!suser()) return(-EPERM);		err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq));		if(err)			return err;		return(arp_req_del((struct arpreq *)arg));	case SIOCGARP:		err=verify_area(VERIFY_WRITE,arg,sizeof(struct arpreq));		if(err)			return err;		return(arp_req_get((struct arpreq *)arg));	case SIOCSARP:		if (!suser()) return(-EPERM);		err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq));		if(err)			return err;		return(arp_req_set((struct arpreq *)arg));	default:		return(-EINVAL);  }  /*NOTREACHED*/  return(0);}

⌨️ 快捷键说明

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