Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 19 Nov 2013 23:50:47 +0000 (15:50 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 19 Nov 2013 23:50:47 +0000 (15:50 -0800)
Pull networking fixes from David Miller:
 "Mostly these are fixes for fallout due to merge window changes, as
  well as cures for problems that have been with us for a much longer
  period of time"

 1) Johannes Berg noticed two major deficiencies in our genetlink
    registration.  Some genetlink protocols we passing in constant
    counts for their ops array rather than something like
    ARRAY_SIZE(ops) or similar.  Also, some genetlink protocols were
    using fixed IDs for their multicast groups.

    We have to retain these fixed IDs to keep existing userland tools
    working, but reserve them so that other multicast groups used by
    other protocols can not possibly conflict.

    In dealing with these two problems, we actually now use less state
    management for genetlink operations and multicast groups.

 2) When configuring interface hardware timestamping, fix several
    drivers that simply do not validate that the hwtstamp_config value
    is one the driver actually supports.  From Ben Hutchings.

 3) Invalid memory references in mwifiex driver, from Amitkumar Karwar.

 4) In dev_forward_skb(), set the skb->protocol in the right order
    relative to skb_scrub_packet().  From Alexei Starovoitov.

 5) Bridge erroneously fails to use the proper wrapper functions to make
    calls to netdev_ops->ndo_vlan_rx_{add,kill}_vid.  Fix from Toshiaki
    Makita.

 6) When detaching a bridge port, make sure to flush all VLAN IDs to
    prevent them from leaking, also from Toshiaki Makita.

 7) Put in a compromise for TCP Small Queues so that deep queued devices
    that delay TX reclaim non-trivially don't have such a performance
    decrease.  One particularly problematic area is 802.11 AMPDU in
    wireless.  From Eric Dumazet.

 8) Fix crashes in tcp_fastopen_cache_get(), we can see NULL socket dsts
    here.  Fix from Eric Dumzaet, reported by Dave Jones.

 9) Fix use after free in ipv6 SIT driver, from Willem de Bruijn.

10) When computing mergeable buffer sizes, virtio-net fails to take the
    virtio-net header into account.  From Michael Dalton.

11) Fix seqlock deadlock in ip4_datagram_connect() wrt.  statistic
    bumping, this one has been with us for a while.  From Eric Dumazet.

12) Fix NULL deref in the new TIPC fragmentation handling, from Erik
    Hugne.

13) 6lowpan bit used for traffic classification was wrong, from Jukka
    Rissanen.

14) macvlan has the same issue as normal vlans did wrt.  propagating LRO
    disabling down to the real device, fix it the same way.  From Michal
    Kubecek.

15) CPSW driver needs to soft reset all slaves during suspend, from
    Daniel Mack.

16) Fix small frame pacing in FQ packet scheduler, from Eric Dumazet.

17) The xen-netfront RX buffer refill timer isn't properly scheduled on
    partial RX allocation success, from Ma JieYue.

18) When ipv6 ping protocol support was added, the AF_INET6 protocol
    initialization cleanup path on failure was borked a little.  Fix
    from Vlad Yasevich.

19) If a socket disconnects during a read/recvmsg/recvfrom/etc that
    blocks we can do the wrong thing with the msg_name we write back to
    userspace.  From Hannes Frederic Sowa.  There is another fix in the
    works from Hannes which will prevent future problems of this nature.

20) Fix route leak in VTI tunnel transmit, from Fan Du.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (106 commits)
  genetlink: make multicast groups const, prevent abuse
  genetlink: pass family to functions using groups
  genetlink: add and use genl_set_err()
  genetlink: remove family pointer from genl_multicast_group
  genetlink: remove genl_unregister_mc_group()
  hsr: don't call genl_unregister_mc_group()
  quota/genetlink: use proper genetlink multicast APIs
  drop_monitor/genetlink: use proper genetlink multicast APIs
  genetlink: only pass array to genl_register_family_with_ops()
  tcp: don't update snd_nxt, when a socket is switched from repair mode
  atm: idt77252: fix dev refcnt leak
  xfrm: Release dst if this dst is improper for vti tunnel
  netlink: fix documentation typo in netlink_set_err()
  be2net: Delete secondary unicast MAC addresses during be_close
  be2net: Fix unconditional enabling of Rx interface options
  net, virtio_net: replace the magic value
  ping: prevent NULL pointer dereference on write to msg_name
  bnx2x: Prevent "timeout waiting for state X"
  bnx2x: prevent CFC attention
  bnx2x: Prevent panic during DMAE timeout
  ...

129 files changed:
Documentation/networking/ip-sysctl.txt
MAINTAINERS
drivers/acpi/event.c
drivers/atm/idt77252.c
drivers/connector/cn_proc.c
drivers/isdn/isdnloop/isdnloop.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/xscale/ixp4xx_eth.c
drivers/net/macvtap.c
drivers/net/team/team.c
drivers/net/tun.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/usbnet.c
drivers/net/virtio_net.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9485_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/dfs_debug.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/wcn36xx/debug.c
drivers/net/wireless/ath/wcn36xx/smd.c
drivers/net/wireless/libertas/debugfs.c
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/ie.c
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_cmdresp.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwifiex/uap_txrx.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2x00lib.h
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/efuse.c
drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
drivers/net/wireless/rtlwifi/rtl8192de/trx.c
drivers/net/wireless/rtlwifi/rtl8192se/rf.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/xen-netfront.c
drivers/scsi/pmcraid.c
drivers/thermal/thermal_core.c
fs/dlm/netlink.c
fs/quota/netlink.c
include/linux/genl_magic_func.h
include/linux/if_macvlan.h
include/linux/skbuff.h
include/net/genetlink.h
include/uapi/linux/genetlink.h
include/uapi/linux/pkt_sched.h
kernel/taskstats.c
lib/random32.c
net/bridge/br_if.c
net/bridge/br_vlan.c
net/core/dev.c
net/core/drop_monitor.c
net/hsr/hsr_netlink.c
net/ieee802154/6lowpan.c
net/ieee802154/dgram.c
net/ieee802154/ieee802154.h
net/ieee802154/netlink.c
net/ieee802154/nl-mac.c
net/ieee802154/nl-phy.c
net/ipv4/datagram.c
net/ipv4/ip_tunnel.c
net/ipv4/ip_vti.c
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv4/tcp.c
net/ipv4/tcp_metrics.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/ip6_tunnel.c
net/ipv6/ndisc.c
net/ipv6/raw.c
net/ipv6/sit.c
net/ipv6/udp.c
net/irda/irnetlink.c
net/l2tp/l2tp_ip.c
net/l2tp/l2tp_netlink.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netlabel/netlabel_cipso_v4.c
net/netlabel/netlabel_mgmt.c
net/netlabel/netlabel_unlabeled.c
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/nfc/netlink.c
net/openvswitch/datapath.c
net/openvswitch/datapath.h
net/openvswitch/dp_notify.c
net/phonet/datagram.c
net/sched/sch_fq.c
net/sctp/associola.c
net/tipc/link.c
net/tipc/netlink.c
net/wimax/op-msg.c
net/wimax/op-reset.c
net/wimax/op-rfkill.c
net/wimax/op-state-get.c
net/wimax/stack.c
net/wimax/wimax-internal.h
net/wireless/nl80211.c

index 8b8a057..3c12d9a 100644 (file)
@@ -577,9 +577,6 @@ tcp_limit_output_bytes - INTEGER
        typical pfifo_fast qdiscs.
        tcp_limit_output_bytes limits the number of bytes on qdisc
        or device to reduce artificial RTT/cwnd and reduce bufferbloat.
-       Note: For GSO/TSO enabled flows, we try to have at least two
-       packets in flight. Reducing tcp_limit_output_bytes might also
-       reduce the size of individual GSO packet (64KB being the max)
        Default: 131072
 
 tcp_challenge_ack_limit - INTEGER
index 0e598ae..63f3048 100644 (file)
@@ -2468,7 +2468,7 @@ S:        Maintained
 F:     drivers/media/dvb-frontends/cxd2820r*
 
 CXGB3 ETHERNET DRIVER (CXGB3)
-M:     Divy Le Ray <divy@chelsio.com>
+M:     Santosh Raspatur <santosh@chelsio.com>
 L:     netdev@vger.kernel.org
 W:     http://www.chelsio.com
 S:     Supported
@@ -8960,8 +8960,8 @@ USB PEGASUS DRIVER
 M:     Petko Manolov <petkan@nucleusys.com>
 L:     linux-usb@vger.kernel.org
 L:     netdev@vger.kernel.org
-T:     git git://git.code.sf.net/p/pegasus2/git
-W:     http://pegasus2.sourceforge.net/
+T:     git git://github.com/petkan/pegasus.git
+W:     https://github.com/petkan/pegasus
 S:     Maintained
 F:     drivers/net/usb/pegasus.*
 
@@ -8982,8 +8982,8 @@ USB RTL8150 DRIVER
 M:     Petko Manolov <petkan@nucleusys.com>
 L:     linux-usb@vger.kernel.org
 L:     netdev@vger.kernel.org
-T:     git git://git.code.sf.net/p/pegasus2/git
-W:     http://pegasus2.sourceforge.net/
+T:     git git://github.com/petkan/rtl8150.git
+W:     https://github.com/petkan/rtl8150
 S:     Maintained
 F:     drivers/net/usb/rtl8150.c
 
index fdef416..cae3b38 100644 (file)
@@ -78,15 +78,17 @@ enum {
 #define ACPI_GENL_VERSION              0x01
 #define ACPI_GENL_MCAST_GROUP_NAME     "acpi_mc_group"
 
+static const struct genl_multicast_group acpi_event_mcgrps[] = {
+       { .name = ACPI_GENL_MCAST_GROUP_NAME, },
+};
+
 static struct genl_family acpi_event_genl_family = {
        .id = GENL_ID_GENERATE,
        .name = ACPI_GENL_FAMILY_NAME,
        .version = ACPI_GENL_VERSION,
        .maxattr = ACPI_GENL_ATTR_MAX,
-};
-
-static struct genl_multicast_group acpi_event_mcgrp = {
-       .name = ACPI_GENL_MCAST_GROUP_NAME,
+       .mcgrps = acpi_event_mcgrps,
+       .n_mcgrps = ARRAY_SIZE(acpi_event_mcgrps),
 };
 
 int acpi_bus_generate_netlink_event(const char *device_class,
@@ -141,7 +143,7 @@ int acpi_bus_generate_netlink_event(const char *device_class,
                return result;
        }
 
-       genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
+       genlmsg_multicast(&acpi_event_genl_family, skb, 0, 0, GFP_ATOMIC);
        return 0;
 }
 
@@ -149,18 +151,7 @@ EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
 
 static int acpi_event_genetlink_init(void)
 {
-       int result;
-
-       result = genl_register_family(&acpi_event_genl_family);
-       if (result)
-               return result;
-
-       result = genl_register_mc_group(&acpi_event_genl_family,
-                                       &acpi_event_mcgrp);
-       if (result)
-               genl_unregister_family(&acpi_event_genl_family);
-
-       return result;
+       return genl_register_family(&acpi_event_genl_family);
 }
 
 #else
index 272f009..1bdf104 100644 (file)
@@ -3511,7 +3511,7 @@ static int init_card(struct atm_dev *dev)
        tmp = dev_get_by_name(&init_net, tname);        /* jhs: was "tmp = dev_get(tname);" */
        if (tmp) {
                memcpy(card->atmdev->esi, tmp->dev_addr, 6);
-
+               dev_put(tmp);
                printk("%s: ESI %pM\n", card->name, card->atmdev->esi);
        }
        /*
index c73fc2b..18c5b9b 100644 (file)
 #include <linux/atomic.h>
 #include <linux/pid_namespace.h>
 
-#include <asm/unaligned.h>
-
 #include <linux/cn_proc.h>
 
-#define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event))
+/*
+ * Size of a cn_msg followed by a proc_event structure.  Since the
+ * sizeof struct cn_msg is a multiple of 4 bytes, but not 8 bytes, we
+ * add one 4-byte word to the size here, and then start the actual
+ * cn_msg structure 4 bytes into the stack buffer.  The result is that
+ * the immediately following proc_event structure is aligned to 8 bytes.
+ */
+#define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event) + 4)
+
+/* See comment above; we test our assumption about sizeof struct cn_msg here. */
+static inline struct cn_msg *buffer_to_cn_msg(__u8 *buffer)
+{
+       BUILD_BUG_ON(sizeof(struct cn_msg) != 20);
+       return (struct cn_msg *)(buffer + 4);
+}
 
 static atomic_t proc_event_num_listeners = ATOMIC_INIT(0);
 static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC };
@@ -56,19 +68,19 @@ void proc_fork_connector(struct task_struct *task)
 {
        struct cn_msg *msg;
        struct proc_event *ev;
-       __u8 buffer[CN_PROC_MSG_SIZE];
+       __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
        struct timespec ts;
        struct task_struct *parent;
 
        if (atomic_read(&proc_event_num_listeners) < 1)
                return;
 
-       msg = (struct cn_msg *)buffer;
+       msg = buffer_to_cn_msg(buffer);
        ev = (struct proc_event *)msg->data;
        memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
-       put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+       ev->timestamp_ns = timespec_to_ns(&ts);
        ev->what = PROC_EVENT_FORK;
        rcu_read_lock();
        parent = rcu_dereference(task->real_parent);
@@ -91,17 +103,17 @@ void proc_exec_connector(struct task_struct *task)
        struct cn_msg *msg;
        struct proc_event *ev;
        struct timespec ts;
-       __u8 buffer[CN_PROC_MSG_SIZE];
+       __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
 
        if (atomic_read(&proc_event_num_listeners) < 1)
                return;
 
-       msg = (struct cn_msg *)buffer;
+       msg = buffer_to_cn_msg(buffer);
        ev = (struct proc_event *)msg->data;
        memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
-       put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+       ev->timestamp_ns = timespec_to_ns(&ts);
        ev->what = PROC_EVENT_EXEC;
        ev->event_data.exec.process_pid = task->pid;
        ev->event_data.exec.process_tgid = task->tgid;
@@ -117,14 +129,14 @@ void proc_id_connector(struct task_struct *task, int which_id)
 {
        struct cn_msg *msg;
        struct proc_event *ev;
-       __u8 buffer[CN_PROC_MSG_SIZE];
+       __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
        struct timespec ts;
        const struct cred *cred;
 
        if (atomic_read(&proc_event_num_listeners) < 1)
                return;
 
-       msg = (struct cn_msg *)buffer;
+       msg = buffer_to_cn_msg(buffer);
        ev = (struct proc_event *)msg->data;
        memset(&ev->event_data, 0, sizeof(ev->event_data));
        ev->what = which_id;
@@ -145,7 +157,7 @@ void proc_id_connector(struct task_struct *task, int which_id)
        rcu_read_unlock();
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
-       put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+       ev->timestamp_ns = timespec_to_ns(&ts);
 
        memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
        msg->ack = 0; /* not used */
@@ -159,17 +171,17 @@ void proc_sid_connector(struct task_struct *task)
        struct cn_msg *msg;
        struct proc_event *ev;
        struct timespec ts;
-       __u8 buffer[CN_PROC_MSG_SIZE];
+       __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
 
        if (atomic_read(&proc_event_num_listeners) < 1)
                return;
 
-       msg = (struct cn_msg *)buffer;
+       msg = buffer_to_cn_msg(buffer);
        ev = (struct proc_event *)msg->data;
        memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
-       put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+       ev->timestamp_ns = timespec_to_ns(&ts);
        ev->what = PROC_EVENT_SID;
        ev->event_data.sid.process_pid = task->pid;
        ev->event_data.sid.process_tgid = task->tgid;
@@ -186,17 +198,17 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
        struct cn_msg *msg;
        struct proc_event *ev;
        struct timespec ts;
-       __u8 buffer[CN_PROC_MSG_SIZE];
+       __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
 
        if (atomic_read(&proc_event_num_listeners) < 1)
                return;
 
-       msg = (struct cn_msg *)buffer;
+       msg = buffer_to_cn_msg(buffer);
        ev = (struct proc_event *)msg->data;
        memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
-       put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+       ev->timestamp_ns = timespec_to_ns(&ts);
        ev->what = PROC_EVENT_PTRACE;
        ev->event_data.ptrace.process_pid  = task->pid;
        ev->event_data.ptrace.process_tgid = task->tgid;
@@ -221,17 +233,17 @@ void proc_comm_connector(struct task_struct *task)
        struct cn_msg *msg;
        struct proc_event *ev;
        struct timespec ts;
-       __u8 buffer[CN_PROC_MSG_SIZE];
+       __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
 
        if (atomic_read(&proc_event_num_listeners) < 1)
                return;
 
-       msg = (struct cn_msg *)buffer;
+       msg = buffer_to_cn_msg(buffer);
        ev = (struct proc_event *)msg->data;
        memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
-       put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+       ev->timestamp_ns = timespec_to_ns(&ts);
        ev->what = PROC_EVENT_COMM;
        ev->event_data.comm.process_pid  = task->pid;
        ev->event_data.comm.process_tgid = task->tgid;
@@ -248,18 +260,18 @@ void proc_coredump_connector(struct task_struct *task)
 {
        struct cn_msg *msg;
        struct proc_event *ev;
-       __u8 buffer[CN_PROC_MSG_SIZE];
+       __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
        struct timespec ts;
 
        if (atomic_read(&proc_event_num_listeners) < 1)
                return;
 
-       msg = (struct cn_msg *)buffer;
+       msg = buffer_to_cn_msg(buffer);
        ev = (struct proc_event *)msg->data;
        memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
-       put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+       ev->timestamp_ns = timespec_to_ns(&ts);
        ev->what = PROC_EVENT_COREDUMP;
        ev->event_data.coredump.process_pid = task->pid;
        ev->event_data.coredump.process_tgid = task->tgid;
@@ -275,18 +287,18 @@ void proc_exit_connector(struct task_struct *task)
 {
        struct cn_msg *msg;
        struct proc_event *ev;
-       __u8 buffer[CN_PROC_MSG_SIZE];
+       __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
        struct timespec ts;
 
        if (atomic_read(&proc_event_num_listeners) < 1)
                return;
 
-       msg = (struct cn_msg *)buffer;
+       msg = buffer_to_cn_msg(buffer);
        ev = (struct proc_event *)msg->data;
        memset(&ev->event_data, 0, sizeof(ev->event_data));
        get_seq(&msg->seq, &ev->cpu);
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
-       put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+       ev->timestamp_ns = timespec_to_ns(&ts);
        ev->what = PROC_EVENT_EXIT;
        ev->event_data.exit.process_pid = task->pid;
        ev->event_data.exit.process_tgid = task->tgid;
@@ -312,18 +324,18 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
 {
        struct cn_msg *msg;
        struct proc_event *ev;
-       __u8 buffer[CN_PROC_MSG_SIZE];
+       __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
        struct timespec ts;
 
        if (atomic_read(&proc_event_num_listeners) < 1)
                return;
 
-       msg = (struct cn_msg *)buffer;
+       msg = buffer_to_cn_msg(buffer);
        ev = (struct proc_event *)msg->data;
        memset(&ev->event_data, 0, sizeof(ev->event_data));
        msg->seq = rcvd_seq;
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
-       put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+       ev->timestamp_ns = timespec_to_ns(&ts);
        ev->cpu = -1;
        ev->what = PROC_EVENT_NONE;
        ev->event_data.ack.err = err;
index baf2686..02125e6 100644 (file)
@@ -1083,8 +1083,10 @@ isdnloop_start(isdnloop_card *card, isdnloop_sdef *sdefp)
                        spin_unlock_irqrestore(&card->isdnloop_lock, flags);
                        return -ENOMEM;
                }
-               for (i = 0; i < 3; i++)
-                       strcpy(card->s0num[i], sdef.num[i]);
+               for (i = 0; i < 3; i++) {
+                       strlcpy(card->s0num[i], sdef.num[i],
+                               sizeof(card->s0num[0]));
+               }
                break;
        case ISDN_PTYPE_1TR6:
                if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95",
@@ -1097,7 +1099,7 @@ isdnloop_start(isdnloop_card *card, isdnloop_sdef *sdefp)
                        spin_unlock_irqrestore(&card->isdnloop_lock, flags);
                        return -ENOMEM;
                }
-               strcpy(card->s0num[0], sdef.num[0]);
+               strlcpy(card->s0num[0], sdef.num[0], sizeof(card->s0num[0]));
                card->s0num[1][0] = '\0';
                card->s0num[2][0] = '\0';
                break;
index bc8fd36..0ec2a7e 100644 (file)
@@ -524,8 +524,9 @@ static ssize_t bonding_store_arp_interval(struct device *d,
                goto out;
        }
        if (bond->params.mode == BOND_MODE_ALB ||
-           bond->params.mode == BOND_MODE_TLB) {
-               pr_info("%s: ARP monitoring cannot be used with ALB/TLB. Only MII monitoring is supported on %s.\n",
+           bond->params.mode == BOND_MODE_TLB ||
+           bond->params.mode == BOND_MODE_8023AD) {
+               pr_info("%s: ARP monitoring cannot be used with ALB/TLB/802.3ad. Only MII monitoring is supported on %s.\n",
                        bond->dev->name, bond->dev->name);
                ret = -EINVAL;
                goto out;
@@ -603,15 +604,14 @@ static ssize_t bonding_store_arp_targets(struct device *d,
                return restart_syscall();
 
        targets = bond->params.arp_targets;
-       newtarget = in_aton(buf + 1);
+       if (!in4_pton(buf + 1, -1, (u8 *)&newtarget, -1, NULL) ||
+           IS_IP_TARGET_UNUSABLE_ADDRESS(newtarget)) {
+               pr_err("%s: invalid ARP target %pI4 specified for addition\n",
+                      bond->dev->name, &newtarget);
+               goto out;
+       }
        /* look for adds */
        if (buf[0] == '+') {
-               if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) {
-                       pr_err("%s: invalid ARP target %pI4 specified for addition\n",
-                              bond->dev->name, &newtarget);
-                       goto out;
-               }
-
                if (bond_get_targets_ip(targets, newtarget) != -1) { /* dup */
                        pr_err("%s: ARP target %pI4 is already present\n",
                               bond->dev->name, &newtarget);
@@ -634,12 +634,6 @@ static ssize_t bonding_store_arp_targets(struct device *d,
                targets[ind] = newtarget;
                write_unlock_bh(&bond->lock);
        } else if (buf[0] == '-')       {
-               if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) {
-                       pr_err("%s: invalid ARP target %pI4 specified for removal\n",
-                              bond->dev->name, &newtarget);
-                       goto out;
-               }
-
                ind = bond_get_targets_ip(targets, newtarget);
                if (ind == -1) {
                        pr_err("%s: unable to remove nonexistent ARP target %pI4.\n",
@@ -701,6 +695,8 @@ static ssize_t bonding_store_downdelay(struct device *d,
        int new_value, ret = count;
        struct bonding *bond = to_bond(d);
 
+       if (!rtnl_trylock())
+               return restart_syscall();
        if (!(bond->params.miimon)) {
                pr_err("%s: Unable to set down delay as MII monitoring is disabled\n",
                       bond->dev->name);
@@ -734,6 +730,7 @@ static ssize_t bonding_store_downdelay(struct device *d,
        }
 
 out:
+       rtnl_unlock();
        return ret;
 }
 static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR,
@@ -756,6 +753,8 @@ static ssize_t bonding_store_updelay(struct device *d,
        int new_value, ret = count;
        struct bonding *bond = to_bond(d);
 
+       if (!rtnl_trylock())
+               return restart_syscall();
        if (!(bond->params.miimon)) {
                pr_err("%s: Unable to set up delay as MII monitoring is disabled\n",
                       bond->dev->name);
@@ -789,6 +788,7 @@ static ssize_t bonding_store_updelay(struct device *d,
        }
 
 out:
+       rtnl_unlock();
        return ret;
 }
 static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR,
index 77a07a1..ca31286 100644 (file)
@@ -63,6 +63,9 @@
                (((mode) == BOND_MODE_TLB) ||   \
                 ((mode) == BOND_MODE_ALB))
 
+#define IS_IP_TARGET_UNUSABLE_ADDRESS(a)       \
+       ((htonl(INADDR_BROADCAST) == a) ||      \
+        ipv4_is_zeronet(a))
 /*
  * Less bad way to call ioctl from within the kernel; this needs to be
  * done some other way to get the call out of interrupt context.
index 5aa5e81..c3c4c26 100644 (file)
@@ -1388,6 +1388,9 @@ static int alx_resume(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct alx_priv *alx = pci_get_drvdata(pdev);
+       struct alx_hw *hw = &alx->hw;
+
+       alx_reset_phy(hw);
 
        if (!netif_running(alx->dev))
                return 0;
index 4e01c57..a1f66e2 100644 (file)
@@ -1376,7 +1376,6 @@ enum {
        BNX2X_SP_RTNL_RX_MODE,
        BNX2X_SP_RTNL_HYPERVISOR_VLAN,
        BNX2X_SP_RTNL_TX_STOP,
-       BNX2X_SP_RTNL_TX_RESUME,
 };
 
 struct bnx2x_prev_path_list {
index dcafbda..ec96130 100644 (file)
@@ -2959,6 +2959,10 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
 
        bp->port.pmf = 0;
 
+       /* clear pending work in rtnl task */
+       bp->sp_rtnl_state = 0;
+       smp_mb();
+
        /* Free SKBs, SGEs, TPA pool and driver internals */
        bnx2x_free_skbs(bp);
        if (CNIC_LOADED(bp))
index fcf2761..fdace20 100644 (file)
@@ -778,11 +778,6 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
 
                /* ets may affect cmng configuration: reinit it in hw */
                bnx2x_set_local_cmng(bp);
-
-               set_bit(BNX2X_SP_RTNL_TX_RESUME, &bp->sp_rtnl_state);
-
-               schedule_delayed_work(&bp->sp_rtnl_task, 0);
-
                return;
        case BNX2X_DCBX_STATE_TX_RELEASED:
                DP(BNX2X_MSG_DCB, "BNX2X_DCBX_STATE_TX_RELEASED\n");
index e622cc1..814d0ec 100644 (file)
@@ -577,7 +577,9 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
        rc = bnx2x_issue_dmae_with_comp(bp, &dmae, bnx2x_sp(bp, wb_comp));
        if (rc) {
                BNX2X_ERR("DMAE returned failure %d\n", rc);
+#ifdef BNX2X_STOP_ON_ERROR
                bnx2x_panic();
+#endif
        }
 }
 
@@ -614,7 +616,9 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
        rc = bnx2x_issue_dmae_with_comp(bp, &dmae, bnx2x_sp(bp, wb_comp));
        if (rc) {
                BNX2X_ERR("DMAE returned failure %d\n", rc);
+#ifdef BNX2X_STOP_ON_ERROR
                bnx2x_panic();
+#endif
        }
 }
 
@@ -5231,18 +5235,18 @@ static void bnx2x_eq_int(struct bnx2x *bp)
 
                case EVENT_RING_OPCODE_STOP_TRAFFIC:
                        DP(BNX2X_MSG_SP | BNX2X_MSG_DCB, "got STOP TRAFFIC\n");
+                       bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_PAUSED);
                        if (f_obj->complete_cmd(bp, f_obj,
                                                BNX2X_F_CMD_TX_STOP))
                                break;
-                       bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_PAUSED);
                        goto next_spqe;
 
                case EVENT_RING_OPCODE_START_TRAFFIC:
                        DP(BNX2X_MSG_SP | BNX2X_MSG_DCB, "got START TRAFFIC\n");
+                       bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_RELEASED);
                        if (f_obj->complete_cmd(bp, f_obj,
                                                BNX2X_F_CMD_TX_START))
                                break;
-                       bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_RELEASED);
                        goto next_spqe;
 
                case EVENT_RING_OPCODE_FUNCTION_UPDATE:
@@ -9352,6 +9356,10 @@ static int bnx2x_process_kill(struct bnx2x *bp, bool global)
        bnx2x_process_kill_chip_reset(bp, global);
        barrier();
 
+       /* clear errors in PGB */
+       if (!CHIP_IS_E1x(bp))
+               REG_WR(bp, PGLUE_B_REG_LATCHED_ERRORS_CLR, 0x7f);
+
        /* Recover after reset: */
        /* MCP */
        if (global && bnx2x_reset_mcp_comp(bp, val))
@@ -9706,11 +9714,10 @@ sp_rtnl_not_reset:
                               &bp->sp_rtnl_state))
                bnx2x_pf_set_vfs_vlan(bp);
 
-       if (test_and_clear_bit(BNX2X_SP_RTNL_TX_STOP, &bp->sp_rtnl_state))
+       if (test_and_clear_bit(BNX2X_SP_RTNL_TX_STOP, &bp->sp_rtnl_state)) {
                bnx2x_dcbx_stop_hw_tx(bp);
-
-       if (test_and_clear_bit(BNX2X_SP_RTNL_TX_RESUME, &bp->sp_rtnl_state))
                bnx2x_dcbx_resume_hw_tx(bp);
+       }
 
        /* work which needs rtnl lock not-taken (as it takes the lock itself and
         * can be called from other contexts as well)
index 5ecf267..3efbb35 100644 (file)
 #define PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ            0x9430
 #define PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_WRITE           0x9434
 #define PGLUE_B_REG_INTERNAL_VFID_ENABLE                        0x9438
+/* [W 7] Writing 1 to each bit in this register clears a corresponding error
+ * details register and enables logging new error details. Bit 0 - clears
+ * INCORRECT_RCV_DETAILS; Bit 1 - clears RX_ERR_DETAILS; Bit 2 - clears
+ * TX_ERR_WR_ADD_31_0 TX_ERR_WR_ADD_63_32 TX_ERR_WR_DETAILS
+ * TX_ERR_WR_DETAILS2 TX_ERR_RD_ADD_31_0 TX_ERR_RD_ADD_63_32
+ * TX_ERR_RD_DETAILS TX_ERR_RD_DETAILS2 TX_ERR_WR_DETAILS_ICPL; Bit 3 -
+ * clears VF_LENGTH_VIOLATION_DETAILS. Bit 4 - clears
+ * VF_GRC_SPACE_VIOLATION_DETAILS. Bit 5 - clears RX_TCPL_ERR_DETAILS. Bit 6
+ * - clears TCPL_IN_TWO_RCBS_DETAILS. */
+#define PGLUE_B_REG_LATCHED_ERRORS_CLR                          0x943c
+
 /* [R 9] Interrupt register #0 read */
 #define PGLUE_B_REG_PGLUE_B_INT_STS                             0x9298
 /* [RC 9] Interrupt register #0 read clear */
index 9199adf..efa8a15 100644 (file)
@@ -152,7 +152,7 @@ static int bnx2x_send_msg2pf(struct bnx2x *bp, u8 *done, dma_addr_t msg_mapping)
        if (bp->old_bulletin.valid_bitmap & 1 << CHANNEL_DOWN) {
                DP(BNX2X_MSG_IOV, "detecting channel down. Aborting message\n");
                *done = PFVF_STATUS_SUCCESS;
-               return 0;
+               return -EINVAL;
        }
 
        /* Write message address */
index 00c5be8..a9e0684 100644 (file)
@@ -13618,16 +13618,9 @@ static int tg3_hwtstamp_ioctl(struct net_device *dev,
        if (stmpconf.flags)
                return -EINVAL;
 
-       switch (stmpconf.tx_type) {
-       case HWTSTAMP_TX_ON:
-               tg3_flag_set(tp, TX_TSTAMP_EN);
-               break;
-       case HWTSTAMP_TX_OFF:
-               tg3_flag_clear(tp, TX_TSTAMP_EN);
-               break;
-       default:
+       if (stmpconf.tx_type != HWTSTAMP_TX_ON &&
+           stmpconf.tx_type != HWTSTAMP_TX_OFF)
                return -ERANGE;
-       }
 
        switch (stmpconf.rx_filter) {
        case HWTSTAMP_FILTER_NONE:
@@ -13689,6 +13682,11 @@ static int tg3_hwtstamp_ioctl(struct net_device *dev,
                tw32(TG3_RX_PTP_CTL,
                     tp->rxptpctl | TG3_RX_PTP_CTL_HWTS_INTERLOCK);
 
+       if (stmpconf.tx_type == HWTSTAMP_TX_ON)
+               tg3_flag_set(tp, TX_TSTAMP_EN);
+       else
+               tg3_flag_clear(tp, TX_TSTAMP_EN);
+
        return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ?
                -EFAULT : 0;
 }
index 7fb0edf..dbcd526 100644 (file)
@@ -1758,7 +1758,7 @@ err:
 
 /* Uses sycnhronous mcc */
 int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
-                       u32 num, bool untagged, bool promiscuous)
+                      u32 num, bool promiscuous)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_vlan_config *req;
@@ -1778,7 +1778,7 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
 
        req->interface_id = if_id;
        req->promiscuous = promiscuous;
-       req->untagged = untagged;
+       req->untagged = BE_IF_FLAGS_UNTAGGED & be_if_cap_flags(adapter) ? 1 : 0;
        req->num_vlan = num;
        if (!promiscuous) {
                memcpy(req->normal_vlan, vtag_array,
@@ -1847,7 +1847,19 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
                        memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN);
        }
 
+       if ((req->if_flags_mask & cpu_to_le32(be_if_cap_flags(adapter))) !=
+            req->if_flags_mask) {
+               dev_warn(&adapter->pdev->dev,
+                        "Cannot set rx filter flags 0x%x\n",
+                        req->if_flags_mask);
+               dev_warn(&adapter->pdev->dev,
+                        "Interface is capable of 0x%x flags only\n",
+                        be_if_cap_flags(adapter));
+       }
+       req->if_flags_mask &= cpu_to_le32(be_if_cap_flags(adapter));
+
        status = be_mcc_notify_wait(adapter);
+
 err:
        spin_unlock_bh(&adapter->mcc_lock);
        return status;
index edf3e8a..0075686 100644 (file)
@@ -1984,7 +1984,7 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver,
                      char *fw_on_flash);
 int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *, int num);
 int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
-                      u32 num, bool untagged, bool promiscuous);
+                      u32 num, bool promiscuous);
 int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status);
 int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc);
 int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc);
index eaecaad..abde974 100644 (file)
@@ -1079,7 +1079,7 @@ static int be_vid_config(struct be_adapter *adapter)
                        vids[num++] = cpu_to_le16(i);
 
        status = be_cmd_vlan_config(adapter, adapter->if_handle,
-                                   vids, num, 1, 0);
+                                   vids, num, 0);
 
        if (status) {
                /* Set to VLAN promisc mode as setting VLAN filter failed */
@@ -2676,6 +2676,11 @@ static int be_close(struct net_device *netdev)
 
        be_rx_qs_destroy(adapter);
 
+       for (i = 1; i < (adapter->uc_macs + 1); i++)
+               be_cmd_pmac_del(adapter, adapter->if_handle,
+                               adapter->pmac_id[i], 0);
+       adapter->uc_macs = 0;
+
        for_all_evt_queues(adapter, eqo, i) {
                if (msix_enabled(adapter))
                        synchronize_irq(be_msix_vec_get(adapter, eqo));
index b2793b9..4cbebf3 100644 (file)
@@ -386,7 +386,14 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
         */
        bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr,
                        FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
-
+       if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) {
+               bdp->cbd_bufaddr = 0;
+               fep->tx_skbuff[index] = NULL;
+               dev_kfree_skb_any(skb);
+               if (net_ratelimit())
+                       netdev_err(ndev, "Tx DMA memory map failed\n");
+               return NETDEV_TX_OK;
+       }
        /* Send it on its way.  Tell FEC it's ready, interrupt when done,
         * it's the last BD of the frame, and to put the CRC on the end.
         */
@@ -861,6 +868,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
        struct  bufdesc_ex *ebdp = NULL;
        bool    vlan_packet_rcvd = false;
        u16     vlan_tag;
+       int     index = 0;
 
 #ifdef CONFIG_M532x
        flush_cache_all();
@@ -916,10 +924,15 @@ fec_enet_rx(struct net_device *ndev, int budget)
                ndev->stats.rx_packets++;
                pkt_len = bdp->cbd_datlen;
                ndev->stats.rx_bytes += pkt_len;
-               data = (__u8*)__va(bdp->cbd_bufaddr);
 
-               dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
-                               FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE);
+               if (fep->bufdesc_ex)
+                       index = (struct bufdesc_ex *)bdp -
+                               (struct bufdesc_ex *)fep->rx_bd_base;
+               else
+                       index = bdp - fep->rx_bd_base;
+               data = fep->rx_skbuff[index]->data;
+               dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr,
+                                       FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 
                if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
                        swap_buffer(data, pkt_len);
@@ -999,8 +1012,8 @@ fec_enet_rx(struct net_device *ndev, int budget)
                        napi_gro_receive(&fep->napi, skb);
                }
 
-               bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data,
-                               FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE);
+               dma_sync_single_for_device(&fep->pdev->dev, bdp->cbd_bufaddr,
+                                       FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 rx_processing_done:
                /* Clear the status flags for this buffer */
                status &= ~BD_ENET_RX_STATS;
@@ -1719,6 +1732,12 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 
                bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data,
                                FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
+               if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) {
+                       fec_enet_free_buffers(ndev);
+                       if (net_ratelimit())
+                               netdev_err(ndev, "Rx DMA memory map failed\n");
+                       return -ENOMEM;
+               }
                bdp->cbd_sc = BD_ENET_RX_EMPTY;
 
                if (fep->bufdesc_ex) {
index aedd573..8d3945a 100644 (file)
@@ -3482,10 +3482,10 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
  * specified. Matching the kind of event packet is not supported, with the
  * exception of "all V2 events regardless of level 2 or 4".
  **/
-static int e1000e_config_hwtstamp(struct e1000_adapter *adapter)
+static int e1000e_config_hwtstamp(struct e1000_adapter *adapter,
+                                 struct hwtstamp_config *config)
 {
        struct e1000_hw *hw = &adapter->hw;
-       struct hwtstamp_config *config = &adapter->hwtstamp_config;
        u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED;
        u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
        u32 rxmtrl = 0;
@@ -3586,6 +3586,8 @@ static int e1000e_config_hwtstamp(struct e1000_adapter *adapter)
                return -ERANGE;
        }
 
+       adapter->hwtstamp_config = *config;
+
        /* enable/disable Tx h/w time stamping */
        regval = er32(TSYNCTXCTL);
        regval &= ~E1000_TSYNCTXCTL_ENABLED;
@@ -3874,7 +3876,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
        e1000e_reset_adaptive(hw);
 
        /* initialize systim and reset the ns time counter */
-       e1000e_config_hwtstamp(adapter);
+       e1000e_config_hwtstamp(adapter, &adapter->hwtstamp_config);
 
        /* Set EEE advertisement as appropriate */
        if (adapter->flags2 & FLAG2_HAS_EEE) {
@@ -5797,14 +5799,10 @@ static int e1000e_hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr)
        if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
                return -EFAULT;
 
-       adapter->hwtstamp_config = config;
-
-       ret_val = e1000e_config_hwtstamp(adapter);
+       ret_val = e1000e_config_hwtstamp(adapter, &config);
        if (ret_val)
                return ret_val;
 
-       config = adapter->hwtstamp_config;
-
        switch (config.rx_filter) {
        case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
        case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
index 00cd36e..61088a6 100644 (file)
@@ -2890,7 +2890,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
                                         PHY_INTERFACE_MODE_GMII);
                if (!mp->phy)
                        err = -ENODEV;
-               phy_addr_set(mp, mp->phy->addr);
+               else
+                       phy_addr_set(mp, mp->phy->addr);
        } else if (pd->phy_addr != MV643XX_ETH_PHY_NONE) {
                mp->phy = phy_scan(mp, pd->phy_addr);
 
index 5a0f04c..27ffe0e 100644 (file)
@@ -245,16 +245,8 @@ static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
        /* Get ieee1588's dev information */
        pdev = adapter->ptp_pdev;
 
-       switch (cfg.tx_type) {
-       case HWTSTAMP_TX_OFF:
-               adapter->hwts_tx_en = 0;
-               break;
-       case HWTSTAMP_TX_ON:
-               adapter->hwts_tx_en = 1;
-               break;
-       default:
+       if (cfg.tx_type != HWTSTAMP_TX_OFF && cfg.tx_type != HWTSTAMP_TX_ON)
                return -ERANGE;
-       }
 
        switch (cfg.rx_filter) {
        case HWTSTAMP_FILTER_NONE:
@@ -284,6 +276,8 @@ static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
                return -ERANGE;
        }
 
+       adapter->hwts_tx_en = cfg.tx_type == HWTSTAMP_TX_ON;
+
        /* Clear out any old time stamps. */
        pch_ch_event_write(pdev, TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED);
 
index 8d4ccd3..8a7a23a 100644 (file)
@@ -435,16 +435,9 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
        if (config.flags)
                return -EINVAL;
 
-       switch (config.tx_type) {
-       case HWTSTAMP_TX_OFF:
-               priv->hwts_tx_en = 0;
-               break;
-       case HWTSTAMP_TX_ON:
-               priv->hwts_tx_en = 1;
-               break;
-       default:
+       if (config.tx_type != HWTSTAMP_TX_OFF &&
+           config.tx_type != HWTSTAMP_TX_ON)
                return -ERANGE;
-       }
 
        if (priv->adv_ts) {
                switch (config.rx_filter) {
@@ -576,6 +569,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
                }
        }
        priv->hwts_rx_en = ((config.rx_filter == HWTSTAMP_FILTER_NONE) ? 0 : 1);
+       priv->hwts_tx_en = config.tx_type == HWTSTAMP_TX_ON;
 
        if (!priv->hwts_tx_en && !priv->hwts_rx_en)
                priv->hw->ptp->config_hw_tstamping(priv->ioaddr, 0);
index 90d41d2..7536a4c 100644 (file)
@@ -967,14 +967,19 @@ static inline void cpsw_add_dual_emac_def_ale_entries(
                priv->host_port, ALE_VLAN, slave->port_vlan);
 }
 
-static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
+static void soft_reset_slave(struct cpsw_slave *slave)
 {
        char name[32];
-       u32 slave_port;
-
-       sprintf(name, "slave-%d", slave->slave_num);
 
+       snprintf(name, sizeof(name), "slave-%d", slave->slave_num);
        soft_reset(name, &slave->sliver->soft_reset);
+}
+
+static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
+{
+       u32 slave_port;
+
+       soft_reset_slave(slave);
 
        /* setup priority mapping */
        __raw_writel(RX_PRIORITY_MAPPING, &slave->sliver->rx_pri_map);
@@ -1323,6 +1328,10 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
        struct cpts *cpts = priv->cpts;
        struct hwtstamp_config cfg;
 
+       if (priv->version != CPSW_VERSION_1 &&
+           priv->version != CPSW_VERSION_2)
+               return -EOPNOTSUPP;
+
        if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
                return -EFAULT;
 
@@ -1330,16 +1339,8 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
        if (cfg.flags)
                return -EINVAL;
 
-       switch (cfg.tx_type) {
-       case HWTSTAMP_TX_OFF:
-               cpts->tx_enable = 0;
-               break;
-       case HWTSTAMP_TX_ON:
-               cpts->tx_enable = 1;
-               break;
-       default:
+       if (cfg.tx_type != HWTSTAMP_TX_OFF && cfg.tx_type != HWTSTAMP_TX_ON)
                return -ERANGE;
-       }
 
        switch (cfg.rx_filter) {
        case HWTSTAMP_FILTER_NONE:
@@ -1366,6 +1367,8 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
                return -ERANGE;
        }
 
+       cpts->tx_enable = cfg.tx_type == HWTSTAMP_TX_ON;
+
        switch (priv->version) {
        case CPSW_VERSION_1:
                cpsw_hwtstamp_v1(priv);
@@ -1374,7 +1377,7 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
                cpsw_hwtstamp_v2(priv);
                break;
        default:
-               return -ENOTSUPP;
+               WARN_ON(1);
        }
 
        return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
@@ -2173,8 +2176,9 @@ static int cpsw_suspend(struct device *dev)
 
        if (netif_running(ndev))
                cpsw_ndo_stop(ndev);
-       soft_reset("sliver 0", &priv->slaves[0].sliver->soft_reset);
-       soft_reset("sliver 1", &priv->slaves[1].sliver->soft_reset);
+
+       for_each_slave(priv, soft_reset_slave);
+
        pm_runtime_put_sync(&pdev->dev);
 
        /* Select sleep pin state */
index e78802e..bcc224a 100644 (file)
@@ -389,16 +389,8 @@ static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
        ch = PORT2CHANNEL(port);
        regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
 
-       switch (cfg.tx_type) {
-       case HWTSTAMP_TX_OFF:
-               port->hwts_tx_en = 0;
-               break;
-       case HWTSTAMP_TX_ON:
-               port->hwts_tx_en = 1;
-               break;
-       default:
+       if (cfg.tx_type != HWTSTAMP_TX_OFF && cfg.tx_type != HWTSTAMP_TX_ON)
                return -ERANGE;
-       }
 
        switch (cfg.rx_filter) {
        case HWTSTAMP_FILTER_NONE:
@@ -416,6 +408,8 @@ static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
                return -ERANGE;
        }
 
+       port->hwts_tx_en = cfg.tx_type == HWTSTAMP_TX_ON;
+
        /* Clear out any old time stamps. */
        __raw_writel(TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED,
                     &regs->channel[ch].ch_event);
index 9dccb1e..dc76670 100644 (file)
@@ -628,6 +628,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                                const struct iovec *iv, unsigned long total_len,
                                size_t count, int noblock)
 {
+       int good_linear = SKB_MAX_HEAD(NET_IP_ALIGN);
        struct sk_buff *skb;
        struct macvlan_dev *vlan;
        unsigned long len = total_len;
@@ -670,6 +671,8 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
 
        if (m && m->msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) {
                copylen = vnet_hdr.hdr_len ? vnet_hdr.hdr_len : GOODCOPY_LEN;
+               if (copylen > good_linear)
+                       copylen = good_linear;
                linear = copylen;
                if (iov_pages(iv, vnet_hdr_len + copylen, count)
                    <= MAX_SKB_FRAGS)
@@ -678,7 +681,10 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
 
        if (!zerocopy) {
                copylen = len;
-               linear = vnet_hdr.hdr_len;
+               if (vnet_hdr.hdr_len > good_linear)
+                       linear = good_linear;
+               else
+                       linear = vnet_hdr.hdr_len;
        }
 
        skb = macvtap_alloc_skb(&q->sk, NET_IP_ALIGN, copylen,
index 6574eb8..34b0de0 100644 (file)
@@ -2650,7 +2650,7 @@ static int team_nl_cmd_port_list_get(struct sk_buff *skb,
        return err;
 }
 
-static struct genl_ops team_nl_ops[] = {
+static const struct genl_ops team_nl_ops[] = {
        {
                .cmd = TEAM_CMD_NOOP,
                .doit = team_nl_cmd_noop,
@@ -2676,15 +2676,15 @@ static struct genl_ops team_nl_ops[] = {
        },
 };
 
-static struct genl_multicast_group team_change_event_mcgrp = {
-       .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME,
+static const struct genl_multicast_group team_nl_mcgrps[] = {
+       { .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME, },
 };
 
 static int team_nl_send_multicast(struct sk_buff *skb,
                                  struct team *team, u32 portid)
 {
-       return genlmsg_multicast_netns(dev_net(team->dev), skb, 0,
-                                      team_change_event_mcgrp.id, GFP_KERNEL);
+       return genlmsg_multicast_netns(&team_nl_family, dev_net(team->dev),
+                                      skb, 0, 0, GFP_KERNEL);
 }
 
 static int team_nl_send_event_options_get(struct team *team,
@@ -2703,23 +2703,8 @@ static int team_nl_send_event_port_get(struct team *team,
 
 static int team_nl_init(void)
 {
-       int err;
-
-       err = genl_register_family_with_ops(&team_nl_family, team_nl_ops,
-                                           ARRAY_SIZE(team_nl_ops));
-       if (err)
-               return err;
-
-       err = genl_register_mc_group(&team_nl_family, &team_change_event_mcgrp);
-       if (err)
-               goto err_change_event_grp_reg;
-
-       return 0;
-
-err_change_event_grp_reg:
-       genl_unregister_family(&team_nl_family);
-
-       return err;
+       return genl_register_family_with_ops_groups(&team_nl_family, team_nl_ops,
+                                                   team_nl_mcgrps);
 }
 
 static void team_nl_fini(void)
index 7cb105c..782e38b 100644 (file)
@@ -981,6 +981,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
        struct sk_buff *skb;
        size_t len = total_len, align = NET_SKB_PAD, linear;
        struct virtio_net_hdr gso = { 0 };
+       int good_linear;
        int offset = 0;
        int copylen;
        bool zerocopy = false;
@@ -1021,12 +1022,16 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                        return -EINVAL;
        }
 
+       good_linear = SKB_MAX_HEAD(align);
+
        if (msg_control) {
                /* There are 256 bytes to be copied in skb, so there is
                 * enough room for skb expand head in case it is used.
                 * The rest of the buffer is mapped from userspace.
                 */
                copylen = gso.hdr_len ? gso.hdr_len : GOODCOPY_LEN;
+               if (copylen > good_linear)
+                       copylen = good_linear;
                linear = copylen;
                if (iov_pages(iv, offset + copylen, count) <= MAX_SKB_FRAGS)
                        zerocopy = true;
@@ -1034,7 +1039,10 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
 
        if (!zerocopy) {
                copylen = len;
-               linear = gso.hdr_len;
+               if (gso.hdr_len > good_linear)
+                       linear = good_linear;
+               else
+                       linear = gso.hdr_len;
        }
 
        skb = tun_alloc_skb(tfile, align, copylen, linear, noblock);
index f74786a..e15ec2b 100644 (file)
@@ -66,7 +66,7 @@ static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);
 static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
 static struct usb_driver cdc_ncm_driver;
 
-static u8 cdc_ncm_setup(struct usbnet *dev)
+static int cdc_ncm_setup(struct usbnet *dev)
 {
        struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
        struct usb_cdc_ncm_ntb_parameters ncm_parm;
index 90a429b..8494bb5 100644 (file)
@@ -204,9 +204,6 @@ static void intr_complete (struct urb *urb)
                break;
        }
 
-       if (!netif_running (dev->net))
-               return;
-
        status = usb_submit_urb (urb, GFP_ATOMIC);
        if (status != 0)
                netif_err(dev, timer, dev->net,
index cdc7c90..7bab4de 100644 (file)
@@ -36,7 +36,10 @@ module_param(csum, bool, 0444);
 module_param(gso, bool, 0444);
 
 /* FIXME: MTU in config. */
-#define MAX_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
+#define GOOD_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
+#define MERGE_BUFFER_LEN (ALIGN(GOOD_PACKET_LEN + \
+                                sizeof(struct virtio_net_hdr_mrg_rxbuf), \
+                                L1_CACHE_BYTES))
 #define GOOD_COPY_LEN  128
 
 #define VIRTNET_DRIVER_VERSION "1.0.0"
@@ -314,10 +317,10 @@ static int receive_mergeable(struct receive_queue *rq, struct sk_buff *head_skb)
                        head_skb->dev->stats.rx_length_errors++;
                        return -EINVAL;
                }
-               if (unlikely(len > MAX_PACKET_LEN)) {
+               if (unlikely(len > MERGE_BUFFER_LEN)) {
                        pr_debug("%s: rx error: merge buffer too long\n",
                                 head_skb->dev->name);
-                       len = MAX_PACKET_LEN;
+                       len = MERGE_BUFFER_LEN;
                }
                if (unlikely(num_skb_frags == MAX_SKB_FRAGS)) {
                        struct sk_buff *nskb = alloc_skb(0, GFP_ATOMIC);
@@ -336,18 +339,17 @@ static int receive_mergeable(struct receive_queue *rq, struct sk_buff *head_skb)
                if (curr_skb != head_skb) {
                        head_skb->data_len += len;
                        head_skb->len += len;
-                       head_skb->truesize += MAX_PACKET_LEN;
+                       head_skb->truesize += MERGE_BUFFER_LEN;
                }
                page = virt_to_head_page(buf);
                offset = buf - (char *)page_address(page);
                if (skb_can_coalesce(curr_skb, num_skb_frags, page, offset)) {
                        put_page(page);
                        skb_coalesce_rx_frag(curr_skb, num_skb_frags - 1,
-                                            len, MAX_PACKET_LEN);
+                                            len, MERGE_BUFFER_LEN);
                } else {
                        skb_add_rx_frag(curr_skb, num_skb_frags, page,
-                                       offset, len,
-                                       MAX_PACKET_LEN);
+                                       offset, len, MERGE_BUFFER_LEN);
                }
                --rq->num;
        }
@@ -383,7 +385,7 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
                struct page *page = virt_to_head_page(buf);
                skb = page_to_skb(rq, page,
                                  (char *)buf - (char *)page_address(page),
-                                 len, MAX_PACKET_LEN);
+                                 len, MERGE_BUFFER_LEN);
                if (unlikely(!skb)) {
                        dev->stats.rx_dropped++;
                        put_page(page);
@@ -471,11 +473,11 @@ static int add_recvbuf_small(struct receive_queue *rq, gfp_t gfp)
        struct skb_vnet_hdr *hdr;
        int err;
 
-       skb = __netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN, gfp);
+       skb = __netdev_alloc_skb_ip_align(vi->dev, GOOD_PACKET_LEN, gfp);
        if (unlikely(!skb))
                return -ENOMEM;
 
-       skb_put(skb, MAX_PACKET_LEN);
+       skb_put(skb, GOOD_PACKET_LEN);
 
        hdr = skb_vnet_hdr(skb);
        sg_set_buf(rq->sg, &hdr->hdr, sizeof hdr->hdr);
@@ -542,20 +544,20 @@ static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
        int err;
 
        if (gfp & __GFP_WAIT) {
-               if (skb_page_frag_refill(MAX_PACKET_LEN, &vi->alloc_frag,
+               if (skb_page_frag_refill(MERGE_BUFFER_LEN, &vi->alloc_frag,
                                         gfp)) {
                        buf = (char *)page_address(vi->alloc_frag.page) +
                              vi->alloc_frag.offset;
                        get_page(vi->alloc_frag.page);
-                       vi->alloc_frag.offset += MAX_PACKET_LEN;
+                       vi->alloc_frag.offset += MERGE_BUFFER_LEN;
                }
        } else {
-               buf = netdev_alloc_frag(MAX_PACKET_LEN);
+               buf = netdev_alloc_frag(MERGE_BUFFER_LEN);
        }
        if (!buf)
                return -ENOMEM;
 
-       sg_init_one(rq->sg, buf, MAX_PACKET_LEN);
+       sg_init_one(rq->sg, buf, MERGE_BUFFER_LEN);
        err = virtqueue_add_inbuf(rq->vq, rq->sg, 1, buf, gfp);
        if (err < 0)
                put_page(virt_to_head_page(buf));
@@ -1619,8 +1621,8 @@ static int virtnet_probe(struct virtio_device *vdev)
        if (err)
                goto free_stats;
 
-       netif_set_real_num_tx_queues(dev, 1);
-       netif_set_real_num_rx_queues(dev, 1);
+       netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
+       netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
 
        err = register_netdev(dev);
        if (err) {
index b07f164..20e4909 100644 (file)
@@ -187,17 +187,17 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
                               ar9485_1_1_baseband_core_txfir_coeff_japan_2484);
 
-               /* Load PCIE SERDES settings from INI */
-
-               /* Awake Setting */
-
-               INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                               ar9485_1_1_pcie_phy_clkreq_disable_L1);
-
-               /* Sleep Setting */
-
-               INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
-                               ar9485_1_1_pcie_phy_clkreq_disable_L1);
+               if (ah->config.no_pll_pwrsave) {
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                                      ar9485_1_1_pcie_phy_clkreq_disable_L1);
+                       INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+                                      ar9485_1_1_pcie_phy_clkreq_disable_L1);
+               } else {
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                                      ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1);
+                       INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+                                      ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1);
+               }
        } else if (AR_SREV_9462_21(ah)) {
                INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
                               ar9462_2p1_mac_core);
index 6f899c6..7c18452 100644 (file)
@@ -32,13 +32,6 @@ static const u32 ar9485_1_1_mac_postamble[][5] = {
        {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
 };
 
-static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = {
-       /* Addr      allmodes  */
-       {0x00018c00, 0x18012e5e},
-       {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0000080c},
-};
-
 static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = {
        /* Addr      allmodes  */
        {0x00009e00, 0x037216a0},
@@ -1101,20 +1094,6 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = {
        {0x0000a1fc, 0x00000296},
 };
 
-static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_enable_L1[][2] = {
-       /* Addr      allmodes  */
-       {0x00018c00, 0x18052e5e},
-       {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0000080c},
-};
-
-static const u32 ar9485_1_1_pcie_phy_clkreq_enable_L1[][2] = {
-       /* Addr      allmodes  */
-       {0x00018c00, 0x18053e5e},
-       {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0000080c},
-};
-
 static const u32 ar9485_1_1_soc_preamble[][2] = {
        /* Addr      allmodes  */
        {0x00004014, 0xba280400},
@@ -1173,13 +1152,6 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {
        {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 };
 
-static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = {
-       /* Addr      allmodes  */
-       {0x00018c00, 0x18013e5e},
-       {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0000080c},
-};
-
 static const u32 ar9485_1_1_radio_postamble[][2] = {
        /* Addr      allmodes  */
        {0x0001609c, 0x0b283f31},
@@ -1358,4 +1330,18 @@ static const u32 ar9485_1_1_baseband_core_txfir_coeff_japan_2484[][2] = {
        {0x0000a3a0, 0xca9228ee},
 };
 
+static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = {
+       /* Addr      allmodes  */
+       {0x00018c00, 0x18013e5e},
+       {0x00018c04, 0x000801d8},
+       {0x00018c08, 0x0000080c},
+};
+
+static const u32 ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1[][2] = {
+       /* Addr      allmodes  */
+       {0x00018c00, 0x1801265e},
+       {0x00018c04, 0x000801d8},
+       {0x00018c08, 0x0000080c},
+};
+
 #endif /* INITVALS_9485_H */
index e7a38d8..60a5da5 100644 (file)
@@ -632,15 +632,16 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
 /* Main driver core */
 /********************/
 
-#define ATH9K_PCI_CUS198      0x0001
-#define ATH9K_PCI_CUS230      0x0002
-#define ATH9K_PCI_CUS217      0x0004
-#define ATH9K_PCI_CUS252      0x0008
-#define ATH9K_PCI_WOW         0x0010
-#define ATH9K_PCI_BT_ANT_DIV  0x0020
-#define ATH9K_PCI_D3_L1_WAR   0x0040
-#define ATH9K_PCI_AR9565_1ANT 0x0080
-#define ATH9K_PCI_AR9565_2ANT 0x0100
+#define ATH9K_PCI_CUS198          0x0001
+#define ATH9K_PCI_CUS230          0x0002
+#define ATH9K_PCI_CUS217          0x0004
+#define ATH9K_PCI_CUS252          0x0008
+#define ATH9K_PCI_WOW             0x0010
+#define ATH9K_PCI_BT_ANT_DIV      0x0020
+#define ATH9K_PCI_D3_L1_WAR       0x0040
+#define ATH9K_PCI_AR9565_1ANT     0x0080
+#define ATH9K_PCI_AR9565_2ANT     0x0100
+#define ATH9K_PCI_NO_PLL_PWRSAVE  0x0200
 
 /*
  * Default cache line size, in bytes.
index 90b8342..8824610 100644 (file)
@@ -44,14 +44,20 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
        if (buf == NULL)
                return -ENOMEM;
 
-       if (sc->dfs_detector)
-               dfs_pool_stats = sc->dfs_detector->get_stats(sc->dfs_detector);
-
        len += scnprintf(buf + len, size - len, "DFS support for "
                         "macVersion = 0x%x, macRev = 0x%x: %s\n",
                         hw_ver->macVersion, hw_ver->macRev,
                         (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ?
                                        "enabled" : "disabled");
+
+       if (!sc->dfs_detector) {
+               len += scnprintf(buf + len, size - len,
+                                "DFS detector not enabled\n");
+               goto exit;
+       }
+
+       dfs_pool_stats = sc->dfs_detector->get_stats(sc->dfs_detector);
+
        len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n");
        ATH9K_DFS_STAT("pulse events reported   ", pulses_total);
        ATH9K_DFS_STAT("invalid pulse events    ", pulses_no_dfs);
@@ -76,6 +82,7 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
        ATH9K_DFS_POOL_STAT("Seqs. alloc error       ", pseq_alloc_error);
        ATH9K_DFS_POOL_STAT("Seqs. in use            ", pseq_used);
 
+exit:
        if (len > size)
                len = size;
 
index 9ea24f1..a2c9a5d 100644 (file)
@@ -316,6 +316,7 @@ struct ath9k_ops_config {
        u32 ant_ctrl_comm2g_switch_enable;
        bool xatten_margin_cfg;
        bool alt_mingainidx;
+       bool no_pll_pwrsave;
 };
 
 enum ath9k_int {
index d8643eb..710192e 100644 (file)
@@ -609,6 +609,11 @@ static void ath9k_init_platform(struct ath_softc *sc)
                ah->config.pcie_waen = 0x0040473b;
                ath_info(common, "Enable WAR for ASPM D3/L1\n");
        }
+
+       if (sc->driver_data & ATH9K_PCI_NO_PLL_PWRSAVE) {
+               ah->config.no_pll_pwrsave = true;
+               ath_info(common, "Disable PLL PowerSave\n");
+       }
 }
 
 static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob,
@@ -863,8 +868,8 @@ static const struct ieee80211_iface_combination if_comb[] = {
                .max_interfaces = 1,
                .num_different_channels = 1,
                .beacon_int_infra_match = true,
-               .radar_detect_widths =  BIT(NL80211_CHAN_NO_HT) |
-                                       BIT(NL80211_CHAN_HT20),
+               .radar_detect_widths =  BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+                                       BIT(NL80211_CHAN_WIDTH_20),
        }
 };
 
index 7e4c252..b5656fc 100644 (file)
@@ -195,6 +195,93 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         0x3219),
          .driver_data = ATH9K_PCI_BT_ANT_DIV },
 
+       /* AR9485 cards with PLL power-save disabled by default. */
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x2C97),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x2100),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        0x1C56, /* ASKEY */
+                        0x4001),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        0x11AD, /* LITEON */
+                        0x6627),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        0x11AD, /* LITEON */
+                        0x6628),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        PCI_VENDOR_ID_FOXCONN,
+                        0xE04E),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        PCI_VENDOR_ID_FOXCONN,
+                        0xE04F),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        0x144F, /* ASKEY */
+                        0x7197),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        0x1B9A, /* XAVI */
+                        0x2000),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        0x1B9A, /* XAVI */
+                        0x2001),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x1186),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x1F86),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x1195),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x1F95),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        0x1B9A, /* XAVI */
+                        0x1C00),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        0x1B9A, /* XAVI */
+                        0x1C01),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0032,
+                        PCI_VENDOR_ID_ASUSTEK,
+                        0x850D),
+         .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+
        { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E  AR9485 */
        { PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E  AR9580 */
 
index 5b84f7a..ef44a2d 100644 (file)
@@ -126,7 +126,7 @@ static ssize_t write_file_dump(struct file *file,
                if (begin == NULL)
                        break;
 
-               if (kstrtoul(begin, 0, (unsigned long *)(arg + i)) != 0)
+               if (kstrtou32(begin, 0, &arg[i]) != 0)
                        break;
        }
 
index f8c3a10..de9eb2c 100644 (file)
@@ -1286,7 +1286,8 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif,
        } else {
                wcn36xx_err("Beacon is to big: beacon size=%d\n",
                              msg_body.beacon_length);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }
        memcpy(msg_body.bssid, vif->addr, ETH_ALEN);
 
@@ -1327,7 +1328,8 @@ int wcn36xx_smd_update_proberesp_tmpl(struct wcn36xx *wcn,
        if (skb->len > BEACON_TEMPLATE_SIZE) {
                wcn36xx_warn("probe response template is too big: %d\n",
                             skb->len);
-               return -E2BIG;
+               ret = -E2BIG;
+               goto out;
        }
 
        msg.probe_resp_template_len = skb->len;
@@ -1606,7 +1608,8 @@ int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn,
                /* TODO: it also support ARP response type */
        } else {
                wcn36xx_warn("unknow keep alive packet type %d\n", packet_type);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
index 668dd27..cc6a0a5 100644 (file)
@@ -913,7 +913,10 @@ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
        char *p2;
        struct debug_data *d = f->private_data;
 
-       pdata = kmalloc(cnt, GFP_KERNEL);
+       if (cnt == 0)
+               return 0;
+
+       pdata = kmalloc(cnt + 1, GFP_KERNEL);
        if (pdata == NULL)
                return 0;
 
@@ -922,6 +925,7 @@ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
                kfree(pdata);
                return 0;
        }
+       pdata[cnt] = '\0';
 
        p0 = pdata;
        for (i = 0; i < num_of_items; i++) {
index ef8c98e..f499efc 100644 (file)
@@ -902,6 +902,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
        if (card->model == MODEL_UNKNOWN) {
                pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
                       p_dev->manf_id, p_dev->card_id);
+               ret = -ENODEV;
                goto out2;
        }
 
index de0df86..9df7bc9 100644 (file)
@@ -2097,7 +2097,7 @@ out:
 }
 
 /* Generic Netlink operations array */
-static struct genl_ops hwsim_ops[] = {
+static const struct genl_ops hwsim_ops[] = {
        {
                .cmd = HWSIM_CMD_REGISTER,
                .policy = hwsim_genl_policy,
@@ -2148,8 +2148,7 @@ static int hwsim_init_netlink(void)
 
        printk(KERN_INFO "mac80211_hwsim: initializing netlink\n");
 
-       rc = genl_register_family_with_ops(&hwsim_genl_family,
-               hwsim_ops, ARRAY_SIZE(hwsim_ops));
+       rc = genl_register_family_with_ops(&hwsim_genl_family, hwsim_ops);
        if (rc)
                goto failure;
 
index f80f30b..c8385ec 100644 (file)
@@ -1020,8 +1020,8 @@ struct mwifiex_power_group {
 } __packed;
 
 struct mwifiex_types_power_group {
-       u16 type;
-       u16 length;
+       __le16 type;
+       __le16 length;
 } __packed;
 
 struct host_cmd_ds_txpwr_cfg {
index 220af4f..81ac001 100644 (file)
@@ -82,7 +82,7 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
                             struct mwifiex_ie_list *ie_list)
 {
        u16 travel_len, index, mask;
-       s16 input_len;
+       s16 input_len, tlv_len;
        struct mwifiex_ie *ie;
        u8 *tmp;
 
@@ -91,11 +91,13 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
 
        ie_list->len = 0;
 
-       while (input_len > 0) {
+       while (input_len >= sizeof(struct mwifiex_ie_types_header)) {
                ie = (struct mwifiex_ie *)(((u8 *)ie_list) + travel_len);
-               input_len -= le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE;
-               travel_len += le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE;
+               tlv_len = le16_to_cpu(ie->ie_length);
+               travel_len += tlv_len + MWIFIEX_IE_HDR_SIZE;
 
+               if (input_len < tlv_len + MWIFIEX_IE_HDR_SIZE)
+                       return -1;
                index = le16_to_cpu(ie->ie_index);
                mask = le16_to_cpu(ie->mgmt_subtype_mask);
 
@@ -132,6 +134,7 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
                le16_add_cpu(&ie_list->len,
                             le16_to_cpu(priv->mgmt_ie[index].ie_length) +
                             MWIFIEX_IE_HDR_SIZE);
+               input_len -= tlv_len + MWIFIEX_IE_HDR_SIZE;
        }
 
        if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
index 1576104..9bf8898 100644 (file)
@@ -1029,7 +1029,10 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
                                    struct sk_buff *skb, u32 upld_typ)
 {
        u8 *cmd_buf;
+       __le16 *curr_ptr = (__le16 *)skb->data;
+       u16 pkt_len = le16_to_cpu(*curr_ptr);
 
+       skb_trim(skb, pkt_len);
        skb_pull(skb, INTF_HEADER_LEN);
 
        switch (upld_typ) {
index 7d66018..2181ee2 100644 (file)
@@ -239,14 +239,14 @@ static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd,
                        memmove(cmd_txp_cfg, txp,
                                sizeof(struct host_cmd_ds_txpwr_cfg) +
                                sizeof(struct mwifiex_types_power_group) +
-                               pg_tlv->length);
+                               le16_to_cpu(pg_tlv->length));
 
                        pg_tlv = (struct mwifiex_types_power_group *) ((u8 *)
                                  cmd_txp_cfg +
                                  sizeof(struct host_cmd_ds_txpwr_cfg));
                        cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) +
                                  sizeof(struct mwifiex_types_power_group) +
-                                 pg_tlv->length);
+                                 le16_to_cpu(pg_tlv->length));
                } else {
                        memmove(cmd_txp_cfg, txp, sizeof(*txp));
                }
index 58a6013..2675ca7 100644 (file)
@@ -274,17 +274,20 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
        struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg;
        struct mwifiex_rate_scope *rate_scope;
        struct mwifiex_ie_types_header *head;
-       u16 tlv, tlv_buf_len;
+       u16 tlv, tlv_buf_len, tlv_buf_left;
        u8 *tlv_buf;
        u32 i;
 
-       tlv_buf = ((u8 *)rate_cfg) +
-                       sizeof(struct host_cmd_ds_tx_rate_cfg);
-       tlv_buf_len = le16_to_cpu(*(__le16 *) (tlv_buf + sizeof(u16)));
+       tlv_buf = ((u8 *)rate_cfg) + sizeof(struct host_cmd_ds_tx_rate_cfg);
+       tlv_buf_left = le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*rate_cfg);
 
-       while (tlv_buf && tlv_buf_len > 0) {
-               tlv = (*tlv_buf);
-               tlv = tlv | (*(tlv_buf + 1) << 8);
+       while (tlv_buf_left >= sizeof(*head)) {
+               head = (struct mwifiex_ie_types_header *)tlv_buf;
+               tlv = le16_to_cpu(head->type);
+               tlv_buf_len = le16_to_cpu(head->len);
+
+               if (tlv_buf_left < (sizeof(*head) + tlv_buf_len))
+                       break;
 
                switch (tlv) {
                case TLV_TYPE_RATE_SCOPE:
@@ -304,9 +307,8 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
                        /* Add RATE_DROP tlv here */
                }
 
-               head = (struct mwifiex_ie_types_header *) tlv_buf;
-               tlv_buf += le16_to_cpu(head->len) + sizeof(*head);
-               tlv_buf_len -= le16_to_cpu(head->len);
+               tlv_buf += (sizeof(*head) + tlv_buf_len);
+               tlv_buf_left -= (sizeof(*head) + tlv_buf_len);
        }
 
        priv->is_data_rate_auto = mwifiex_is_rate_auto(priv);
@@ -340,13 +342,17 @@ static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf)
                ((u8 *) data_buf + sizeof(struct host_cmd_ds_txpwr_cfg));
        pg = (struct mwifiex_power_group *)
                ((u8 *) pg_tlv_hdr + sizeof(struct mwifiex_types_power_group));
-       length = pg_tlv_hdr->length;
-       if (length > 0) {
-               max_power = pg->power_max;
-               min_power = pg->power_min;
-               length -= sizeof(struct mwifiex_power_group);
-       }
-       while (length) {
+       length = le16_to_cpu(pg_tlv_hdr->length);
+
+       /* At least one structure required to update power */
+       if (length < sizeof(struct mwifiex_power_group))
+               return 0;
+
+       max_power = pg->power_max;
+       min_power = pg->power_min;
+       length -= sizeof(struct mwifiex_power_group);
+
+       while (length >= sizeof(struct mwifiex_power_group)) {
                pg++;
                if (max_power < pg->power_max)
                        max_power = pg->power_max;
@@ -356,10 +362,8 @@ static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf)
 
                length -= sizeof(struct mwifiex_power_group);
        }
-       if (pg_tlv_hdr->length > 0) {
-               priv->min_tx_power_level = (u8) min_power;
-               priv->max_tx_power_level = (u8) max_power;
-       }
+       priv->min_tx_power_level = (u8) min_power;
+       priv->max_tx_power_level = (u8) max_power;
 
        return 0;
 }
index f084412..c8e029d 100644 (file)
@@ -638,8 +638,9 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
                txp_cfg->mode = cpu_to_le32(1);
                pg_tlv = (struct mwifiex_types_power_group *)
                         (buf + sizeof(struct host_cmd_ds_txpwr_cfg));
-               pg_tlv->type = TLV_TYPE_POWER_GROUP;
-               pg_tlv->length = 4 * sizeof(struct mwifiex_power_group);
+               pg_tlv->type = cpu_to_le16(TLV_TYPE_POWER_GROUP);
+               pg_tlv->length =
+                       cpu_to_le16(4 * sizeof(struct mwifiex_power_group));
                pg = (struct mwifiex_power_group *)
                     (buf + sizeof(struct host_cmd_ds_txpwr_cfg)
                      + sizeof(struct mwifiex_types_power_group));
index 1cfe5a7..92f76d6 100644 (file)
@@ -97,6 +97,7 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
        struct mwifiex_txinfo *tx_info;
        int hdr_chop;
        struct timeval tv;
+       struct ethhdr *p_ethhdr;
        u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
 
        uap_rx_pd = (struct uap_rxpd *)(skb->data);
@@ -112,14 +113,36 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
        }
 
        if (!memcmp(&rx_pkt_hdr->rfc1042_hdr,
-                   rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)))
+                   rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) {
+               /* Replace the 803 header and rfc1042 header (llc/snap) with
+                * an Ethernet II header, keep the src/dst and snap_type
+                * (ethertype).
+                *
+                * The firmware only passes up SNAP frames converting all RX
+                * data from 802.11 to 802.2/LLC/SNAP frames.
+                *
+                * To create the Ethernet II, just move the src, dst address
+                * right before the snap_type.
+                */
+               p_ethhdr = (struct ethhdr *)
+                       ((u8 *)(&rx_pkt_hdr->eth803_hdr)
+                        + sizeof(rx_pkt_hdr->eth803_hdr)
+                        + sizeof(rx_pkt_hdr->rfc1042_hdr)
+                        - sizeof(rx_pkt_hdr->eth803_hdr.h_dest)
+                        - sizeof(rx_pkt_hdr->eth803_hdr.h_source)
+                        - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type));
+               memcpy(p_ethhdr->h_source, rx_pkt_hdr->eth803_hdr.h_source,
+                      sizeof(p_ethhdr->h_source));
+               memcpy(p_ethhdr->h_dest, rx_pkt_hdr->eth803_hdr.h_dest,
+                      sizeof(p_ethhdr->h_dest));
                /* Chop off the rxpd + the excess memory from
                 * 802.2/llc/snap header that was removed.
                 */
-               hdr_chop = (u8 *)eth_hdr - (u8 *)uap_rx_pd;
-       else
+               hdr_chop = (u8 *)p_ethhdr - (u8 *)uap_rx_pd;
+       } else {
                /* Chop off the rxpd */
                hdr_chop = (u8 *)&rx_pkt_hdr->eth803_hdr - (u8 *)uap_rx_pd;
+       }
 
        /* Chop off the leading header bytes so the it points
         * to the start of either the reconstructed EthII frame
index 5dd0ccc..13eaeed 100644 (file)
@@ -722,6 +722,9 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
                tlv_hdr = (struct mwifiex_ie_types_data *) curr;
                tlv_len = le16_to_cpu(tlv_hdr->header.len);
 
+               if (resp_len < tlv_len + sizeof(tlv_hdr->header))
+                       break;
+
                switch (le16_to_cpu(tlv_hdr->header.type)) {
                case TLV_TYPE_WMMQSTATUS:
                        tlv_wmm_qstatus =
index 41a16d3..e05d9b4 100644 (file)
@@ -811,6 +811,10 @@ static const struct net_device_ops islpci_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
+static struct device_type wlan_type = {
+       .name   = "wlan",
+};
+
 struct net_device *
 islpci_setup(struct pci_dev *pdev)
 {
@@ -821,9 +825,8 @@ islpci_setup(struct pci_dev *pdev)
                return ndev;
 
        pci_set_drvdata(pdev, ndev);
-#if defined(SET_NETDEV_DEV)
        SET_NETDEV_DEV(ndev, &pdev->dev);
-#endif
+       SET_NETDEV_DEVTYPE(ndev, &wlan_type);
 
        /* setup the structure members */
        ndev->base_addr = pci_resource_start(pdev, 0);
index c5738f1..776aff3 100644 (file)
@@ -2640,7 +2640,7 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
 
        if (rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr);
-               if (info->default_power1 > POWER_BOUND)
+               if (info->default_power2 > POWER_BOUND)
                        rt2x00_set_field8(&rfcsr, RFCSR50_TX, POWER_BOUND);
                else
                        rt2x00_set_field8(&rfcsr, RFCSR50_TX,
index a093598..7f40ab8 100644 (file)
@@ -146,7 +146,7 @@ void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length);
  * @local: frame is not from mac80211
  */
 int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
-                              bool local);
+                              struct ieee80211_sta *sta, bool local);
 
 /**
  * rt2x00queue_update_beacon - Send new beacon from mac80211
index 7c15785..2183e79 100644 (file)
@@ -90,7 +90,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
                                  frag_skb->data, data_length, tx_info,
                                  (struct ieee80211_rts *)(skb->data));
 
-       retval = rt2x00queue_write_tx_frame(queue, skb, true);
+       retval = rt2x00queue_write_tx_frame(queue, skb, NULL, true);
        if (retval) {
                dev_kfree_skb_any(skb);
                rt2x00_warn(rt2x00dev, "Failed to send RTS/CTS frame\n");
@@ -151,7 +151,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw,
                        goto exit_fail;
        }
 
-       if (unlikely(rt2x00queue_write_tx_frame(queue, skb, false)))
+       if (unlikely(rt2x00queue_write_tx_frame(queue, skb, control->sta, false)))
                goto exit_fail;
 
        /*
index 50590b1..a5d38e8 100644 (file)
@@ -635,7 +635,7 @@ static void rt2x00queue_bar_check(struct queue_entry *entry)
 }
 
 int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
-                              bool local)
+                              struct ieee80211_sta *sta, bool local)
 {
        struct ieee80211_tx_info *tx_info;
        struct queue_entry *entry;
@@ -649,7 +649,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
         * after that we are free to use the skb->cb array
         * for our information.
         */
-       rt2x00queue_create_tx_descriptor(queue->rt2x00dev, skb, &txdesc, NULL);
+       rt2x00queue_create_tx_descriptor(queue->rt2x00dev, skb, &txdesc, sta);
 
        /*
         * All information is retrieved from the skb->cb array,
index 9a78e3d..ff78407 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <linux/ip.h>
 #include <linux/module.h>
+#include <linux/udp.h>
 
 /*
  *NOTICE!!!: This file will be very big, we should
@@ -1074,64 +1075,52 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
        if (!ieee80211_is_data(fc))
                return false;
 
+       ip = (const struct iphdr *)(skb->data + mac_hdr_len +
+                                   SNAP_SIZE + PROTOC_TYPE_SIZE);
+       ether_type = be16_to_cpup((__be16 *)
+                                 (skb->data + mac_hdr_len + SNAP_SIZE));
 
-       ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len +
-                             SNAP_SIZE + PROTOC_TYPE_SIZE);
-       ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE);
-       /*      ether_type = ntohs(ether_type); */
-
-       if (ETH_P_IP == ether_type) {
-               if (IPPROTO_UDP == ip->protocol) {
-                       struct udphdr *udp = (struct udphdr *)((u8 *) ip +
-                                                              (ip->ihl << 2));
-                       if (((((u8 *) udp)[1] == 68) &&
-                            (((u8 *) udp)[3] == 67)) ||
-                           ((((u8 *) udp)[1] == 67) &&
-                            (((u8 *) udp)[3] == 68))) {
-                               /*
-                                * 68 : UDP BOOTP client
-                                * 67 : UDP BOOTP server
-                                */
-                               RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV),
-                                        DBG_DMESG, "dhcp %s !!\n",
-                                        is_tx ? "Tx" : "Rx");
-
-                               if (is_tx) {
-                                       rtlpriv->enter_ps = false;
-                                       schedule_work(&rtlpriv->
-                                                     works.lps_change_work);
-                                       ppsc->last_delaylps_stamp_jiffies =
-                                           jiffies;
-                               }
+       switch (ether_type) {
+       case ETH_P_IP: {
+               struct udphdr *udp;
+               u16 src;
+               u16 dst;
 
-                               return true;
-                       }
-               }
-       } else if (ETH_P_ARP == ether_type) {
-               if (is_tx) {
-                       rtlpriv->enter_ps = false;
-                       schedule_work(&rtlpriv->works.lps_change_work);
-                       ppsc->last_delaylps_stamp_jiffies = jiffies;
-               }
+               if (ip->protocol != IPPROTO_UDP)
+                       return false;
+               udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2));
+               src = be16_to_cpu(udp->source);
+               dst = be16_to_cpu(udp->dest);
 
-               return true;
-       } else if (ETH_P_PAE == ether_type) {
+               /* If this case involves port 68 (UDP BOOTP client) connecting
+                * with port 67 (UDP BOOTP server), then return true so that
+                * the lowest speed is used.
+                */
+               if (!((src == 68 && dst == 67) || (src == 67 && dst == 68)))
+                       return false;
+
+               RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
+                        "dhcp %s !!\n", is_tx ? "Tx" : "Rx");
+               break;
+       }
+       case ETH_P_ARP:
+               break;
+       case ETH_P_PAE:
                RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
                         "802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx");
-
-               if (is_tx) {
-                       rtlpriv->enter_ps = false;
-                       schedule_work(&rtlpriv->works.lps_change_work);
-                       ppsc->last_delaylps_stamp_jiffies = jiffies;
-               }
-
-               return true;
-       } else if (ETH_P_IPV6 == ether_type) {
-               /* IPv6 */
-               return true;
+               break;
+       case ETH_P_IPV6:
+               /* TODO: Is this right? */
+               return false;
+       default:
+               return false;
        }
-
-       return false;
+       if (is_tx) {
+               rtlpriv->enter_ps = false;
+               schedule_work(&rtlpriv->works.lps_change_work);
+               ppsc->last_delaylps_stamp_jiffies = jiffies;
+       }
+       return true;
 }
 EXPORT_SYMBOL_GPL(rtl_is_special_data);
 
index ae13fb9..2ffc729 100644 (file)
@@ -262,9 +262,9 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
                            sizeof(u8), GFP_ATOMIC);
        if (!efuse_tbl)
                return;
-       efuse_word = kmalloc(EFUSE_MAX_WORD_UNIT * sizeof(u16 *), GFP_ATOMIC);
+       efuse_word = kzalloc(EFUSE_MAX_WORD_UNIT * sizeof(u16 *), GFP_ATOMIC);
        if (!efuse_word)
-               goto done;
+               goto out;
        for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
                efuse_word[i] = kmalloc(efuse_max_section * sizeof(u16),
                                        GFP_ATOMIC);
@@ -378,6 +378,7 @@ done:
        for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++)
                kfree(efuse_word[i]);
        kfree(efuse_word);
+out:
        kfree(efuse_tbl);
 }
 
index 25e50ff..b0c346a 100644 (file)
@@ -349,7 +349,7 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
                                                 p_drvinfo);
        }
        /*rx_status->qual = stats->signal; */
-       rx_status->signal = stats->rssi + 10;
+       rx_status->signal = stats->recvsignalpower + 10;
        return true;
 }
 
index 945ddec..0eb0f4a 100644 (file)
@@ -525,7 +525,7 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
                                                   p_drvinfo);
        }
        /*rx_status->qual = stats->signal; */
-       rx_status->signal = stats->rssi + 10;
+       rx_status->signal = stats->recvsignalpower + 10;
        return true;
 }
 
index 5061f1d..92d38ab 100644 (file)
@@ -265,7 +265,7 @@ static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,
                                    rtlefuse->pwrgroup_ht40
                                    [RF90_PATH_A][chnl - 1]) {
                                        pwrdiff_limit[i] =
-                                         rtlefuse->pwrgroup_ht20
+                                         rtlefuse->pwrgroup_ht40
                                          [RF90_PATH_A][chnl - 1];
                                }
                        } else {
index 222d2e7..27efbcd 100644 (file)
@@ -329,7 +329,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
        }
 
        /*rx_status->qual = stats->signal; */
-       rx_status->signal = stats->rssi + 10;
+       rx_status->signal = stats->recvsignalpower + 10;
 
        return true;
 }
index d224dc3..0c65386 100644 (file)
 #define RTL_SLOT_TIME_9                                9
 #define RTL_SLOT_TIME_20                       20
 
-/*related with tcp/ip. */
-/*if_ehther.h*/
-#define ETH_P_PAE              0x888E  /*Port Access Entity (IEEE 802.1X) */
-#define ETH_P_IP               0x0800  /*Internet Protocol packet */
-#define ETH_P_ARP              0x0806  /*Address Resolution packet */
+/*related to tcp/ip. */
 #define SNAP_SIZE              6
 #define PROTOC_TYPE_SIZE       2
 
index d85e669..e59acb1 100644 (file)
@@ -277,12 +277,13 @@ static void xennet_alloc_rx_buffers(struct net_device *dev)
                if (!page) {
                        kfree_skb(skb);
 no_skb:
-                       /* Any skbuffs queued for refill? Force them out. */
-                       if (i != 0)
-                               goto refill;
                        /* Could not allocate any skbuffs. Try again later. */
                        mod_timer(&np->rx_refill_timer,
                                  jiffies + (HZ/10));
+
+                       /* Any skbuffs queued for refill? Force them out. */
+                       if (i != 0)
+                               goto refill;
                        break;
                }
 
index e43db77..bd6f743 100644 (file)
@@ -1512,7 +1512,8 @@ static int pmcraid_notify_aen(
        }
 
        result =
-               genlmsg_multicast(skb, 0, pmcraid_event_family.id, GFP_ATOMIC);
+               genlmsg_multicast(&pmcraid_event_family, skb, 0,
+                                 pmcraid_event_family.id, GFP_ATOMIC);
 
        /* If there are no listeners, genlmsg_multicast may return non-zero
         * value.
index 03a5671..f1d511a 100644 (file)
@@ -1608,15 +1608,17 @@ exit:
 EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name);
 
 #ifdef CONFIG_NET
+static const struct genl_multicast_group thermal_event_mcgrps[] = {
+       { .name = THERMAL_GENL_MCAST_GROUP_NAME, },
+};
+
 static struct genl_family thermal_event_genl_family = {
        .id = GENL_ID_GENERATE,
        .name = THERMAL_GENL_FAMILY_NAME,
        .version = THERMAL_GENL_VERSION,
        .maxattr = THERMAL_GENL_ATTR_MAX,
-};
-
-static struct genl_multicast_group thermal_event_mcgrp = {
-       .name = THERMAL_GENL_MCAST_GROUP_NAME,
+       .mcgrps = thermal_event_mcgrps,
+       .n_mcgrps = ARRAY_SIZE(thermal_event_mcgrps),
 };
 
 int thermal_generate_netlink_event(struct thermal_zone_device *tz,
@@ -1677,7 +1679,8 @@ int thermal_generate_netlink_event(struct thermal_zone_device *tz,
                return result;
        }
 
-       result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
+       result = genlmsg_multicast(&thermal_event_genl_family, skb, 0,
+                                  0, GFP_ATOMIC);
        if (result)
                dev_err(&tz->device, "Failed to send netlink event:%d", result);
 
@@ -1687,17 +1690,7 @@ EXPORT_SYMBOL_GPL(thermal_generate_netlink_event);
 
 static int genetlink_init(void)
 {
-       int result;
-
-       result = genl_register_family(&thermal_event_genl_family);
-       if (result)
-               return result;
-
-       result = genl_register_mc_group(&thermal_event_genl_family,
-                                       &thermal_event_mcgrp);
-       if (result)
-               genl_unregister_family(&thermal_event_genl_family);
-       return result;
+       return genl_register_family(&thermal_event_genl_family);
 }
 
 static void genetlink_exit(void)
index 60a3278..e7cfbaf 100644 (file)
@@ -74,14 +74,16 @@ static int user_cmd(struct sk_buff *skb, struct genl_info *info)
        return 0;
 }
 
-static struct genl_ops dlm_nl_ops = {
-       .cmd            = DLM_CMD_HELLO,
-       .doit           = user_cmd,
+static struct genl_ops dlm_nl_ops[] = {
+       {
+               .cmd    = DLM_CMD_HELLO,
+               .doit   = user_cmd,
+       },
 };
 
 int __init dlm_netlink_init(void)
 {
-       return genl_register_family_with_ops(&family, &dlm_nl_ops, 1);
+       return genl_register_family_with_ops(&family, dlm_nl_ops);
 }
 
 void dlm_netlink_exit(void)
index 16e8abb..72d2917 100644 (file)
@@ -9,13 +9,25 @@
 #include <net/netlink.h>
 #include <net/genetlink.h>
 
+static const struct genl_multicast_group quota_mcgrps[] = {
+       { .name = "events", },
+};
+
 /* Netlink family structure for quota */
 static struct genl_family quota_genl_family = {
-       .id = GENL_ID_GENERATE,
+       /*
+        * Needed due to multicast group ID abuse - old code assumed
+        * the family ID was also a valid multicast group ID (which
+        * isn't true) and userspace might thus rely on it. Assign a
+        * static ID for this group to make dealing with that easier.
+        */
+       .id = GENL_ID_VFS_DQUOT,
        .hdrsize = 0,
        .name = "VFS_DQUOT",
        .version = 1,
        .maxattr = QUOTA_NL_A_MAX,
+       .mcgrps = quota_mcgrps,
+       .n_mcgrps = ARRAY_SIZE(quota_mcgrps),
 };
 
 /**
@@ -78,7 +90,7 @@ void quota_send_warning(struct kqid qid, dev_t dev,
                goto attr_err_out;
        genlmsg_end(skb, msg_head);
 
-       genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS);
+       genlmsg_multicast(&quota_genl_family, skb, 0, 0, GFP_NOFS);
        return;
 attr_err_out:
        printk(KERN_ERR "VFS: Not enough space to compose quota message!\n");
index 023bc34..c0894dd 100644 (file)
@@ -273,49 +273,40 @@ static struct genl_family ZZZ_genl_family __read_mostly = {
  * Magic: define multicast groups
  * Magic: define multicast group registration helper
  */
+#define ZZZ_genl_mcgrps                CONCAT_(GENL_MAGIC_FAMILY, _genl_mcgrps)
+static const struct genl_multicast_group ZZZ_genl_mcgrps[] = {
+#undef GENL_mc_group
+#define GENL_mc_group(group) { .name = #group, },
+#include GENL_MAGIC_INCLUDE_FILE
+};
+
+enum CONCAT_(GENL_MAGIC_FAMILY, group_ids) {
+#undef GENL_mc_group
+#define GENL_mc_group(group) CONCAT_(GENL_MAGIC_FAMILY, _group_ ## group),
+#include GENL_MAGIC_INCLUDE_FILE
+};
+
 #undef GENL_mc_group
 #define GENL_mc_group(group)                                           \
-static struct genl_multicast_group                                     \
-CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group) __read_mostly = {           \
-       .name = #group,                                                 \
-};                                                                     \
 static int CONCAT_(GENL_MAGIC_FAMILY, _genl_multicast_ ## group)(      \
        struct sk_buff *skb, gfp_t flags)                               \
 {                                                                      \
        unsigned int group_id =                                         \
-               CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group).id;  \
-       if (!group_id)                                                  \
-               return -EINVAL;                                         \
-       return genlmsg_multicast(skb, 0, group_id, flags);              \
+               CONCAT_(GENL_MAGIC_FAMILY, _group_ ## group);           \
+       return genlmsg_multicast(&ZZZ_genl_family, skb, 0,              \
+                                group_id, flags);                      \
 }
 
 #include GENL_MAGIC_INCLUDE_FILE
 
-int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void)
-{
-       int err = genl_register_family_with_ops(&ZZZ_genl_family,
-               ZZZ_genl_ops, ARRAY_SIZE(ZZZ_genl_ops));
-       if (err)
-               return err;
-#undef GENL_mc_group
-#define GENL_mc_group(group)                                           \
-       err = genl_register_mc_group(&ZZZ_genl_family,                  \
-               &CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group));           \
-       if (err)                                                        \
-               goto fail;                                              \
-       else                                                            \
-               pr_info("%s: mcg %s: %u\n", #group,                     \
-                       __stringify(GENL_MAGIC_FAMILY),                 \
-                       CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group).id);
-
-#include GENL_MAGIC_INCLUDE_FILE
-
 #undef GENL_mc_group
 #define GENL_mc_group(group)
-       return 0;
-fail:
-       genl_unregister_family(&ZZZ_genl_family);
-       return err;
+
+int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void)
+{
+       return genl_register_family_with_ops_groups(&ZZZ_genl_family,   \
+                                                   ZZZ_genl_ops,       \
+                                                   ZZZ_genl_mcgrps);
 }
 
 void CONCAT_(GENL_MAGIC_FAMILY, _genl_unregister)(void)
index c270285..84ba5ac 100644 (file)
@@ -119,4 +119,21 @@ extern int macvlan_link_register(struct rtnl_link_ops *ops);
 extern netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
                                      struct net_device *dev);
 
+#if IS_ENABLED(CONFIG_MACVLAN)
+static inline struct net_device *
+macvlan_dev_real_dev(const struct net_device *dev)
+{
+       struct macvlan_dev *macvlan = netdev_priv(dev);
+
+       return macvlan->lowerdev;
+}
+#else
+static inline struct net_device *
+macvlan_dev_real_dev(const struct net_device *dev)
+{
+       BUG();
+       return NULL;
+}
+#endif
+
 #endif /* _LINUX_IF_MACVLAN_H */
index 215b5ea..bec1cc7 100644 (file)
@@ -2263,24 +2263,6 @@ static inline void skb_postpull_rcsum(struct sk_buff *skb,
 
 unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len);
 
-/**
- *     pskb_trim_rcsum - trim received skb and update checksum
- *     @skb: buffer to trim
- *     @len: new length
- *
- *     This is exactly the same as pskb_trim except that it ensures the
- *     checksum of received packets are still valid after the operation.
- */
-
-static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
-{
-       if (likely(len >= skb->len))
-               return 0;
-       if (skb->ip_summed == CHECKSUM_COMPLETE)
-               skb->ip_summed = CHECKSUM_NONE;
-       return __pskb_trim(skb, len);
-}
-
 #define skb_queue_walk(queue, skb) \
                for (skb = (queue)->next;                                       \
                     skb != (struct sk_buff *)(queue);                          \
@@ -2378,6 +2360,27 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
 __wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
                    __wsum csum);
 
+/**
+ *     pskb_trim_rcsum - trim received skb and update checksum
+ *     @skb: buffer to trim
+ *     @len: new length
+ *
+ *     This is exactly the same as pskb_trim except that it ensures the
+ *     checksum of received packets are still valid after the operation.
+ */
+
+static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
+{
+       if (likely(len >= skb->len))
+               return 0;
+       if (skb->ip_summed == CHECKSUM_COMPLETE) {
+               __wsum adj = skb_checksum(skb, len, skb->len - len, 0);
+
+               skb->csum = csum_sub(skb->csum, adj);
+       }
+       return __pskb_trim(skb, len);
+}
+
 static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
                                       int len, void *buffer)
 {
index 9b787b6..ace4abf 100644 (file)
 /**
  * struct genl_multicast_group - generic netlink multicast group
  * @name: name of the multicast group, names are per-family
- * @id: multicast group ID, assigned by the core, to use with
- *      genlmsg_multicast().
- * @list: list entry for linking
- * @family: pointer to family, need not be set before registering
  */
 struct genl_multicast_group {
-       struct genl_family      *family;        /* private */
-       struct list_head        list;           /* private */
        char                    name[GENL_NAMSIZ];
-       u32                     id;
 };
 
 struct genl_ops;
@@ -39,9 +32,12 @@ struct genl_info;
  * @post_doit: called after an operation's doit callback, it may
  *     undo operations done by pre_doit, for example release locks
  * @attrbuf: buffer to store parsed attributes
- * @ops_list: list of all assigned operations
  * @family_list: family list
- * @mcast_groups: multicast groups list
+ * @mcgrps: multicast groups used by this family (private)
+ * @n_mcgrps: number of multicast groups (private)
+ * @mcgrp_offset: starting number of multicast group IDs in this family
+ * @ops: the operations supported by this family (private)
+ * @n_ops: number of operations supported by this family (private)
  */
 struct genl_family {
        unsigned int            id;
@@ -51,16 +47,19 @@ struct genl_family {
        unsigned int            maxattr;
        bool                    netnsok;
        bool                    parallel_ops;
-       int                     (*pre_doit)(struct genl_ops *ops,
+       int                     (*pre_doit)(const struct genl_ops *ops,
                                            struct sk_buff *skb,
                                            struct genl_info *info);
-       void                    (*post_doit)(struct genl_ops *ops,
+       void                    (*post_doit)(const struct genl_ops *ops,
                                             struct sk_buff *skb,
                                             struct genl_info *info);
        struct nlattr **        attrbuf;        /* private */
-       struct list_head        ops_list;       /* private */
+       const struct genl_ops * ops;            /* private */
+       const struct genl_multicast_group *mcgrps; /* private */
+       unsigned int            n_ops;          /* private */
+       unsigned int            n_mcgrps;       /* private */
+       unsigned int            mcgrp_offset;   /* private */
        struct list_head        family_list;    /* private */
-       struct list_head        mcast_groups;   /* private */
        struct module           *module;
 };
 
@@ -110,16 +109,15 @@ static inline void genl_info_net_set(struct genl_info *info, struct net *net)
  * @ops_list: operations list
  */
 struct genl_ops {
-       u8                      cmd;
-       u8                      internal_flags;
-       unsigned int            flags;
        const struct nla_policy *policy;
        int                    (*doit)(struct sk_buff *skb,
                                       struct genl_info *info);
        int                    (*dumpit)(struct sk_buff *skb,
                                         struct netlink_callback *cb);
        int                    (*done)(struct netlink_callback *cb);
-       struct list_head        ops_list;
+       u8                      cmd;
+       u8                      internal_flags;
+       u8                      flags;
 };
 
 int __genl_register_family(struct genl_family *family);
@@ -130,24 +128,53 @@ static inline int genl_register_family(struct genl_family *family)
        return __genl_register_family(family);
 }
 
-int __genl_register_family_with_ops(struct genl_family *family,
-                                   struct genl_ops *ops, size_t n_ops);
-
-static inline int genl_register_family_with_ops(struct genl_family *family,
-       struct genl_ops *ops, size_t n_ops)
+/**
+ * genl_register_family_with_ops - register a generic netlink family with ops
+ * @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.
+ *
+ * Return 0 on success or a negative error code.
+ */
+static inline int
+_genl_register_family_with_ops_grps(struct genl_family *family,
+                                   const struct genl_ops *ops, size_t n_ops,
+                                   const struct genl_multicast_group *mcgrps,
+                                   size_t n_mcgrps)
 {
        family->module = THIS_MODULE;
-       return __genl_register_family_with_ops(family, ops, n_ops);
+       family->ops = ops;
+       family->n_ops = n_ops;
+       family->mcgrps = mcgrps;
+       family->n_mcgrps = n_mcgrps;
+       return __genl_register_family(family);
 }
 
+#define genl_register_family_with_ops(family, ops)                     \
+       _genl_register_family_with_ops_grps((family),                   \
+                                           (ops), ARRAY_SIZE(ops),     \
+                                           NULL, 0)
+#define genl_register_family_with_ops_groups(family, ops, grps)        \
+       _genl_register_family_with_ops_grps((family),                   \
+                                           (ops), ARRAY_SIZE(ops),     \
+                                           (grps), ARRAY_SIZE(grps))
+
 int genl_unregister_family(struct genl_family *family);
-int genl_register_ops(struct genl_family *, struct genl_ops *ops);
-int genl_unregister_ops(struct genl_family *, struct genl_ops *ops);
-int genl_register_mc_group(struct genl_family *family,
-                          struct genl_multicast_group *grp);
-void genl_unregister_mc_group(struct genl_family *family,
-                             struct genl_multicast_group *grp);
-void genl_notify(struct sk_buff *skb, struct net *net, u32 portid,
+void genl_notify(struct genl_family *family,
+                struct sk_buff *skb, struct net *net, u32 portid,
                 u32 group, struct nlmsghdr *nlh, gfp_t flags);
 
 void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
@@ -227,41 +254,54 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
 
 /**
  * genlmsg_multicast_netns - multicast a netlink message to a specific netns
+ * @family: the generic netlink family
  * @net: the net namespace
  * @skb: netlink message as socket buffer
  * @portid: own netlink portid to avoid sending to yourself
- * @group: multicast group id
+ * @group: offset of multicast group in groups array
  * @flags: allocation flags
  */
-static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb,
+static inline int genlmsg_multicast_netns(struct genl_family *family,
+                                         struct net *net, 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 nlmsg_multicast(net->genl_sock, skb, portid, group, flags);
 }
 
 /**
  * genlmsg_multicast - multicast a netlink message to the default netns
+ * @family: the generic netlink family
  * @skb: netlink message as socket buffer
  * @portid: own netlink portid to avoid sending to yourself
- * @group: multicast group id
+ * @group: offset of multicast group in groups array
  * @flags: allocation flags
  */
-static inline int genlmsg_multicast(struct sk_buff *skb, u32 portid,
+static inline int genlmsg_multicast(struct genl_family *family,
+                                   struct sk_buff *skb, u32 portid,
                                    unsigned int group, gfp_t flags)
 {
-       return genlmsg_multicast_netns(&init_net, skb, portid, group, flags);
+       if (group >= family->n_mcgrps)
+               return -EINVAL;
+       group = family->mcgrp_offset + group;
+       return genlmsg_multicast_netns(family, &init_net, skb,
+                                      portid, group, flags);
 }
 
 /**
  * genlmsg_multicast_allns - multicast a netlink message to all net namespaces
+ * @family: the generic netlink family
  * @skb: netlink message as socket buffer
  * @portid: own netlink portid to avoid sending to yourself
- * @group: multicast group id
+ * @group: offset of multicast group in groups array
  * @flags: allocation flags
  *
  * This function must hold the RTNL or rcu_read_lock().
  */
-int genlmsg_multicast_allns(struct sk_buff *skb, u32 portid,
+int genlmsg_multicast_allns(struct genl_family *family,
+                           struct sk_buff *skb, u32 portid,
                            unsigned int group, gfp_t flags);
 
 /**
@@ -332,5 +372,22 @@ static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags)
        return nlmsg_new(genlmsg_total_size(payload), flags);
 }
 
+/**
+ * genl_set_err - report error to genetlink broadcast listeners
+ * @family: the generic netlink family
+ * @net: the network namespace to report the error to
+ * @portid: the PORTID of a process that we want to skip (if any)
+ * @group: the broadcast group that will notice the error
+ *     (this is the offset of the multicast group in the groups array)
+ * @code: error code, must be negative (as usual in kernelspace)
+ *
+ * This function returns the number of broadcast listeners that have set the
+ * NETLINK_RECV_NO_ENOBUFS socket option.
+ */
+static inline int genl_set_err(struct genl_family *family, struct net *net,
+                              u32 portid, u32 group, int code)
+{
+       return netlink_set_err(net->genl_sock, portid, group, code);
+}
 
 #endif /* __NET_GENERIC_NETLINK_H */
index c880a41..1af72d8 100644 (file)
@@ -27,6 +27,7 @@ struct genlmsghdr {
  */
 #define GENL_ID_GENERATE       0
 #define GENL_ID_CTRL           NLMSG_MIN_TYPE
+#define GENL_ID_VFS_DQUOT      (NLMSG_MIN_TYPE + 1)
 
 /**************************************************************************
  * Controller
index 307f293..a806687 100644 (file)
@@ -763,13 +763,14 @@ enum {
 
        TCA_FQ_RATE_ENABLE,     /* enable/disable rate limiting */
 
-       TCA_FQ_FLOW_DEFAULT_RATE,/* for sockets with unspecified sk_rate,
-                                 * use the following rate
-                                 */
+       TCA_FQ_FLOW_DEFAULT_RATE,/* obsolete, do not use */
 
        TCA_FQ_FLOW_MAX_RATE,   /* per flow max rate */
 
        TCA_FQ_BUCKETS_LOG,     /* log2(number of buckets) */
+
+       TCA_FQ_FLOW_REFILL_DELAY,       /* flow credit refill delay in usec */
+
        __TCA_FQ_MAX
 };
 
index 9f4618e..13d2f7c 100644 (file)
@@ -673,17 +673,18 @@ err:
        nlmsg_free(rep_skb);
 }
 
-static struct genl_ops taskstats_ops = {
-       .cmd            = TASKSTATS_CMD_GET,
-       .doit           = taskstats_user_cmd,
-       .policy         = taskstats_cmd_get_policy,
-       .flags          = GENL_ADMIN_PERM,
-};
-
-static struct genl_ops cgroupstats_ops = {
-       .cmd            = CGROUPSTATS_CMD_GET,
-       .doit           = cgroupstats_user_cmd,
-       .policy         = cgroupstats_cmd_get_policy,
+static const struct genl_ops taskstats_ops[] = {
+       {
+               .cmd            = TASKSTATS_CMD_GET,
+               .doit           = taskstats_user_cmd,
+               .policy         = taskstats_cmd_get_policy,
+               .flags          = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd            = CGROUPSTATS_CMD_GET,
+               .doit           = cgroupstats_user_cmd,
+               .policy         = cgroupstats_cmd_get_policy,
+       },
 };
 
 /* Needed early in initialization */
@@ -702,26 +703,13 @@ static int __init taskstats_init(void)
 {
        int rc;
 
-       rc = genl_register_family(&family);
+       rc = genl_register_family_with_ops(&family, taskstats_ops);
        if (rc)
                return rc;
 
-       rc = genl_register_ops(&family, &taskstats_ops);
-       if (rc < 0)
-               goto err;
-
-       rc = genl_register_ops(&family, &cgroupstats_ops);
-       if (rc < 0)
-               goto err_cgroup_ops;
-
        family_registered = 1;
        pr_info("registered taskstats version %d\n", TASKSTATS_GENL_VERSION);
        return 0;
-err_cgroup_ops:
-       genl_unregister_ops(&family, &taskstats_ops);
-err:
-       genl_unregister_family(&family);
-       return rc;
 }
 
 /*
index 82da4f4..1e5b2df 100644 (file)
@@ -214,18 +214,22 @@ static DEFINE_TIMER(seed_timer, __prandom_timer, 0, 0);
 static void __prandom_timer(unsigned long dontcare)
 {
        u32 entropy;
+       unsigned long expires;
 
        get_random_bytes(&entropy, sizeof(entropy));
        prandom_seed(entropy);
+
        /* reseed every ~60 seconds, in [40 .. 80) interval with slack */
-       seed_timer.expires = jiffies + (40 * HZ + (prandom_u32() % (40 * HZ)));
+       expires = 40 + (prandom_u32() % 40);
+       seed_timer.expires = jiffies + msecs_to_jiffies(expires * MSEC_PER_SEC);
+
        add_timer(&seed_timer);
 }
 
-static void prandom_start_seed_timer(void)
+static void __init __prandom_start_seed_timer(void)
 {
        set_timer_slack(&seed_timer, HZ);
-       seed_timer.expires = jiffies + 40 * HZ;
+       seed_timer.expires = jiffies + msecs_to_jiffies(40 * MSEC_PER_SEC);
        add_timer(&seed_timer);
 }
 
@@ -270,7 +274,7 @@ void prandom_reseed_late(void)
 static int __init prandom_reseed(void)
 {
        __prandom_reseed(false);
-       prandom_start_seed_timer();
+       __prandom_start_seed_timer();
        return 0;
 }
 late_initcall(prandom_reseed);
index c41d5fb..6e6194f 100644 (file)
@@ -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);
index 53f0990..af5ebd1 100644 (file)
@@ -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);
 }
 
index 8ffc52e..7e00a73 100644 (file)
 #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);
 }
index 5e78d44..9589718 100644 (file)
@@ -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) {
index 4e66bf6..5325af8 100644 (file)
@@ -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);
 }
 
index 426b5df..459e200 100644 (file)
@@ -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;
 
index 581a595..1865fdf 100644 (file)
@@ -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;
index aadec42..cee4425 100644 (file)
@@ -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
index 7e49bbc..43f1b2b 100644 (file)
@@ -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);
 }
-
index b0bdd8c..ba5c1e0 100644 (file)
 
 #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;
-}
index 22b1a70..d08c7a4 100644 (file)
@@ -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;
-}
index b28e863..19e3637 100644 (file)
@@ -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;
        }
 
index caf0117..90ff957 100644 (file)
@@ -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;
 
index 5d9c845..52b802a 100644 (file)
@@ -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;
index cbc85f6..876c6ca 100644 (file)
@@ -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);
index 41e1d28..5cb8ddb 100644 (file)
@@ -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);
index 8e8529d..3dc0c6c 100644 (file)
@@ -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 */
index 2ab09cb..0649373 100644 (file)
@@ -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;
index 6728546..7820f3a 100644 (file)
@@ -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);
        }
 }
index de86e5b..5944d7d 100644 (file)
@@ -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);
index 5658d9d..12c97d8 100644 (file)
@@ -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);
 }
index ff75313..4fbdb70 100644 (file)
@@ -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:
index df1fa58..d606232 100644 (file)
@@ -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();
 }
 
index f8a55ff..3512177 100644 (file)
@@ -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
index 3c00842..e24ff1d 100644 (file)
@@ -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);
index bfc6fce..1b4a4a9 100644 (file)
@@ -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();
 }
index f3893e8..81eb8cf 100644 (file)
@@ -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)
index c329712..a37b81f 100644 (file)
@@ -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)
index 571db8d..da1a1ce 100644 (file)
@@ -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);
index be446d5..4cfd722 100644 (file)
@@ -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)
index 1ded5c6..35be035 100644 (file)
@@ -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)
index a110064..69345ce 100644 (file)
@@ -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);
 }
index dd1c37d..8ef83ee 100644 (file)
@@ -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);
 }
index 8f08974..43817d7 100644 (file)
@@ -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);
 }
 
 /*
index 8df7f64..f0176e1 100644 (file)
@@ -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
index 0c741ce..7dbc4f7 100644 (file)
@@ -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 == &notify_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;
 
@@ -432,52 +418,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, &notify_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);
index 84b7e3e..a9b2342 100644 (file)
@@ -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;
 }
 
 /**
index 449e077..6f5e1dd 100644 (file)
 
 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;
index d3d14a5..4067ea4 100644 (file)
@@ -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 *);
index 5c2dab2..2c631fe 100644 (file)
@@ -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)
index 12c30f3..38946b2 100644 (file)
@@ -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);
index fdc041c..95d8439 100644 (file)
@@ -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;
 
index c9b91cb..68a27f9 100644 (file)
@@ -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.
         */
index cf465d6..69cd9bf 100644 (file)
@@ -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)
index 8bcd498..9f72a63 100644 (file)
@@ -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;
index 0694d62..c278b33 100644 (file)
@@ -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,
-};
-
index 7ceffe3..eb45807 100644 (file)
@@ -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,
-};
index 7ab60ba..403078d 100644 (file)
@@ -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,
-};
-
index aff8776..995c08c 100644 (file)
 #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,
-};
index a6470ac..ef2191b 100644 (file)
@@ -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);
index 5dcd9c0..b445b82 100644 (file)
@@ -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__ */
index a7f4e79..a1eb210 100644 (file)
@@ -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;