📄 arp.c
字号:
goto out_of_mem; memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); return NF_HOOK(NF_ARP, NF_ARP_IN, skb, dev, NULL, arp_process);freeskb: kfree_skb(skb);out_of_mem: return 0;}/* * User level interface (ioctl) *//* * Set (create) an ARP cache entry. */static int arp_req_set(struct arpreq *r, struct net_device * dev){ __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; int err; if (r->arp_flags&ATF_PUBL) { __be32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr; if (mask && mask != htonl(0xFFFFFFFF)) return -EINVAL; if (!dev && (r->arp_flags & ATF_COM)) { dev = dev_getbyhwaddr(&init_net, 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_ALL(PROXY_ARP) = 1; return 0; } if (__in_dev_get_rtnl(dev)) { IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, 1); return 0; } return -ENXIO; } if (r->arp_flags & ATF_PERM) r->arp_flags |= ATF_COM; if (dev == NULL) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = RTO_ONLINK } } }; struct rtable * rt; if ((err = ip_route_output_key(&rt, &fl)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); if (!dev) return -EINVAL; } switch (dev->type) {#ifdef CONFIG_FDDI case ARPHRD_FDDI: /* * According to RFC 1390, FDDI devices should accept ARP * hardware types of 1 (Ethernet). However, to be more * robust, we'll accept hardware types of either 1 (Ethernet) * or 6 (IEEE 802.2). */ if (r->arp_ha.sa_family != ARPHRD_FDDI && r->arp_ha.sa_family != ARPHRD_ETHER && r->arp_ha.sa_family != ARPHRD_IEEE802) return -EINVAL; break;#endif default: if (r->arp_ha.sa_family != dev->type) return -EINVAL; break; } 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, NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_ADMIN); 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){ __be32 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; strlcpy(r->arp_dev, dev->name, sizeof(r->arp_dev)); neigh_release(neigh); err = 0; } return err;}static int arp_req_delete(struct arpreq *r, struct net_device * dev){ int err; __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; if (r->arp_flags & ATF_PUBL) { __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; if (mask == htonl(0xFFFFFFFF)) return pneigh_delete(&arp_tbl, &ip, dev); if (mask == 0) { if (dev == NULL) { IPV4_DEVCONF_ALL(PROXY_ARP) = 0; return 0; } if (__in_dev_get_rtnl(dev)) { IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, 0); return 0; } return -ENXIO; } return -EINVAL; } if (dev == NULL) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = RTO_ONLINK } } }; struct rtable * rt; if ((err = ip_route_output_key(&rt, &fl)) != 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, NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_ADMIN); neigh_release(neigh); } return err;}/* * Handle an ARP layer I/O control request. */int arp_ioctl(unsigned int cmd, void __user *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 = htonl(0xFFFFFFFFUL); rtnl_lock(); if (r.arp_dev[0]) { err = -ENODEV; if ((dev = __dev_get_by_name(&init_net, 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;}static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr){ struct net_device *dev = ptr; if (dev->nd_net != &init_net) return NOTIFY_DONE; switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&arp_tbl, dev); rt_cache_flush(0); break; default: break; } return NOTIFY_DONE;}static struct notifier_block arp_netdev_notifier = { .notifier_call = arp_netdev_event,};/* 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,};static int arp_proc_init(void);void __init arp_init(void){ neigh_table_init(&arp_tbl); dev_add_pack(&arp_packet_type); arp_proc_init();#ifdef CONFIG_SYSCTL neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4", NULL, NULL);#endif register_netdevice_notifier(&arp_netdev_notifier);}#ifdef CONFIG_PROC_FS#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)/* ------------------------------------------------------------------------ *//* * ax25 -> ASCII conversion */static 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 /* CONFIG_AX25 */#define HBUFFERLEN 30static void arp_format_neigh_entry(struct seq_file *seq, struct neighbour *n){ char hbuffer[HBUFFERLEN]; const char hexbuf[] = "0123456789ABCDEF"; int k, j; char tbuf[16]; struct net_device *dev = n->dev; int hatype = dev->type; 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 sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->primary_key)); seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", tbuf, hatype, arp_state_to_flags(n), hbuffer, dev->name); read_unlock(&n->lock);}static void arp_format_pneigh_entry(struct seq_file *seq, struct pneigh_entry *n){ 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)); seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", tbuf, hatype, ATF_PUBL | ATF_PERM, "00:00:00:00:00:00", dev ? dev->name : "*");}static int arp_seq_show(struct seq_file *seq, void *v){ if (v == SEQ_START_TOKEN) { seq_puts(seq, "IP address HW type Flags " "HW address Mask Device\n"); } else { struct neigh_seq_state *state = seq->private; if (state->flags & NEIGH_SEQ_IS_PNEIGH) arp_format_pneigh_entry(seq, v); else arp_format_neigh_entry(seq, v); } return 0;}static void *arp_seq_start(struct seq_file *seq, loff_t *pos){ /* Don't want to confuse "arp -a" w/ magic entries, * so we tell the generic iterator to skip NUD_NOARP. */ return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_SKIP_NOARP);}/* ------------------------------------------------------------------------ */static const struct seq_operations arp_seq_ops = { .start = arp_seq_start, .next = neigh_seq_next, .stop = neigh_seq_stop, .show = arp_seq_show,};static int arp_seq_open(struct inode *inode, struct file *file){ return seq_open_private(file, &arp_seq_ops, sizeof(struct neigh_seq_state));}static const struct file_operations arp_seq_fops = { .owner = THIS_MODULE, .open = arp_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private,};static int __init arp_proc_init(void){ if (!proc_net_fops_create(&init_net, "arp", S_IRUGO, &arp_seq_fops)) return -ENOMEM; return 0;}#else /* CONFIG_PROC_FS */static int __init arp_proc_init(void){ return 0;}#endif /* CONFIG_PROC_FS */EXPORT_SYMBOL(arp_broken_ops);EXPORT_SYMBOL(arp_find);EXPORT_SYMBOL(arp_create);EXPORT_SYMBOL(arp_xmit);EXPORT_SYMBOL(arp_send);EXPORT_SYMBOL(arp_tbl);#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)EXPORT_SYMBOL(clip_tbl_hook);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -