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 8b8a0578764112c1dacc4a719f454c676c09100c..3c12d9a7ed00391d5c3f49ef80d7b1ae9abc40fe 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 0e598aeed5398551362b582d314995c3a47eaf9b..63f30484932b1cddbe5f9c5bd05ca6473d612e0b 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 fdef416c0ff6f0384e107466b47b1ff8f2bac9aa..cae3b387b867a99ab7013cfc2b731b2125abc961 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 272f00927761b1e34e5676ad018e0f72ef623b8c..1bdf104e90bb7f1924acf51f78caa39817d78efb 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 c73fc2b74de2a1dd0665bde5693b1fce03f6d6c5..18c5b9b16645dfa49a218d4b12253240f97310b7 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 baf2686aa8eb0cb027044e815dafa8b2aa6afae4..02125e6a91093e22bda1849bad209f6d3ebe8962 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 bc8fd362a5aa7624fc01a6c79722f4b57e824aef..0ec2a7e8c8a9588170c97715856e7b5f34cf7c60 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 77a07a12e77fea8e44376e40fd4c0d12caba53af..ca31286aa028158341a5847382b75afb74a6ea2f 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 5aa5e8146496ba807ece60fe5b287d70a79a8ad4..c3c4c266b8465981b658676617fa79202aa4396d 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 4e01c57d8c8de349da61e80cb0e4cb0f4aece3fd..a1f66e2c9a8694c9d83471dd63f6659d431840eb 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 dcafbda3e5be1035034d61c486f4eefceb6887f6..ec96130533cc54630c3f26f6253e58b5a0f5a7cf 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 fcf2761d8828804d3edf7ca8e2ad245576d23685..fdace204b0549aa2599edd67c1c3112e0c4bf9de 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 e622cc1f96ffe58336ee8c24f12c54e1679e11b7..814d0eca9b334ea86c862bc617a46f137f04d475 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 5ecf267dc4cc8da779112356057cb8253d27e7cb..3efbb35267c853d576cc3a4d3104ec4ba1a18d1d 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 9199adf32d33c1639dfa2354e609ef92b638ef91..efa8a151d78907d4b17d5f5dd07eaed9b1f2c02c 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 00c5be8c55b8ff7186a670645cb654dc46779399..a9e068423ba0651414cc0c5b23f0eda6937a6c23 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 7fb0edfe3d2482514f32f48afef1a5a1c46e9805..dbcd5262c0167c1ae0dacf7dd578b5c3a2a43ce5 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 edf3e8a0ff839c069bc05154f85c1e68e89544f2..0075686276aa7f703a6fa63856065a971b5d8388 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 eaecaadfa8c56436994c2afbe9a70223467ceec2..abde97471636918a6b7e2381634cdc743678d24c 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 b2793b91cc553e41e80170ac791d10b83f0e776d..4cbebf3d80eb1492d847f1ad8a9888e2a6c17b97 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 aedd5736a87d53862fa2be4176e9762fcd8df18a..8d3945ab7334840684db42ea6eefa9bafc52c061 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 00cd36e0860105aaa577d089e8a169e7d7b1fd97..61088a6a94245144f46fa42e92fdce9eb07f1599 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 5a0f04c2c813661991047174c7a2643e74d694bd..27ffe0ebf0a686793c30f25f033895bf70ddfe51 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 8d4ccd35a01692d911f50d91bfe9bee0d89d883f..8a7a23a84ac5c3b6a7b7d4979e8c5866097895a5 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 90d41d26ec6d8c37f04682aa05b8731a4d4c3002..7536a4c01293a9b3e97bf1171941b6724213ad6c 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 e78802e75ea6cb358d6e3bec8d3a25efcffc66d4..bcc224a83734cdb49c25993066babe904a42d32f 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 9dccb1edfd2aba2070023f4ae874bac0cc432293..dc76670c2f2a16c244d0ec58a779a8742d0e6c3e 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 6574eb8766f90997c38d0ea56d67ad542ecf99b3..34b0de09d88190a04e30d867e31ad001f35f0e34 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 7cb105c103fe9408eb7c02b96dac4f4bfb702456..782e38bfc1eeea38215492aee5aaa587cc534525 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 f74786aa37be3cca7a4020cc82b08f0777aec4f5..e15ec2b12035aa06b4662c284a7bb3abda148eff 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 90a429b7ebad8497d317639389c041d534366255..8494bb53ebdc9f33abee1d8e5a27f7d0dea3cc17 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 cdc7c90a6a9e3053d3a2e26eb78100a0f518b646..7bab4de658a91d9fb1231f5e45461a268efc8487 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 b07f164d65cf582a63c2ddfbfccaced509a6ceca..20e49095db2ae2ba0c2d7d83071aa2a14a81252d 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 6f899c6926474ba2f60cd642399e10d61814ec3d..7c1845221e1cc08a0904b35a491e64b1cd70b953 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 e7a38d844a6a4e7a2e9ba738e56606d946fea47a..60a5da53668f54f9987692ccf7389794d13ea851 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 90b8342d1ed4bd2e95389541f299d49d59261e6a..8824610c21fb3a3476a281f6b3435213ebef12cd 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 9ea24f1cba73f812de0b3352806e89434c0d59f9..a2c9a5dbac6b0317fba5131ee212d3ef9292c77a 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 d8643ebabd3001b6a00544157a65a9bc9f3265c5..710192ed27ed3118656f1a3b08bc41ec92c649a1 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 7e4c2524b63052006650ff76b92b3b839d6c9cd6..b5656fce4ff5f042b9053258e31c9b503802d217 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 5b84f7ae0b1e3820cdee9737f9e4bacd8ed7b8d3..ef44a2da644d47be1613041703093cf7567f8979 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 f8c3a10510c22b01eb06d9b51310562cb0c8b7dd..de9eb2cfbf4b5784c36a97da2748acd357250c37 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 668dd27616a0c83f9a4a39b94de2ad22b8e98a2b..cc6a0a586f0b748c054c4c0e8631ea0d706501cb 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 ef8c98e21098479d231df5844fb2abab8ddab04f..f499efc6abcf8bed36c46c7aaa342c8b8be3c878 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 de0df86704e714778891b7fb1af6b2cfc1340bef..9df7bc91a26f54c9812718e481c538895aa5b4f8 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 f80f30b6160e7f4be38811198e76c245f26e08ca..c8385ec77a86af678b36cf28a5d7c2fa8448de84 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 220af4fe0fc65b18b575c81025c436d303f01bbd..81ac001ee74187d325f7a7d166666f9ec3c497fa 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 1576104e3d9531ada721dc41ec5740f021345b83..9bf8898743ab3d8a31aaad7641ecad09204e0265 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 7d66018a2e33060d1bdc1a96b970fd61f6480e4a..2181ee283d823e19dafaa5b1b8a09fcb1b4f2b1a 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 58a6013712d2d2c7e063282e056fa31e2dd7a955..2675ca7f8d146ca579a7a4bb4c1397f641a95ee0 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 f084412eee0b7cdeced4f2b21b4140b01d1b141e..c8e029df770e38cac9a52dccb660666bd8cc9f74 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 1cfe5a738c479e53e3dd5ba21f460096d2a16e53..92f76d655e6cc1206e46c4fc0e60b147b62280e0 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 5dd0ccc70b863ea15fad25d739adebd39ce09dbd..13eaeed03898288d43abf107090346d513132820 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 41a16d30c79c5be46f89229d3185a033d8131f0f..e05d9b4c8317c44df17b9ca0c2dea0577741b1a6 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 c5738f14c4ba21b7a60453ab282309089134bdc2..776aff3678ff23bddda925dfbb48bde925cb7b82 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 a0935987fa3a3ca22dfa0298d7bef054408830e6..7f40ab8e1bd809d017d6dff41b68b815c7ade240 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 7c157857f5cee925e796a49396a5843a758a01cd..2183e79783995eea92cb8d8498d0a8582c43c820 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 50590b1420a516863845249c96f689b28e766964..a5d38e8ad9e4925cabd9f90744befd6b9a35d522 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 9a78e3daf74264fa13f446a4779d342ab6341488..ff784072fb4233a29a46a55bf21d75e094bb8d5c 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 ae13fb94b2e8d7b82a259cdc830643cb2e144901..2ffc7298f686ec6002ee54dd210ebc7e8b13b757 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 25e50ffc44ec8b42fd35b4ab0b60a08ee09edd7d..b0c346a9e4b8ca8adf9df562ac444d478a3ece57 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 945ddecf90c9a3b6c6bcd916c3c1d293ac51dc15..0eb0f4ae592054f7ebf1ee9182169fc57adbc11c 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 5061f1db3f021072b32a0617385ccb75db427d07..92d38ab3c60e87861f992411e3774aeceed30f56 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 222d2e792ca6d259885fa6da3a8ad792bbb338ad..27efbcdac6a979875976a7a74d1c15e07c1afa49 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 d224dc3bb092b0ef04545cc57891a7bdb4de4b2f..0c65386fa30d5cecda61d9d4ca290b6577df2f59 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 d85e66979711cbe62a168d9012f1a40ed2d5c405..e59acb1daa2355efd56e4398ab82d0c0f8647ab4 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 e43db7742047aca836fab57c61b1530740f6d383..bd6f743d87a78af19c698d38d70291723fd28dfb 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 03a567199bbe313cd36dd0a4d62e3d9f7cab957d..f1d511a9475b4dc29ec28864cb3b948e8ba13183 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 60a327863b1122e246b79bf91ecdf23136eccac9..e7cfbaf8d0e2ed66b404c259dcd64c2d4ccd5f54 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 16e8abb7709ba04fb1bcc1520573acf568e68eb9..72d29177998ebbf22e9888c9cd4cf43b3cc37e91 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 023bc346b877f08bd75be65edaba526af7314558..c0894dd8827b27378d31bb88f591bc2fd1e43a9c 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 c2702856295ebaaa06db6dddb7106a53d2e71315..84ba5ac39e039f80da563305155800cd1332782c 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 215b5ea1cb302c43f0e8b9532fbe3ce59ff0f612..bec1cc7d5e3c41efbc4939ab742eeb955b64b7f0 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 9b787b62cf16066e6f2335301865849fa674f7a1..ace4abf118d7d4b0501fa3c6829001da905e728b 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 c880a417d8a93693874b76a3e364a203ed4d0a9c..1af72d8228e04db8c1d6de05cacfa1bfd4a577b7 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 307f293477e83684970fc5c6dc05225d750d0882..a806687ad98fc1258ae0b36c75164ecf5d59eec4 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 9f4618eb51c8528fe808d91f6dfdc6237af3ab65..13d2f7cd65dbfd851eaa61cf08645994c9fd0037 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 82da4f4c3489eb0fa2a814adf477be16c14cbed4..1e5b2df442916de82ef497f844c068724f8cd555 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 c41d5fbb91d0c3e07bf0eff148d57e6cd74ef8d0..6e6194fcd88e1c3427c24a9c914956cc1bd1e66d 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 53f0990eab58e08a3da9160a27ee0834bd0f0272..af5ebd18d7059f2d0cc289e226c544f210309dc2 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 8ffc52e01ece35db173fee05a3fdc160d733b684..7e00a7342ee6aa4e9d7ab408423694fecb2966db 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 5e78d44333b9bc39fdb56fdd489d0ac4f7f5d4e8..95897183226e18882bdbe16d8e9ba3a111ffae71 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 4e66bf61f585e58c2f975799833d540b5e5c9813..5325af85eea670f5c865367fc991eaf9b907cd98 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 426b5df1c98f1cc195158c9829a536cfbd0fefd6..459e200c08a40e4e737798582524cd973064b143 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 581a59504bd5f49d9a54584f3441c4e323b7bcd5..1865fdf5a5a5116be8bf28b25f9c340f8b8fd50b 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 aadec428e6ec206deb3c41c75a69f2c527bbab1d..cee4425b995689702375435f0be7dd85eca3ed73 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 7e49bbcc6967ebfaac72ee9e6b3e3b9032f1f88a..43f1b2bf469f40938a431582b305c45587049a04 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 b0bdd8c51e9c83a0ef968fc678588f3807559b13..ba5c1e002f37b2630c53a0284736f5d177bded76 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 22b1a7058fd3f841d94ee27655840c1ae325f011..d08c7a43dcd1c72f1512b01e8a00dd2b9e6b1869 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 b28e863fe0a7143b199bee51cfdf242c125f31cf..19e36376d2a083b5c8b307208ebd17ade086dcaa 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 caf01176a5e49774555b9c4dea5809e4f57cce19..90ff9570d7d4def935f3224514312fc217812d9c 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 5d9c845d288a3d8cce3eb96aeb65384e4a56edbc..52b802a0cd8cbda18579dd1811bce3405ecbdfdc 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 cbc85f660d54a683f5e989bc729e1f5f0b52e4f0..876c6ca2d8f9e77a28f1e629aa6523df1ee8f42f 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 41e1d2845c8f6690b5588888134bd80e49fc5dcf..5cb8ddb505ee8911461ec92a5c74feef0b441e00 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 8e8529d3c8c92a4473a3ed9fd8db876ca83533bd..3dc0c6cf02a896e66071cd5f66b0a93f0dd3fc06 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 2ab09cbae74d29155d08f7dd701851136d205e0f..06493736fbc826842876180a24510d9e348cb7f3 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 672854664ff5c1d36783ac1bfb72fea481648ca1..7820f3a7dd704bd6375c5cdc858e71b7be4261ed 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 de86e5bc44629eaeaf1f8fc935dfd4abe5625703..5944d7d668dd91da21e945eac748bbbbbb11d67a 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 5658d9d51637beaa07790b49e4d405cc290afe16..12c97d8aa6bbb31ff1519459b89b7b9fb33817f5 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 ff75313f27a848db69dc0af6cf1a367205e13d2d..4fbdb7046d286cf64f60c61e3ae87ba657f042a0 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 df1fa58528c6fdeae476193f3bf7ae53d2e38a7e..d6062325db08411207fd63b435ec1e5e4e0f2001 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 f8a55ff1971b36db95ae7c22dd8c65062fbdcb61..3512177deb4d0e7d12c6d145781802074f490615 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 3c00842b0079240f1788c83bfab346d5879336d8..e24ff1df0401288e4e810cf79ec3ea20d86a06c0 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 bfc6fcea38410e3a5817ad7ba254a98151bb0749..1b4a4a95367552c8cc22d19850b0779eee87cdc6 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 f3893e897f721aa4345c82f0ea2b899c44fa0ae4..81eb8cf8389b6a5af55f7b2994d7dbefe3d732bf 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 c32971269280116543c0bf560e1bbc3248df034d..a37b81fe04798e0c8cb0196f72b2cf97e4b610b7 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 571db8dd2292a7c5b1f2e940073edce370b13699..da1a1cee1a088e39816d565e99975bbc69a392d3 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 be446d517bc96641d413dc0bba09d9150398a81e..4cfd722e91536c1de137ec64f1e33bbc7fc5e1ea 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 1ded5c6d268c662af2e4743fedfb8226b5715cc3..35be035ee0cec79b5b797efb46c287661b8dbc93 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 a1100640495d3d3b106e850e9af6a9cc4e1ed547..69345cebe3a3e397beffbe56536bf971fb81ddf9 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 dd1c37d7acbcfa6d126a8056360b8d6a56985035..8ef83ee97c6ad0fa934bbbe3d4988003e9ee287b 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 8f0897407a2cf950240082cfde9ab07969f96404..43817d73ccf997b69ec15da814e274404e08a2c7 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 8df7f64c6db35a0f538bef1fa0206f7826fd1a14..f0176e1a5a81a01e59cfdbb59c51d54decf2c0e6 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 0c741cec4d0d294d808ddc26fdaacecc3e6a0b94..7dbc4f732c75a1ae7b18a59f07acbab5743c9e7f 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 84b7e3ea7b7ad7ce09e9256916589e4724d55969..a9b2342d5253295b607f3a3a1aa760e47c4d5ebe 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 449e0776a2c0887bea75fbc963224a37d20ccb33..6f5e1dd3be2dbdcfdb591d64323c3558d0636e6d 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 d3d14a58aa91413bb18dae53bbb8aa1babd42c73..4067ea41be28d725c1312f2bb995df4e2c2209ab 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 5c2dab27610962caed49d6017a6cda5b5ac855fc..2c631fe76be191c1a7dd1bc33c1901c8507621b4 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 12c30f3e643e00e3fa495cfc7d471e0078b00114..38946b26e471c9754c922d3451e8ec2682f5ae3d 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 fdc041c5785360731154521fb3492dba825776ff..95d843961907bf4b852743ea81015e7954db342b 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 c9b91cb1cb0dfdd4561ef3632d7443416a66b19d..68a27f9796d2ece54bcb53b98a47e8f98645077b 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 cf465d66ccdec9506bab01cb7390fcd169b50dfc..69cd9bf3f561d64d377ddb65091b98e1017e15cf 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 8bcd4985d0fb341f795346f06c55d1f059c4c643..9f72a6376362e613cb87185acbb3581174c45592 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 0694d62e4dbc1b03f2b075269e23957c28ce85a2..c278b3356f75fe2de50b99b9e7e71609eb25a8df 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 7ceffe39d70e4bb69b046b2de1e604834412abb5..eb4580784d9dc5abdcaf5be27b24578ed6b0ca0e 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 7ab60babdd22a32bd44bd28afc80972e4311084c..403078d670a909cb20b4660e1a33965fd996bb52 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 aff8776e2d41a5d4020bdd5f8c937830e6e214a6..995c08c827b512bf4a9e6650f77ac834015e60fe 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 a6470ac39498e807a5d760e96b95bbc6b748129d..ef2191b969a7aa6967f2a3f7855e5b20cfef5cfc 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 5dcd9c067bf0ac72a3c6e1067818053e31f7b748..b445b82020a83143aee4e9e89815dc921fdb4759 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 a7f4e7902104907adf86c9fffcfc0ab956d36095..a1eb21073176115a587f9eb1edf5d36dba582484 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;