📄 arp.c
字号:
kfree_skb(skb);out_of_mem: return 0;}/* * User level interface (ioctl, /proc) *//* * Set (create) an ARP cache entry. */int arp_req_set(struct arpreq *r, struct net_device * dev){ u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; int err; if (r->arp_flags&ATF_PUBL) { u32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr; if (mask && mask != 0xFFFFFFFF) return -EINVAL; if (!dev && (r->arp_flags & ATF_COM)) { dev = dev_getbyhwaddr(r->arp_ha.sa_family, r->arp_ha.sa_data); if (!dev) return -ENODEV; } if (mask) { if (pneigh_lookup(&arp_tbl, &ip, dev, 1) == NULL) return -ENOBUFS; return 0; } if (dev == NULL) { ipv4_devconf.proxy_arp = 1; return 0; } if (__in_dev_get(dev)) { __in_dev_get(dev)->cnf.proxy_arp = 1; return 0; } return -ENXIO; } if (r->arp_flags & ATF_PERM) r->arp_flags |= ATF_COM; if (dev == NULL) { struct rtable * rt; if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); if (!dev) return -EINVAL; } if (r->arp_ha.sa_family != dev->type) return -EINVAL; neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev); err = PTR_ERR(neigh); if (!IS_ERR(neigh)) { unsigned state = NUD_STALE; if (r->arp_flags & ATF_PERM) state = NUD_PERMANENT; err = neigh_update(neigh, (r->arp_flags&ATF_COM) ? r->arp_ha.sa_data : NULL, state, 1, 0); neigh_release(neigh); } return err;}static unsigned arp_state_to_flags(struct neighbour *neigh){ unsigned flags = 0; if (neigh->nud_state&NUD_PERMANENT) flags = ATF_PERM|ATF_COM; else if (neigh->nud_state&NUD_VALID) flags = ATF_COM; return flags;}/* * Get an ARP cache entry. */static int arp_req_get(struct arpreq *r, struct net_device *dev){ u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; int err = -ENXIO; neigh = neigh_lookup(&arp_tbl, &ip, dev); if (neigh) { read_lock_bh(&neigh->lock); memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len); r->arp_flags = arp_state_to_flags(neigh); read_unlock_bh(&neigh->lock); r->arp_ha.sa_family = dev->type; strncpy(r->arp_dev, dev->name, sizeof(r->arp_dev)); neigh_release(neigh); err = 0; } return err;}int arp_req_delete(struct arpreq *r, struct net_device * dev){ int err; u32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; if (r->arp_flags & ATF_PUBL) { u32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr; if (mask == 0xFFFFFFFF) return pneigh_delete(&arp_tbl, &ip, dev); if (mask == 0) { if (dev == NULL) { ipv4_devconf.proxy_arp = 0; return 0; } if (__in_dev_get(dev)) { __in_dev_get(dev)->cnf.proxy_arp = 0; return 0; } return -ENXIO; } return -EINVAL; } if (dev == NULL) { struct rtable * rt; if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); if (!dev) return -EINVAL; } err = -ENXIO; neigh = neigh_lookup(&arp_tbl, &ip, dev); if (neigh) { if (neigh->nud_state&~NUD_NOARP) err = neigh_update(neigh, NULL, NUD_FAILED, 1, 0); neigh_release(neigh); } return err;}/* * Handle an ARP layer I/O control request. */int arp_ioctl(unsigned int cmd, void *arg){ int err; struct arpreq r; struct net_device * dev = NULL; switch(cmd) { case SIOCDARP: case SIOCSARP: if (!capable(CAP_NET_ADMIN)) return -EPERM; case SIOCGARP: err = copy_from_user(&r, arg, sizeof(struct arpreq)); if (err) return -EFAULT; break; default: return -EINVAL; } if (r.arp_pa.sa_family != AF_INET) return -EPFNOSUPPORT; if (!(r.arp_flags & ATF_PUBL) && (r.arp_flags & (ATF_NETMASK|ATF_DONTPUB))) return -EINVAL; if (!(r.arp_flags & ATF_NETMASK)) ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr=__constant_htonl(0xFFFFFFFFUL); rtnl_lock(); if (r.arp_dev[0]) { err = -ENODEV; if ((dev = __dev_get_by_name(r.arp_dev)) == NULL) goto out; /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ if (!r.arp_ha.sa_family) r.arp_ha.sa_family = dev->type; err = -EINVAL; if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type) goto out; } else if (cmd == SIOCGARP) { err = -ENODEV; goto out; } switch(cmd) { case SIOCDARP: err = arp_req_delete(&r, dev); break; case SIOCSARP: err = arp_req_set(&r, dev); break; case SIOCGARP: err = arp_req_get(&r, dev); if (!err && copy_to_user(arg, &r, sizeof(r))) err = -EFAULT; break; }out: rtnl_unlock(); return err;}/* * Write the contents of the ARP cache to a PROCfs file. */#ifndef CONFIG_PROC_FSstatic int arp_get_info(char *buffer, char **start, off_t offset, int length) { return 0; }#else#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)static char *ax2asc2(ax25_address *a, char *buf);#endif#define HBUFFERLEN 30static int arp_get_info(char *buffer, char **start, off_t offset, int length){ int len=0; off_t pos=0; int size; char hbuffer[HBUFFERLEN]; int i,j,k; const char hexbuf[] = "0123456789ABCDEF"; size = sprintf(buffer,"IP address HW type Flags HW address Mask Device\n"); pos+=size; len+=size; for(i=0; i<=NEIGH_HASHMASK; i++) { struct neighbour *n; read_lock_bh(&arp_tbl.lock); for (n=arp_tbl.hash_buckets[i]; n; n=n->next) { struct net_device *dev = n->dev; int hatype = dev->type; /* Do not confuse users "arp -a" with magic entries */ if (!(n->nud_state&~NUD_NOARP)) continue; read_lock(&n->lock);/* * Convert hardware address to XX:XX:XX:XX ... form. */#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM) ax2asc2((ax25_address *)n->ha, hbuffer); else {#endif for (k=0,j=0;k<HBUFFERLEN-3 && j<dev->addr_len;j++) { hbuffer[k++]=hexbuf[(n->ha[j]>>4)&15 ]; hbuffer[k++]=hexbuf[n->ha[j]&15 ]; hbuffer[k++]=':'; } hbuffer[--k]=0;#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) }#endif { char tbuf[16]; sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->primary_key)); size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s" " * %s\n", tbuf, hatype, arp_state_to_flags(n), hbuffer, dev->name); } read_unlock(&n->lock); len += size; pos += size; if (pos <= offset) len=0; if (pos >= offset+length) { read_unlock_bh(&arp_tbl.lock); goto done; } } read_unlock_bh(&arp_tbl.lock); } for (i=0; i<=PNEIGH_HASHMASK; i++) { struct pneigh_entry *n; for (n=arp_tbl.phash_buckets[i]; n; n=n->next) { struct net_device *dev = n->dev; int hatype = dev ? dev->type : 0; { char tbuf[16]; sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key)); size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s" " * %s\n", tbuf, hatype, ATF_PUBL|ATF_PERM, "00:00:00:00:00:00", dev ? dev->name : "*"); } len += size; pos += size; if (pos <= offset) len=0; if (pos >= offset+length) goto done; } }done: *start = buffer+len-(pos-offset); /* Start of wanted data */ len = pos-offset; /* Start slop */ if (len>length) len = length; /* Ending slop */ if (len<0) len = 0; return len;}#endif/* Note, that it is not on notifier chain. It is necessary, that this routine was called after route cache will be flushed. */void arp_ifdown(struct net_device *dev){ neigh_ifdown(&arp_tbl, dev);}/* * Called once on startup. */static struct packet_type arp_packet_type = { type: __constant_htons(ETH_P_ARP), func: arp_rcv, data: (void*) 1, /* understand shared skbs */};void __init arp_init (void){ neigh_table_init(&arp_tbl); dev_add_pack(&arp_packet_type); proc_net_create ("arp", 0, arp_get_info);#ifdef CONFIG_SYSCTL neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");#endif}#ifdef CONFIG_PROC_FS#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)/* * ax25 -> ASCII conversion */char *ax2asc2(ax25_address *a, char *buf){ char c, *s; int n; for (n = 0, s = buf; n < 6; n++) { c = (a->ax25_call[n] >> 1) & 0x7F; if (c != ' ') *s++ = c; } *s++ = '-'; if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) { *s++ = '1'; n -= 10; } *s++ = n + '0'; *s++ = '\0'; if (*buf == '\0' || *buf == '-') return "*"; return buf;}#endif#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -