diff options
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r-- | net/core/rtnetlink.c | 178 |
1 files changed, 93 insertions, 85 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 23854b51a259..a08bd2b7fe3f 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -517,32 +517,6 @@ out: | |||
517 | return err; | 517 | return err; |
518 | } | 518 | } |
519 | 519 | ||
520 | static const int rtm_min[RTM_NR_FAMILIES] = | ||
521 | { | ||
522 | [RTM_FAM(RTM_NEWLINK)] = NLMSG_LENGTH(sizeof(struct ifinfomsg)), | ||
523 | [RTM_FAM(RTM_NEWADDR)] = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), | ||
524 | [RTM_FAM(RTM_NEWROUTE)] = NLMSG_LENGTH(sizeof(struct rtmsg)), | ||
525 | [RTM_FAM(RTM_NEWRULE)] = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)), | ||
526 | [RTM_FAM(RTM_NEWQDISC)] = NLMSG_LENGTH(sizeof(struct tcmsg)), | ||
527 | [RTM_FAM(RTM_NEWTCLASS)] = NLMSG_LENGTH(sizeof(struct tcmsg)), | ||
528 | [RTM_FAM(RTM_NEWTFILTER)] = NLMSG_LENGTH(sizeof(struct tcmsg)), | ||
529 | [RTM_FAM(RTM_NEWACTION)] = NLMSG_LENGTH(sizeof(struct tcamsg)), | ||
530 | [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), | ||
531 | [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), | ||
532 | }; | ||
533 | |||
534 | static const int rta_max[RTM_NR_FAMILIES] = | ||
535 | { | ||
536 | [RTM_FAM(RTM_NEWLINK)] = IFLA_MAX, | ||
537 | [RTM_FAM(RTM_NEWADDR)] = IFA_MAX, | ||
538 | [RTM_FAM(RTM_NEWROUTE)] = RTA_MAX, | ||
539 | [RTM_FAM(RTM_NEWRULE)] = FRA_MAX, | ||
540 | [RTM_FAM(RTM_NEWQDISC)] = TCA_MAX, | ||
541 | [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX, | ||
542 | [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX, | ||
543 | [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX, | ||
544 | }; | ||
545 | |||
546 | int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned int group, int echo) | 520 | int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned int group, int echo) |
547 | { | 521 | { |
548 | struct sock *rtnl = net->rtnl; | 522 | struct sock *rtnl = net->rtnl; |
@@ -1539,7 +1513,7 @@ errout: | |||
1539 | return err; | 1513 | return err; |
1540 | } | 1514 | } |
1541 | 1515 | ||
1542 | static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1516 | static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh) |
1543 | { | 1517 | { |
1544 | struct net *net = sock_net(skb->sk); | 1518 | struct net *net = sock_net(skb->sk); |
1545 | struct ifinfomsg *ifm; | 1519 | struct ifinfomsg *ifm; |
@@ -1580,7 +1554,7 @@ errout: | |||
1580 | return err; | 1554 | return err; |
1581 | } | 1555 | } |
1582 | 1556 | ||
1583 | static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1557 | static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh) |
1584 | { | 1558 | { |
1585 | struct net *net = sock_net(skb->sk); | 1559 | struct net *net = sock_net(skb->sk); |
1586 | const struct rtnl_link_ops *ops; | 1560 | const struct rtnl_link_ops *ops; |
@@ -1711,7 +1685,7 @@ static int rtnl_group_changelink(struct net *net, int group, | |||
1711 | return 0; | 1685 | return 0; |
1712 | } | 1686 | } |
1713 | 1687 | ||
1714 | static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1688 | static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh) |
1715 | { | 1689 | { |
1716 | struct net *net = sock_net(skb->sk); | 1690 | struct net *net = sock_net(skb->sk); |
1717 | const struct rtnl_link_ops *ops; | 1691 | const struct rtnl_link_ops *ops; |
@@ -1866,7 +1840,7 @@ out: | |||
1866 | } | 1840 | } |
1867 | } | 1841 | } |
1868 | 1842 | ||
1869 | static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 1843 | static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh) |
1870 | { | 1844 | { |
1871 | struct net *net = sock_net(skb->sk); | 1845 | struct net *net = sock_net(skb->sk); |
1872 | struct ifinfomsg *ifm; | 1846 | struct ifinfomsg *ifm; |
@@ -1957,8 +1931,11 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) | |||
1957 | if (rtnl_msg_handlers[idx] == NULL || | 1931 | if (rtnl_msg_handlers[idx] == NULL || |
1958 | rtnl_msg_handlers[idx][type].dumpit == NULL) | 1932 | rtnl_msg_handlers[idx][type].dumpit == NULL) |
1959 | continue; | 1933 | continue; |
1960 | if (idx > s_idx) | 1934 | if (idx > s_idx) { |
1961 | memset(&cb->args[0], 0, sizeof(cb->args)); | 1935 | memset(&cb->args[0], 0, sizeof(cb->args)); |
1936 | cb->prev_seq = 0; | ||
1937 | cb->seq = 0; | ||
1938 | } | ||
1962 | if (rtnl_msg_handlers[idx][type].dumpit(skb, cb)) | 1939 | if (rtnl_msg_handlers[idx][type].dumpit(skb, cb)) |
1963 | break; | 1940 | break; |
1964 | } | 1941 | } |
@@ -2051,7 +2028,39 @@ errout: | |||
2051 | rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); | 2028 | rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); |
2052 | } | 2029 | } |
2053 | 2030 | ||
2054 | static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 2031 | /** |
2032 | * ndo_dflt_fdb_add - default netdevice operation to add an FDB entry | ||
2033 | */ | ||
2034 | int ndo_dflt_fdb_add(struct ndmsg *ndm, | ||
2035 | struct nlattr *tb[], | ||
2036 | struct net_device *dev, | ||
2037 | const unsigned char *addr, | ||
2038 | u16 flags) | ||
2039 | { | ||
2040 | int err = -EINVAL; | ||
2041 | |||
2042 | /* If aging addresses are supported device will need to | ||
2043 | * implement its own handler for this. | ||
2044 | */ | ||
2045 | if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) { | ||
2046 | pr_info("%s: FDB only supports static addresses\n", dev->name); | ||
2047 | return err; | ||
2048 | } | ||
2049 | |||
2050 | if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) | ||
2051 | err = dev_uc_add_excl(dev, addr); | ||
2052 | else if (is_multicast_ether_addr(addr)) | ||
2053 | err = dev_mc_add_excl(dev, addr); | ||
2054 | |||
2055 | /* Only return duplicate errors if NLM_F_EXCL is set */ | ||
2056 | if (err == -EEXIST && !(flags & NLM_F_EXCL)) | ||
2057 | err = 0; | ||
2058 | |||
2059 | return err; | ||
2060 | } | ||
2061 | EXPORT_SYMBOL(ndo_dflt_fdb_add); | ||
2062 | |||
2063 | static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh) | ||
2055 | { | 2064 | { |
2056 | struct net *net = sock_net(skb->sk); | 2065 | struct net *net = sock_net(skb->sk); |
2057 | struct ndmsg *ndm; | 2066 | struct ndmsg *ndm; |
@@ -2082,7 +2091,7 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2082 | } | 2091 | } |
2083 | 2092 | ||
2084 | addr = nla_data(tb[NDA_LLADDR]); | 2093 | addr = nla_data(tb[NDA_LLADDR]); |
2085 | if (!is_valid_ether_addr(addr)) { | 2094 | if (is_zero_ether_addr(addr)) { |
2086 | pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid ether address\n"); | 2095 | pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid ether address\n"); |
2087 | return -EINVAL; | 2096 | return -EINVAL; |
2088 | } | 2097 | } |
@@ -2103,10 +2112,13 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2103 | } | 2112 | } |
2104 | 2113 | ||
2105 | /* Embedded bridge, macvlan, and any other device support */ | 2114 | /* Embedded bridge, macvlan, and any other device support */ |
2106 | if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_add) { | 2115 | if ((ndm->ndm_flags & NTF_SELF)) { |
2107 | err = dev->netdev_ops->ndo_fdb_add(ndm, tb, | 2116 | if (dev->netdev_ops->ndo_fdb_add) |
2108 | dev, addr, | 2117 | err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr, |
2109 | nlh->nlmsg_flags); | 2118 | nlh->nlmsg_flags); |
2119 | else | ||
2120 | err = ndo_dflt_fdb_add(ndm, tb, dev, addr, | ||
2121 | nlh->nlmsg_flags); | ||
2110 | 2122 | ||
2111 | if (!err) { | 2123 | if (!err) { |
2112 | rtnl_fdb_notify(dev, addr, RTM_NEWNEIGH); | 2124 | rtnl_fdb_notify(dev, addr, RTM_NEWNEIGH); |
@@ -2117,7 +2129,36 @@ out: | |||
2117 | return err; | 2129 | return err; |
2118 | } | 2130 | } |
2119 | 2131 | ||
2120 | static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 2132 | /** |
2133 | * ndo_dflt_fdb_del - default netdevice operation to delete an FDB entry | ||
2134 | */ | ||
2135 | int ndo_dflt_fdb_del(struct ndmsg *ndm, | ||
2136 | struct nlattr *tb[], | ||
2137 | struct net_device *dev, | ||
2138 | const unsigned char *addr) | ||
2139 | { | ||
2140 | int err = -EOPNOTSUPP; | ||
2141 | |||
2142 | /* If aging addresses are supported device will need to | ||
2143 | * implement its own handler for this. | ||
2144 | */ | ||
2145 | if (ndm->ndm_state & NUD_PERMANENT) { | ||
2146 | pr_info("%s: FDB only supports static addresses\n", dev->name); | ||
2147 | return -EINVAL; | ||
2148 | } | ||
2149 | |||
2150 | if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) | ||
2151 | err = dev_uc_del(dev, addr); | ||
2152 | else if (is_multicast_ether_addr(addr)) | ||
2153 | err = dev_mc_del(dev, addr); | ||
2154 | else | ||
2155 | err = -EINVAL; | ||
2156 | |||
2157 | return err; | ||
2158 | } | ||
2159 | EXPORT_SYMBOL(ndo_dflt_fdb_del); | ||
2160 | |||
2161 | static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh) | ||
2121 | { | 2162 | { |
2122 | struct net *net = sock_net(skb->sk); | 2163 | struct net *net = sock_net(skb->sk); |
2123 | struct ndmsg *ndm; | 2164 | struct ndmsg *ndm; |
@@ -2151,7 +2192,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2151 | } | 2192 | } |
2152 | 2193 | ||
2153 | addr = nla_data(tb[NDA_LLADDR]); | 2194 | addr = nla_data(tb[NDA_LLADDR]); |
2154 | if (!is_valid_ether_addr(addr)) { | 2195 | if (is_zero_ether_addr(addr)) { |
2155 | pr_info("PF_BRIDGE: RTM_DELNEIGH with invalid ether address\n"); | 2196 | pr_info("PF_BRIDGE: RTM_DELNEIGH with invalid ether address\n"); |
2156 | return -EINVAL; | 2197 | return -EINVAL; |
2157 | } | 2198 | } |
@@ -2174,8 +2215,11 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2174 | } | 2215 | } |
2175 | 2216 | ||
2176 | /* Embedded bridge, macvlan, and any other device support */ | 2217 | /* Embedded bridge, macvlan, and any other device support */ |
2177 | if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) { | 2218 | if (ndm->ndm_flags & NTF_SELF) { |
2178 | err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr); | 2219 | if (dev->netdev_ops->ndo_fdb_del) |
2220 | err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr); | ||
2221 | else | ||
2222 | err = ndo_dflt_fdb_del(ndm, tb, dev, addr); | ||
2179 | 2223 | ||
2180 | if (!err) { | 2224 | if (!err) { |
2181 | rtnl_fdb_notify(dev, addr, RTM_DELNEIGH); | 2225 | rtnl_fdb_notify(dev, addr, RTM_DELNEIGH); |
@@ -2220,7 +2264,7 @@ skip: | |||
2220 | * @dev: netdevice | 2264 | * @dev: netdevice |
2221 | * | 2265 | * |
2222 | * Default netdevice operation to dump the existing unicast address list. | 2266 | * Default netdevice operation to dump the existing unicast address list. |
2223 | * Returns zero on success. | 2267 | * Returns number of addresses from list put in skb. |
2224 | */ | 2268 | */ |
2225 | int ndo_dflt_fdb_dump(struct sk_buff *skb, | 2269 | int ndo_dflt_fdb_dump(struct sk_buff *skb, |
2226 | struct netlink_callback *cb, | 2270 | struct netlink_callback *cb, |
@@ -2260,6 +2304,8 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
2260 | 2304 | ||
2261 | if (dev->netdev_ops->ndo_fdb_dump) | 2305 | if (dev->netdev_ops->ndo_fdb_dump) |
2262 | idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx); | 2306 | idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx); |
2307 | else | ||
2308 | idx = ndo_dflt_fdb_dump(skb, cb, dev, idx); | ||
2263 | } | 2309 | } |
2264 | rcu_read_unlock(); | 2310 | rcu_read_unlock(); |
2265 | 2311 | ||
@@ -2411,8 +2457,7 @@ errout: | |||
2411 | return err; | 2457 | return err; |
2412 | } | 2458 | } |
2413 | 2459 | ||
2414 | static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, | 2460 | static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh) |
2415 | void *arg) | ||
2416 | { | 2461 | { |
2417 | struct net *net = sock_net(skb->sk); | 2462 | struct net *net = sock_net(skb->sk); |
2418 | struct ifinfomsg *ifm; | 2463 | struct ifinfomsg *ifm; |
@@ -2482,8 +2527,7 @@ out: | |||
2482 | return err; | 2527 | return err; |
2483 | } | 2528 | } |
2484 | 2529 | ||
2485 | static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, | 2530 | static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh) |
2486 | void *arg) | ||
2487 | { | 2531 | { |
2488 | struct net *net = sock_net(skb->sk); | 2532 | struct net *net = sock_net(skb->sk); |
2489 | struct ifinfomsg *ifm; | 2533 | struct ifinfomsg *ifm; |
@@ -2553,10 +2597,6 @@ out: | |||
2553 | return err; | 2597 | return err; |
2554 | } | 2598 | } |
2555 | 2599 | ||
2556 | /* Protected by RTNL sempahore. */ | ||
2557 | static struct rtattr **rta_buf; | ||
2558 | static int rtattr_max; | ||
2559 | |||
2560 | /* Process one rtnetlink message. */ | 2600 | /* Process one rtnetlink message. */ |
2561 | 2601 | ||
2562 | static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | 2602 | static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
@@ -2564,7 +2604,6 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
2564 | struct net *net = sock_net(skb->sk); | 2604 | struct net *net = sock_net(skb->sk); |
2565 | rtnl_doit_func doit; | 2605 | rtnl_doit_func doit; |
2566 | int sz_idx, kind; | 2606 | int sz_idx, kind; |
2567 | int min_len; | ||
2568 | int family; | 2607 | int family; |
2569 | int type; | 2608 | int type; |
2570 | int err; | 2609 | int err; |
@@ -2576,10 +2615,10 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
2576 | type -= RTM_BASE; | 2615 | type -= RTM_BASE; |
2577 | 2616 | ||
2578 | /* All the messages must have at least 1 byte length */ | 2617 | /* All the messages must have at least 1 byte length */ |
2579 | if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg))) | 2618 | if (nlmsg_len(nlh) < sizeof(struct rtgenmsg)) |
2580 | return 0; | 2619 | return 0; |
2581 | 2620 | ||
2582 | family = ((struct rtgenmsg *)NLMSG_DATA(nlh))->rtgen_family; | 2621 | family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family; |
2583 | sz_idx = type>>2; | 2622 | sz_idx = type>>2; |
2584 | kind = type&3; | 2623 | kind = type&3; |
2585 | 2624 | ||
@@ -2612,32 +2651,11 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
2612 | return err; | 2651 | return err; |
2613 | } | 2652 | } |
2614 | 2653 | ||
2615 | memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *))); | ||
2616 | |||
2617 | min_len = rtm_min[sz_idx]; | ||
2618 | if (nlh->nlmsg_len < min_len) | ||
2619 | return -EINVAL; | ||
2620 | |||
2621 | if (nlh->nlmsg_len > min_len) { | ||
2622 | int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); | ||
2623 | struct rtattr *attr = (void *)nlh + NLMSG_ALIGN(min_len); | ||
2624 | |||
2625 | while (RTA_OK(attr, attrlen)) { | ||
2626 | unsigned int flavor = attr->rta_type & NLA_TYPE_MASK; | ||
2627 | if (flavor) { | ||
2628 | if (flavor > rta_max[sz_idx]) | ||
2629 | return -EINVAL; | ||
2630 | rta_buf[flavor-1] = attr; | ||
2631 | } | ||
2632 | attr = RTA_NEXT(attr, attrlen); | ||
2633 | } | ||
2634 | } | ||
2635 | |||
2636 | doit = rtnl_get_doit(family, type); | 2654 | doit = rtnl_get_doit(family, type); |
2637 | if (doit == NULL) | 2655 | if (doit == NULL) |
2638 | return -EOPNOTSUPP; | 2656 | return -EOPNOTSUPP; |
2639 | 2657 | ||
2640 | return doit(skb, nlh, (void *)&rta_buf[0]); | 2658 | return doit(skb, nlh); |
2641 | } | 2659 | } |
2642 | 2660 | ||
2643 | static void rtnetlink_rcv(struct sk_buff *skb) | 2661 | static void rtnetlink_rcv(struct sk_buff *skb) |
@@ -2707,16 +2725,6 @@ static struct pernet_operations rtnetlink_net_ops = { | |||
2707 | 2725 | ||
2708 | void __init rtnetlink_init(void) | 2726 | void __init rtnetlink_init(void) |
2709 | { | 2727 | { |
2710 | int i; | ||
2711 | |||
2712 | rtattr_max = 0; | ||
2713 | for (i = 0; i < ARRAY_SIZE(rta_max); i++) | ||
2714 | if (rta_max[i] > rtattr_max) | ||
2715 | rtattr_max = rta_max[i]; | ||
2716 | rta_buf = kmalloc(rtattr_max * sizeof(struct rtattr *), GFP_KERNEL); | ||
2717 | if (!rta_buf) | ||
2718 | panic("rtnetlink_init: cannot allocate rta_buf\n"); | ||
2719 | |||
2720 | if (register_pernet_subsys(&rtnetlink_net_ops)) | 2728 | if (register_pernet_subsys(&rtnetlink_net_ops)) |
2721 | panic("rtnetlink_init: cannot initialize rtnetlink\n"); | 2729 | panic("rtnetlink_init: cannot initialize rtnetlink\n"); |
2722 | 2730 | ||