diff options
Diffstat (limited to 'net')
53 files changed, 697 insertions, 933 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index c41d5fbb91d0..6e6194fcd88e 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -172,6 +172,7 @@ void br_dev_delete(struct net_device *dev, struct list_head *head) del_nbp(p); } + br_vlan_flush(br); del_timer_sync(&br->gc_timer); br_sysfs_delbr(br->dev); diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 53f0990eab58..af5ebd18d705 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -34,7 +34,6 @@ static void __vlan_add_flags(struct net_port_vlans *v, u16 vid, u16 flags) static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags) { - const struct net_device_ops *ops; struct net_bridge_port *p = NULL; struct net_bridge *br; struct net_device *dev; @@ -53,17 +52,15 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags) br = v->parent.br; dev = br->dev; } - ops = dev->netdev_ops; - if (p && (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) { + if (p) { /* Add VLAN to the device filter if it is supported. * Stricly speaking, this is not necessary now, since * devices are made promiscuous by the bridge, but if * that ever changes this code will allow tagged * traffic to enter the bridge. */ - err = ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q), - vid); + err = vlan_vid_add(dev, htons(ETH_P_8021Q), vid); if (err) return err; } @@ -82,8 +79,8 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags) return 0; out_filt: - if (p && (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) - ops->ndo_vlan_rx_kill_vid(dev, htons(ETH_P_8021Q), vid); + if (p) + vlan_vid_del(dev, htons(ETH_P_8021Q), vid); return err; } @@ -95,13 +92,8 @@ static int __vlan_del(struct net_port_vlans *v, u16 vid) __vlan_delete_pvid(v, vid); clear_bit(vid, v->untagged_bitmap); - if (v->port_idx) { - struct net_device *dev = v->parent.port->dev; - const struct net_device_ops *ops = dev->netdev_ops; - - if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) - ops->ndo_vlan_rx_kill_vid(dev, htons(ETH_P_8021Q), vid); - } + if (v->port_idx) + vlan_vid_del(v->parent.port->dev, htons(ETH_P_8021Q), vid); clear_bit(vid, v->vlan_bitmap); v->num_vlans--; @@ -398,6 +390,7 @@ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) void nbp_vlan_flush(struct net_bridge_port *port) { struct net_port_vlans *pv; + u16 vid; ASSERT_RTNL(); @@ -405,6 +398,9 @@ void nbp_vlan_flush(struct net_bridge_port *port) if (!pv) return; + for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) + vlan_vid_del(port->dev, htons(ETH_P_8021Q), vid); + __vlan_flush(pv); } diff --git a/net/core/dev.c b/net/core/dev.c index 8ffc52e01ece..7e00a7342ee6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -131,6 +131,7 @@ #include <linux/static_key.h> #include <linux/hashtable.h> #include <linux/vmalloc.h> +#include <linux/if_macvlan.h> #include "net-sysfs.h" @@ -1424,6 +1425,10 @@ void dev_disable_lro(struct net_device *dev) if (is_vlan_dev(dev)) dev = vlan_dev_real_dev(dev); + /* the same for macvlan devices */ + if (netif_is_macvlan(dev)) + dev = macvlan_dev_real_dev(dev); + dev->wanted_features &= ~NETIF_F_LRO; netdev_update_features(dev); @@ -1690,13 +1695,9 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) kfree_skb(skb); return NET_RX_DROP; } - skb->protocol = eth_type_trans(skb, dev); - /* eth_type_trans() can set pkt_type. - * call skb_scrub_packet() after it to clear pkt_type _after_ calling - * eth_type_trans(). - */ skb_scrub_packet(skb, true); + skb->protocol = eth_type_trans(skb, dev); return netif_rx(skb); } diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 5e78d44333b9..95897183226e 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -106,6 +106,10 @@ static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data) return skb; } +static struct genl_multicast_group dropmon_mcgrps[] = { + { .name = "events", }, +}; + static void send_dm_alert(struct work_struct *work) { struct sk_buff *skb; @@ -116,7 +120,8 @@ static void send_dm_alert(struct work_struct *work) skb = reset_per_cpu_data(data); if (skb) - genlmsg_multicast(skb, 0, NET_DM_GRP_ALERT, GFP_KERNEL); + genlmsg_multicast(&net_drop_monitor_family, skb, 0, + 0, GFP_KERNEL); } /* @@ -333,7 +338,7 @@ out: return NOTIFY_DONE; } -static struct genl_ops dropmon_ops[] = { +static const struct genl_ops dropmon_ops[] = { { .cmd = NET_DM_CMD_CONFIG, .doit = net_dm_cmd_config, @@ -364,13 +369,13 @@ static int __init init_net_drop_monitor(void) return -ENOSPC; } - rc = genl_register_family_with_ops(&net_drop_monitor_family, - dropmon_ops, - ARRAY_SIZE(dropmon_ops)); + rc = genl_register_family_with_ops_groups(&net_drop_monitor_family, + dropmon_ops, dropmon_mcgrps); if (rc) { pr_err("Could not create drop monitor netlink family\n"); return rc; } + WARN_ON(net_drop_monitor_family.mcgrp_offset != NET_DM_GRP_ALERT); rc = register_netdevice_notifier(&dropmon_net_notifier); if (rc < 0) { diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index 4e66bf61f585..5325af85eea6 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c @@ -90,8 +90,8 @@ static struct genl_family hsr_genl_family = { .maxattr = HSR_A_MAX, }; -static struct genl_multicast_group hsr_network_genl_mcgrp = { - .name = "hsr-network", +static const struct genl_multicast_group hsr_mcgrps[] = { + { .name = "hsr-network", }, }; @@ -129,7 +129,7 @@ void hsr_nl_ringerror(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN], goto nla_put_failure; genlmsg_end(skb, msg_head); - genlmsg_multicast(skb, 0, hsr_network_genl_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&hsr_genl_family, skb, 0, 0, GFP_ATOMIC); return; @@ -163,7 +163,7 @@ void hsr_nl_nodedown(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN]) goto nla_put_failure; genlmsg_end(skb, msg_head); - genlmsg_multicast(skb, 0, hsr_network_genl_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&hsr_genl_family, skb, 0, 0, GFP_ATOMIC); return; @@ -249,7 +249,7 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) &hsr_node_if2_age, &hsr_node_if2_seq); if (res < 0) - goto fail; + goto nla_put_failure; res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, nla_data(info->attrs[HSR_A_NODE_ADDR])); @@ -306,15 +306,6 @@ fail: return res; } -static struct genl_ops hsr_ops_get_node_status = { - .cmd = HSR_C_GET_NODE_STATUS, - .flags = 0, - .policy = hsr_genl_policy, - .doit = hsr_get_node_status, - .dumpit = NULL, -}; - - /* Get a list of MacAddressA of all nodes known to this node (other than self). */ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) @@ -398,12 +389,21 @@ fail: } -static struct genl_ops hsr_ops_get_node_list = { - .cmd = HSR_C_GET_NODE_LIST, - .flags = 0, - .policy = hsr_genl_policy, - .doit = hsr_get_node_list, - .dumpit = NULL, +static const struct genl_ops hsr_ops[] = { + { + .cmd = HSR_C_GET_NODE_STATUS, + .flags = 0, + .policy = hsr_genl_policy, + .doit = hsr_get_node_status, + .dumpit = NULL, + }, + { + .cmd = HSR_C_GET_NODE_LIST, + .flags = 0, + .policy = hsr_genl_policy, + .doit = hsr_get_node_list, + .dumpit = NULL, + }, }; int __init hsr_netlink_init(void) @@ -414,30 +414,13 @@ int __init hsr_netlink_init(void) if (rc) goto fail_rtnl_link_register; - rc = genl_register_family(&hsr_genl_family); + rc = genl_register_family_with_ops_groups(&hsr_genl_family, hsr_ops, + hsr_mcgrps); if (rc) goto fail_genl_register_family; - rc = genl_register_ops(&hsr_genl_family, &hsr_ops_get_node_status); - if (rc) - goto fail_genl_register_ops; - - rc = genl_register_ops(&hsr_genl_family, &hsr_ops_get_node_list); - if (rc) - goto fail_genl_register_ops_node_list; - - rc = genl_register_mc_group(&hsr_genl_family, &hsr_network_genl_mcgrp); - if (rc) - goto fail_genl_register_mc_group; - return 0; -fail_genl_register_mc_group: - genl_unregister_ops(&hsr_genl_family, &hsr_ops_get_node_list); -fail_genl_register_ops_node_list: - genl_unregister_ops(&hsr_genl_family, &hsr_ops_get_node_status); -fail_genl_register_ops: - genl_unregister_family(&hsr_genl_family); fail_genl_register_family: rtnl_link_unregister(&hsr_link_ops); fail_rtnl_link_register: @@ -447,10 +430,7 @@ fail_rtnl_link_register: void __exit hsr_netlink_exit(void) { - genl_unregister_mc_group(&hsr_genl_family, &hsr_network_genl_mcgrp); - genl_unregister_ops(&hsr_genl_family, &hsr_ops_get_node_status); genl_unregister_family(&hsr_genl_family); - rtnl_link_unregister(&hsr_link_ops); } diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index 426b5df1c98f..459e200c08a4 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c @@ -956,7 +956,7 @@ lowpan_process_data(struct sk_buff *skb) * Traffic class carried in-line * ECN + DSCP (1 byte), Flow Label is elided */ - case 1: /* 10b */ + case 2: /* 10b */ if (lowpan_fetch_skb_u8(skb, &tmp)) goto drop; @@ -967,7 +967,7 @@ lowpan_process_data(struct sk_buff *skb) * Flow Label carried in-line * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided */ - case 2: /* 01b */ + case 1: /* 01b */ if (lowpan_fetch_skb_u8(skb, &tmp)) goto drop; diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 581a59504bd5..1865fdf5a5a5 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -315,9 +315,8 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, if (saddr) { saddr->family = AF_IEEE802154; saddr->addr = mac_cb(skb)->sa; - } - if (addr_len) *addr_len = sizeof(*saddr); + } if (flags & MSG_TRUNC) copied = skb->len; diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h index aadec428e6ec..cee4425b9956 100644 --- a/net/ieee802154/ieee802154.h +++ b/net/ieee802154/ieee802154.h @@ -47,7 +47,24 @@ struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info, int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info); extern struct genl_family nl802154_family; -int nl802154_mac_register(void); -int nl802154_phy_register(void); + +/* genetlink ops/groups */ +int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info); +int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb); +int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info); +int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info); + +enum ieee802154_mcgrp_ids { + IEEE802154_COORD_MCGRP, + IEEE802154_BEACON_MCGRP, +}; + +int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info); +int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info); +int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info); +int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info); +int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info); +int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info); +int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb); #endif diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 7e49bbcc6967..43f1b2bf469f 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -70,7 +70,7 @@ int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group) if (genlmsg_end(msg, hdr) < 0) goto out; - return genlmsg_multicast(msg, 0, group, GFP_ATOMIC); + return genlmsg_multicast(&nl802154_family, msg, 0, group, GFP_ATOMIC); out: nlmsg_free(msg); return -ENOBUFS; @@ -109,31 +109,36 @@ out: return -ENOBUFS; } -int __init ieee802154_nl_init(void) -{ - int rc; - - rc = genl_register_family(&nl802154_family); - if (rc) - goto fail; - - rc = nl802154_mac_register(); - if (rc) - goto fail; +static const struct genl_ops ieee8021154_ops[] = { + /* see nl-phy.c */ + IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy, + ieee802154_dump_phy), + IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface), + IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface), + /* see nl-mac.c */ + IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), + IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), + IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), + IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), + IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), + IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface, + ieee802154_dump_iface), +}; - rc = nl802154_phy_register(); - if (rc) - goto fail; +static const struct genl_multicast_group ieee802154_mcgrps[] = { + [IEEE802154_COORD_MCGRP] = { .name = IEEE802154_MCAST_COORD_NAME, }, + [IEEE802154_BEACON_MCGRP] = { .name = IEEE802154_MCAST_BEACON_NAME, }, +}; - return 0; -fail: - genl_unregister_family(&nl802154_family); - return rc; +int __init ieee802154_nl_init(void) +{ + return genl_register_family_with_ops_groups(&nl802154_family, + ieee8021154_ops, + ieee802154_mcgrps); } void __exit ieee802154_nl_exit(void) { genl_unregister_family(&nl802154_family); } - diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index b0bdd8c51e9c..ba5c1e002f37 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -39,14 +39,6 @@ #include "ieee802154.h" -static struct genl_multicast_group ieee802154_coord_mcgrp = { - .name = IEEE802154_MCAST_COORD_NAME, -}; - -static struct genl_multicast_group ieee802154_beacon_mcgrp = { - .name = IEEE802154_MCAST_BEACON_NAME, -}; - int ieee802154_nl_assoc_indic(struct net_device *dev, struct ieee802154_addr *addr, u8 cap) { @@ -72,7 +64,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev, nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap)) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -98,7 +90,7 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) || nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -133,7 +125,7 @@ int ieee802154_nl_disassoc_indic(struct net_device *dev, } if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason)) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -157,7 +149,7 @@ int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) dev->dev_addr) || nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -183,7 +175,7 @@ int ieee802154_nl_beacon_indic(struct net_device *dev, nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) || nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid)) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -214,7 +206,7 @@ int ieee802154_nl_scan_confirm(struct net_device *dev, (edl && nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl))) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -238,7 +230,7 @@ int ieee802154_nl_start_confirm(struct net_device *dev, u8 status) dev->dev_addr) || nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -309,8 +301,7 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) return dev; } -static int ieee802154_associate_req(struct sk_buff *skb, - struct genl_info *info) +int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; struct ieee802154_addr addr; @@ -357,8 +348,7 @@ out: return ret; } -static int ieee802154_associate_resp(struct sk_buff *skb, - struct genl_info *info) +int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; struct ieee802154_addr addr; @@ -390,8 +380,7 @@ out: return ret; } -static int ieee802154_disassociate_req(struct sk_buff *skb, - struct genl_info *info) +int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; struct ieee802154_addr addr; @@ -433,7 +422,7 @@ out: * PAN_coordinator, battery_life_extension = 0, * coord_realignment = 0, security_enable = 0 */ -static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) +int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; struct ieee802154_addr addr; @@ -492,7 +481,7 @@ out: return ret; } -static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) +int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) { struct net_device *dev; int ret = -EOPNOTSUPP; @@ -530,8 +519,7 @@ out: return ret; } -static int ieee802154_list_iface(struct sk_buff *skb, - struct genl_info *info) +int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info) { /* Request for interface name, index, type, IEEE address, PAN Id, short address */ @@ -565,8 +553,7 @@ out_dev: } -static int ieee802154_dump_iface(struct sk_buff *skb, - struct netlink_callback *cb) +int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); struct net_device *dev; @@ -590,41 +577,3 @@ cont: return skb->len; } - -static struct genl_ops ieee802154_coordinator_ops[] = { - IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), - IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), - IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), - IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), - IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), - IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface, - ieee802154_dump_iface), -}; - -/* - * No need to unregister as family unregistration will do it. - */ -int nl802154_mac_register(void) -{ - int i; - int rc; - - rc = genl_register_mc_group(&nl802154_family, - &ieee802154_coord_mcgrp); - if (rc) - return rc; - - rc = genl_register_mc_group(&nl802154_family, - &ieee802154_beacon_mcgrp); - if (rc) - return rc; - - for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) { - rc = genl_register_ops(&nl802154_family, - &ieee802154_coordinator_ops[i]); - if (rc) - return rc; - } - - return 0; -} diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 22b1a7058fd3..d08c7a43dcd1 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -77,8 +77,7 @@ out: return -EMSGSIZE; } -static int ieee802154_list_phy(struct sk_buff *skb, - struct genl_info *info) +int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info) { /* Request for interface name, index, type, IEEE address, PAN Id, short address */ @@ -151,8 +150,7 @@ static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data) return 0; } -static int ieee802154_dump_phy(struct sk_buff *skb, - struct netlink_callback *cb) +int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb) { struct dump_phy_data data = { .cb = cb, @@ -170,8 +168,7 @@ static int ieee802154_dump_phy(struct sk_buff *skb, return skb->len; } -static int ieee802154_add_iface(struct sk_buff *skb, - struct genl_info *info) +int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; struct wpan_phy *phy; @@ -273,8 +270,7 @@ out_dev: return rc; } -static int ieee802154_del_iface(struct sk_buff *skb, - struct genl_info *info) +int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; struct wpan_phy *phy; @@ -356,28 +352,3 @@ out_dev: return rc; } - -static struct genl_ops ieee802154_phy_ops[] = { - IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy, - ieee802154_dump_phy), - IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface), - IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface), -}; - -/* - * No need to unregister as family unregistration will do it. - */ -int nl802154_phy_register(void) -{ - int i; - int rc; - - for (i = 0; i < ARRAY_SIZE(ieee802154_phy_ops); i++) { - rc = genl_register_ops(&nl802154_family, - &ieee802154_phy_ops[i]); - if (rc) - return rc; - } - - return 0; -} diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index b28e863fe0a7..19e36376d2a0 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -57,7 +57,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (IS_ERR(rt)) { err = PTR_ERR(rt); if (err == -ENETUNREACH) - IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); + IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); goto out; } diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index caf01176a5e4..90ff9570d7d4 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -454,6 +454,8 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, tstats->rx_bytes += skb->len; u64_stats_update_end(&tstats->syncp); + skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(tunnel->dev))); + if (tunnel->dev->type == ARPHRD_ETHER) { skb->protocol = eth_type_trans(skb, tunnel->dev); skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); @@ -461,8 +463,6 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, skb->dev = tunnel->dev; } - skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(tunnel->dev))); - gro_cells_receive(&tunnel->gro_cells, skb); return 0; diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 5d9c845d288a..52b802a0cd8c 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -126,6 +126,7 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (!rt->dst.xfrm || rt->dst.xfrm->props.mode != XFRM_MODE_TUNNEL) { dev->stats.tx_carrier_errors++; + ip_rt_put(rt); goto tx_error_icmp; } tdev = rt->dst.dev; diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index cbc85f660d54..876c6ca2d8f9 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -830,8 +830,6 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, { struct inet_sock *isk = inet_sk(sk); int family = sk->sk_family; - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; struct sk_buff *skb; int copied, err; @@ -841,13 +839,6 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (flags & MSG_OOB) goto out; - if (addr_len) { - if (family == AF_INET) - *addr_len = sizeof(*sin); - else if (family == AF_INET6 && addr_len) - *addr_len = sizeof(*sin6); - } - if (flags & MSG_ERRQUEUE) { if (family == AF_INET) { return ip_recv_error(sk, msg, len); @@ -877,11 +868,15 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* Copy the address and add cmsg data. */ if (family == AF_INET) { - sin = (struct sockaddr_in *) msg->msg_name; - sin->sin_family = AF_INET; - sin->sin_port = 0 /* skb->h.uh->source */; - sin->sin_addr.s_addr = ip_hdr(skb)->saddr; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; + + if (sin) { + sin->sin_family = AF_INET; + sin->sin_port = 0 /* skb->h.uh->source */; + sin->sin_addr.s_addr = ip_hdr(skb)->saddr; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + *addr_len = sizeof(*sin); + } if (isk->cmsg_flags) ip_cmsg_recv(msg, skb); @@ -890,17 +885,21 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } else if (family == AF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6hdr *ip6 = ipv6_hdr(skb); - sin6 = (struct sockaddr_in6 *) msg->msg_name; - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_addr = ip6->saddr; - - sin6->sin6_flowinfo = 0; - if (np->sndflow) - sin6->sin6_flowinfo = ip6_flowinfo(ip6); - - sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, - IP6CB(skb)->iif); + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *)msg->msg_name; + + if (sin6) { + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + sin6->sin6_addr = ip6->saddr; + sin6->sin6_flowinfo = 0; + if (np->sndflow) + sin6->sin6_flowinfo = ip6_flowinfo(ip6); + sin6->sin6_scope_id = + ipv6_iface_scope_id(&sin6->sin6_addr, + IP6CB(skb)->iif); + *addr_len = sizeof(*sin6); + } if (inet6_sk(sk)->rxopt.all) pingv6_ops.ip6_datagram_recv_ctl(sk, msg, skb); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 41e1d2845c8f..5cb8ddb505ee 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -696,9 +696,6 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (flags & MSG_OOB) goto out; - if (addr_len) - *addr_len = sizeof(*sin); - if (flags & MSG_ERRQUEUE) { err = ip_recv_error(sk, msg, len); goto out; @@ -726,6 +723,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, sin->sin_addr.s_addr = ip_hdr(skb)->saddr; sin->sin_port = 0; memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); + *addr_len = sizeof(*sin); } if (inet->cmsg_flags) ip_cmsg_recv(msg, skb); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8e8529d3c8c9..c4638e6f0238 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -808,12 +808,6 @@ static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, xmit_size_goal = min_t(u32, gso_size, sk->sk_gso_max_size - 1 - hlen); - /* TSQ : try to have at least two segments in flight - * (one in NIC TX ring, another in Qdisc) - */ - xmit_size_goal = min_t(u32, xmit_size_goal, - sysctl_tcp_limit_output_bytes >> 1); - xmit_size_goal = tcp_bound_to_half_wnd(tp, xmit_size_goal); /* We try hard to avoid divides here */ @@ -1431,7 +1425,7 @@ static void tcp_service_net_dma(struct sock *sk, bool wait) do { if (dma_async_is_tx_complete(tp->ucopy.dma_chan, last_issued, &done, - &used) == DMA_SUCCESS) { + &used) == DMA_COMPLETE) { /* Safe to free early-copied skbs now */ __skb_queue_purge(&sk->sk_async_wait_queue); break; @@ -1439,7 +1433,7 @@ static void tcp_service_net_dma(struct sock *sk, bool wait) struct sk_buff *skb; while ((skb = skb_peek(&sk->sk_async_wait_queue)) && (dma_async_is_complete(skb->dma_cookie, done, - used) == DMA_SUCCESS)) { + used) == DMA_COMPLETE)) { __skb_dequeue(&sk->sk_async_wait_queue); kfree_skb(skb); } diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 2ab09cbae74d..06493736fbc8 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -663,10 +663,13 @@ void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, void tcp_fastopen_cache_set(struct sock *sk, u16 mss, struct tcp_fastopen_cookie *cookie, bool syn_lost) { + struct dst_entry *dst = __sk_dst_get(sk); struct tcp_metrics_block *tm; + if (!dst) + return; rcu_read_lock(); - tm = tcp_get_metrics(sk, __sk_dst_get(sk), true); + tm = tcp_get_metrics(sk, dst, true); if (tm) { struct tcp_fastopen_metrics *tfom = &tm->tcpm_fastopen; @@ -988,7 +991,7 @@ static int tcp_metrics_nl_cmd_del(struct sk_buff *skb, struct genl_info *info) return 0; } -static struct genl_ops tcp_metrics_nl_ops[] = { +static const struct genl_ops tcp_metrics_nl_ops[] = { { .cmd = TCP_METRICS_CMD_GET, .doit = tcp_metrics_nl_cmd_get, @@ -1079,8 +1082,7 @@ void __init tcp_metrics_init(void) if (ret < 0) goto cleanup; ret = genl_register_family_with_ops(&tcp_metrics_nl_family, - tcp_metrics_nl_ops, - ARRAY_SIZE(tcp_metrics_nl_ops)); + tcp_metrics_nl_ops); if (ret < 0) goto cleanup_subsys; return; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 672854664ff5..7820f3a7dd70 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1875,8 +1875,12 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, * - better RTT estimation and ACK scheduling * - faster recovery * - high rates + * Alas, some drivers / subsystems require a fair amount + * of queued bytes to ensure line rate. + * One example is wifi aggregation (802.11 AMPDU) */ - limit = max(skb->truesize, sk->sk_pacing_rate >> 10); + limit = max_t(unsigned int, sysctl_tcp_limit_output_bytes, + sk->sk_pacing_rate >> 10); if (atomic_read(&sk->sk_wmem_alloc) > limit) { set_bit(TSQ_THROTTLED, &tp->tsq_flags); @@ -3093,7 +3097,6 @@ void tcp_send_window_probe(struct sock *sk) { if (sk->sk_state == TCP_ESTABLISHED) { tcp_sk(sk)->snd_wl1 = tcp_sk(sk)->rcv_nxt - 1; - tcp_sk(sk)->snd_nxt = tcp_sk(sk)->write_seq; tcp_xmit_probe_skb(sk, 0); } } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index de86e5bc4462..5944d7d668dd 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1235,12 +1235,6 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int is_udplite = IS_UDPLITE(sk); bool slow; - /* - * Check any passed addresses - */ - if (addr_len) - *addr_len = sizeof(*sin); - if (flags & MSG_ERRQUEUE) return ip_recv_error(sk, msg, len); @@ -1302,6 +1296,7 @@ try_again: sin->sin_port = udp_hdr(skb)->source; sin->sin_addr.s_addr = ip_hdr(skb)->saddr; memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + *addr_len = sizeof(*sin); } if (inet->cmsg_flags) ip_cmsg_recv(msg, skb); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 5658d9d51637..12c97d8aa6bb 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1996,23 +1996,6 @@ static void addrconf_add_mroute(struct net_device *dev) ip6_route_add(&cfg); } -#if IS_ENABLED(CONFIG_IPV6_SIT) -static void sit_route_add(struct net_device *dev) -{ - struct fib6_config cfg = { - .fc_table = RT6_TABLE_MAIN, - .fc_metric = IP6_RT_PRIO_ADDRCONF, - .fc_ifindex = dev->ifindex, - .fc_dst_len = 96, - .fc_flags = RTF_UP | RTF_NONEXTHOP, - .fc_nlinfo.nl_net = dev_net(dev), - }; - - /* prefix length - 96 bits "::d.d.d.d" */ - ip6_route_add(&cfg); -} -#endif - static struct inet6_dev *addrconf_add_dev(struct net_device *dev) { struct inet6_dev *idev; @@ -2542,7 +2525,8 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) struct in6_addr addr; struct net_device *dev; struct net *net = dev_net(idev->dev); - int scope; + int scope, plen; + u32 pflags = 0; ASSERT_RTNL(); @@ -2552,12 +2536,16 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) if (idev->dev->flags&IFF_POINTOPOINT) { addr.s6_addr32[0] = htonl(0xfe800000); scope = IFA_LINK; + plen = 64; } else { scope = IPV6_ADDR_COMPATv4; + plen = 96; + pflags |= RTF_NONEXTHOP; } if (addr.s6_addr32[3]) { - add_addr(idev, &addr, 128, scope); + add_addr(idev, &addr, plen, scope); + addrconf_prefix_route(&addr, plen, idev->dev, 0, pflags); return; } @@ -2569,7 +2557,6 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) int flag = scope; for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { - int plen; addr.s6_addr32[3] = ifa->ifa_local; @@ -2580,12 +2567,10 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) continue; flag |= IFA_HOST; } - if (idev->dev->flags&IFF_POINTOPOINT) - plen = 64; - else - plen = 96; add_addr(idev, &addr, plen, flag); + addrconf_prefix_route(&addr, plen, idev->dev, 0, + pflags); } } } @@ -2711,7 +2696,6 @@ static void addrconf_sit_config(struct net_device *dev) struct in6_addr addr; ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); - addrconf_prefix_route(&addr, 64, dev, 0, 0); if (!ipv6_generate_eui64(addr.s6_addr + 8, dev)) addrconf_add_linklocal(idev, &addr); return; @@ -2721,8 +2705,6 @@ static void addrconf_sit_config(struct net_device *dev) if (dev->flags&IFF_POINTOPOINT) addrconf_add_mroute(dev); - else - sit_route_add(dev); } #endif @@ -2740,8 +2722,6 @@ static void addrconf_gre_config(struct net_device *dev) } ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); - addrconf_prefix_route(&addr, 64, dev, 0, 0); - if (!ipv6_generate_eui64(addr.s6_addr + 8, dev)) addrconf_add_linklocal(idev, &addr); } diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index ff75313f27a8..4fbdb7046d28 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -972,10 +972,10 @@ out: #ifdef CONFIG_SYSCTL sysctl_fail: - ipv6_packet_cleanup(); + pingv6_exit(); #endif pingv6_fail: - pingv6_exit(); + ipv6_packet_cleanup(); ipv6_packet_fail: tcpv6_exit(); tcpv6_fail: diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index df1fa58528c6..d6062325db08 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1642,6 +1642,15 @@ static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[], return ip6_tnl_update(t, &p); } +static void ip6_tnl_dellink(struct net_device *dev, struct list_head *head) +{ + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + + if (dev != ip6n->fb_tnl_dev) + unregister_netdevice_queue(dev, head); +} + static size_t ip6_tnl_get_size(const struct net_device *dev) { return @@ -1706,6 +1715,7 @@ static struct rtnl_link_ops ip6_link_ops __read_mostly = { .validate = ip6_tnl_validate, .newlink = ip6_tnl_newlink, .changelink = ip6_tnl_changelink, + .dellink = ip6_tnl_dellink, .get_size = ip6_tnl_get_size, .fill_info = ip6_tnl_fill_info, }; @@ -1722,9 +1732,9 @@ static struct xfrm6_tunnel ip6ip6_handler __read_mostly = { .priority = 1, }; -static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) +static void __net_exit ip6_tnl_destroy_tunnels(struct net *net) { - struct net *net = dev_net(ip6n->fb_tnl_dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); struct net_device *dev, *aux; int h; struct ip6_tnl *t; @@ -1792,10 +1802,8 @@ err_alloc_dev: static void __net_exit ip6_tnl_exit_net(struct net *net) { - struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); - rtnl_lock(); - ip6_tnl_destroy_tunnels(ip6n); + ip6_tnl_destroy_tunnels(net); rtnl_unlock(); } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index f8a55ff1971b..3512177deb4d 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1726,8 +1726,8 @@ int __init ndisc_init(void) &ndisc_ifinfo_sysctl_change); if (err) goto out_unregister_pernet; -#endif out: +#endif return err; #ifdef CONFIG_SYSCTL diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 3c00842b0079..e24ff1df0401 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -465,9 +465,6 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, if (flags & MSG_OOB) return -EOPNOTSUPP; - if (addr_len) - *addr_len=sizeof(*sin6); - if (flags & MSG_ERRQUEUE) return ipv6_recv_error(sk, msg, len); @@ -506,6 +503,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, sin6->sin6_flowinfo = 0; sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, IP6CB(skb)->iif); + *addr_len = sizeof(*sin6); } sock_recv_ts_and_drops(msg, sk, skb); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index bfc6fcea3841..1b4a4a953675 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1619,6 +1619,15 @@ static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = { #endif }; +static void ipip6_dellink(struct net_device *dev, struct list_head *head) +{ + struct net *net = dev_net(dev); + struct sit_net *sitn = net_generic(net, sit_net_id); + + if (dev != sitn->fb_tunnel_dev) + unregister_netdevice_queue(dev, head); +} + static struct rtnl_link_ops sit_link_ops __read_mostly = { .kind = "sit", .maxtype = IFLA_IPTUN_MAX, @@ -1630,6 +1639,7 @@ static struct rtnl_link_ops sit_link_ops __read_mostly = { .changelink = ipip6_changelink, .get_size = ipip6_get_size, .fill_info = ipip6_fill_info, + .dellink = ipip6_dellink, }; static struct xfrm_tunnel sit_handler __read_mostly = { @@ -1644,9 +1654,10 @@ static struct xfrm_tunnel ipip_handler __read_mostly = { .priority = 2, }; -static void __net_exit sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) +static void __net_exit sit_destroy_tunnels(struct net *net, + struct list_head *head) { - struct net *net = dev_net(sitn->fb_tunnel_dev); + struct sit_net *sitn = net_generic(net, sit_net_id); struct net_device *dev, *aux; int prio; @@ -1721,11 +1732,10 @@ err_alloc_dev: static void __net_exit sit_exit_net(struct net *net) { - struct sit_net *sitn = net_generic(net, sit_net_id); LIST_HEAD(list); rtnl_lock(); - sit_destroy_tunnels(sitn, &list); + sit_destroy_tunnels(net, &list); unregister_netdevice_many(&list); rtnl_unlock(); } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index f3893e897f72..81eb8cf8389b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -392,9 +392,6 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, int is_udp4; bool slow; - if (addr_len) - *addr_len = sizeof(struct sockaddr_in6); - if (flags & MSG_ERRQUEUE) return ipv6_recv_error(sk, msg, len); @@ -480,7 +477,7 @@ try_again: ipv6_iface_scope_id(&sin6->sin6_addr, IP6CB(skb)->iif); } - + *addr_len = sizeof(*sin6); } if (is_udp4) { if (inet->cmsg_flags) diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c index c32971269280..a37b81fe0479 100644 --- a/net/irda/irnetlink.c +++ b/net/irda/irnetlink.c @@ -131,7 +131,7 @@ static const struct nla_policy irda_nl_policy[IRDA_NL_ATTR_MAX + 1] = { [IRDA_NL_ATTR_MODE] = { .type = NLA_U32 }, }; -static struct genl_ops irda_nl_ops[] = { +static const struct genl_ops irda_nl_ops[] = { { .cmd = IRDA_NL_CMD_SET_MODE, .doit = irda_nl_set_mode, @@ -149,8 +149,7 @@ static struct genl_ops irda_nl_ops[] = { int irda_nl_register(void) { - return genl_register_family_with_ops(&irda_nl_family, - irda_nl_ops, ARRAY_SIZE(irda_nl_ops)); + return genl_register_family_with_ops(&irda_nl_family, irda_nl_ops); } void irda_nl_unregister(void) diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 571db8dd2292..da1a1cee1a08 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -518,9 +518,6 @@ static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m if (flags & MSG_OOB) goto out; - if (addr_len) - *addr_len = sizeof(*sin); - skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) goto out; @@ -543,6 +540,7 @@ static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m sin->sin_addr.s_addr = ip_hdr(skb)->saddr; sin->sin_port = 0; memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); + *addr_len = sizeof(*sin); } if (inet->cmsg_flags) ip_cmsg_recv(msg, skb); diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index be446d517bc9..4cfd722e9153 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -793,7 +793,7 @@ static struct nla_policy l2tp_nl_policy[L2TP_ATTR_MAX + 1] = { }, }; -static struct genl_ops l2tp_nl_ops[] = { +static const struct genl_ops l2tp_nl_ops[] = { { .cmd = L2TP_CMD_NOOP, .doit = l2tp_nl_cmd_noop, @@ -887,13 +887,8 @@ EXPORT_SYMBOL_GPL(l2tp_nl_unregister_ops); static int l2tp_nl_init(void) { - int err; - pr_info("L2TP netlink interface\n"); - err = genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops, - ARRAY_SIZE(l2tp_nl_ops)); - - return err; + return genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops); } static void l2tp_nl_cleanup(void) diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 1ded5c6d268c..35be035ee0ce 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3580,7 +3580,7 @@ out: } -static struct genl_ops ip_vs_genl_ops[] __read_mostly = { +static const struct genl_ops ip_vs_genl_ops[] __read_mostly = { { .cmd = IPVS_CMD_NEW_SERVICE, .flags = GENL_ADMIN_PERM, @@ -3679,7 +3679,7 @@ static struct genl_ops ip_vs_genl_ops[] __read_mostly = { static int __init ip_vs_genl_register(void) { return genl_register_family_with_ops(&ip_vs_genl_family, - ip_vs_genl_ops, ARRAY_SIZE(ip_vs_genl_ops)); + ip_vs_genl_ops); } static void ip_vs_genl_unregister(void) diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index a1100640495d..69345cebe3a3 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -737,7 +737,7 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) * NetLabel Generic NETLINK Command Definitions */ -static struct genl_ops netlbl_cipsov4_ops[] = { +static const struct genl_ops netlbl_cipsov4_ops[] = { { .cmd = NLBL_CIPSOV4_C_ADD, .flags = GENL_ADMIN_PERM, @@ -783,5 +783,5 @@ static struct genl_ops netlbl_cipsov4_ops[] = { int __init netlbl_cipsov4_genl_init(void) { return genl_register_family_with_ops(&netlbl_cipsov4_gnl_family, - netlbl_cipsov4_ops, ARRAY_SIZE(netlbl_cipsov4_ops)); + netlbl_cipsov4_ops); } diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index dd1c37d7acbc..8ef83ee97c6a 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -705,7 +705,7 @@ version_failure: * NetLabel Generic NETLINK Command Definitions */ -static struct genl_ops netlbl_mgmt_genl_ops[] = { +static const struct genl_ops netlbl_mgmt_genl_ops[] = { { .cmd = NLBL_MGMT_C_ADD, .flags = GENL_ADMIN_PERM, @@ -779,5 +779,5 @@ static struct genl_ops netlbl_mgmt_genl_ops[] = { int __init netlbl_mgmt_genl_init(void) { return genl_register_family_with_ops(&netlbl_mgmt_gnl_family, - netlbl_mgmt_genl_ops, ARRAY_SIZE(netlbl_mgmt_genl_ops)); + netlbl_mgmt_genl_ops); } diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 8f0897407a2c..43817d73ccf9 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -1323,7 +1323,7 @@ unlabel_staticlistdef_return: * NetLabel Generic NETLINK Command Definitions */ -static struct genl_ops netlbl_unlabel_genl_ops[] = { +static const struct genl_ops netlbl_unlabel_genl_ops[] = { { .cmd = NLBL_UNLABEL_C_STATICADD, .flags = GENL_ADMIN_PERM, @@ -1397,7 +1397,7 @@ static struct genl_ops netlbl_unlabel_genl_ops[] = { int __init netlbl_unlabel_genl_init(void) { return genl_register_family_with_ops(&netlbl_unlabel_gnl_family, - netlbl_unlabel_genl_ops, ARRAY_SIZE(netlbl_unlabel_genl_ops)); + netlbl_unlabel_genl_ops); } /* diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 8df7f64c6db3..f0176e1a5a81 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2017,7 +2017,7 @@ out: * netlink_set_err - report error to broadcast listeners * @ssk: the kernel netlink socket, as returned by netlink_kernel_create() * @portid: the PORTID of a process that we want to skip (if any) - * @groups: the broadcast group that will notice the error + * @group: the broadcast group that will notice the error * @code: error code, must be negative (as usual in kernelspace) * * This function returns the number of broadcast listeners that have set the diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 0c741cec4d0d..7dbc4f732c75 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -65,12 +65,24 @@ static struct list_head family_ht[GENL_FAM_TAB_SIZE]; * To avoid an allocation at boot of just one unsigned long, * declare it global instead. * Bit 0 is marked as already used since group 0 is invalid. + * Bit 1 is marked as already used since the drop-monitor code + * abuses the API and thinks it can statically use group 1. + * That group will typically conflict with other groups that + * any proper users use. + * Bit 16 is marked as used since it's used for generic netlink + * and the code no longer marks pre-reserved IDs as used. + * Bit 17 is marked as already used since the VFS quota code + * also abused this API and relied on family == group ID, we + * cater to that by giving it a static family and group ID. */ -static unsigned long mc_group_start = 0x1; +static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_CTRL) | + BIT(GENL_ID_VFS_DQUOT); static unsigned long *mc_groups = &mc_group_start; static unsigned long mc_groups_longs = 1; -static int genl_ctrl_event(int event, void *data); +static int genl_ctrl_event(int event, struct genl_family *family, + const struct genl_multicast_group *grp, + int grp_id); static inline unsigned int genl_family_hash(unsigned int id) { @@ -106,13 +118,13 @@ static struct genl_family *genl_family_find_byname(char *name) return NULL; } -static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) +static const struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) { - struct genl_ops *ops; + int i; - list_for_each_entry(ops, &family->ops_list, ops_list) - if (ops->cmd == cmd) - return ops; + for (i = 0; i < family->n_ops; i++) + if (family->ops[i].cmd == cmd) + return &family->ops[i]; return NULL; } @@ -126,7 +138,8 @@ static u16 genl_generate_id(void) int i; for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) { - if (!genl_family_find_byid(id_gen_idx)) + if (id_gen_idx != GENL_ID_VFS_DQUOT && + !genl_family_find_byid(id_gen_idx)) return id_gen_idx; if (++id_gen_idx > GENL_MAX_ID) id_gen_idx = GENL_MIN_ID; @@ -135,62 +148,110 @@ static u16 genl_generate_id(void) return 0; } -static struct genl_multicast_group notify_grp; - -/** - * genl_register_mc_group - register a multicast group - * - * Registers the specified multicast group and notifies userspace - * about the new group. - * - * Returns 0 on success or a negative error code. - * - * @family: The generic netlink family the group shall be registered for. - * @grp: The group to register, must have a name. - */ -int genl_register_mc_group(struct genl_family *family, - struct genl_multicast_group *grp) +static int genl_allocate_reserve_groups(int n_groups, int *first_id) { - int id; unsigned long *new_groups; - int err = 0; + int start = 0; + int i; + int id; + bool fits; + + do { + if (start == 0) + id = find_first_zero_bit(mc_groups, + mc_groups_longs * + BITS_PER_LONG); + else + id = find_next_zero_bit(mc_groups, + mc_groups_longs * BITS_PER_LONG, + start); + + fits = true; + for (i = id; + i < min_t(int, id + n_groups, + mc_groups_longs * BITS_PER_LONG); + i++) { + if (test_bit(i, mc_groups)) { + start = i; + fits = false; + break; + } + } - BUG_ON(grp->name[0] == '\0'); - BUG_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL); + if (id >= mc_groups_longs * BITS_PER_LONG) { + unsigned long new_longs = mc_groups_longs + + BITS_TO_LONGS(n_groups); + size_t nlen = new_longs * sizeof(unsigned long); + + if (mc_groups == &mc_group_start) { + new_groups = kzalloc(nlen, GFP_KERNEL); + if (!new_groups) + return -ENOMEM; + mc_groups = new_groups; + *mc_groups = mc_group_start; + } else { + new_groups = krealloc(mc_groups, nlen, + GFP_KERNEL); + if (!new_groups) + return -ENOMEM; + mc_groups = new_groups; + for (i = 0; i < BITS_TO_LONGS(n_groups); i++) + mc_groups[mc_groups_longs + i] = 0; + } + mc_groups_longs = new_longs; + } + } while (!fits); - genl_lock_all(); + for (i = id; i < id + n_groups; i++) + set_bit(i, mc_groups); + *first_id = id; + return 0; +} - /* special-case our own group */ - if (grp == ¬ify_grp) - id = GENL_ID_CTRL; - else - id = find_first_zero_bit(mc_groups, - mc_groups_longs * BITS_PER_LONG); +static struct genl_family genl_ctrl; +static int genl_validate_assign_mc_groups(struct genl_family *family) +{ + int first_id; + int n_groups = family->n_mcgrps; + int err, i; + bool groups_allocated = false; - if (id >= mc_groups_longs * BITS_PER_LONG) { - size_t nlen = (mc_groups_longs + 1) * sizeof(unsigned long); + if (!n_groups) + return 0; - if (mc_groups == &mc_group_start) { - new_groups = kzalloc(nlen, GFP_KERNEL); - if (!new_groups) { - err = -ENOMEM; - goto out; - } - mc_groups = new_groups; - *mc_groups = mc_group_start; - } else { - new_groups = krealloc(mc_groups, nlen, GFP_KERNEL); - if (!new_groups) { - err = -ENOMEM; - goto out; - } - mc_groups = new_groups; - mc_groups[mc_groups_longs] = 0; - } - mc_groups_longs++; + for (i = 0; i < n_groups; i++) { + const struct genl_multicast_group *grp = &family->mcgrps[i]; + + if (WARN_ON(grp->name[0] == '\0')) + return -EINVAL; + if (WARN_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL)) + return -EINVAL; + } + + /* special-case our own group and hacks */ + if (family == &genl_ctrl) { + first_id = GENL_ID_CTRL; + BUG_ON(n_groups != 1); + } else if (strcmp(family->name, "NET_DM") == 0) { + first_id = 1; + BUG_ON(n_groups != 1); + } else if (strcmp(family->name, "VFS_DQUOT") == 0) { + first_id = GENL_ID_VFS_DQUOT; + BUG_ON(n_groups != 1); + } else { + groups_allocated = true; + err = genl_allocate_reserve_groups(n_groups, &first_id); + if (err) + return err; } + family->mcgrp_offset = first_id; + + /* if still initializing, can't and don't need to to realloc bitmaps */ + if (!init_net.genl_sock) + return 0; + if (family->netnsok) { struct net *net; @@ -206,9 +267,7 @@ int genl_register_mc_group(struct genl_family *family, * number of _possible_ groups has been * increased on some sockets which is ok. */ - rcu_read_unlock(); - netlink_table_ungrab(); - goto out; + break; } } rcu_read_unlock(); @@ -216,152 +275,67 @@ int genl_register_mc_group(struct genl_family *family, } else { err = netlink_change_ngroups(init_net.genl_sock, mc_groups_longs * BITS_PER_LONG); - if (err) - goto out; } - grp->id = id; - set_bit(id, mc_groups); - list_add_tail(&grp->list, &family->mcast_groups); - grp->family = family; + if (groups_allocated && err) { + for (i = 0; i < family->n_mcgrps; i++) + clear_bit(family->mcgrp_offset + i, mc_groups); + } - genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp); - out: - genl_unlock_all(); return err; } -EXPORT_SYMBOL(genl_register_mc_group); -static void __genl_unregister_mc_group(struct genl_family *family, - struct genl_multicast_group *grp) +static void genl_unregister_mc_groups(struct genl_family *family) { struct net *net; - BUG_ON(grp->family != family); + int i; netlink_table_grab(); rcu_read_lock(); - for_each_net_rcu(net) - __netlink_clear_multicast_users(net->genl_sock, grp->id); + for_each_net_rcu(net) { + for (i = 0; i < family->n_mcgrps; i++) + __netlink_clear_multicast_users( + net->genl_sock, family->mcgrp_offset + i); + } rcu_read_unlock(); netlink_table_ungrab(); - clear_bit(grp->id, mc_groups); - list_del(&grp->list); - genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp); - grp->id = 0; - grp->family = NULL; -} + for (i = 0; i < family->n_mcgrps; i++) { + int grp_id = family->mcgrp_offset + i; -/** - * genl_unregister_mc_group - unregister a multicast group - * - * Unregisters the specified multicast group and notifies userspace - * about it. All current listeners on the group are removed. - * - * Note: It is not necessary to unregister all multicast groups before - * unregistering the family, unregistering the family will cause - * all assigned multicast groups to be unregistered automatically. - * - * @family: Generic netlink family the group belongs to. - * @grp: The group to unregister, must have been registered successfully - * previously. - */ -void genl_unregister_mc_group(struct genl_family *family, - struct genl_multicast_group *grp) -{ - genl_lock_all(); - __genl_unregister_mc_group(family, grp); - genl_unlock_all(); + if (grp_id != 1) + clear_bit(grp_id, mc_groups); + genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, family, + &family->mcgrps[i], grp_id); + } } -EXPORT_SYMBOL(genl_unregister_mc_group); -static void genl_unregister_mc_groups(struct genl_family *family) +static int genl_validate_ops(struct genl_family *family) { - struct genl_multicast_group *grp, *tmp; + const struct genl_ops *ops = family->ops; + unsigned int n_ops = family->n_ops; + int i, j; - list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list) - __genl_unregister_mc_group(family, grp); -} - -/** - * genl_register_ops - register generic netlink operations - * @family: generic netlink family - * @ops: operations to be registered - * - * Registers the specified operations and assigns them to the specified - * family. Either a doit or dumpit callback must be specified or the - * operation will fail. Only one operation structure per command - * identifier may be registered. - * - * See include/net/genetlink.h for more documenation on the operations - * structure. - * - * Returns 0 on success or a negative error code. - */ -int genl_register_ops(struct genl_family *family, struct genl_ops *ops) -{ - int err = -EINVAL; + if (WARN_ON(n_ops && !ops)) + return -EINVAL; - if (ops->dumpit == NULL && ops->doit == NULL) - goto errout; + if (!n_ops) + return 0; - if (genl_get_cmd(ops->cmd, family)) { - err = -EEXIST; - goto errout; + for (i = 0; i < n_ops; i++) { + if (ops[i].dumpit == NULL && ops[i].doit == NULL) + return -EINVAL; + for (j = i + 1; j < n_ops; j++) + if (ops[i].cmd == ops[j].cmd) + return -EINVAL; } - if (ops->dumpit) - ops->flags |= GENL_CMD_CAP_DUMP; - if (ops->doit) - ops->flags |= GENL_CMD_CAP_DO; - if (ops->policy) - ops->flags |= GENL_CMD_CAP_HASPOL; + /* family is not registered yet, so no locking needed */ + family->ops = ops; + family->n_ops = n_ops; - genl_lock_all(); - list_add_tail(&ops->ops_list, &family->ops_list); - genl_unlock_all(); - - genl_ctrl_event(CTRL_CMD_NEWOPS, ops); - err = 0; -errout: - return err; -} -EXPORT_SYMBOL(genl_register_ops); - -/** - * genl_unregister_ops - unregister generic netlink operations - * @family: generic netlink family - * @ops: operations to be unregistered - * - * Unregisters the specified operations and unassigns them from the - * specified family. The operation blocks until the current message - * processing has finished and doesn't start again until the - * unregister process has finished. - * - * Note: It is not necessary to unregister all operations before - * unregistering the family, unregistering the family will cause - * all assigned operations to be unregistered automatically. - * - * Returns 0 on success or a negative error code. - */ -int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops) -{ - struct genl_ops *rc; - - genl_lock_all(); - list_for_each_entry(rc, &family->ops_list, ops_list) { - if (rc == ops) { - list_del(&ops->ops_list); - genl_unlock_all(); - genl_ctrl_event(CTRL_CMD_DELOPS, ops); - return 0; - } - } - genl_unlock_all(); - - return -ENOENT; + return 0; } -EXPORT_SYMBOL(genl_unregister_ops); /** * __genl_register_family - register a generic netlink family @@ -372,11 +346,14 @@ EXPORT_SYMBOL(genl_unregister_ops); * The family id may equal GENL_ID_GENERATE causing an unique id to * be automatically generated and assigned. * + * The family's ops array must already be assigned, you can use the + * genl_register_family_with_ops() helper function. + * * Return 0 on success or a negative error code. */ int __genl_register_family(struct genl_family *family) { - int err = -EINVAL; + int err = -EINVAL, i; if (family->id && family->id < GENL_MIN_ID) goto errout; @@ -384,8 +361,9 @@ int __genl_register_family(struct genl_family *family) if (family->id > GENL_MAX_ID) goto errout; - INIT_LIST_HEAD(&family->ops_list); - INIT_LIST_HEAD(&family->mcast_groups); + err = genl_validate_ops(family); + if (err) + return err; genl_lock_all(); @@ -418,10 +396,18 @@ int __genl_register_family(struct genl_family *family) } else family->attrbuf = NULL; + err = genl_validate_assign_mc_groups(family); + if (err) + goto errout_locked; + list_add_tail(&family->family_list, genl_family_chain(family->id)); genl_unlock_all(); - genl_ctrl_event(CTRL_CMD_NEWFAMILY, family); + /* send all events */ + genl_ctrl_event(CTRL_CMD_NEWFAMILY, family, NULL, 0); + for (i = 0; i < family->n_mcgrps; i++) + genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, family, + &family->mcgrps[i], family->mcgrp_offset + i); return 0; @@ -433,52 +419,6 @@ errout: EXPORT_SYMBOL(__genl_register_family); /** - * __genl_register_family_with_ops - register a generic netlink family - * @family: generic netlink family - * @ops: operations to be registered - * @n_ops: number of elements to register - * - * Registers the specified family and operations from the specified table. - * Only one family may be registered with the same family name or identifier. - * - * The family id may equal GENL_ID_GENERATE causing an unique id to - * be automatically generated and assigned. - * - * Either a doit or dumpit callback must be specified for every registered - * operation or the function will fail. Only one operation structure per - * command identifier may be registered. - * - * See include/net/genetlink.h for more documenation on the operations - * structure. - * - * This is equivalent to calling genl_register_family() followed by - * genl_register_ops() for every operation entry in the table taking - * care to unregister the family on error path. - * - * Return 0 on success or a negative error code. - */ -int __genl_register_family_with_ops(struct genl_family *family, - struct genl_ops *ops, size_t n_ops) -{ - int err, i; - - err = __genl_register_family(family); - if (err) - return err; - - for (i = 0; i < n_ops; ++i, ++ops) { - err = genl_register_ops(family, ops); - if (err) - goto err_out; - } - return 0; -err_out: - genl_unregister_family(family); - return err; -} -EXPORT_SYMBOL(__genl_register_family_with_ops); - -/** * genl_unregister_family - unregister generic netlink family * @family: generic netlink family * @@ -499,11 +439,11 @@ int genl_unregister_family(struct genl_family *family) continue; list_del(&rc->family_list); - INIT_LIST_HEAD(&family->ops_list); + family->n_ops = 0; genl_unlock_all(); kfree(family->attrbuf); - genl_ctrl_event(CTRL_CMD_DELFAMILY, family); + genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0); return 0; } @@ -546,7 +486,8 @@ EXPORT_SYMBOL(genlmsg_put); static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { - struct genl_ops *ops = cb->data; + /* our ops are always const - netlink API doesn't propagate that */ + const struct genl_ops *ops = cb->data; int rc; genl_lock(); @@ -557,7 +498,8 @@ static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb) static int genl_lock_done(struct netlink_callback *cb) { - struct genl_ops *ops = cb->data; + /* our ops are always const - netlink API doesn't propagate that */ + const struct genl_ops *ops = cb->data; int rc = 0; if (ops->done) { @@ -572,7 +514,7 @@ static int genl_family_rcv_msg(struct genl_family *family, struct sk_buff *skb, struct nlmsghdr *nlh) { - struct genl_ops *ops; + const struct genl_ops *ops; struct net *net = sock_net(skb->sk); struct genl_info info; struct genlmsghdr *hdr = nlmsg_data(nlh); @@ -604,7 +546,8 @@ static int genl_family_rcv_msg(struct genl_family *family, if (!family->parallel_ops) { struct netlink_dump_control c = { .module = family->module, - .data = ops, + /* we have const, but the netlink API doesn't */ + .data = (void *)ops, .dump = genl_lock_dumpit, .done = genl_lock_done, }; @@ -726,24 +669,32 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq, nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr)) goto nla_put_failure; - if (!list_empty(&family->ops_list)) { + if (family->n_ops) { struct nlattr *nla_ops; - struct genl_ops *ops; - int idx = 1; + int i; nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS); if (nla_ops == NULL) goto nla_put_failure; - list_for_each_entry(ops, &family->ops_list, ops_list) { + for (i = 0; i < family->n_ops; i++) { struct nlattr *nest; + const struct genl_ops *ops = &family->ops[i]; + u32 op_flags = ops->flags; - nest = nla_nest_start(skb, idx++); + if (ops->dumpit) + op_flags |= GENL_CMD_CAP_DUMP; + if (ops->doit) + op_flags |= GENL_CMD_CAP_DO; + if (ops->policy) + op_flags |= GENL_CMD_CAP_HASPOL; + + nest = nla_nest_start(skb, i + 1); if (nest == NULL) goto nla_put_failure; if (nla_put_u32(skb, CTRL_ATTR_OP_ID, ops->cmd) || - nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, ops->flags)) + nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, op_flags)) goto nla_put_failure; nla_nest_end(skb, nest); @@ -752,23 +703,26 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq, nla_nest_end(skb, nla_ops); } - if (!list_empty(&family->mcast_groups)) { - struct genl_multicast_group *grp; + if (family->n_mcgrps) { struct nlattr *nla_grps; - int idx = 1; + int i; nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS); if (nla_grps == NULL) goto nla_put_failure; - list_for_each_entry(grp, &family->mcast_groups, list) { + for (i = 0; i < family->n_mcgrps; i++) { struct nlattr *nest; + const struct genl_multicast_group *grp; + + grp = &family->mcgrps[i]; - nest = nla_nest_start(skb, idx++); + nest = nla_nest_start(skb, i + 1); if (nest == NULL) goto nla_put_failure; - if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id) || + if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, + family->mcgrp_offset + i) || nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME, grp->name)) goto nla_put_failure; @@ -785,9 +739,10 @@ nla_put_failure: return -EMSGSIZE; } -static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 portid, - u32 seq, u32 flags, struct sk_buff *skb, - u8 cmd) +static int ctrl_fill_mcgrp_info(struct genl_family *family, + const struct genl_multicast_group *grp, + int grp_id, u32 portid, u32 seq, u32 flags, + struct sk_buff *skb, u8 cmd) { void *hdr; struct nlattr *nla_grps; @@ -797,8 +752,8 @@ static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 portid, if (hdr == NULL) return -1; - if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, grp->family->name) || - nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, grp->family->id)) + if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) || + nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id)) goto nla_put_failure; nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS); @@ -809,7 +764,7 @@ static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 portid, if (nest == NULL) goto nla_put_failure; - if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id) || + if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp_id) || nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME, grp->name)) goto nla_put_failure; @@ -875,8 +830,10 @@ static struct sk_buff *ctrl_build_family_msg(struct genl_family *family, return skb; } -static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp, - u32 portid, int seq, u8 cmd) +static struct sk_buff * +ctrl_build_mcgrp_msg(struct genl_family *family, + const struct genl_multicast_group *grp, + int grp_id, u32 portid, int seq, u8 cmd) { struct sk_buff *skb; int err; @@ -885,7 +842,8 @@ static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp, if (skb == NULL) return ERR_PTR(-ENOBUFS); - err = ctrl_fill_mcgrp_info(grp, portid, seq, 0, skb, cmd); + err = ctrl_fill_mcgrp_info(family, grp, grp_id, portid, + seq, 0, skb, cmd); if (err < 0) { nlmsg_free(skb); return ERR_PTR(err); @@ -947,11 +905,11 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) return genlmsg_reply(msg, info); } -static int genl_ctrl_event(int event, void *data) +static int genl_ctrl_event(int event, struct genl_family *family, + const struct genl_multicast_group *grp, + int grp_id) { struct sk_buff *msg; - struct genl_family *family; - struct genl_multicast_group *grp; /* genl is still initialising */ if (!init_net.genl_sock) @@ -960,14 +918,13 @@ static int genl_ctrl_event(int event, void *data) switch (event) { case CTRL_CMD_NEWFAMILY: case CTRL_CMD_DELFAMILY: - family = data; + WARN_ON(grp); msg = ctrl_build_family_msg(family, 0, 0, event); break; case CTRL_CMD_NEWMCAST_GRP: case CTRL_CMD_DELMCAST_GRP: - grp = data; - family = grp->family; - msg = ctrl_build_mcgrp_msg(data, 0, 0, event); + BUG_ON(!grp); + msg = ctrl_build_mcgrp_msg(family, grp, grp_id, 0, 0, event); break; default: return -EINVAL; @@ -977,26 +934,29 @@ static int genl_ctrl_event(int event, void *data) return PTR_ERR(msg); if (!family->netnsok) { - genlmsg_multicast_netns(&init_net, msg, 0, - GENL_ID_CTRL, GFP_KERNEL); + genlmsg_multicast_netns(&genl_ctrl, &init_net, msg, 0, + 0, GFP_KERNEL); } else { rcu_read_lock(); - genlmsg_multicast_allns(msg, 0, GENL_ID_CTRL, GFP_ATOMIC); + genlmsg_multicast_allns(&genl_ctrl, msg, 0, + 0, GFP_ATOMIC); rcu_read_unlock(); } return 0; } -static struct genl_ops genl_ctrl_ops = { - .cmd = CTRL_CMD_GETFAMILY, - .doit = ctrl_getfamily, - .dumpit = ctrl_dumpfamily, - .policy = ctrl_policy, +static struct genl_ops genl_ctrl_ops[] = { + { + .cmd = CTRL_CMD_GETFAMILY, + .doit = ctrl_getfamily, + .dumpit = ctrl_dumpfamily, + .policy = ctrl_policy, + }, }; -static struct genl_multicast_group notify_grp = { - .name = "notify", +static struct genl_multicast_group genl_ctrl_groups[] = { + { .name = "notify", }, }; static int __net_init genl_pernet_init(struct net *net) @@ -1036,7 +996,8 @@ static int __init genl_init(void) for (i = 0; i < GENL_FAM_TAB_SIZE; i++) INIT_LIST_HEAD(&family_ht[i]); - err = genl_register_family_with_ops(&genl_ctrl, &genl_ctrl_ops, 1); + err = genl_register_family_with_ops_groups(&genl_ctrl, genl_ctrl_ops, + genl_ctrl_groups); if (err < 0) goto problem; @@ -1044,10 +1005,6 @@ static int __init genl_init(void) if (err) goto problem; - err = genl_register_mc_group(&genl_ctrl, ¬ify_grp); - if (err < 0) - goto problem; - return 0; problem: @@ -1085,14 +1042,18 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group, return err; } -int genlmsg_multicast_allns(struct sk_buff *skb, u32 portid, unsigned int group, - gfp_t flags) +int genlmsg_multicast_allns(struct genl_family *family, struct sk_buff *skb, + u32 portid, unsigned int group, gfp_t flags) { + if (group >= family->n_mcgrps) + return -EINVAL; + group = family->mcgrp_offset + group; return genlmsg_mcast(skb, portid, group, flags); } EXPORT_SYMBOL(genlmsg_multicast_allns); -void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, u32 group, +void genl_notify(struct genl_family *family, + struct sk_buff *skb, struct net *net, u32 portid, u32 group, struct nlmsghdr *nlh, gfp_t flags) { struct sock *sk = net->genl_sock; @@ -1101,6 +1062,9 @@ void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, u32 group, if (nlh) report = nlmsg_report(nlh); + if (group >= family->n_mcgrps) + return; + group = family->mcgrp_offset + group; nlmsg_notify(sk, skb, portid, group, report, flags); } EXPORT_SYMBOL(genl_notify); diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 84b7e3ea7b7a..a9b2342d5253 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -30,8 +30,8 @@ #include "nfc.h" #include "llcp.h" -static struct genl_multicast_group nfc_genl_event_mcgrp = { - .name = NFC_GENL_MCAST_EVENT_NAME, +static const struct genl_multicast_group nfc_genl_mcgrps[] = { + { .name = NFC_GENL_MCAST_EVENT_NAME, }, }; static struct genl_family nfc_genl_family = { @@ -194,7 +194,7 @@ int nfc_genl_targets_found(struct nfc_dev *dev) genlmsg_end(msg, hdr); - return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC); + return genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); nla_put_failure: genlmsg_cancel(msg, hdr); @@ -223,7 +223,7 @@ int nfc_genl_target_lost(struct nfc_dev *dev, u32 target_idx) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -255,7 +255,7 @@ int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -285,7 +285,7 @@ int nfc_genl_tm_deactivated(struct nfc_dev *dev) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -318,7 +318,7 @@ int nfc_genl_device_added(struct nfc_dev *dev) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -348,7 +348,7 @@ int nfc_genl_device_removed(struct nfc_dev *dev) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -414,7 +414,7 @@ int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list) genlmsg_end(msg, hdr); - return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC); + return genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); nla_put_failure: genlmsg_cancel(msg, hdr); @@ -448,7 +448,7 @@ int nfc_genl_se_added(struct nfc_dev *dev, u32 se_idx, u16 type) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -479,7 +479,7 @@ int nfc_genl_se_removed(struct nfc_dev *dev, u32 se_idx) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -600,7 +600,7 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx, dev->dep_link_up = true; - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); return 0; @@ -632,7 +632,7 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); return 0; @@ -1137,7 +1137,7 @@ int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name, genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -1308,7 +1308,7 @@ static void se_io_cb(void *context, u8 *apdu, size_t apdu_len, int err) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); kfree(ctx); @@ -1364,7 +1364,7 @@ static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info) return dev->ops->se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx); } -static struct genl_ops nfc_genl_ops[] = { +static const struct genl_ops nfc_genl_ops[] = { { .cmd = NFC_CMD_GET_DEVICE, .doit = nfc_genl_get_device, @@ -1536,16 +1536,15 @@ int __init nfc_genl_init(void) { int rc; - rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops, - ARRAY_SIZE(nfc_genl_ops)); + rc = genl_register_family_with_ops_groups(&nfc_genl_family, + nfc_genl_ops, + nfc_genl_mcgrps); if (rc) return rc; - rc = genl_register_mc_group(&nfc_genl_family, &nfc_genl_event_mcgrp); - netlink_register_notifier(&nl_notifier); - return rc; + return 0; } /** diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 449e0776a2c0..6f5e1dd3be2d 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -61,11 +61,11 @@ int ovs_net_id __read_mostly; -static void ovs_notify(struct sk_buff *skb, struct genl_info *info, - struct genl_multicast_group *grp) +static void ovs_notify(struct genl_family *family, + struct sk_buff *skb, struct genl_info *info) { - genl_notify(skb, genl_info_net(info), info->snd_portid, - grp->id, info->nlhdr, GFP_KERNEL); + genl_notify(family, skb, genl_info_net(info), info->snd_portid, + 0, info->nlhdr, GFP_KERNEL); } /** @@ -557,7 +557,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = { [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED }, }; -static struct genl_ops dp_packet_genl_ops[] = { +static const struct genl_ops dp_packet_genl_ops[] = { { .cmd = OVS_PACKET_CMD_EXECUTE, .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ .policy = packet_policy, @@ -877,10 +877,10 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) ovs_unlock(); if (!IS_ERR(reply)) - ovs_notify(reply, info, &ovs_dp_flow_multicast_group); + ovs_notify(&dp_flow_genl_family, reply, info); else - netlink_set_err(sock_net(skb->sk)->genl_sock, 0, - ovs_dp_flow_multicast_group.id, PTR_ERR(reply)); + genl_set_err(&dp_flow_genl_family, sock_net(skb->sk), 0, + 0, PTR_ERR(reply)); return 0; err_flow_free: @@ -990,7 +990,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) ovs_flow_free(flow, true); ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_flow_multicast_group); + ovs_notify(&dp_flow_genl_family, reply, info); return 0; unlock: ovs_unlock(); @@ -1034,7 +1034,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } -static struct genl_ops dp_flow_genl_ops[] = { +static const struct genl_ops dp_flow_genl_ops[] = { { .cmd = OVS_FLOW_CMD_NEW, .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ .policy = flow_policy, @@ -1243,7 +1243,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_datapath_multicast_group); + ovs_notify(&dp_datapath_genl_family, reply, info); return 0; err_destroy_local_port: @@ -1308,7 +1308,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info) __dp_destroy(dp); ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_datapath_multicast_group); + ovs_notify(&dp_datapath_genl_family, reply, info); return 0; unlock: @@ -1332,14 +1332,14 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info) info->snd_seq, OVS_DP_CMD_NEW); if (IS_ERR(reply)) { err = PTR_ERR(reply); - netlink_set_err(sock_net(skb->sk)->genl_sock, 0, - ovs_dp_datapath_multicast_group.id, err); + genl_set_err(&dp_datapath_genl_family, sock_net(skb->sk), 0, + 0, err); err = 0; goto unlock; } ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_datapath_multicast_group); + ovs_notify(&dp_datapath_genl_family, reply, info); return 0; unlock: @@ -1398,7 +1398,7 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } -static struct genl_ops dp_datapath_genl_ops[] = { +static const struct genl_ops dp_datapath_genl_ops[] = { { .cmd = OVS_DP_CMD_NEW, .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ .policy = datapath_policy, @@ -1431,7 +1431,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, }; -static struct genl_family dp_vport_genl_family = { +struct genl_family dp_vport_genl_family = { .id = GENL_ID_GENERATE, .hdrsize = sizeof(struct ovs_header), .name = OVS_VPORT_FAMILY, @@ -1601,7 +1601,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) goto exit_unlock; } - ovs_notify(reply, info, &ovs_dp_vport_multicast_group); + ovs_notify(&dp_vport_genl_family, reply, info); exit_unlock: ovs_unlock(); @@ -1648,7 +1648,7 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info) BUG_ON(err < 0); ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_vport_multicast_group); + ovs_notify(&dp_vport_genl_family, reply, info); return 0; exit_free: @@ -1685,7 +1685,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info) err = 0; ovs_dp_detach_port(vport); - ovs_notify(reply, info, &ovs_dp_vport_multicast_group); + ovs_notify(&dp_vport_genl_family, reply, info); exit_unlock: ovs_unlock(); @@ -1759,7 +1759,7 @@ out: return skb->len; } -static struct genl_ops dp_vport_genl_ops[] = { +static const struct genl_ops dp_vport_genl_ops[] = { { .cmd = OVS_VPORT_CMD_NEW, .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ .policy = vport_policy, @@ -1785,9 +1785,9 @@ static struct genl_ops dp_vport_genl_ops[] = { struct genl_family_and_ops { struct genl_family *family; - struct genl_ops *ops; + const struct genl_ops *ops; int n_ops; - struct genl_multicast_group *group; + const struct genl_multicast_group *group; }; static const struct genl_family_and_ops dp_genl_families[] = { @@ -1823,17 +1823,14 @@ static int dp_register_genl(void) for (i = 0; i < ARRAY_SIZE(dp_genl_families); i++) { const struct genl_family_and_ops *f = &dp_genl_families[i]; - err = genl_register_family_with_ops(f->family, f->ops, - f->n_ops); + f->family->ops = f->ops; + f->family->n_ops = f->n_ops; + f->family->mcgrps = f->group; + f->family->n_mcgrps = f->group ? 1 : 0; + err = genl_register_family(f->family); if (err) goto error; n_registered++; - - if (f->group) { - err = genl_register_mc_group(f->family, f->group); - if (err) - goto error; - } } return 0; diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index d3d14a58aa91..4067ea41be28 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -177,6 +177,7 @@ static inline struct vport *ovs_vport_ovsl(const struct datapath *dp, int port_n } extern struct notifier_block ovs_dp_device_notifier; +extern struct genl_family dp_vport_genl_family; extern struct genl_multicast_group ovs_dp_vport_multicast_group; void ovs_dp_process_received_packet(struct vport *, struct sk_buff *); diff --git a/net/openvswitch/dp_notify.c b/net/openvswitch/dp_notify.c index 5c2dab276109..2c631fe76be1 100644 --- a/net/openvswitch/dp_notify.c +++ b/net/openvswitch/dp_notify.c @@ -34,15 +34,14 @@ static void dp_detach_port_notify(struct vport *vport) OVS_VPORT_CMD_DEL); ovs_dp_detach_port(vport); if (IS_ERR(notify)) { - netlink_set_err(ovs_dp_get_net(dp)->genl_sock, 0, - ovs_dp_vport_multicast_group.id, - PTR_ERR(notify)); + genl_set_err(&dp_vport_genl_family, ovs_dp_get_net(dp), 0, + 0, PTR_ERR(notify)); return; } - genlmsg_multicast_netns(ovs_dp_get_net(dp), notify, 0, - ovs_dp_vport_multicast_group.id, - GFP_KERNEL); + genlmsg_multicast_netns(&dp_vport_genl_family, + ovs_dp_get_net(dp), notify, 0, + 0, GFP_KERNEL); } void ovs_dp_notify_wq(struct work_struct *work) diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c index 12c30f3e643e..38946b26e471 100644 --- a/net/phonet/datagram.c +++ b/net/phonet/datagram.c @@ -139,9 +139,6 @@ static int pn_recvmsg(struct kiocb *iocb, struct sock *sk, MSG_CMSG_COMPAT)) goto out_nofree; - if (addr_len) - *addr_len = sizeof(sa); - skb = skb_recv_datagram(sk, flags, noblock, &rval); if (skb == NULL) goto out_nofree; @@ -162,8 +159,10 @@ static int pn_recvmsg(struct kiocb *iocb, struct sock *sk, rval = (flags & MSG_TRUNC) ? skb->len : copylen; - if (msg->msg_name != NULL) - memcpy(msg->msg_name, &sa, sizeof(struct sockaddr_pn)); + if (msg->msg_name != NULL) { + memcpy(msg->msg_name, &sa, sizeof(sa)); + *addr_len = sizeof(sa); + } out: skb_free_datagram(sk, skb); diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index fdc041c57853..95d843961907 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -88,7 +88,7 @@ struct fq_sched_data { struct fq_flow internal; /* for non classified or high prio packets */ u32 quantum; u32 initial_quantum; - u32 flow_default_rate;/* rate per flow : bytes per second */ + u32 flow_refill_delay; u32 flow_max_rate; /* optional max rate per flow */ u32 flow_plimit; /* max packets per flow */ struct rb_root *fq_root; @@ -115,6 +115,7 @@ static struct fq_flow detached, throttled; static void fq_flow_set_detached(struct fq_flow *f) { f->next = &detached; + f->age = jiffies; } static bool fq_flow_is_detached(const struct fq_flow *f) @@ -209,21 +210,15 @@ static void fq_gc(struct fq_sched_data *q, } } -static const u8 prio2band[TC_PRIO_MAX + 1] = { - 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 -}; - static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q) { struct rb_node **p, *parent; struct sock *sk = skb->sk; struct rb_root *root; struct fq_flow *f; - int band; /* warning: no starvation prevention... */ - band = prio2band[skb->priority & TC_PRIO_MAX]; - if (unlikely(band == 0)) + if (unlikely((skb->priority & TC_PRIO_MAX) == TC_PRIO_CONTROL)) return &q->internal; if (unlikely(!sk)) { @@ -373,17 +368,20 @@ static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch) } f->qlen++; - flow_queue_add(f, skb); if (skb_is_retransmit(skb)) q->stat_tcp_retrans++; sch->qstats.backlog += qdisc_pkt_len(skb); if (fq_flow_is_detached(f)) { fq_flow_add_tail(&q->new_flows, f); - if (q->quantum > f->credit) - f->credit = q->quantum; + if (time_after(jiffies, f->age + q->flow_refill_delay)) + f->credit = max_t(u32, f->credit, q->quantum); q->inactive_flows--; qdisc_unthrottled(sch); } + + /* Note: this overwrites f->age */ + flow_queue_add(f, skb); + if (unlikely(f == &q->internal)) { q->stat_internal_packets++; qdisc_unthrottled(sch); @@ -461,7 +459,6 @@ begin: fq_flow_add_tail(&q->old_flows, f); } else { fq_flow_set_detached(f); - f->age = jiffies; q->inactive_flows++; } goto begin; @@ -615,6 +612,7 @@ static const struct nla_policy fq_policy[TCA_FQ_MAX + 1] = { [TCA_FQ_FLOW_DEFAULT_RATE] = { .type = NLA_U32 }, [TCA_FQ_FLOW_MAX_RATE] = { .type = NLA_U32 }, [TCA_FQ_BUCKETS_LOG] = { .type = NLA_U32 }, + [TCA_FQ_FLOW_REFILL_DELAY] = { .type = NLA_U32 }, }; static int fq_change(struct Qdisc *sch, struct nlattr *opt) @@ -656,7 +654,8 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt) q->initial_quantum = nla_get_u32(tb[TCA_FQ_INITIAL_QUANTUM]); if (tb[TCA_FQ_FLOW_DEFAULT_RATE]) - q->flow_default_rate = nla_get_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE]); + pr_warn_ratelimited("sch_fq: defrate %u ignored.\n", + nla_get_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE])); if (tb[TCA_FQ_FLOW_MAX_RATE]) q->flow_max_rate = nla_get_u32(tb[TCA_FQ_FLOW_MAX_RATE]); @@ -670,6 +669,12 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt) err = -EINVAL; } + if (tb[TCA_FQ_FLOW_REFILL_DELAY]) { + u32 usecs_delay = nla_get_u32(tb[TCA_FQ_FLOW_REFILL_DELAY]) ; + + q->flow_refill_delay = usecs_to_jiffies(usecs_delay); + } + if (!err) err = fq_resize(q, fq_log); @@ -705,7 +710,7 @@ static int fq_init(struct Qdisc *sch, struct nlattr *opt) q->flow_plimit = 100; q->quantum = 2 * psched_mtu(qdisc_dev(sch)); q->initial_quantum = 10 * psched_mtu(qdisc_dev(sch)); - q->flow_default_rate = 0; + q->flow_refill_delay = msecs_to_jiffies(40); q->flow_max_rate = ~0U; q->rate_enable = 1; q->new_flows.first = NULL; @@ -732,15 +737,16 @@ static int fq_dump(struct Qdisc *sch, struct sk_buff *skb) if (opts == NULL) goto nla_put_failure; - /* TCA_FQ_FLOW_DEFAULT_RATE is not used anymore, - * do not bother giving its value - */ + /* TCA_FQ_FLOW_DEFAULT_RATE is not used anymore */ + if (nla_put_u32(skb, TCA_FQ_PLIMIT, sch->limit) || nla_put_u32(skb, TCA_FQ_FLOW_PLIMIT, q->flow_plimit) || nla_put_u32(skb, TCA_FQ_QUANTUM, q->quantum) || nla_put_u32(skb, TCA_FQ_INITIAL_QUANTUM, q->initial_quantum) || nla_put_u32(skb, TCA_FQ_RATE_ENABLE, q->rate_enable) || nla_put_u32(skb, TCA_FQ_FLOW_MAX_RATE, q->flow_max_rate) || + nla_put_u32(skb, TCA_FQ_FLOW_REFILL_DELAY, + jiffies_to_usecs(q->flow_refill_delay)) || nla_put_u32(skb, TCA_FQ_BUCKETS_LOG, q->fq_trees_log)) goto nla_put_failure; diff --git a/net/sctp/associola.c b/net/sctp/associola.c index c9b91cb1cb0d..68a27f9796d2 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -907,8 +907,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, if (!first || t->last_time_heard > first->last_time_heard) { second = first; first = t; - } - if (!second || t->last_time_heard > second->last_time_heard) + } else if (!second || + t->last_time_heard > second->last_time_heard) second = t; } @@ -929,6 +929,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, first = asoc->peer.primary_path; } + if (!second) + second = first; /* If we failed to find a usable transport, just camp on the * primary, even if it is inactive. */ diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index d0d14a04dce1..bf04b30a788a 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -471,15 +471,6 @@ struct rpc_filelist { umode_t mode; }; -static int rpc_delete_dentry(const struct dentry *dentry) -{ - return 1; -} - -static const struct dentry_operations rpc_dentry_operations = { - .d_delete = rpc_delete_dentry, -}; - static struct inode * rpc_get_inode(struct super_block *sb, umode_t mode) { @@ -1266,7 +1257,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = RPCAUTH_GSSMAGIC; sb->s_op = &s_ops; - sb->s_d_op = &rpc_dentry_operations; + sb->s_d_op = &simple_dentry_operations; sb->s_time_gran = 1; inode = rpc_get_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); diff --git a/net/tipc/link.c b/net/tipc/link.c index cf465d66ccde..69cd9bf3f561 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -2358,7 +2358,8 @@ int tipc_link_recv_fragment(struct sk_buff **head, struct sk_buff **tail, *head = frag; skb_frag_list_init(*head); return 0; - } else if (skb_try_coalesce(*head, frag, &headstolen, &delta)) { + } else if (*head && + skb_try_coalesce(*head, frag, &headstolen, &delta)) { kfree_skb_partial(frag, headstolen); } else { if (!*head) diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 8bcd4985d0fb..9f72a6376362 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -76,9 +76,11 @@ static struct genl_family tipc_genl_family = { .maxattr = 0, }; -static struct genl_ops tipc_genl_ops = { - .cmd = TIPC_GENL_CMD, - .doit = handle_cmd, +static struct genl_ops tipc_genl_ops[] = { + { + .cmd = TIPC_GENL_CMD, + .doit = handle_cmd, + }, }; static int tipc_genl_family_registered; @@ -87,8 +89,7 @@ int tipc_netlink_start(void) { int res; - res = genl_register_family_with_ops(&tipc_genl_family, - &tipc_genl_ops, 1); + res = genl_register_family_with_ops(&tipc_genl_family, tipc_genl_ops); if (res) { pr_err("Failed to register netlink interface\n"); return res; diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c index 0694d62e4dbc..c278b3356f75 100644 --- a/net/wimax/op-msg.c +++ b/net/wimax/op-msg.c @@ -279,7 +279,7 @@ int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size); d_dump(2, dev, msg, size); - genlmsg_multicast(skb, 0, wimax_gnl_mcg.id, GFP_KERNEL); + genlmsg_multicast(&wimax_gnl_family, skb, 0, 0, GFP_KERNEL); d_printf(1, dev, "CTX: genl multicast done\n"); return 0; } @@ -321,17 +321,6 @@ int wimax_msg(struct wimax_dev *wimax_dev, const char *pipe_name, } EXPORT_SYMBOL_GPL(wimax_msg); - -static const struct nla_policy wimax_gnl_msg_policy[WIMAX_GNL_ATTR_MAX + 1] = { - [WIMAX_GNL_MSG_IFIDX] = { - .type = NLA_U32, - }, - [WIMAX_GNL_MSG_DATA] = { - .type = NLA_UNSPEC, /* libnl doesn't grok BINARY yet */ - }, -}; - - /* * Relays a message from user space to the driver * @@ -340,7 +329,6 @@ static const struct nla_policy wimax_gnl_msg_policy[WIMAX_GNL_ATTR_MAX + 1] = { * * This call will block while handling/relaying the message. */ -static int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info) { int result, ifindex; @@ -418,16 +406,3 @@ error_no_wimax_dev: return result; } - -/* - * Generic Netlink glue - */ - -struct genl_ops wimax_gnl_msg_from_user = { - .cmd = WIMAX_GNL_OP_MSG_FROM_USER, - .flags = GENL_ADMIN_PERM, - .policy = wimax_gnl_msg_policy, - .doit = wimax_gnl_doit_msg_from_user, - .dumpit = NULL, -}; - diff --git a/net/wimax/op-reset.c b/net/wimax/op-reset.c index 7ceffe39d70e..eb4580784d9d 100644 --- a/net/wimax/op-reset.c +++ b/net/wimax/op-reset.c @@ -92,13 +92,6 @@ int wimax_reset(struct wimax_dev *wimax_dev) EXPORT_SYMBOL(wimax_reset); -static const struct nla_policy wimax_gnl_reset_policy[WIMAX_GNL_ATTR_MAX + 1] = { - [WIMAX_GNL_RESET_IFIDX] = { - .type = NLA_U32, - }, -}; - - /* * Exporting to user space over generic netlink * @@ -106,7 +99,6 @@ static const struct nla_policy wimax_gnl_reset_policy[WIMAX_GNL_ATTR_MAX + 1] = * * No attributes. */ -static int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info) { int result, ifindex; @@ -130,12 +122,3 @@ error_no_wimax_dev: d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); return result; } - - -struct genl_ops wimax_gnl_reset = { - .cmd = WIMAX_GNL_OP_RESET, - .flags = GENL_ADMIN_PERM, - .policy = wimax_gnl_reset_policy, - .doit = wimax_gnl_doit_reset, - .dumpit = NULL, -}; diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c index 7ab60babdd22..403078d670a9 100644 --- a/net/wimax/op-rfkill.c +++ b/net/wimax/op-rfkill.c @@ -411,17 +411,6 @@ void wimax_rfkill_rm(struct wimax_dev *wimax_dev) * just query). */ -static const struct nla_policy wimax_gnl_rfkill_policy[WIMAX_GNL_ATTR_MAX + 1] = { - [WIMAX_GNL_RFKILL_IFIDX] = { - .type = NLA_U32, - }, - [WIMAX_GNL_RFKILL_STATE] = { - .type = NLA_U32 /* enum wimax_rf_state */ - }, -}; - - -static int wimax_gnl_doit_rfkill(struct sk_buff *skb, struct genl_info *info) { int result, ifindex; @@ -457,13 +446,3 @@ error_no_wimax_dev: d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); return result; } - - -struct genl_ops wimax_gnl_rfkill = { - .cmd = WIMAX_GNL_OP_RFKILL, - .flags = GENL_ADMIN_PERM, - .policy = wimax_gnl_rfkill_policy, - .doit = wimax_gnl_doit_rfkill, - .dumpit = NULL, -}; - diff --git a/net/wimax/op-state-get.c b/net/wimax/op-state-get.c index aff8776e2d41..995c08c827b5 100644 --- a/net/wimax/op-state-get.c +++ b/net/wimax/op-state-get.c @@ -33,13 +33,6 @@ #include "debug-levels.h" -static const struct nla_policy wimax_gnl_state_get_policy[WIMAX_GNL_ATTR_MAX + 1] = { - [WIMAX_GNL_STGET_IFIDX] = { - .type = NLA_U32, - }, -}; - - /* * Exporting to user space over generic netlink * @@ -48,7 +41,6 @@ static const struct nla_policy wimax_gnl_state_get_policy[WIMAX_GNL_ATTR_MAX + 1 * * No attributes. */ -static int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info) { int result, ifindex; @@ -72,12 +64,3 @@ error_no_wimax_dev: d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); return result; } - - -struct genl_ops wimax_gnl_state_get = { - .cmd = WIMAX_GNL_OP_STATE_GET, - .flags = GENL_ADMIN_PERM, - .policy = wimax_gnl_state_get_policy, - .doit = wimax_gnl_doit_state_get, - .dumpit = NULL, -}; diff --git a/net/wimax/stack.c b/net/wimax/stack.c index a6470ac39498..ef2191b969a7 100644 --- a/net/wimax/stack.c +++ b/net/wimax/stack.c @@ -116,8 +116,9 @@ struct sk_buff *wimax_gnl_re_state_change_alloc( dev_err(dev, "RE_STCH: can't create message\n"); goto error_new; } - data = genlmsg_put(report_skb, 0, wimax_gnl_mcg.id, &wimax_gnl_family, - 0, WIMAX_GNL_RE_STATE_CHANGE); + /* FIXME: sending a group ID as the seq is wrong */ + data = genlmsg_put(report_skb, 0, wimax_gnl_family.mcgrp_offset, + &wimax_gnl_family, 0, WIMAX_GNL_RE_STATE_CHANGE); if (data == NULL) { dev_err(dev, "RE_STCH: can't put data into message\n"); goto error_put; @@ -177,7 +178,7 @@ int wimax_gnl_re_state_change_send( goto out; } genlmsg_end(report_skb, header); - genlmsg_multicast(report_skb, 0, wimax_gnl_mcg.id, GFP_KERNEL); + genlmsg_multicast(&wimax_gnl_family, report_skb, 0, 0, GFP_KERNEL); out: d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n", wimax_dev, report_skb, result); @@ -402,22 +403,44 @@ void wimax_dev_init(struct wimax_dev *wimax_dev) } EXPORT_SYMBOL_GPL(wimax_dev_init); -/* - * This extern is declared here because it's easier to keep track -- - * both declarations are a list of the same - */ -extern struct genl_ops - wimax_gnl_msg_from_user, - wimax_gnl_reset, - wimax_gnl_rfkill, - wimax_gnl_state_get; +static const struct nla_policy wimax_gnl_policy[WIMAX_GNL_ATTR_MAX + 1] = { + [WIMAX_GNL_RESET_IFIDX] = { .type = NLA_U32, }, + [WIMAX_GNL_RFKILL_IFIDX] = { .type = NLA_U32, }, + [WIMAX_GNL_RFKILL_STATE] = { + .type = NLA_U32 /* enum wimax_rf_state */ + }, + [WIMAX_GNL_STGET_IFIDX] = { .type = NLA_U32, }, + [WIMAX_GNL_MSG_IFIDX] = { .type = NLA_U32, }, + [WIMAX_GNL_MSG_DATA] = { + .type = NLA_UNSPEC, /* libnl doesn't grok BINARY yet */ + }, +}; -static -struct genl_ops *wimax_gnl_ops[] = { - &wimax_gnl_msg_from_user, - &wimax_gnl_reset, - &wimax_gnl_rfkill, - &wimax_gnl_state_get, +static const struct genl_ops wimax_gnl_ops[] = { + { + .cmd = WIMAX_GNL_OP_MSG_FROM_USER, + .flags = GENL_ADMIN_PERM, + .policy = wimax_gnl_policy, + .doit = wimax_gnl_doit_msg_from_user, + }, + { + .cmd = WIMAX_GNL_OP_RESET, + .flags = GENL_ADMIN_PERM, + .policy = wimax_gnl_policy, + .doit = wimax_gnl_doit_reset, + }, + { + .cmd = WIMAX_GNL_OP_RFKILL, + .flags = GENL_ADMIN_PERM, + .policy = wimax_gnl_policy, + .doit = wimax_gnl_doit_rfkill, + }, + { + .cmd = WIMAX_GNL_OP_STATE_GET, + .flags = GENL_ADMIN_PERM, + .policy = wimax_gnl_policy, + .doit = wimax_gnl_doit_state_get, + }, }; @@ -557,8 +580,8 @@ struct genl_family wimax_gnl_family = { .maxattr = WIMAX_GNL_ATTR_MAX, }; -struct genl_multicast_group wimax_gnl_mcg = { - .name = "msg", +static const struct genl_multicast_group wimax_gnl_mcgrps[] = { + { .name = "msg", }, }; @@ -567,7 +590,7 @@ struct genl_multicast_group wimax_gnl_mcg = { static int __init wimax_subsys_init(void) { - int result, cnt; + int result; d_fnstart(4, NULL, "()\n"); d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params, @@ -575,37 +598,18 @@ int __init wimax_subsys_init(void) snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name), "WiMAX"); - result = genl_register_family(&wimax_gnl_family); + result = genl_register_family_with_ops_groups(&wimax_gnl_family, + wimax_gnl_ops, + wimax_gnl_mcgrps); if (unlikely(result < 0)) { printk(KERN_ERR "cannot register generic netlink family: %d\n", result); goto error_register_family; } - for (cnt = 0; cnt < ARRAY_SIZE(wimax_gnl_ops); cnt++) { - result = genl_register_ops(&wimax_gnl_family, - wimax_gnl_ops[cnt]); - d_printf(4, NULL, "registering generic netlink op code " - "%u: %d\n", wimax_gnl_ops[cnt]->cmd, result); - if (unlikely(result < 0)) { - printk(KERN_ERR "cannot register generic netlink op " - "code %u: %d\n", - wimax_gnl_ops[cnt]->cmd, result); - goto error_register_ops; - } - } - - result = genl_register_mc_group(&wimax_gnl_family, &wimax_gnl_mcg); - if (result < 0) - goto error_mc_group; d_fnend(4, NULL, "() = 0\n"); return 0; -error_mc_group: -error_register_ops: - for (cnt--; cnt >= 0; cnt--) - genl_unregister_ops(&wimax_gnl_family, - wimax_gnl_ops[cnt]); genl_unregister_family(&wimax_gnl_family); error_register_family: d_fnend(4, NULL, "() = %d\n", result); @@ -619,12 +623,7 @@ module_init(wimax_subsys_init); static void __exit wimax_subsys_exit(void) { - int cnt; wimax_id_table_release(); - genl_unregister_mc_group(&wimax_gnl_family, &wimax_gnl_mcg); - for (cnt = ARRAY_SIZE(wimax_gnl_ops) - 1; cnt >= 0; cnt--) - genl_unregister_ops(&wimax_gnl_family, - wimax_gnl_ops[cnt]); genl_unregister_family(&wimax_gnl_family); } module_exit(wimax_subsys_exit); diff --git a/net/wimax/wimax-internal.h b/net/wimax/wimax-internal.h index 5dcd9c067bf0..b445b82020a8 100644 --- a/net/wimax/wimax-internal.h +++ b/net/wimax/wimax-internal.h @@ -84,8 +84,14 @@ void wimax_id_table_release(void); int wimax_rfkill_add(struct wimax_dev *); void wimax_rfkill_rm(struct wimax_dev *); +/* generic netlink */ extern struct genl_family wimax_gnl_family; -extern struct genl_multicast_group wimax_gnl_mcg; + +/* ops */ +int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info); +int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info); +int wimax_gnl_doit_rfkill(struct sk_buff *skb, struct genl_info *info); +int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info); #endif /* #ifdef __KERNEL__ */ #endif /* #ifndef __WIMAX_INTERNAL_H__ */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a7f4e7902104..a1eb21073176 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -30,9 +30,9 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, struct cfg80211_crypto_settings *settings, int cipher_limit); -static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, +static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info); -static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, +static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info); /* the netlink family */ @@ -47,6 +47,25 @@ static struct genl_family nl80211_fam = { .post_doit = nl80211_post_doit, }; +/* multicast groups */ +enum nl80211_multicast_groups { + NL80211_MCGRP_CONFIG, + NL80211_MCGRP_SCAN, + NL80211_MCGRP_REGULATORY, + NL80211_MCGRP_MLME, + NL80211_MCGRP_TESTMODE /* keep last - ifdef! */ +}; + +static const struct genl_multicast_group nl80211_mcgrps[] = { + [NL80211_MCGRP_CONFIG] = { .name = "config", }, + [NL80211_MCGRP_SCAN] = { .name = "scan", }, + [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", }, + [NL80211_MCGRP_MLME] = { .name = "mlme", }, +#ifdef CONFIG_NL80211_TESTMODE + [NL80211_MCGRP_TESTMODE] = { .name = "testmode", } +#endif +}; + /* returns ERR_PTR values */ static struct wireless_dev * __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) @@ -6656,10 +6675,6 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info) #ifdef CONFIG_NL80211_TESTMODE -static struct genl_multicast_group nl80211_testmode_mcgrp = { - .name = "testmode", -}; - static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -6868,8 +6883,8 @@ void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) nla_nest_end(skb, data); genlmsg_end(skb, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0, - nl80211_testmode_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0, + NL80211_MCGRP_TESTMODE, gfp); } EXPORT_SYMBOL(cfg80211_testmode_event); #endif @@ -8851,7 +8866,7 @@ static int nl80211_crit_protocol_stop(struct sk_buff *skb, #define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\ NL80211_FLAG_CHECK_NETDEV_UP) -static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, +static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; @@ -8920,7 +8935,7 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, return 0; } -static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, +static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { if (info->user_ptr[1]) { @@ -8937,7 +8952,7 @@ static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, rtnl_unlock(); } -static struct genl_ops nl80211_ops[] = { +static const struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, .doit = nl80211_get_wiphy, @@ -9566,21 +9581,6 @@ static struct genl_ops nl80211_ops[] = { }, }; -static struct genl_multicast_group nl80211_mlme_mcgrp = { - .name = "mlme", -}; - -/* multicast groups */ -static struct genl_multicast_group nl80211_config_mcgrp = { - .name = "config", -}; -static struct genl_multicast_group nl80211_scan_mcgrp = { - .name = "scan", -}; -static struct genl_multicast_group nl80211_regulatory_mcgrp = { - .name = "regulatory", -}; - /* notification functions */ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) @@ -9597,8 +9597,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_config_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_CONFIG, GFP_KERNEL); } static int nl80211_add_scan_req(struct sk_buff *msg, @@ -9707,8 +9707,8 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_scan_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_SCAN, GFP_KERNEL); } void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, @@ -9726,8 +9726,8 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_scan_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_SCAN, GFP_KERNEL); } void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, @@ -9745,8 +9745,8 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_scan_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_SCAN, GFP_KERNEL); } void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, @@ -9764,8 +9764,8 @@ void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_scan_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_SCAN, GFP_KERNEL); } void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, @@ -9782,8 +9782,8 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_scan_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_SCAN, GFP_KERNEL); } /* @@ -9837,8 +9837,8 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) genlmsg_end(msg, hdr); rcu_read_lock(); - genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, - GFP_ATOMIC); + genlmsg_multicast_allns(&nl80211_fam, msg, 0, + NL80211_MCGRP_REGULATORY, GFP_ATOMIC); rcu_read_unlock(); return; @@ -9873,8 +9873,8 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -9961,8 +9961,8 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10017,8 +10017,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10056,8 +10056,8 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10094,8 +10094,8 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, GFP_KERNEL); return; nla_put_failure: @@ -10128,8 +10128,8 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10169,8 +10169,8 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10208,8 +10208,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10261,8 +10261,8 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, genlmsg_end(msg, hdr); rcu_read_lock(); - genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, - GFP_ATOMIC); + genlmsg_multicast_allns(&nl80211_fam, msg, 0, + NL80211_MCGRP_REGULATORY, GFP_ATOMIC); rcu_read_unlock(); return; @@ -10307,8 +10307,8 @@ static void nl80211_send_remain_on_chan_event( genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10362,8 +10362,8 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); } EXPORT_SYMBOL(cfg80211_new_sta); @@ -10392,8 +10392,8 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10428,8 +10428,8 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10590,8 +10590,8 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10639,8 +10639,8 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10684,8 +10684,8 @@ static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10742,8 +10742,8 @@ nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10789,8 +10789,8 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10866,8 +10866,8 @@ void cfg80211_cqm_txe_notify(struct net_device *dev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10915,8 +10915,8 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10962,8 +10962,8 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -11002,8 +11002,8 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -11154,8 +11154,8 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; free_msg: @@ -11196,8 +11196,8 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -11279,8 +11279,8 @@ void cfg80211_ft_event(struct net_device *netdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, GFP_KERNEL); } EXPORT_SYMBOL(cfg80211_ft_event); @@ -11329,33 +11329,11 @@ int nl80211_init(void) { int err; - err = genl_register_family_with_ops(&nl80211_fam, - nl80211_ops, ARRAY_SIZE(nl80211_ops)); + err = genl_register_family_with_ops_groups(&nl80211_fam, nl80211_ops, + nl80211_mcgrps); if (err) return err; - err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); - if (err) - goto err_out; - - err = genl_register_mc_group(&nl80211_fam, &nl80211_scan_mcgrp); - if (err) - goto err_out; - - err = genl_register_mc_group(&nl80211_fam, &nl80211_regulatory_mcgrp); - if (err) - goto err_out; - - err = genl_register_mc_group(&nl80211_fam, &nl80211_mlme_mcgrp); - if (err) - goto err_out; - -#ifdef CONFIG_NL80211_TESTMODE - err = genl_register_mc_group(&nl80211_fam, &nl80211_testmode_mcgrp); - if (err) - goto err_out; -#endif - err = netlink_register_notifier(&nl80211_netlink_notifier); if (err) goto err_out; |