diff options
Diffstat (limited to 'net/ipv4/arp.c')
| -rw-r--r-- | net/ipv4/arp.c | 114 |
1 files changed, 77 insertions, 37 deletions
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index c95cd93acf29..96c1955b3e2f 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c | |||
| @@ -70,6 +70,7 @@ | |||
| 70 | * bonding can change the skb before | 70 | * bonding can change the skb before |
| 71 | * sending (e.g. insert 8021q tag). | 71 | * sending (e.g. insert 8021q tag). |
| 72 | * Harald Welte : convert to make use of jenkins hash | 72 | * Harald Welte : convert to make use of jenkins hash |
| 73 | * Jesper D. Brouer: Proxy ARP PVLAN RFC 3069 support. | ||
| 73 | */ | 74 | */ |
| 74 | 75 | ||
| 75 | #include <linux/module.h> | 76 | #include <linux/module.h> |
| @@ -97,6 +98,7 @@ | |||
| 97 | #include <linux/net.h> | 98 | #include <linux/net.h> |
| 98 | #include <linux/rcupdate.h> | 99 | #include <linux/rcupdate.h> |
| 99 | #include <linux/jhash.h> | 100 | #include <linux/jhash.h> |
| 101 | #include <linux/slab.h> | ||
| 100 | #ifdef CONFIG_SYSCTL | 102 | #ifdef CONFIG_SYSCTL |
| 101 | #include <linux/sysctl.h> | 103 | #include <linux/sysctl.h> |
| 102 | #endif | 104 | #endif |
| @@ -114,6 +116,7 @@ | |||
| 114 | #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) | 116 | #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) |
| 115 | #include <net/atmclip.h> | 117 | #include <net/atmclip.h> |
| 116 | struct neigh_table *clip_tbl_hook; | 118 | struct neigh_table *clip_tbl_hook; |
| 119 | EXPORT_SYMBOL(clip_tbl_hook); | ||
| 117 | #endif | 120 | #endif |
| 118 | 121 | ||
| 119 | #include <asm/system.h> | 122 | #include <asm/system.h> |
| @@ -167,6 +170,7 @@ const struct neigh_ops arp_broken_ops = { | |||
| 167 | .hh_output = dev_queue_xmit, | 170 | .hh_output = dev_queue_xmit, |
| 168 | .queue_xmit = dev_queue_xmit, | 171 | .queue_xmit = dev_queue_xmit, |
| 169 | }; | 172 | }; |
| 173 | EXPORT_SYMBOL(arp_broken_ops); | ||
| 170 | 174 | ||
| 171 | struct neigh_table arp_tbl = { | 175 | struct neigh_table arp_tbl = { |
| 172 | .family = AF_INET, | 176 | .family = AF_INET, |
| @@ -196,6 +200,7 @@ struct neigh_table arp_tbl = { | |||
| 196 | .gc_thresh2 = 512, | 200 | .gc_thresh2 = 512, |
| 197 | .gc_thresh3 = 1024, | 201 | .gc_thresh3 = 1024, |
| 198 | }; | 202 | }; |
| 203 | EXPORT_SYMBOL(arp_tbl); | ||
| 199 | 204 | ||
| 200 | int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) | 205 | int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) |
| 201 | { | 206 | { |
| @@ -331,11 +336,14 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
| 331 | struct net_device *dev = neigh->dev; | 336 | struct net_device *dev = neigh->dev; |
| 332 | __be32 target = *(__be32*)neigh->primary_key; | 337 | __be32 target = *(__be32*)neigh->primary_key; |
| 333 | int probes = atomic_read(&neigh->probes); | 338 | int probes = atomic_read(&neigh->probes); |
| 334 | struct in_device *in_dev = in_dev_get(dev); | 339 | struct in_device *in_dev; |
| 335 | 340 | ||
| 336 | if (!in_dev) | 341 | rcu_read_lock(); |
| 342 | in_dev = __in_dev_get_rcu(dev); | ||
| 343 | if (!in_dev) { | ||
| 344 | rcu_read_unlock(); | ||
| 337 | return; | 345 | return; |
| 338 | 346 | } | |
| 339 | switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { | 347 | switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { |
| 340 | default: | 348 | default: |
| 341 | case 0: /* By default announce any local IP */ | 349 | case 0: /* By default announce any local IP */ |
| @@ -356,9 +364,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
| 356 | case 2: /* Avoid secondary IPs, get a primary/preferred one */ | 364 | case 2: /* Avoid secondary IPs, get a primary/preferred one */ |
| 357 | break; | 365 | break; |
| 358 | } | 366 | } |
| 367 | rcu_read_unlock(); | ||
| 359 | 368 | ||
| 360 | if (in_dev) | ||
| 361 | in_dev_put(in_dev); | ||
| 362 | if (!saddr) | 369 | if (!saddr) |
| 363 | saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); | 370 | saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); |
| 364 | 371 | ||
| @@ -425,7 +432,7 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) | |||
| 425 | 432 | ||
| 426 | if (ip_route_output_key(net, &rt, &fl) < 0) | 433 | if (ip_route_output_key(net, &rt, &fl) < 0) |
| 427 | return 1; | 434 | return 1; |
| 428 | if (rt->u.dst.dev != dev) { | 435 | if (rt->dst.dev != dev) { |
| 429 | NET_INC_STATS_BH(net, LINUX_MIB_ARPFILTER); | 436 | NET_INC_STATS_BH(net, LINUX_MIB_ARPFILTER); |
| 430 | flag = 1; | 437 | flag = 1; |
| 431 | } | 438 | } |
| @@ -495,6 +502,7 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb) | |||
| 495 | kfree_skb(skb); | 502 | kfree_skb(skb); |
| 496 | return 1; | 503 | return 1; |
| 497 | } | 504 | } |
| 505 | EXPORT_SYMBOL(arp_find); | ||
| 498 | 506 | ||
| 499 | /* END OF OBSOLETE FUNCTIONS */ | 507 | /* END OF OBSOLETE FUNCTIONS */ |
| 500 | 508 | ||
| @@ -524,12 +532,15 @@ int arp_bind_neighbour(struct dst_entry *dst) | |||
| 524 | /* | 532 | /* |
| 525 | * Check if we can use proxy ARP for this path | 533 | * Check if we can use proxy ARP for this path |
| 526 | */ | 534 | */ |
| 527 | 535 | static inline int arp_fwd_proxy(struct in_device *in_dev, | |
| 528 | static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt) | 536 | struct net_device *dev, struct rtable *rt) |
| 529 | { | 537 | { |
| 530 | struct in_device *out_dev; | 538 | struct in_device *out_dev; |
| 531 | int imi, omi = -1; | 539 | int imi, omi = -1; |
| 532 | 540 | ||
| 541 | if (rt->dst.dev == dev) | ||
| 542 | return 0; | ||
| 543 | |||
| 533 | if (!IN_DEV_PROXY_ARP(in_dev)) | 544 | if (!IN_DEV_PROXY_ARP(in_dev)) |
| 534 | return 0; | 545 | return 0; |
| 535 | 546 | ||
| @@ -540,14 +551,51 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt) | |||
| 540 | 551 | ||
| 541 | /* place to check for proxy_arp for routes */ | 552 | /* place to check for proxy_arp for routes */ |
| 542 | 553 | ||
| 543 | if ((out_dev = in_dev_get(rt->u.dst.dev)) != NULL) { | 554 | out_dev = __in_dev_get_rcu(rt->dst.dev); |
| 555 | if (out_dev) | ||
| 544 | omi = IN_DEV_MEDIUM_ID(out_dev); | 556 | omi = IN_DEV_MEDIUM_ID(out_dev); |
| 545 | in_dev_put(out_dev); | 557 | |
| 546 | } | ||
| 547 | return (omi != imi && omi != -1); | 558 | return (omi != imi && omi != -1); |
| 548 | } | 559 | } |
| 549 | 560 | ||
| 550 | /* | 561 | /* |
| 562 | * Check for RFC3069 proxy arp private VLAN (allow to send back to same dev) | ||
| 563 | * | ||
| 564 | * RFC3069 supports proxy arp replies back to the same interface. This | ||
| 565 | * is done to support (ethernet) switch features, like RFC 3069, where | ||
| 566 | * the individual ports are not allowed to communicate with each | ||
| 567 | * other, BUT they are allowed to talk to the upstream router. As | ||
| 568 | * described in RFC 3069, it is possible to allow these hosts to | ||
| 569 | * communicate through the upstream router, by proxy_arp'ing. | ||
| 570 | * | ||
| 571 | * RFC 3069: "VLAN Aggregation for Efficient IP Address Allocation" | ||
| 572 | * | ||
| 573 | * This technology is known by different names: | ||
| 574 | * In RFC 3069 it is called VLAN Aggregation. | ||
| 575 | * Cisco and Allied Telesyn call it Private VLAN. | ||
| 576 | * Hewlett-Packard call it Source-Port filtering or port-isolation. | ||
| 577 | * Ericsson call it MAC-Forced Forwarding (RFC Draft). | ||
| 578 | * | ||
| 579 | */ | ||
| 580 | static inline int arp_fwd_pvlan(struct in_device *in_dev, | ||
| 581 | struct net_device *dev, struct rtable *rt, | ||
| 582 | __be32 sip, __be32 tip) | ||
| 583 | { | ||
| 584 | /* Private VLAN is only concerned about the same ethernet segment */ | ||
| 585 | if (rt->dst.dev != dev) | ||
| 586 | return 0; | ||
| 587 | |||
| 588 | /* Don't reply on self probes (often done by windowz boxes)*/ | ||
| 589 | if (sip == tip) | ||
| 590 | return 0; | ||
| 591 | |||
| 592 | if (IN_DEV_PROXY_ARP_PVLAN(in_dev)) | ||
| 593 | return 1; | ||
| 594 | else | ||
| 595 | return 0; | ||
| 596 | } | ||
| 597 | |||
| 598 | /* | ||
| 551 | * Interface to link layer: send routine and receive handler. | 599 | * Interface to link layer: send routine and receive handler. |
| 552 | */ | 600 | */ |
| 553 | 601 | ||
| @@ -619,13 +667,13 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, | |||
| 619 | #endif | 667 | #endif |
| 620 | #endif | 668 | #endif |
| 621 | 669 | ||
| 622 | #ifdef CONFIG_FDDI | 670 | #if defined(CONFIG_FDDI) || defined(CONFIG_FDDI_MODULE) |
| 623 | case ARPHRD_FDDI: | 671 | case ARPHRD_FDDI: |
| 624 | arp->ar_hrd = htons(ARPHRD_ETHER); | 672 | arp->ar_hrd = htons(ARPHRD_ETHER); |
| 625 | arp->ar_pro = htons(ETH_P_IP); | 673 | arp->ar_pro = htons(ETH_P_IP); |
| 626 | break; | 674 | break; |
| 627 | #endif | 675 | #endif |
| 628 | #ifdef CONFIG_TR | 676 | #if defined(CONFIG_TR) || defined(CONFIG_TR_MODULE) |
| 629 | case ARPHRD_IEEE802_TR: | 677 | case ARPHRD_IEEE802_TR: |
| 630 | arp->ar_hrd = htons(ARPHRD_IEEE802); | 678 | arp->ar_hrd = htons(ARPHRD_IEEE802); |
| 631 | arp->ar_pro = htons(ETH_P_IP); | 679 | arp->ar_pro = htons(ETH_P_IP); |
| @@ -656,6 +704,7 @@ out: | |||
| 656 | kfree_skb(skb); | 704 | kfree_skb(skb); |
| 657 | return NULL; | 705 | return NULL; |
| 658 | } | 706 | } |
| 707 | EXPORT_SYMBOL(arp_create); | ||
| 659 | 708 | ||
| 660 | /* | 709 | /* |
| 661 | * Send an arp packet. | 710 | * Send an arp packet. |
| @@ -665,6 +714,7 @@ void arp_xmit(struct sk_buff *skb) | |||
| 665 | /* Send it off, maybe filter it using firewalling first. */ | 714 | /* Send it off, maybe filter it using firewalling first. */ |
| 666 | NF_HOOK(NFPROTO_ARP, NF_ARP_OUT, skb, NULL, skb->dev, dev_queue_xmit); | 715 | NF_HOOK(NFPROTO_ARP, NF_ARP_OUT, skb, NULL, skb->dev, dev_queue_xmit); |
| 667 | } | 716 | } |
| 717 | EXPORT_SYMBOL(arp_xmit); | ||
| 668 | 718 | ||
| 669 | /* | 719 | /* |
| 670 | * Create and send an arp packet. | 720 | * Create and send an arp packet. |
| @@ -691,6 +741,7 @@ void arp_send(int type, int ptype, __be32 dest_ip, | |||
| 691 | 741 | ||
| 692 | arp_xmit(skb); | 742 | arp_xmit(skb); |
| 693 | } | 743 | } |
| 744 | EXPORT_SYMBOL(arp_send); | ||
| 694 | 745 | ||
| 695 | /* | 746 | /* |
| 696 | * Process an arp request. | 747 | * Process an arp request. |
| @@ -699,7 +750,7 @@ void arp_send(int type, int ptype, __be32 dest_ip, | |||
| 699 | static int arp_process(struct sk_buff *skb) | 750 | static int arp_process(struct sk_buff *skb) |
| 700 | { | 751 | { |
| 701 | struct net_device *dev = skb->dev; | 752 | struct net_device *dev = skb->dev; |
| 702 | struct in_device *in_dev = in_dev_get(dev); | 753 | struct in_device *in_dev = __in_dev_get_rcu(dev); |
| 703 | struct arphdr *arp; | 754 | struct arphdr *arp; |
| 704 | unsigned char *arp_ptr; | 755 | unsigned char *arp_ptr; |
| 705 | struct rtable *rt; | 756 | struct rtable *rt; |
| @@ -812,7 +863,7 @@ static int arp_process(struct sk_buff *skb) | |||
| 812 | } | 863 | } |
| 813 | 864 | ||
| 814 | if (arp->ar_op == htons(ARPOP_REQUEST) && | 865 | if (arp->ar_op == htons(ARPOP_REQUEST) && |
| 815 | ip_route_input(skb, tip, sip, 0, dev) == 0) { | 866 | ip_route_input_noref(skb, tip, sip, 0, dev) == 0) { |
| 816 | 867 | ||
| 817 | rt = skb_rtable(skb); | 868 | rt = skb_rtable(skb); |
| 818 | addr_type = rt->rt_type; | 869 | addr_type = rt->rt_type; |
| @@ -833,8 +884,11 @@ static int arp_process(struct sk_buff *skb) | |||
| 833 | } | 884 | } |
| 834 | goto out; | 885 | goto out; |
| 835 | } else if (IN_DEV_FORWARD(in_dev)) { | 886 | } else if (IN_DEV_FORWARD(in_dev)) { |
| 836 | if (addr_type == RTN_UNICAST && rt->u.dst.dev != dev && | 887 | if (addr_type == RTN_UNICAST && |
| 837 | (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) { | 888 | (arp_fwd_proxy(in_dev, dev, rt) || |
| 889 | arp_fwd_pvlan(in_dev, dev, rt, sip, tip) || | ||
| 890 | pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) | ||
| 891 | { | ||
| 838 | n = neigh_event_ns(&arp_tbl, sha, &sip, dev); | 892 | n = neigh_event_ns(&arp_tbl, sha, &sip, dev); |
| 839 | if (n) | 893 | if (n) |
| 840 | neigh_release(n); | 894 | neigh_release(n); |
| @@ -845,7 +899,6 @@ static int arp_process(struct sk_buff *skb) | |||
| 845 | arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); | 899 | arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); |
| 846 | } else { | 900 | } else { |
| 847 | pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb); | 901 | pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb); |
| 848 | in_dev_put(in_dev); | ||
| 849 | return 0; | 902 | return 0; |
| 850 | } | 903 | } |
| 851 | goto out; | 904 | goto out; |
| @@ -863,7 +916,8 @@ static int arp_process(struct sk_buff *skb) | |||
| 863 | devices (strip is candidate) | 916 | devices (strip is candidate) |
| 864 | */ | 917 | */ |
| 865 | if (n == NULL && | 918 | if (n == NULL && |
| 866 | arp->ar_op == htons(ARPOP_REPLY) && | 919 | (arp->ar_op == htons(ARPOP_REPLY) || |
| 920 | (arp->ar_op == htons(ARPOP_REQUEST) && tip == sip)) && | ||
| 867 | inet_addr_type(net, sip) == RTN_UNICAST) | 921 | inet_addr_type(net, sip) == RTN_UNICAST) |
| 868 | n = __neigh_lookup(&arp_tbl, &sip, dev, 1); | 922 | n = __neigh_lookup(&arp_tbl, &sip, dev, 1); |
| 869 | } | 923 | } |
| @@ -890,8 +944,6 @@ static int arp_process(struct sk_buff *skb) | |||
| 890 | } | 944 | } |
| 891 | 945 | ||
| 892 | out: | 946 | out: |
| 893 | if (in_dev) | ||
| 894 | in_dev_put(in_dev); | ||
| 895 | consume_skb(skb); | 947 | consume_skb(skb); |
| 896 | return 0; | 948 | return 0; |
| 897 | } | 949 | } |
| @@ -999,13 +1051,13 @@ static int arp_req_set(struct net *net, struct arpreq *r, | |||
| 999 | struct rtable * rt; | 1051 | struct rtable * rt; |
| 1000 | if ((err = ip_route_output_key(net, &rt, &fl)) != 0) | 1052 | if ((err = ip_route_output_key(net, &rt, &fl)) != 0) |
| 1001 | return err; | 1053 | return err; |
| 1002 | dev = rt->u.dst.dev; | 1054 | dev = rt->dst.dev; |
| 1003 | ip_rt_put(rt); | 1055 | ip_rt_put(rt); |
| 1004 | if (!dev) | 1056 | if (!dev) |
| 1005 | return -EINVAL; | 1057 | return -EINVAL; |
| 1006 | } | 1058 | } |
| 1007 | switch (dev->type) { | 1059 | switch (dev->type) { |
| 1008 | #ifdef CONFIG_FDDI | 1060 | #if defined(CONFIG_FDDI) || defined(CONFIG_FDDI_MODULE) |
| 1009 | case ARPHRD_FDDI: | 1061 | case ARPHRD_FDDI: |
| 1010 | /* | 1062 | /* |
| 1011 | * According to RFC 1390, FDDI devices should accept ARP | 1063 | * According to RFC 1390, FDDI devices should accept ARP |
| @@ -1106,7 +1158,7 @@ static int arp_req_delete(struct net *net, struct arpreq *r, | |||
| 1106 | struct rtable * rt; | 1158 | struct rtable * rt; |
| 1107 | if ((err = ip_route_output_key(net, &rt, &fl)) != 0) | 1159 | if ((err = ip_route_output_key(net, &rt, &fl)) != 0) |
| 1108 | return err; | 1160 | return err; |
| 1109 | dev = rt->u.dst.dev; | 1161 | dev = rt->dst.dev; |
| 1110 | ip_rt_put(rt); | 1162 | ip_rt_put(rt); |
| 1111 | if (!dev) | 1163 | if (!dev) |
| 1112 | return -EINVAL; | 1164 | return -EINVAL; |
| @@ -1239,8 +1291,7 @@ void __init arp_init(void) | |||
| 1239 | dev_add_pack(&arp_packet_type); | 1291 | dev_add_pack(&arp_packet_type); |
| 1240 | arp_proc_init(); | 1292 | arp_proc_init(); |
| 1241 | #ifdef CONFIG_SYSCTL | 1293 | #ifdef CONFIG_SYSCTL |
| 1242 | neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, | 1294 | neigh_sysctl_register(NULL, &arp_tbl.parms, "ipv4", NULL); |
| 1243 | NET_IPV4_NEIGH, "ipv4", NULL); | ||
| 1244 | #endif | 1295 | #endif |
| 1245 | register_netdevice_notifier(&arp_netdev_notifier); | 1296 | register_netdevice_notifier(&arp_netdev_notifier); |
| 1246 | } | 1297 | } |
| @@ -1408,14 +1459,3 @@ static int __init arp_proc_init(void) | |||
| 1408 | } | 1459 | } |
| 1409 | 1460 | ||
| 1410 | #endif /* CONFIG_PROC_FS */ | 1461 | #endif /* CONFIG_PROC_FS */ |
| 1411 | |||
| 1412 | EXPORT_SYMBOL(arp_broken_ops); | ||
| 1413 | EXPORT_SYMBOL(arp_find); | ||
| 1414 | EXPORT_SYMBOL(arp_create); | ||
| 1415 | EXPORT_SYMBOL(arp_xmit); | ||
| 1416 | EXPORT_SYMBOL(arp_send); | ||
| 1417 | EXPORT_SYMBOL(arp_tbl); | ||
| 1418 | |||
| 1419 | #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) | ||
| 1420 | EXPORT_SYMBOL(clip_tbl_hook); | ||
| 1421 | #endif | ||
