summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/802/fc.c2
-rw-r--r--net/802/fddi.c2
-rw-r--r--net/802/garp.c8
-rw-r--r--net/802/hippi.c2
-rw-r--r--net/802/tr.c12
-rw-r--r--net/8021q/vlan_netlink.c16
-rw-r--r--net/9p/client.c6
-rw-r--r--net/9p/trans_fd.c2
-rw-r--r--net/appletalk/ddp.c6
-rw-r--r--net/appletalk/sysctl_net_atalk.c10
-rw-r--r--net/atm/br2684.c2
-rw-r--r--net/atm/mpoa_proc.c2
-rw-r--r--net/atm/pppoatm.c95
-rw-r--r--net/atm/signaling.c2
-rw-r--r--net/ax25/af_ax25.c2
-rw-r--r--net/ax25/ax25_dev.c10
-rw-r--r--net/ax25/ax25_ip.c4
-rw-r--r--net/ax25/sysctl_net_ax25.c82
-rw-r--r--net/batman-adv/Kconfig27
-rw-r--r--net/batman-adv/Makefile1
-rw-r--r--net/batman-adv/bat_debugfs.c19
-rw-r--r--net/batman-adv/bat_iv_ogm.c78
-rw-r--r--net/batman-adv/bat_sysfs.c14
-rw-r--r--net/batman-adv/bitarray.c118
-rw-r--r--net/batman-adv/bitarray.h26
-rw-r--r--net/batman-adv/bridge_loop_avoidance.c1580
-rw-r--r--net/batman-adv/bridge_loop_avoidance.h98
-rw-r--r--net/batman-adv/hard-interface.c51
-rw-r--r--net/batman-adv/icmp_socket.c4
-rw-r--r--net/batman-adv/main.c14
-rw-r--r--net/batman-adv/main.h11
-rw-r--r--net/batman-adv/originator.c3
-rw-r--r--net/batman-adv/packet.h49
-rw-r--r--net/batman-adv/routing.c39
-rw-r--r--net/batman-adv/routing.h1
-rw-r--r--net/batman-adv/send.c14
-rw-r--r--net/batman-adv/soft-interface.c500
-rw-r--r--net/batman-adv/soft-interface.h2
-rw-r--r--net/batman-adv/translation-table.c437
-rw-r--r--net/batman-adv/translation-table.h8
-rw-r--r--net/batman-adv/types.h89
-rw-r--r--net/batman-adv/vis.c8
-rw-r--r--net/bridge/br_device.c3
-rw-r--r--net/bridge/br_fdb.c136
-rw-r--r--net/bridge/br_forward.c2
-rw-r--r--net/bridge/br_multicast.c74
-rw-r--r--net/bridge/br_netfilter.c10
-rw-r--r--net/bridge/br_netlink.c39
-rw-r--r--net/bridge/br_private.h17
-rw-r--r--net/bridge/br_private_stp.h7
-rw-r--r--net/bridge/br_stp.c4
-rw-r--r--net/bridge/br_stp_timer.c6
-rw-r--r--net/bridge/br_sysfs_br.c20
-rw-r--r--net/caif/caif_socket.c18
-rw-r--r--net/caif/cfctrl.c4
-rw-r--r--net/caif/cfpkt_skbuff.c7
-rw-r--r--net/caif/cfsrvl.c3
-rw-r--r--net/caif/chnl_net.c14
-rw-r--r--net/can/gw.c2
-rw-r--r--net/ceph/auth_x.h6
-rw-r--r--net/ceph/ceph_common.c4
-rw-r--r--net/ceph/ceph_hash.c6
-rw-r--r--net/ceph/crush/mapper.c8
-rw-r--r--net/ceph/debugfs.c6
-rw-r--r--net/ceph/messenger.c16
-rw-r--r--net/ceph/mon_client.c10
-rw-r--r--net/ceph/osd_client.c2
-rw-r--r--net/ceph/osdmap.c14
-rw-r--r--net/compat.c10
-rw-r--r--net/core/datagram.c6
-rw-r--r--net/core/dev.c12
-rw-r--r--net/core/dev_addr_lists.c97
-rw-r--r--net/core/ethtool.c59
-rw-r--r--net/core/fib_rules.c32
-rw-r--r--net/core/filter.c72
-rw-r--r--net/core/gen_stats.c3
-rw-r--r--net/core/kmap_skb.h19
-rw-r--r--net/core/neighbour.c115
-rw-r--r--net/core/net-sysfs.c13
-rw-r--r--net/core/pktgen.c20
-rw-r--r--net/core/rtnetlink.c351
-rw-r--r--net/core/skbuff.c135
-rw-r--r--net/core/sock.c8
-rw-r--r--net/core/sysctl_net_core.c15
-rw-r--r--net/core/utils.c9
-rw-r--r--net/dcb/dcbnl.c92
-rw-r--r--net/dccp/ccids/ccid3.c12
-rw-r--r--net/dccp/dccp.h8
-rw-r--r--net/dccp/input.c10
-rw-r--r--net/dccp/ipv4.c6
-rw-r--r--net/dccp/ipv6.c3
-rw-r--r--net/dccp/sysctl.c11
-rw-r--r--net/decnet/af_decnet.c6
-rw-r--r--net/decnet/dn_dev.c35
-rw-r--r--net/decnet/dn_fib.c5
-rw-r--r--net/decnet/dn_nsp_in.c2
-rw-r--r--net/decnet/dn_nsp_out.c4
-rw-r--r--net/decnet/dn_route.c18
-rw-r--r--net/decnet/dn_rules.c14
-rw-r--r--net/decnet/sysctl_net_decnet.c10
-rw-r--r--net/dns_resolver/dns_key.c2
-rw-r--r--net/dns_resolver/internal.h2
-rw-r--r--net/econet/af_econet.c4
-rw-r--r--net/ethernet/eth.c2
-rw-r--r--net/ieee802154/6lowpan.c2
-rw-r--r--net/ieee802154/dgram.c6
-rw-r--r--net/ieee802154/nl-mac.c146
-rw-r--r--net/ieee802154/nl-phy.c29
-rw-r--r--net/ieee802154/raw.c2
-rw-r--r--net/ipv4/af_inet.c4
-rw-r--r--net/ipv4/ah4.c2
-rw-r--r--net/ipv4/arp.c4
-rw-r--r--net/ipv4/devinet.c61
-rw-r--r--net/ipv4/fib_frontend.c10
-rw-r--r--net/ipv4/fib_rules.c16
-rw-r--r--net/ipv4/fib_semantics.c47
-rw-r--r--net/ipv4/igmp.c18
-rw-r--r--net/ipv4/inet_connection_sock.c29
-rw-r--r--net/ipv4/inet_hashtables.c2
-rw-r--r--net/ipv4/inet_timewait_sock.c2
-rw-r--r--net/ipv4/ip_forward.c4
-rw-r--r--net/ipv4/ip_fragment.c6
-rw-r--r--net/ipv4/ip_gre.c102
-rw-r--r--net/ipv4/ip_options.c26
-rw-r--r--net/ipv4/ip_sockglue.c6
-rw-r--r--net/ipv4/ipconfig.c2
-rw-r--r--net/ipv4/ipip.c57
-rw-r--r--net/ipv4/ipmr.c9
-rw-r--r--net/ipv4/netfilter.c12
-rw-r--r--net/ipv4/netfilter/arp_tables.c2
-rw-r--r--net/ipv4/netfilter/ip_queue.c6
-rw-r--r--net/ipv4/netfilter/ip_tables.c2
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c7
-rw-r--r--net/ipv4/netfilter/nf_conntrack_proto_icmp.c12
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c2
-rw-r--r--net/ipv4/ping.c10
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/route.c103
-rw-r--r--net/ipv4/sysctl_net_ipv4.c16
-rw-r--r--net/ipv4/tcp.c304
-rw-r--r--net/ipv4/tcp_input.c168
-rw-r--r--net/ipv4/tcp_ipv4.c77
-rw-r--r--net/ipv4/tcp_output.c45
-rw-r--r--net/ipv4/tcp_probe.c4
-rw-r--r--net/ipv4/udp.c20
-rw-r--r--net/ipv4/udp_impl.h2
-rw-r--r--net/ipv4/xfrm4_policy.c6
-rw-r--r--net/ipv6/addrconf.c101
-rw-r--r--net/ipv6/addrconf_core.c4
-rw-r--r--net/ipv6/af_inet6.c17
-rw-r--r--net/ipv6/datagram.c12
-rw-r--r--net/ipv6/exthdrs.c29
-rw-r--r--net/ipv6/exthdrs_core.c3
-rw-r--r--net/ipv6/fib6_rules.c18
-rw-r--r--net/ipv6/icmp.c5
-rw-r--r--net/ipv6/inet6_connection_sock.c2
-rw-r--r--net/ipv6/ip6_flowlabel.c4
-rw-r--r--net/ipv6/ip6_tunnel.c4
-rw-r--r--net/ipv6/ip6mr.c9
-rw-r--r--net/ipv6/ipv6_sockglue.c3
-rw-r--r--net/ipv6/mcast.c2
-rw-r--r--net/ipv6/ndisc.c9
-rw-r--r--net/ipv6/netfilter/ip6_queue.c6
-rw-r--r--net/ipv6/netfilter/ip6_tables.c2
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c9
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c12
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c6
-rw-r--r--net/ipv6/reassembly.c4
-rw-r--r--net/ipv6/route.c50
-rw-r--r--net/ipv6/sit.c58
-rw-r--r--net/ipv6/sysctl_net_ipv6.c83
-rw-r--r--net/ipv6/tcp_ipv6.c58
-rw-r--r--net/ipv6/udp.c8
-rw-r--r--net/ipv6/xfrm6_policy.c4
-rw-r--r--net/ipv6/xfrm6_tunnel.c6
-rw-r--r--net/ipx/sysctl_net_ipx.c11
-rw-r--r--net/irda/ircomm/ircomm_tty_ioctl.c2
-rw-r--r--net/irda/irsysctl.c10
-rw-r--r--net/key/af_key.c4
-rw-r--r--net/l2tp/l2tp_core.c1
-rw-r--r--net/l2tp/l2tp_core.h16
-rw-r--r--net/l2tp/l2tp_netlink.c114
-rw-r--r--net/llc/af_llc.c2
-rw-r--r--net/llc/llc_conn.c2
-rw-r--r--net/llc/sysctl_net_llc.c52
-rw-r--r--net/mac80211/Kconfig11
-rw-r--r--net/mac80211/Makefile3
-rw-r--r--net/mac80211/agg-rx.c18
-rw-r--r--net/mac80211/agg-tx.c57
-rw-r--r--net/mac80211/cfg.c64
-rw-r--r--net/mac80211/chan.c26
-rw-r--r--net/mac80211/debugfs_netdev.c83
-rw-r--r--net/mac80211/debugfs_sta.c5
-rw-r--r--net/mac80211/driver-ops.h41
-rw-r--r--net/mac80211/driver-trace.h55
-rw-r--r--net/mac80211/ht.c9
-rw-r--r--net/mac80211/ibss.c22
-rw-r--r--net/mac80211/ieee80211_i.h72
-rw-r--r--net/mac80211/iface.c151
-rw-r--r--net/mac80211/main.c12
-rw-r--r--net/mac80211/mesh.c53
-rw-r--r--net/mac80211/mesh.h25
-rw-r--r--net/mac80211/mesh_hwmp.c33
-rw-r--r--net/mac80211/mesh_pathtbl.c2
-rw-r--r--net/mac80211/mesh_plink.c17
-rw-r--r--net/mac80211/mesh_sync.c316
-rw-r--r--net/mac80211/mlme.c338
-rw-r--r--net/mac80211/pm.c4
-rw-r--r--net/mac80211/rate.h7
-rw-r--r--net/mac80211/rc80211_minstrel.c13
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c20
-rw-r--r--net/mac80211/rx.c10
-rw-r--r--net/mac80211/scan.c43
-rw-r--r--net/mac80211/sta_info.c16
-rw-r--r--net/mac80211/sta_info.h11
-rw-r--r--net/mac80211/status.c8
-rw-r--r--net/mac80211/tx.c83
-rw-r--r--net/mac80211/util.c235
-rw-r--r--net/mac80211/wme.c46
-rw-r--r--net/mac80211/wme.h3
-rw-r--r--net/mac80211/work.c15
-rw-r--r--net/netfilter/core.c9
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ip.c33
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ipmac.c43
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_port.c29
-rw-r--r--net/netfilter/ipset/ip_set_core.c49
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c20
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c37
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c45
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c69
-rw-r--r--net/netfilter/ipset/ip_set_hash_net.c45
-rw-r--r--net/netfilter/ipset/ip_set_hash_netiface.c52
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c61
-rw-r--r--net/netfilter/ipset/ip_set_list_set.c23
-rw-r--r--net/netfilter/ipvs/ip_vs_app.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c34
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c144
-rw-r--r--net/netfilter/ipvs/ip_vs_dh.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_ftp.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_lblc.c9
-rw-r--r--net/netfilter/ipvs/ip_vs_lblcr.c9
-rw-r--r--net/netfilter/ipvs/ip_vs_proto.c12
-rw-r--r--net/netfilter/ipvs/ip_vs_sh.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c6
-rw-r--r--net/netfilter/nf_conntrack_acct.c4
-rw-r--r--net/netfilter/nf_conntrack_core.c5
-rw-r--r--net/netfilter/nf_conntrack_ecache.c3
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c2
-rw-r--r--net/netfilter/nf_conntrack_netlink.c83
-rw-r--r--net/netfilter/nf_conntrack_proto.c10
-rw-r--r--net/netfilter/nf_conntrack_proto_dccp.c22
-rw-r--r--net/netfilter/nf_conntrack_proto_generic.c3
-rw-r--r--net/netfilter/nf_conntrack_proto_gre.c9
-rw-r--r--net/netfilter/nf_conntrack_proto_sctp.c22
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c68
-rw-r--r--net/netfilter/nf_conntrack_proto_udp.c9
-rw-r--r--net/netfilter/nf_conntrack_proto_udplite.c9
-rw-r--r--net/netfilter/nf_conntrack_standalone.c14
-rw-r--r--net/netfilter/nf_conntrack_timestamp.c4
-rw-r--r--net/netfilter/nf_log.c9
-rw-r--r--net/netfilter/nfnetlink.c2
-rw-r--r--net/netfilter/nfnetlink_acct.c10
-rw-r--r--net/netfilter/nfnetlink_cttimeout.c11
-rw-r--r--net/netfilter/nfnetlink_log.c100
-rw-r--r--net/netfilter/nfnetlink_queue.c59
-rw-r--r--net/netfilter/xt_recent.c2
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/netlink/genetlink.c35
-rw-r--r--net/netrom/nr_dev.c2
-rw-r--r--net/netrom/sysctl_net_netrom.c10
-rw-r--r--net/nfc/Kconfig1
-rw-r--r--net/nfc/Makefile1
-rw-r--r--net/nfc/core.c144
-rw-r--r--net/nfc/hci/Kconfig16
-rw-r--r--net/nfc/hci/Makefile8
-rw-r--r--net/nfc/hci/command.c354
-rw-r--r--net/nfc/hci/core.c830
-rw-r--r--net/nfc/hci/hci.h139
-rw-r--r--net/nfc/hci/hcp.c156
-rw-r--r--net/nfc/hci/shdlc.c945
-rw-r--r--net/nfc/llcp/commands.c8
-rw-r--r--net/nfc/llcp/llcp.c21
-rw-r--r--net/nfc/nci/core.c2
-rw-r--r--net/nfc/nci/ntf.c11
-rw-r--r--net/nfc/netlink.c101
-rw-r--r--net/nfc/nfc.h3
-rw-r--r--net/nfc/rawsock.c6
-rw-r--r--net/openvswitch/datapath.c34
-rw-r--r--net/openvswitch/flow.c18
-rw-r--r--net/openvswitch/vport-netdev.c4
-rw-r--r--net/packet/af_packet.c50
-rw-r--r--net/phonet/af_phonet.c2
-rw-r--r--net/phonet/pep.c8
-rw-r--r--net/phonet/pn_dev.c4
-rw-r--r--net/phonet/pn_netlink.c8
-rw-r--r--net/phonet/socket.c12
-rw-r--r--net/phonet/sysctl.c17
-rw-r--r--net/rds/ib_sysctl.c11
-rw-r--r--net/rds/iw_sysctl.c11
-rw-r--r--net/rds/sysctl.c11
-rw-r--r--net/rds/tcp_listen.c2
-rw-r--r--net/rose/rose_dev.c2
-rw-r--r--net/rose/rose_subr.c2
-rw-r--r--net/rose/sysctl_net_rose.c10
-rw-r--r--net/rxrpc/af_rxrpc.c8
-rw-r--r--net/rxrpc/ar-ack.c6
-rw-r--r--net/rxrpc/ar-call.c4
-rw-r--r--net/rxrpc/ar-input.c2
-rw-r--r--net/rxrpc/ar-internal.h16
-rw-r--r--net/rxrpc/ar-key.c22
-rw-r--r--net/rxrpc/rxkad.c6
-rw-r--r--net/sched/act_api.c9
-rw-r--r--net/sched/act_csum.c6
-rw-r--r--net/sched/act_gact.c9
-rw-r--r--net/sched/act_ipt.c14
-rw-r--r--net/sched/act_mirred.c6
-rw-r--r--net/sched/act_nat.c6
-rw-r--r--net/sched/act_pedit.c6
-rw-r--r--net/sched/act_police.c13
-rw-r--r--net/sched/act_simple.c8
-rw-r--r--net/sched/act_skbedit.c27
-rw-r--r--net/sched/cls_api.c3
-rw-r--r--net/sched/cls_basic.c5
-rw-r--r--net/sched/cls_flow.c35
-rw-r--r--net/sched/cls_fw.c15
-rw-r--r--net/sched/cls_route.c16
-rw-r--r--net/sched/cls_rsvp.h16
-rw-r--r--net/sched/cls_tcindex.c14
-rw-r--r--net/sched/cls_u32.c40
-rw-r--r--net/sched/em_meta.c19
-rw-r--r--net/sched/ematch.c6
-rw-r--r--net/sched/sch_api.c9
-rw-r--r--net/sched/sch_atm.c21
-rw-r--r--net/sched/sch_cbq.c18
-rw-r--r--net/sched/sch_choke.c5
-rw-r--r--net/sched/sch_drr.c3
-rw-r--r--net/sched/sch_dsmark.c18
-rw-r--r--net/sched/sch_fifo.c3
-rw-r--r--net/sched/sch_generic.c3
-rw-r--r--net/sched/sch_gred.c6
-rw-r--r--net/sched/sch_hfsc.c6
-rw-r--r--net/sched/sch_htb.c6
-rw-r--r--net/sched/sch_mqprio.c3
-rw-r--r--net/sched/sch_multiq.c3
-rw-r--r--net/sched/sch_netem.c21
-rw-r--r--net/sched/sch_prio.c3
-rw-r--r--net/sched/sch_qfq.c5
-rw-r--r--net/sched/sch_red.c5
-rw-r--r--net/sched/sch_sfb.c3
-rw-r--r--net/sched/sch_sfq.c3
-rw-r--r--net/sched/sch_tbf.c3
-rw-r--r--net/sctp/associola.c4
-rw-r--r--net/sctp/input.c4
-rw-r--r--net/sctp/output.c4
-rw-r--r--net/sctp/outqueue.c2
-rw-r--r--net/sctp/sm_sideeffect.c4
-rw-r--r--net/sctp/sm_statefuns.c4
-rw-r--r--net/sctp/sysctl.c10
-rw-r--r--net/socket.c61
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c2
-rw-r--r--net/sunrpc/cache.c2
-rw-r--r--net/sunrpc/svcsock.c2
-rw-r--r--net/sunrpc/timer.c6
-rw-r--r--net/sunrpc/xdr.c2
-rw-r--r--net/sunrpc/xprt.c2
-rw-r--r--net/sysctl_net.c45
-rw-r--r--net/tipc/addr.h20
-rw-r--r--net/tipc/bearer.c2
-rw-r--r--net/tipc/config.c2
-rw-r--r--net/tipc/link.c2
-rw-r--r--net/tipc/name_distr.c119
-rw-r--r--net/tipc/name_table.c14
-rw-r--r--net/tipc/net.c3
-rw-r--r--net/tipc/node.c2
-rw-r--r--net/tipc/node_subscr.c2
-rw-r--r--net/tipc/port.c101
-rw-r--r--net/tipc/port.h11
-rw-r--r--net/tipc/socket.c13
-rw-r--r--net/unix/af_unix.c36
-rw-r--r--net/unix/sysctl_net_unix.c10
-rw-r--r--net/wimax/stack.c5
-rw-r--r--net/wireless/core.c9
-rw-r--r--net/wireless/mesh.c3
-rw-r--r--net/wireless/mlme.c59
-rw-r--r--net/wireless/nl80211.c1276
-rw-r--r--net/wireless/nl80211.h4
-rw-r--r--net/wireless/reg.c10
-rw-r--r--net/wireless/scan.c4
-rw-r--r--net/wireless/util.c10
-rw-r--r--net/wireless/wext-compat.c3
-rw-r--r--net/wireless/wext-core.c9
-rw-r--r--net/x25/sysctl_net_x25.c10
-rw-r--r--net/x25/x25_dev.c2
-rw-r--r--net/x25/x25_facilities.c4
-rw-r--r--net/xfrm/xfrm_hash.h8
-rw-r--r--net/xfrm/xfrm_sysctl.c2
-rw-r--r--net/xfrm/xfrm_user.c105
398 files changed, 10939 insertions, 4936 deletions
diff --git a/net/802/fc.c b/net/802/fc.c
index b324e31401a9..05eea6b98bb8 100644
--- a/net/802/fc.c
+++ b/net/802/fc.c
@@ -35,7 +35,7 @@
static int fc_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
- const void *daddr, const void *saddr, unsigned len)
+ const void *daddr, const void *saddr, unsigned int len)
{
struct fch_hdr *fch;
int hdr_len;
diff --git a/net/802/fddi.c b/net/802/fddi.c
index 5ab25cd4314b..9cda40661e0d 100644
--- a/net/802/fddi.c
+++ b/net/802/fddi.c
@@ -51,7 +51,7 @@
static int fddi_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
- const void *daddr, const void *saddr, unsigned len)
+ const void *daddr, const void *saddr, unsigned int len)
{
int hl = FDDI_K_SNAP_HLEN;
struct fddihdr *fddi;
diff --git a/net/802/garp.c b/net/802/garp.c
index a5c224830439..8456f5d98b85 100644
--- a/net/802/garp.c
+++ b/net/802/garp.c
@@ -157,9 +157,9 @@ static struct garp_attr *garp_attr_lookup(const struct garp_applicant *app,
while (parent) {
attr = rb_entry(parent, struct garp_attr, node);
d = garp_attr_cmp(attr, data, len, type);
- if (d < 0)
+ if (d > 0)
parent = parent->rb_left;
- else if (d > 0)
+ else if (d < 0)
parent = parent->rb_right;
else
return attr;
@@ -178,9 +178,9 @@ static struct garp_attr *garp_attr_create(struct garp_applicant *app,
parent = *p;
attr = rb_entry(parent, struct garp_attr, node);
d = garp_attr_cmp(attr, data, len, type);
- if (d < 0)
+ if (d > 0)
p = &parent->rb_left;
- else if (d > 0)
+ else if (d < 0)
p = &parent->rb_right;
else {
/* The attribute already exists; re-use it. */
diff --git a/net/802/hippi.c b/net/802/hippi.c
index 056794e66375..51a1f530417d 100644
--- a/net/802/hippi.c
+++ b/net/802/hippi.c
@@ -45,7 +45,7 @@
static int hippi_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
- const void *daddr, const void *saddr, unsigned len)
+ const void *daddr, const void *saddr, unsigned int len)
{
struct hippi_hdr *hip = (struct hippi_hdr *)skb_push(skb, HIPPI_HLEN);
struct hippi_cb *hcb = (struct hippi_cb *) skb->cb;
diff --git a/net/802/tr.c b/net/802/tr.c
index b9a3a145e348..30a352ed09b1 100644
--- a/net/802/tr.c
+++ b/net/802/tr.c
@@ -101,7 +101,7 @@ static inline unsigned long rif_hash(const unsigned char *addr)
static int tr_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
- const void *daddr, const void *saddr, unsigned len)
+ const void *daddr, const void *saddr, unsigned int len)
{
struct trh_hdr *trh;
int hdr_len;
@@ -193,7 +193,7 @@ __be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev)
struct trh_hdr *trh;
struct trllc *trllc;
- unsigned riflen=0;
+ unsigned int riflen=0;
skb->dev = dev;
skb_reset_mac_header(skb);
@@ -643,12 +643,6 @@ static struct ctl_table tr_table[] = {
},
{ },
};
-
-static __initdata struct ctl_path tr_path[] = {
- { .procname = "net", },
- { .procname = "token-ring", },
- { }
-};
#endif
/*
@@ -662,7 +656,7 @@ static int __init rif_init(void)
setup_timer(&rif_timer, rif_check_expire, 0);
add_timer(&rif_timer);
#ifdef CONFIG_SYSCTL
- register_sysctl_paths(tr_path, tr_table);
+ register_net_sysctl(&init_net, "net/token-ring", tr_table);
#endif
proc_net_fops_create(&init_net, "tr_rif", S_IRUGO, &rif_seq_fops);
return 0;
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index 50711368ad6a..708c80ea1874 100644
--- a/net/8021q/vlan_netlink.c
+++ b/net/8021q/vlan_netlink.c
@@ -166,11 +166,13 @@ static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
struct nlattr *nest;
unsigned int i;
- NLA_PUT_U16(skb, IFLA_VLAN_ID, vlan_dev_priv(dev)->vlan_id);
+ if (nla_put_u16(skb, IFLA_VLAN_ID, vlan_dev_priv(dev)->vlan_id))
+ goto nla_put_failure;
if (vlan->flags) {
f.flags = vlan->flags;
f.mask = ~0;
- NLA_PUT(skb, IFLA_VLAN_FLAGS, sizeof(f), &f);
+ if (nla_put(skb, IFLA_VLAN_FLAGS, sizeof(f), &f))
+ goto nla_put_failure;
}
if (vlan->nr_ingress_mappings) {
nest = nla_nest_start(skb, IFLA_VLAN_INGRESS_QOS);
@@ -183,8 +185,9 @@ static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
m.from = i;
m.to = vlan->ingress_priority_map[i];
- NLA_PUT(skb, IFLA_VLAN_QOS_MAPPING,
- sizeof(m), &m);
+ if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
+ sizeof(m), &m))
+ goto nla_put_failure;
}
nla_nest_end(skb, nest);
}
@@ -202,8 +205,9 @@ static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
m.from = pm->priority;
m.to = (pm->vlan_qos >> 13) & 0x7;
- NLA_PUT(skb, IFLA_VLAN_QOS_MAPPING,
- sizeof(m), &m);
+ if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
+ sizeof(m), &m))
+ goto nla_put_failure;
}
}
nla_nest_end(skb, nest);
diff --git a/net/9p/client.c b/net/9p/client.c
index b23a17c431c8..a170893d70e0 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -1530,7 +1530,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n",
- fid->fid, (long long unsigned) offset, count);
+ fid->fid, (unsigned long long) offset, count);
err = 0;
clnt = fid->clnt;
@@ -1605,7 +1605,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
struct p9_req_t *req;
p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n",
- fid->fid, (long long unsigned) offset, count);
+ fid->fid, (unsigned long long) offset, count);
err = 0;
clnt = fid->clnt;
@@ -2040,7 +2040,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
char *dataptr;
p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
- fid->fid, (long long unsigned) offset, count);
+ fid->fid, (unsigned long long) offset, count);
err = 0;
clnt = fid->clnt;
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index fccae26fa674..6449bae15702 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -513,7 +513,7 @@ error:
clear_bit(Wworksched, &m->wsched);
}
-static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
+static int p9_pollwake(wait_queue_t *wait, unsigned int mode, int sync, void *key)
{
struct p9_poll_wait *pwait =
container_of(wait, struct p9_poll_wait, wait);
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index bfa9ab93eda5..0301b328cf0f 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -63,7 +63,7 @@
#include <net/tcp_states.h>
#include <net/route.h>
#include <linux/atalk.h>
-#include "../core/kmap_skb.h"
+#include <linux/highmem.h>
struct datalink_proto *ddp_dl, *aarp_dl;
static const struct proto_ops atalk_dgram_ops;
@@ -960,10 +960,10 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,
if (copy > len)
copy = len;
- vaddr = kmap_skb_frag(frag);
+ vaddr = kmap_atomic(skb_frag_page(frag));
sum = atalk_sum_partial(vaddr + frag->page_offset +
offset - start, copy, sum);
- kunmap_skb_frag(vaddr);
+ kunmap_atomic(vaddr);
if (!(len -= copy))
return sum;
diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c
index 04e9c0da7aa9..ebb864361f7a 100644
--- a/net/appletalk/sysctl_net_atalk.c
+++ b/net/appletalk/sysctl_net_atalk.c
@@ -42,20 +42,14 @@ static struct ctl_table atalk_table[] = {
{ },
};
-static struct ctl_path atalk_path[] = {
- { .procname = "net", },
- { .procname = "appletalk", },
- { }
-};
-
static struct ctl_table_header *atalk_table_header;
void atalk_register_sysctl(void)
{
- atalk_table_header = register_sysctl_paths(atalk_path, atalk_table);
+ atalk_table_header = register_net_sysctl(&init_net, "net/appletalk", atalk_table);
}
void atalk_unregister_sysctl(void)
{
- unregister_sysctl_table(atalk_table_header);
+ unregister_net_sysctl_table(atalk_table_header);
}
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 353fccf1cde3..4819d31533e0 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -73,7 +73,7 @@ struct br2684_vcc {
#ifdef CONFIG_ATM_BR2684_IPFILTER
struct br2684_filter filter;
#endif /* CONFIG_ATM_BR2684_IPFILTER */
- unsigned copies_needed, copies_failed;
+ unsigned int copies_needed, copies_failed;
};
struct br2684_dev {
diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c
index 53e500292271..5bdd300db0f7 100644
--- a/net/atm/mpoa_proc.c
+++ b/net/atm/mpoa_proc.c
@@ -207,7 +207,7 @@ static ssize_t proc_mpc_write(struct file *file, const char __user *buff,
size_t nbytes, loff_t *ppos)
{
char *page, *p;
- unsigned len;
+ unsigned int len;
if (nbytes == 0)
return 0;
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
index 614d3fc47ede..ce1e59fdae7b 100644
--- a/net/atm/pppoatm.c
+++ b/net/atm/pppoatm.c
@@ -62,12 +62,25 @@ struct pppoatm_vcc {
void (*old_pop)(struct atm_vcc *, struct sk_buff *);
/* keep old push/pop for detaching */
enum pppoatm_encaps encaps;
+ atomic_t inflight;
+ unsigned long blocked;
int flags; /* SC_COMP_PROT - compress protocol */
struct ppp_channel chan; /* interface to generic ppp layer */
struct tasklet_struct wakeup_tasklet;
};
/*
+ * We want to allow two packets in the queue. The one that's currently in
+ * flight, and *one* queued up ready for the ATM device to send immediately
+ * from its TX done IRQ. We want to be able to use atomic_inc_not_zero(), so
+ * inflight == -2 represents an empty queue, -1 one packet, and zero means
+ * there are two packets in the queue.
+ */
+#define NONE_INFLIGHT -2
+
+#define BLOCKED 0
+
+/*
* Header used for LLC Encapsulated PPP (4 bytes) followed by the LCP protocol
* ID (0xC021) used in autodetection
*/
@@ -102,16 +115,30 @@ static void pppoatm_wakeup_sender(unsigned long arg)
static void pppoatm_pop(struct atm_vcc *atmvcc, struct sk_buff *skb)
{
struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);
+
pvcc->old_pop(atmvcc, skb);
+ atomic_dec(&pvcc->inflight);
+
/*
- * We don't really always want to do this since it's
- * really inefficient - it would be much better if we could
- * test if we had actually throttled the generic layer.
- * Unfortunately then there would be a nasty SMP race where
- * we could clear that flag just as we refuse another packet.
- * For now we do the safe thing.
+ * We always used to run the wakeup tasklet unconditionally here, for
+ * fear of race conditions where we clear the BLOCKED flag just as we
+ * refuse another packet in pppoatm_send(). This was quite inefficient.
+ *
+ * In fact it's OK. The PPP core will only ever call pppoatm_send()
+ * while holding the channel->downl lock. And ppp_output_wakeup() as
+ * called by the tasklet will *also* grab that lock. So even if another
+ * CPU is in pppoatm_send() right now, the tasklet isn't going to race
+ * with it. The wakeup *will* happen after the other CPU is safely out
+ * of pppoatm_send() again.
+ *
+ * So if the CPU in pppoatm_send() has already set the BLOCKED bit and
+ * it about to return, that's fine. We trigger a wakeup which will
+ * happen later. And if the CPU in pppoatm_send() *hasn't* set the
+ * BLOCKED bit yet, that's fine too because of the double check in
+ * pppoatm_may_send() which is commented there.
*/
- tasklet_schedule(&pvcc->wakeup_tasklet);
+ if (test_and_clear_bit(BLOCKED, &pvcc->blocked))
+ tasklet_schedule(&pvcc->wakeup_tasklet);
}
/*
@@ -184,6 +211,51 @@ error:
ppp_input_error(&pvcc->chan, 0);
}
+static inline int pppoatm_may_send(struct pppoatm_vcc *pvcc, int size)
+{
+ /*
+ * It's not clear that we need to bother with using atm_may_send()
+ * to check we don't exceed sk->sk_sndbuf. If userspace sets a
+ * value of sk_sndbuf which is lower than the MTU, we're going to
+ * block for ever. But the code always did that before we introduced
+ * the packet count limit, so...
+ */
+ if (atm_may_send(pvcc->atmvcc, size) &&
+ atomic_inc_not_zero_hint(&pvcc->inflight, NONE_INFLIGHT))
+ return 1;
+
+ /*
+ * We use test_and_set_bit() rather than set_bit() here because
+ * we need to ensure there's a memory barrier after it. The bit
+ * *must* be set before we do the atomic_inc() on pvcc->inflight.
+ * There's no smp_mb__after_set_bit(), so it's this or abuse
+ * smp_mb__after_clear_bit().
+ */
+ test_and_set_bit(BLOCKED, &pvcc->blocked);
+
+ /*
+ * We may have raced with pppoatm_pop(). If it ran for the
+ * last packet in the queue, *just* before we set the BLOCKED
+ * bit, then it might never run again and the channel could
+ * remain permanently blocked. Cope with that race by checking
+ * *again*. If it did run in that window, we'll have space on
+ * the queue now and can return success. It's harmless to leave
+ * the BLOCKED flag set, since it's only used as a trigger to
+ * run the wakeup tasklet. Another wakeup will never hurt.
+ * If pppoatm_pop() is running but hasn't got as far as making
+ * space on the queue yet, then it hasn't checked the BLOCKED
+ * flag yet either, so we're safe in that case too. It'll issue
+ * an "immediate" wakeup... where "immediate" actually involves
+ * taking the PPP channel's ->downl lock, which is held by the
+ * code path that calls pppoatm_send(), and is thus going to
+ * wait for us to finish.
+ */
+ if (atm_may_send(pvcc->atmvcc, size) &&
+ atomic_inc_not_zero(&pvcc->inflight))
+ return 1;
+
+ return 0;
+}
/*
* Called by the ppp_generic.c to send a packet - returns true if packet
* was accepted. If we return false, then it's our job to call
@@ -207,7 +279,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
struct sk_buff *n;
n = skb_realloc_headroom(skb, LLC_LEN);
if (n != NULL &&
- !atm_may_send(pvcc->atmvcc, n->truesize)) {
+ !pppoatm_may_send(pvcc, n->truesize)) {
kfree_skb(n);
goto nospace;
}
@@ -215,12 +287,12 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
skb = n;
if (skb == NULL)
return DROP_PACKET;
- } else if (!atm_may_send(pvcc->atmvcc, skb->truesize))
+ } else if (!pppoatm_may_send(pvcc, skb->truesize))
goto nospace;
memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN);
break;
case e_vc:
- if (!atm_may_send(pvcc->atmvcc, skb->truesize))
+ if (!pppoatm_may_send(pvcc, skb->truesize))
goto nospace;
break;
case e_autodetect:
@@ -285,6 +357,9 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg)
if (pvcc == NULL)
return -ENOMEM;
pvcc->atmvcc = atmvcc;
+
+ /* Maximum is zero, so that we can use atomic_inc_not_zero() */
+ atomic_set(&pvcc->inflight, NONE_INFLIGHT);
pvcc->old_push = atmvcc->push;
pvcc->old_pop = atmvcc->pop;
pvcc->encaps = (enum pppoatm_encaps) be.encaps;
diff --git a/net/atm/signaling.c b/net/atm/signaling.c
index 509c8ac02b63..86767ca908a3 100644
--- a/net/atm/signaling.c
+++ b/net/atm/signaling.c
@@ -166,7 +166,7 @@ void sigd_enq2(struct atm_vcc *vcc, enum atmsvc_msg_type type,
{
struct sk_buff *skb;
struct atmsvc_msg *msg;
- static unsigned session = 0;
+ static unsigned int session = 0;
pr_debug("%d (0x%p)\n", (int)type, vcc);
while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL)))
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 9d9a6a3edbd5..051f7abae66d 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1990,7 +1990,6 @@ static int __init ax25_init(void)
sock_register(&ax25_family_ops);
dev_add_pack(&ax25_packet_type);
register_netdevice_notifier(&ax25_dev_notifier);
- ax25_register_sysctl();
proc_net_fops_create(&init_net, "ax25_route", S_IRUGO, &ax25_route_fops);
proc_net_fops_create(&init_net, "ax25", S_IRUGO, &ax25_info_fops);
@@ -2013,7 +2012,6 @@ static void __exit ax25_exit(void)
proc_net_remove(&init_net, "ax25_calls");
unregister_netdevice_notifier(&ax25_dev_notifier);
- ax25_unregister_sysctl();
dev_remove_pack(&ax25_packet_type);
diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c
index d0de30e89591..3d106767b272 100644
--- a/net/ax25/ax25_dev.c
+++ b/net/ax25/ax25_dev.c
@@ -59,8 +59,6 @@ void ax25_dev_device_up(struct net_device *dev)
return;
}
- ax25_unregister_sysctl();
-
dev->ax25_ptr = ax25_dev;
ax25_dev->dev = dev;
dev_hold(dev);
@@ -90,7 +88,7 @@ void ax25_dev_device_up(struct net_device *dev)
ax25_dev_list = ax25_dev;
spin_unlock_bh(&ax25_dev_lock);
- ax25_register_sysctl();
+ ax25_register_dev_sysctl(ax25_dev);
}
void ax25_dev_device_down(struct net_device *dev)
@@ -100,7 +98,7 @@ void ax25_dev_device_down(struct net_device *dev)
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
return;
- ax25_unregister_sysctl();
+ ax25_unregister_dev_sysctl(ax25_dev);
spin_lock_bh(&ax25_dev_lock);
@@ -120,7 +118,6 @@ void ax25_dev_device_down(struct net_device *dev)
spin_unlock_bh(&ax25_dev_lock);
dev_put(dev);
kfree(ax25_dev);
- ax25_register_sysctl();
return;
}
@@ -130,7 +127,6 @@ void ax25_dev_device_down(struct net_device *dev)
spin_unlock_bh(&ax25_dev_lock);
dev_put(dev);
kfree(ax25_dev);
- ax25_register_sysctl();
return;
}
@@ -138,8 +134,6 @@ void ax25_dev_device_down(struct net_device *dev)
}
spin_unlock_bh(&ax25_dev_lock);
dev->ax25_ptr = NULL;
-
- ax25_register_sysctl();
}
int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
index 846ae4e2b115..67de6b33f2c3 100644
--- a/net/ax25/ax25_ip.c
+++ b/net/ax25/ax25_ip.c
@@ -48,7 +48,7 @@
int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, const void *daddr,
- const void *saddr, unsigned len)
+ const void *saddr, unsigned int len)
{
unsigned char *buff;
@@ -219,7 +219,7 @@ put:
int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, const void *daddr,
- const void *saddr, unsigned len)
+ const void *saddr, unsigned int len)
{
return -AX25_HEADER_LEN;
}
diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c
index ebe0ef3f1d83..d5744b752511 100644
--- a/net/ax25/sysctl_net_ax25.c
+++ b/net/ax25/sysctl_net_ax25.c
@@ -29,17 +29,6 @@ static int min_proto[1], max_proto[] = { AX25_PROTO_MAX };
static int min_ds_timeout[1], max_ds_timeout[] = {65535000};
#endif
-static struct ctl_table_header *ax25_table_header;
-
-static ctl_table *ax25_table;
-static int ax25_table_size;
-
-static struct ctl_path ax25_path[] = {
- { .procname = "net", },
- { .procname = "ax25", },
- { }
-};
-
static const ctl_table ax25_param_table[] = {
{
.procname = "ip_default_mode",
@@ -159,52 +148,37 @@ static const ctl_table ax25_param_table[] = {
{ } /* that's all, folks! */
};
-void ax25_register_sysctl(void)
+int ax25_register_dev_sysctl(ax25_dev *ax25_dev)
{
- ax25_dev *ax25_dev;
- int n, k;
-
- spin_lock_bh(&ax25_dev_lock);
- for (ax25_table_size = sizeof(ctl_table), ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
- ax25_table_size += sizeof(ctl_table);
-
- if ((ax25_table = kzalloc(ax25_table_size, GFP_ATOMIC)) == NULL) {
- spin_unlock_bh(&ax25_dev_lock);
- return;
- }
-
- for (n = 0, ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) {
- struct ctl_table *child = kmemdup(ax25_param_table,
- sizeof(ax25_param_table),
- GFP_ATOMIC);
- if (!child) {
- while (n--)
- kfree(ax25_table[n].child);
- kfree(ax25_table);
- spin_unlock_bh(&ax25_dev_lock);
- return;
- }
- ax25_table[n].child = ax25_dev->systable = child;
- ax25_table[n].procname = ax25_dev->dev->name;
- ax25_table[n].mode = 0555;
-
-
- for (k = 0; k < AX25_MAX_VALUES; k++)
- child[k].data = &ax25_dev->values[k];
-
- n++;
+ char path[sizeof("net/ax25/") + IFNAMSIZ];
+ int k;
+ struct ctl_table *table;
+
+ table = kmemdup(ax25_param_table, sizeof(ax25_param_table), GFP_KERNEL);
+ if (!table)
+ return -ENOMEM;
+
+ for (k = 0; k < AX25_MAX_VALUES; k++)
+ table[k].data = &ax25_dev->values[k];
+
+ snprintf(path, sizeof(path), "net/ax25/%s", ax25_dev->dev->name);
+ ax25_dev->sysheader = register_net_sysctl(&init_net, path, table);
+ if (!ax25_dev->sysheader) {
+ kfree(table);
+ return -ENOMEM;
}
- spin_unlock_bh(&ax25_dev_lock);
-
- ax25_table_header = register_sysctl_paths(ax25_path, ax25_table);
+ return 0;
}
-void ax25_unregister_sysctl(void)
+void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev)
{
- ctl_table *p;
- unregister_sysctl_table(ax25_table_header);
-
- for (p = ax25_table; p->procname; p++)
- kfree(p->child);
- kfree(ax25_table);
+ struct ctl_table_header *header = ax25_dev->sysheader;
+ struct ctl_table *table;
+
+ if (header) {
+ ax25_dev->sysheader = NULL;
+ table = header->ctl_table_arg;
+ unregister_net_sysctl_table(header);
+ kfree(table);
+ }
}
diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig
index 2b68d068eaf3..53f5244e28f8 100644
--- a/net/batman-adv/Kconfig
+++ b/net/batman-adv/Kconfig
@@ -7,19 +7,28 @@ config BATMAN_ADV
depends on NET
select CRC16
default n
- ---help---
+ help
+ B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is
+ a routing protocol for multi-hop ad-hoc mesh networks. The
+ networks may be wired or wireless. See
+ http://www.open-mesh.org/ for more information and user space
+ tools.
- B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is
- a routing protocol for multi-hop ad-hoc mesh networks. The
- networks may be wired or wireless. See
- http://www.open-mesh.org/ for more information and user space
- tools.
+config BATMAN_ADV_BLA
+ bool "Bridge Loop Avoidance"
+ depends on BATMAN_ADV && INET
+ default y
+ help
+ This option enables BLA (Bridge Loop Avoidance), a mechanism
+ to avoid Ethernet frames looping when mesh nodes are connected
+ to both the same LAN and the same mesh. If you will never use
+ more than one mesh node in the same LAN, you can safely remove
+ this feature and save some space.
config BATMAN_ADV_DEBUG
bool "B.A.T.M.A.N. debugging"
- depends on BATMAN_ADV != n
- ---help---
-
+ depends on BATMAN_ADV
+ help
This is an option for use by developers; most people should
say N here. This enables compilation of support for
outputting debugging information to the kernel log. The
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile
index 4e392ebedb64..6d5c1940667d 100644
--- a/net/batman-adv/Makefile
+++ b/net/batman-adv/Makefile
@@ -23,6 +23,7 @@ batman-adv-y += bat_debugfs.o
batman-adv-y += bat_iv_ogm.o
batman-adv-y += bat_sysfs.o
batman-adv-y += bitarray.o
+batman-adv-$(CONFIG_BATMAN_ADV_BLA) += bridge_loop_avoidance.o
batman-adv-y += gateway_client.o
batman-adv-y += gateway_common.o
batman-adv-y += hard-interface.o
diff --git a/net/batman-adv/bat_debugfs.c b/net/batman-adv/bat_debugfs.c
index c3b0548b175d..916380c73ab7 100644
--- a/net/batman-adv/bat_debugfs.c
+++ b/net/batman-adv/bat_debugfs.c
@@ -32,6 +32,7 @@
#include "soft-interface.h"
#include "vis.h"
#include "icmp_socket.h"
+#include "bridge_loop_avoidance.h"
static struct dentry *bat_debugfs;
@@ -238,17 +239,19 @@ static int gateways_open(struct inode *inode, struct file *file)
return single_open(file, gw_client_seq_print_text, net_dev);
}
-static int softif_neigh_open(struct inode *inode, struct file *file)
+static int transtable_global_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
- return single_open(file, softif_neigh_seq_print_text, net_dev);
+ return single_open(file, tt_global_seq_print_text, net_dev);
}
-static int transtable_global_open(struct inode *inode, struct file *file)
+#ifdef CONFIG_BATMAN_ADV_BLA
+static int bla_claim_table_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
- return single_open(file, tt_global_seq_print_text, net_dev);
+ return single_open(file, bla_claim_table_seq_print_text, net_dev);
}
+#endif
static int transtable_local_open(struct inode *inode, struct file *file)
{
@@ -282,16 +285,20 @@ struct bat_debuginfo bat_debuginfo_##_name = { \
static BAT_DEBUGINFO(routing_algos, S_IRUGO, bat_algorithms_open);
static BAT_DEBUGINFO(originators, S_IRUGO, originators_open);
static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open);
-static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open);
static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open);
+#ifdef CONFIG_BATMAN_ADV_BLA
+static BAT_DEBUGINFO(bla_claim_table, S_IRUGO, bla_claim_table_open);
+#endif
static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open);
static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open);
static struct bat_debuginfo *mesh_debuginfos[] = {
&bat_debuginfo_originators,
&bat_debuginfo_gateways,
- &bat_debuginfo_softif_neigh,
&bat_debuginfo_transtable_global,
+#ifdef CONFIG_BATMAN_ADV_BLA
+ &bat_debuginfo_bla_claim_table,
+#endif
&bat_debuginfo_transtable_local,
&bat_debuginfo_vis_data,
NULL,
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index a6d5d63fb6ad..8b2db2e76c7e 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -30,24 +30,44 @@
#include "send.h"
#include "bat_algo.h"
-static void bat_iv_ogm_init(struct hard_iface *hard_iface)
+static int bat_iv_ogm_iface_enable(struct hard_iface *hard_iface)
{
struct batman_ogm_packet *batman_ogm_packet;
+ uint32_t random_seqno;
+ int res = -1;
- hard_iface->packet_len = BATMAN_OGM_LEN;
+ /* randomize initial seqno to avoid collision */
+ get_random_bytes(&random_seqno, sizeof(random_seqno));
+ atomic_set(&hard_iface->seqno, random_seqno);
+
+ hard_iface->packet_len = BATMAN_OGM_HLEN;
hard_iface->packet_buff = kmalloc(hard_iface->packet_len, GFP_ATOMIC);
+ if (!hard_iface->packet_buff)
+ goto out;
+
batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
- batman_ogm_packet->header.packet_type = BAT_OGM;
+ batman_ogm_packet->header.packet_type = BAT_IV_OGM;
batman_ogm_packet->header.version = COMPAT_VERSION;
batman_ogm_packet->header.ttl = 2;
batman_ogm_packet->flags = NO_FLAGS;
batman_ogm_packet->tq = TQ_MAX_VALUE;
batman_ogm_packet->tt_num_changes = 0;
batman_ogm_packet->ttvn = 0;
+
+ res = 0;
+
+out:
+ return res;
+}
+
+static void bat_iv_ogm_iface_disable(struct hard_iface *hard_iface)
+{
+ kfree(hard_iface->packet_buff);
+ hard_iface->packet_buff = NULL;
}
-static void bat_iv_ogm_init_primary(struct hard_iface *hard_iface)
+static void bat_iv_ogm_primary_iface_set(struct hard_iface *hard_iface)
{
struct batman_ogm_packet *batman_ogm_packet;
@@ -92,7 +112,7 @@ static uint8_t hop_penalty(uint8_t tq, const struct bat_priv *bat_priv)
static int bat_iv_ogm_aggr_packet(int buff_pos, int packet_len,
int tt_num_changes)
{
- int next_buff_pos = buff_pos + BATMAN_OGM_LEN + tt_len(tt_num_changes);
+ int next_buff_pos = buff_pos + BATMAN_OGM_HLEN + tt_len(tt_num_changes);
return (next_buff_pos <= packet_len) &&
(next_buff_pos <= MAX_AGGREGATION_BYTES);
@@ -132,7 +152,7 @@ static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet,
"Sending own" :
"Forwarding"));
bat_dbg(DBG_BATMAN, bat_priv,
- "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d, IDF %s, ttvn %d) on interface %s [%pM]\n",
+ "%s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s, ttvn %d) on interface %s [%pM]\n",
fwd_str, (packet_num > 0 ? "aggregated " : ""),
batman_ogm_packet->orig,
ntohl(batman_ogm_packet->seqno),
@@ -142,7 +162,7 @@ static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet,
batman_ogm_packet->ttvn, hard_iface->net_dev->name,
hard_iface->net_dev->dev_addr);
- buff_pos += BATMAN_OGM_LEN +
+ buff_pos += BATMAN_OGM_HLEN +
tt_len(batman_ogm_packet->tt_num_changes);
packet_num++;
batman_ogm_packet = (struct batman_ogm_packet *)
@@ -191,7 +211,7 @@ static void bat_iv_ogm_emit(struct forw_packet *forw_packet)
/* FIXME: what about aggregated packets ? */
bat_dbg(DBG_BATMAN, bat_priv,
- "%s packet (originator %pM, seqno %d, TTL %d) on interface %s [%pM]\n",
+ "%s packet (originator %pM, seqno %u, TTL %d) on interface %s [%pM]\n",
(forw_packet->own ? "Sending own" : "Forwarding"),
batman_ogm_packet->orig,
ntohl(batman_ogm_packet->seqno),
@@ -335,10 +355,9 @@ static void bat_iv_ogm_aggregate_new(const unsigned char *packet_buff,
if ((atomic_read(&bat_priv->aggregated_ogms)) &&
(packet_len < MAX_AGGREGATION_BYTES))
forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES +
- sizeof(struct ethhdr));
+ ETH_HLEN);
else
- forw_packet_aggr->skb = dev_alloc_skb(packet_len +
- sizeof(struct ethhdr));
+ forw_packet_aggr->skb = dev_alloc_skb(packet_len + ETH_HLEN);
if (!forw_packet_aggr->skb) {
if (!own_packet)
@@ -346,7 +365,7 @@ static void bat_iv_ogm_aggregate_new(const unsigned char *packet_buff,
kfree(forw_packet_aggr);
goto out;
}
- skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr));
+ skb_reserve(forw_packet_aggr->skb, ETH_HLEN);
INIT_HLIST_NODE(&forw_packet_aggr->list);
@@ -520,7 +539,7 @@ static void bat_iv_ogm_forward(struct orig_node *orig_node,
batman_ogm_packet->flags &= ~DIRECTLINK;
bat_iv_ogm_queue_add(bat_priv, (unsigned char *)batman_ogm_packet,
- BATMAN_OGM_LEN + tt_len(tt_num_changes),
+ BATMAN_OGM_HLEN + tt_len(tt_num_changes),
if_incoming, 0, bat_iv_ogm_fwd_send_time());
}
@@ -842,7 +861,8 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
seq_diff = batman_ogm_packet->seqno - orig_node->last_real_seqno;
/* signalize caller that the packet is to be dropped. */
- if (window_protected(bat_priv, seq_diff,
+ if (!hlist_empty(&orig_node->neigh_list) &&
+ window_protected(bat_priv, seq_diff,
&orig_node->batman_seqno_reset))
goto out;
@@ -850,9 +870,9 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
hlist_for_each_entry_rcu(tmp_neigh_node, node,
&orig_node->neigh_list, list) {
- is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,
- orig_node->last_real_seqno,
- batman_ogm_packet->seqno);
+ is_duplicate |= bat_test_bit(tmp_neigh_node->real_bits,
+ orig_node->last_real_seqno,
+ batman_ogm_packet->seqno);
if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
(tmp_neigh_node->if_incoming == if_incoming))
@@ -866,13 +886,14 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
seq_diff, set_mark);
tmp_neigh_node->real_packet_count =
- bit_packet_count(tmp_neigh_node->real_bits);
+ bitmap_weight(tmp_neigh_node->real_bits,
+ TQ_LOCAL_WINDOW_SIZE);
}
rcu_read_unlock();
if (need_update) {
bat_dbg(DBG_BATMAN, bat_priv,
- "updating last_seqno: old %d, new %d\n",
+ "updating last_seqno: old %u, new %u\n",
orig_node->last_real_seqno, batman_ogm_packet->seqno);
orig_node->last_real_seqno = batman_ogm_packet->seqno;
}
@@ -913,7 +934,7 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
* packet in an aggregation. Here we expect that the padding
* is always zero (or not 0x01)
*/
- if (batman_ogm_packet->header.packet_type != BAT_OGM)
+ if (batman_ogm_packet->header.packet_type != BAT_IV_OGM)
return;
/* could be changed by schedule_own_packet() */
@@ -925,7 +946,7 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
batman_ogm_packet->orig) ? 1 : 0);
bat_dbg(DBG_BATMAN, bat_priv,
- "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
+ "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, ttvn %u, crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
ethhdr->h_source, if_incoming->net_dev->name,
if_incoming->net_dev->dev_addr, batman_ogm_packet->orig,
batman_ogm_packet->prev_sender, batman_ogm_packet->seqno,
@@ -998,11 +1019,11 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);
word = &(orig_neigh_node->bcast_own[offset]);
- bit_mark(word,
- if_incoming_seqno -
+ bat_set_bit(word,
+ if_incoming_seqno -
batman_ogm_packet->seqno - 2);
orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
- bit_packet_count(word);
+ bitmap_weight(word, TQ_LOCAL_WINDOW_SIZE);
spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
}
@@ -1152,12 +1173,12 @@ static void bat_iv_ogm_receive(struct hard_iface *if_incoming,
batman_ogm_packet->seqno = ntohl(batman_ogm_packet->seqno);
batman_ogm_packet->tt_crc = ntohs(batman_ogm_packet->tt_crc);
- tt_buff = packet_buff + buff_pos + BATMAN_OGM_LEN;
+ tt_buff = packet_buff + buff_pos + BATMAN_OGM_HLEN;
bat_iv_ogm_process(ethhdr, batman_ogm_packet,
tt_buff, if_incoming);
- buff_pos += BATMAN_OGM_LEN +
+ buff_pos += BATMAN_OGM_HLEN +
tt_len(batman_ogm_packet->tt_num_changes);
batman_ogm_packet = (struct batman_ogm_packet *)
@@ -1168,8 +1189,9 @@ static void bat_iv_ogm_receive(struct hard_iface *if_incoming,
static struct bat_algo_ops batman_iv __read_mostly = {
.name = "BATMAN IV",
- .bat_ogm_init = bat_iv_ogm_init,
- .bat_ogm_init_primary = bat_iv_ogm_init_primary,
+ .bat_iface_enable = bat_iv_ogm_iface_enable,
+ .bat_iface_disable = bat_iv_ogm_iface_disable,
+ .bat_primary_iface_set = bat_iv_ogm_primary_iface_set,
.bat_ogm_update_mac = bat_iv_ogm_update_mac,
.bat_ogm_schedule = bat_iv_ogm_schedule,
.bat_ogm_emit = bat_iv_ogm_emit,
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c
index 68ff759fc304..2c816883ca13 100644
--- a/net/batman-adv/bat_sysfs.c
+++ b/net/batman-adv/bat_sysfs.c
@@ -149,7 +149,7 @@ static int store_bool_attr(char *buff, size_t count,
atomic_read(attr) == 1 ? "enabled" : "disabled",
enabled == 1 ? "enabled" : "disabled");
- atomic_set(attr, (unsigned)enabled);
+ atomic_set(attr, (unsigned int)enabled);
return count;
}
@@ -268,7 +268,7 @@ static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr,
"client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ?
"client" : "server");
- atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp);
+ atomic_set(&bat_priv->vis_mode, (unsigned int)vis_mode_tmp);
return count;
}
@@ -354,7 +354,7 @@ static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr,
curr_gw_mode_str, buff);
gw_deselect(bat_priv);
- atomic_set(&bat_priv->gw_mode, (unsigned)gw_mode_tmp);
+ atomic_set(&bat_priv->gw_mode, (unsigned int)gw_mode_tmp);
return count;
}
@@ -386,6 +386,9 @@ static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr,
BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
+#ifdef CONFIG_BATMAN_ADV_BLA
+BAT_ATTR_BOOL(bridge_loop_avoidance, S_IRUGO | S_IWUSR, NULL);
+#endif
BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu);
BAT_ATTR_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL);
static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
@@ -398,12 +401,15 @@ BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth,
store_gw_bwidth);
#ifdef CONFIG_BATMAN_ADV_DEBUG
-BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 7, NULL);
+BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 15, NULL);
#endif
static struct bat_attribute *mesh_attrs[] = {
&bat_attr_aggregated_ogms,
&bat_attr_bonding,
+#ifdef CONFIG_BATMAN_ADV_BLA
+ &bat_attr_bridge_loop_avoidance,
+#endif
&bat_attr_fragmentation,
&bat_attr_ap_isolation,
&bat_attr_vis_mode,
diff --git a/net/batman-adv/bitarray.c b/net/batman-adv/bitarray.c
index 6d0aa216b232..07ae6e1b8aca 100644
--- a/net/batman-adv/bitarray.c
+++ b/net/batman-adv/bitarray.c
@@ -24,100 +24,13 @@
#include <linux/bitops.h>
-/* returns true if the corresponding bit in the given seq_bits indicates true
- * and curr_seqno is within range of last_seqno */
-int get_bit_status(const unsigned long *seq_bits, uint32_t last_seqno,
- uint32_t curr_seqno)
-{
- int32_t diff, word_offset, word_num;
-
- diff = last_seqno - curr_seqno;
- if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE) {
- return 0;
- } else {
- /* which word */
- word_num = (last_seqno - curr_seqno) / WORD_BIT_SIZE;
- /* which position in the selected word */
- word_offset = (last_seqno - curr_seqno) % WORD_BIT_SIZE;
-
- if (test_bit(word_offset, &seq_bits[word_num]))
- return 1;
- else
- return 0;
- }
-}
-
-/* turn corresponding bit on, so we can remember that we got the packet */
-void bit_mark(unsigned long *seq_bits, int32_t n)
-{
- int32_t word_offset, word_num;
-
- /* if too old, just drop it */
- if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE)
- return;
-
- /* which word */
- word_num = n / WORD_BIT_SIZE;
- /* which position in the selected word */
- word_offset = n % WORD_BIT_SIZE;
-
- set_bit(word_offset, &seq_bits[word_num]); /* turn the position on */
-}
-
/* shift the packet array by n places. */
-static void bit_shift(unsigned long *seq_bits, int32_t n)
+static void bat_bitmap_shift_left(unsigned long *seq_bits, int32_t n)
{
- int32_t word_offset, word_num;
- int32_t i;
-
if (n <= 0 || n >= TQ_LOCAL_WINDOW_SIZE)
return;
- word_offset = n % WORD_BIT_SIZE;/* shift how much inside each word */
- word_num = n / WORD_BIT_SIZE; /* shift over how much (full) words */
-
- for (i = NUM_WORDS - 1; i > word_num; i--) {
- /* going from old to new, so we don't overwrite the data we copy
- * from.
- *
- * left is high, right is low: FEDC BA98 7654 3210
- * ^^ ^^
- * vvvv
- * ^^^^ = from, vvvvv =to, we'd have word_num==1 and
- * word_offset==WORD_BIT_SIZE/2 ????? in this example.
- * (=24 bits)
- *
- * our desired output would be: 9876 5432 1000 0000
- * */
-
- seq_bits[i] =
- (seq_bits[i - word_num] << word_offset) +
- /* take the lower port from the left half, shift it left
- * to its final position */
- (seq_bits[i - word_num - 1] >>
- (WORD_BIT_SIZE-word_offset));
- /* and the upper part of the right half and shift it left to
- * its position */
- /* for our example that would be: word[0] = 9800 + 0076 =
- * 9876 */
- }
- /* now for our last word, i==word_num, we only have its "left" half.
- * that's the 1000 word in our example.*/
-
- seq_bits[i] = (seq_bits[i - word_num] << word_offset);
-
- /* pad the rest with 0, if there is anything */
- i--;
-
- for (; i >= 0; i--)
- seq_bits[i] = 0;
-}
-
-static void bit_reset_window(unsigned long *seq_bits)
-{
- int i;
- for (i = 0; i < NUM_WORDS; i++)
- seq_bits[i] = 0;
+ bitmap_shift_left(seq_bits, seq_bits, n, TQ_LOCAL_WINDOW_SIZE);
}
@@ -137,7 +50,7 @@ int bit_get_packet(void *priv, unsigned long *seq_bits,
if ((seq_num_diff <= 0) && (seq_num_diff > -TQ_LOCAL_WINDOW_SIZE)) {
if (set_mark)
- bit_mark(seq_bits, -seq_num_diff);
+ bat_set_bit(seq_bits, -seq_num_diff);
return 0;
}
@@ -145,10 +58,10 @@ int bit_get_packet(void *priv, unsigned long *seq_bits,
* set the mark if required */
if ((seq_num_diff > 0) && (seq_num_diff < TQ_LOCAL_WINDOW_SIZE)) {
- bit_shift(seq_bits, seq_num_diff);
+ bat_bitmap_shift_left(seq_bits, seq_num_diff);
if (set_mark)
- bit_mark(seq_bits, 0);
+ bat_set_bit(seq_bits, 0);
return 1;
}
@@ -159,9 +72,9 @@ int bit_get_packet(void *priv, unsigned long *seq_bits,
bat_dbg(DBG_BATMAN, bat_priv,
"We missed a lot of packets (%i) !\n",
seq_num_diff - 1);
- bit_reset_window(seq_bits);
+ bitmap_zero(seq_bits, TQ_LOCAL_WINDOW_SIZE);
if (set_mark)
- bit_mark(seq_bits, 0);
+ bat_set_bit(seq_bits, 0);
return 1;
}
@@ -176,9 +89,9 @@ int bit_get_packet(void *priv, unsigned long *seq_bits,
bat_dbg(DBG_BATMAN, bat_priv,
"Other host probably restarted!\n");
- bit_reset_window(seq_bits);
+ bitmap_zero(seq_bits, TQ_LOCAL_WINDOW_SIZE);
if (set_mark)
- bit_mark(seq_bits, 0);
+ bat_set_bit(seq_bits, 0);
return 1;
}
@@ -186,16 +99,3 @@ int bit_get_packet(void *priv, unsigned long *seq_bits,
/* never reached */
return 0;
}
-
-/* count the hamming weight, how many good packets did we receive? just count
- * the 1's.
- */
-int bit_packet_count(const unsigned long *seq_bits)
-{
- int i, hamming = 0;
-
- for (i = 0; i < NUM_WORDS; i++)
- hamming += hweight_long(seq_bits[i]);
-
- return hamming;
-}
diff --git a/net/batman-adv/bitarray.h b/net/batman-adv/bitarray.h
index c6135728a680..1835c15cda41 100644
--- a/net/batman-adv/bitarray.h
+++ b/net/batman-adv/bitarray.h
@@ -22,23 +22,33 @@
#ifndef _NET_BATMAN_ADV_BITARRAY_H_
#define _NET_BATMAN_ADV_BITARRAY_H_
-#define WORD_BIT_SIZE (sizeof(unsigned long) * 8)
-
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
-int get_bit_status(const unsigned long *seq_bits, uint32_t last_seqno,
- uint32_t curr_seqno);
+static inline int bat_test_bit(const unsigned long *seq_bits,
+ uint32_t last_seqno, uint32_t curr_seqno)
+{
+ int32_t diff;
+
+ diff = last_seqno - curr_seqno;
+ if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE)
+ return 0;
+ else
+ return test_bit(diff, seq_bits);
+}
/* turn corresponding bit on, so we can remember that we got the packet */
-void bit_mark(unsigned long *seq_bits, int32_t n);
+static inline void bat_set_bit(unsigned long *seq_bits, int32_t n)
+{
+ /* if too old, just drop it */
+ if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE)
+ return;
+ set_bit(n, seq_bits); /* turn the position on */
+}
/* receive and process one packet, returns 1 if received seq_num is considered
* new, 0 if old */
int bit_get_packet(void *priv, unsigned long *seq_bits,
int32_t seq_num_diff, int set_mark);
-/* count the hamming weight, how many good packets did we receive? */
-int bit_packet_count(const unsigned long *seq_bits);
-
#endif /* _NET_BATMAN_ADV_BITARRAY_H_ */
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
new file mode 100644
index 000000000000..ad394c6496cc
--- /dev/null
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -0,0 +1,1580 @@
+/*
+ * Copyright (C) 2011 B.A.T.M.A.N. contributors:
+ *
+ * Simon Wunderlich
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#include "main.h"
+#include "hash.h"
+#include "hard-interface.h"
+#include "originator.h"
+#include "bridge_loop_avoidance.h"
+#include "translation-table.h"
+#include "send.h"
+
+#include <linux/etherdevice.h>
+#include <linux/crc16.h>
+#include <linux/if_arp.h>
+#include <net/arp.h>
+#include <linux/if_vlan.h>
+
+static const uint8_t announce_mac[4] = {0x43, 0x05, 0x43, 0x05};
+
+static void bla_periodic_work(struct work_struct *work);
+static void bla_send_announce(struct bat_priv *bat_priv,
+ struct backbone_gw *backbone_gw);
+
+/* return the index of the claim */
+static inline uint32_t choose_claim(const void *data, uint32_t size)
+{
+ const unsigned char *key = data;
+ uint32_t hash = 0;
+ size_t i;
+
+ for (i = 0; i < ETH_ALEN + sizeof(short); i++) {
+ hash += key[i];
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+
+ return hash % size;
+}
+
+/* return the index of the backbone gateway */
+static inline uint32_t choose_backbone_gw(const void *data, uint32_t size)
+{
+ const unsigned char *key = data;
+ uint32_t hash = 0;
+ size_t i;
+
+ for (i = 0; i < ETH_ALEN + sizeof(short); i++) {
+ hash += key[i];
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+
+ return hash % size;
+}
+
+
+/* compares address and vid of two backbone gws */
+static int compare_backbone_gw(const struct hlist_node *node, const void *data2)
+{
+ const void *data1 = container_of(node, struct backbone_gw,
+ hash_entry);
+
+ return (memcmp(data1, data2, ETH_ALEN + sizeof(short)) == 0 ? 1 : 0);
+}
+
+/* compares address and vid of two claims */
+static int compare_claim(const struct hlist_node *node, const void *data2)
+{
+ const void *data1 = container_of(node, struct claim,
+ hash_entry);
+
+ return (memcmp(data1, data2, ETH_ALEN + sizeof(short)) == 0 ? 1 : 0);
+}
+
+/* free a backbone gw */
+static void backbone_gw_free_ref(struct backbone_gw *backbone_gw)
+{
+ if (atomic_dec_and_test(&backbone_gw->refcount))
+ kfree_rcu(backbone_gw, rcu);
+}
+
+/* finally deinitialize the claim */
+static void claim_free_rcu(struct rcu_head *rcu)
+{
+ struct claim *claim;
+
+ claim = container_of(rcu, struct claim, rcu);
+
+ backbone_gw_free_ref(claim->backbone_gw);
+ kfree(claim);
+}
+
+/* free a claim, call claim_free_rcu if its the last reference */
+static void claim_free_ref(struct claim *claim)
+{
+ if (atomic_dec_and_test(&claim->refcount))
+ call_rcu(&claim->rcu, claim_free_rcu);
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @data: search data (may be local/static data)
+ *
+ * looks for a claim in the hash, and returns it if found
+ * or NULL otherwise.
+ */
+static struct claim *claim_hash_find(struct bat_priv *bat_priv,
+ struct claim *data)
+{
+ struct hashtable_t *hash = bat_priv->claim_hash;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct claim *claim;
+ struct claim *claim_tmp = NULL;
+ int index;
+
+ if (!hash)
+ return NULL;
+
+ index = choose_claim(data, hash->size);
+ head = &hash->table[index];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(claim, node, head, hash_entry) {
+ if (!compare_claim(&claim->hash_entry, data))
+ continue;
+
+ if (!atomic_inc_not_zero(&claim->refcount))
+ continue;
+
+ claim_tmp = claim;
+ break;
+ }
+ rcu_read_unlock();
+
+ return claim_tmp;
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @addr: the address of the originator
+ * @vid: the VLAN ID
+ *
+ * looks for a claim in the hash, and returns it if found
+ * or NULL otherwise.
+ */
+static struct backbone_gw *backbone_hash_find(struct bat_priv *bat_priv,
+ uint8_t *addr, short vid)
+{
+ struct hashtable_t *hash = bat_priv->backbone_hash;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct backbone_gw search_entry, *backbone_gw;
+ struct backbone_gw *backbone_gw_tmp = NULL;
+ int index;
+
+ if (!hash)
+ return NULL;
+
+ memcpy(search_entry.orig, addr, ETH_ALEN);
+ search_entry.vid = vid;
+
+ index = choose_backbone_gw(&search_entry, hash->size);
+ head = &hash->table[index];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(backbone_gw, node, head, hash_entry) {
+ if (!compare_backbone_gw(&backbone_gw->hash_entry,
+ &search_entry))
+ continue;
+
+ if (!atomic_inc_not_zero(&backbone_gw->refcount))
+ continue;
+
+ backbone_gw_tmp = backbone_gw;
+ break;
+ }
+ rcu_read_unlock();
+
+ return backbone_gw_tmp;
+}
+
+/* delete all claims for a backbone */
+static void bla_del_backbone_claims(struct backbone_gw *backbone_gw)
+{
+ struct hashtable_t *hash;
+ struct hlist_node *node, *node_tmp;
+ struct hlist_head *head;
+ struct claim *claim;
+ int i;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
+
+ hash = backbone_gw->bat_priv->claim_hash;
+ if (!hash)
+ return;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(claim, node, node_tmp,
+ head, hash_entry) {
+
+ if (claim->backbone_gw != backbone_gw)
+ continue;
+
+ claim_free_ref(claim);
+ hlist_del_rcu(node);
+ }
+ spin_unlock_bh(list_lock);
+ }
+
+ /* all claims gone, intialize CRC */
+ backbone_gw->crc = BLA_CRC_INIT;
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig: the mac address to be announced within the claim
+ * @vid: the VLAN ID
+ * @claimtype: the type of the claim (CLAIM, UNCLAIM, ANNOUNCE, ...)
+ *
+ * sends a claim frame according to the provided info.
+ */
+static void bla_send_claim(struct bat_priv *bat_priv, uint8_t *mac,
+ short vid, int claimtype)
+{
+ struct sk_buff *skb;
+ struct ethhdr *ethhdr;
+ struct hard_iface *primary_if;
+ struct net_device *soft_iface;
+ uint8_t *hw_src;
+ struct bla_claim_dst local_claim_dest;
+ uint32_t zeroip = 0;
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ return;
+
+ memcpy(&local_claim_dest, &bat_priv->claim_dest,
+ sizeof(local_claim_dest));
+ local_claim_dest.type = claimtype;
+
+ soft_iface = primary_if->soft_iface;
+
+ skb = arp_create(ARPOP_REPLY, ETH_P_ARP,
+ /* IP DST: 0.0.0.0 */
+ zeroip,
+ primary_if->soft_iface,
+ /* IP SRC: 0.0.0.0 */
+ zeroip,
+ /* Ethernet DST: Broadcast */
+ NULL,
+ /* Ethernet SRC/HW SRC: originator mac */
+ primary_if->net_dev->dev_addr,
+ /* HW DST: FF:43:05:XX:00:00
+ * with XX = claim type
+ * and YY:YY = group id
+ */
+ (uint8_t *)&local_claim_dest);
+
+ if (!skb)
+ goto out;
+
+ ethhdr = (struct ethhdr *)skb->data;
+ hw_src = (uint8_t *)ethhdr + ETH_HLEN + sizeof(struct arphdr);
+
+ /* now we pretend that the client would have sent this ... */
+ switch (claimtype) {
+ case CLAIM_TYPE_ADD:
+ /* normal claim frame
+ * set Ethernet SRC to the clients mac
+ */
+ memcpy(ethhdr->h_source, mac, ETH_ALEN);
+ bat_dbg(DBG_BLA, bat_priv,
+ "bla_send_claim(): CLAIM %pM on vid %d\n", mac, vid);
+ break;
+ case CLAIM_TYPE_DEL:
+ /* unclaim frame
+ * set HW SRC to the clients mac
+ */
+ memcpy(hw_src, mac, ETH_ALEN);
+ bat_dbg(DBG_BLA, bat_priv,
+ "bla_send_claim(): UNCLAIM %pM on vid %d\n", mac, vid);
+ break;
+ case CLAIM_TYPE_ANNOUNCE:
+ /* announcement frame
+ * set HW SRC to the special mac containg the crc
+ */
+ memcpy(hw_src, mac, ETH_ALEN);
+ bat_dbg(DBG_BLA, bat_priv,
+ "bla_send_claim(): ANNOUNCE of %pM on vid %d\n",
+ ethhdr->h_source, vid);
+ break;
+ case CLAIM_TYPE_REQUEST:
+ /* request frame
+ * set HW SRC to the special mac containg the crc
+ */
+ memcpy(hw_src, mac, ETH_ALEN);
+ memcpy(ethhdr->h_dest, mac, ETH_ALEN);
+ bat_dbg(DBG_BLA, bat_priv,
+ "bla_send_claim(): REQUEST of %pM to %pMon vid %d\n",
+ ethhdr->h_source, ethhdr->h_dest, vid);
+ break;
+
+ }
+
+ if (vid != -1)
+ skb = vlan_insert_tag(skb, vid);
+
+ skb_reset_mac_header(skb);
+ skb->protocol = eth_type_trans(skb, soft_iface);
+ bat_priv->stats.rx_packets++;
+ bat_priv->stats.rx_bytes += skb->len + ETH_HLEN;
+ soft_iface->last_rx = jiffies;
+
+ netif_rx(skb);
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig: the mac address of the originator
+ * @vid: the VLAN ID
+ *
+ * searches for the backbone gw or creates a new one if it could not
+ * be found.
+ */
+static struct backbone_gw *bla_get_backbone_gw(struct bat_priv *bat_priv,
+ uint8_t *orig, short vid)
+{
+ struct backbone_gw *entry;
+ struct orig_node *orig_node;
+ int hash_added;
+
+ entry = backbone_hash_find(bat_priv, orig, vid);
+
+ if (entry)
+ return entry;
+
+ bat_dbg(DBG_BLA, bat_priv,
+ "bla_get_backbone_gw(): not found (%pM, %d), creating new entry\n",
+ orig, vid);
+
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry)
+ return NULL;
+
+ entry->vid = vid;
+ entry->lasttime = jiffies;
+ entry->crc = BLA_CRC_INIT;
+ entry->bat_priv = bat_priv;
+ atomic_set(&entry->request_sent, 0);
+ memcpy(entry->orig, orig, ETH_ALEN);
+
+ /* one for the hash, one for returning */
+ atomic_set(&entry->refcount, 2);
+
+ hash_added = hash_add(bat_priv->backbone_hash, compare_backbone_gw,
+ choose_backbone_gw, entry, &entry->hash_entry);
+
+ if (unlikely(hash_added != 0)) {
+ /* hash failed, free the structure */
+ kfree(entry);
+ return NULL;
+ }
+
+ /* this is a gateway now, remove any tt entries */
+ orig_node = orig_hash_find(bat_priv, orig);
+ if (orig_node) {
+ tt_global_del_orig(bat_priv, orig_node,
+ "became a backbone gateway");
+ orig_node_free_ref(orig_node);
+ }
+ return entry;
+}
+
+/* update or add the own backbone gw to make sure we announce
+ * where we receive other backbone gws
+ */
+static void bla_update_own_backbone_gw(struct bat_priv *bat_priv,
+ struct hard_iface *primary_if,
+ short vid)
+{
+ struct backbone_gw *backbone_gw;
+
+ backbone_gw = bla_get_backbone_gw(bat_priv,
+ primary_if->net_dev->dev_addr, vid);
+ if (unlikely(!backbone_gw))
+ return;
+
+ backbone_gw->lasttime = jiffies;
+ backbone_gw_free_ref(backbone_gw);
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @vid: the vid where the request came on
+ *
+ * Repeat all of our own claims, and finally send an ANNOUNCE frame
+ * to allow the requester another check if the CRC is correct now.
+ */
+static void bla_answer_request(struct bat_priv *bat_priv,
+ struct hard_iface *primary_if, short vid)
+{
+ struct hlist_node *node;
+ struct hlist_head *head;
+ struct hashtable_t *hash;
+ struct claim *claim;
+ struct backbone_gw *backbone_gw;
+ int i;
+
+ bat_dbg(DBG_BLA, bat_priv,
+ "bla_answer_request(): received a claim request, send all of our own claims again\n");
+
+ backbone_gw = backbone_hash_find(bat_priv,
+ primary_if->net_dev->dev_addr, vid);
+ if (!backbone_gw)
+ return;
+
+ hash = bat_priv->claim_hash;
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(claim, node, head, hash_entry) {
+ /* only own claims are interesting */
+ if (claim->backbone_gw != backbone_gw)
+ continue;
+
+ bla_send_claim(bat_priv, claim->addr, claim->vid,
+ CLAIM_TYPE_ADD);
+ }
+ rcu_read_unlock();
+ }
+
+ /* finally, send an announcement frame */
+ bla_send_announce(bat_priv, backbone_gw);
+ backbone_gw_free_ref(backbone_gw);
+}
+
+/**
+ * @backbone_gw: the backbone gateway from whom we are out of sync
+ *
+ * When the crc is wrong, ask the backbone gateway for a full table update.
+ * After the request, it will repeat all of his own claims and finally
+ * send an announcement claim with which we can check again.
+ */
+static void bla_send_request(struct backbone_gw *backbone_gw)
+{
+ /* first, remove all old entries */
+ bla_del_backbone_claims(backbone_gw);
+
+ bat_dbg(DBG_BLA, backbone_gw->bat_priv,
+ "Sending REQUEST to %pM\n",
+ backbone_gw->orig);
+
+ /* send request */
+ bla_send_claim(backbone_gw->bat_priv, backbone_gw->orig,
+ backbone_gw->vid, CLAIM_TYPE_REQUEST);
+
+ /* no local broadcasts should be sent or received, for now. */
+ if (!atomic_read(&backbone_gw->request_sent)) {
+ atomic_inc(&backbone_gw->bat_priv->bla_num_requests);
+ atomic_set(&backbone_gw->request_sent, 1);
+ }
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @backbone_gw: our backbone gateway which should be announced
+ *
+ * This function sends an announcement. It is called from multiple
+ * places.
+ */
+static void bla_send_announce(struct bat_priv *bat_priv,
+ struct backbone_gw *backbone_gw)
+{
+ uint8_t mac[ETH_ALEN];
+ uint16_t crc;
+
+ memcpy(mac, announce_mac, 4);
+ crc = htons(backbone_gw->crc);
+ memcpy(&mac[4], (uint8_t *)&crc, 2);
+
+ bla_send_claim(bat_priv, mac, backbone_gw->vid, CLAIM_TYPE_ANNOUNCE);
+
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @mac: the mac address of the claim
+ * @vid: the VLAN ID of the frame
+ * @backbone_gw: the backbone gateway which claims it
+ *
+ * Adds a claim in the claim hash.
+ */
+static void bla_add_claim(struct bat_priv *bat_priv, const uint8_t *mac,
+ const short vid, struct backbone_gw *backbone_gw)
+{
+ struct claim *claim;
+ struct claim search_claim;
+ int hash_added;
+
+ memcpy(search_claim.addr, mac, ETH_ALEN);
+ search_claim.vid = vid;
+ claim = claim_hash_find(bat_priv, &search_claim);
+
+ /* create a new claim entry if it does not exist yet. */
+ if (!claim) {
+ claim = kzalloc(sizeof(*claim), GFP_ATOMIC);
+ if (!claim)
+ return;
+
+ memcpy(claim->addr, mac, ETH_ALEN);
+ claim->vid = vid;
+ claim->lasttime = jiffies;
+ claim->backbone_gw = backbone_gw;
+
+ atomic_set(&claim->refcount, 2);
+ bat_dbg(DBG_BLA, bat_priv,
+ "bla_add_claim(): adding new entry %pM, vid %d to hash ...\n",
+ mac, vid);
+ hash_added = hash_add(bat_priv->claim_hash, compare_claim,
+ choose_claim, claim, &claim->hash_entry);
+
+ if (unlikely(hash_added != 0)) {
+ /* only local changes happened. */
+ kfree(claim);
+ return;
+ }
+ } else {
+ claim->lasttime = jiffies;
+ if (claim->backbone_gw == backbone_gw)
+ /* no need to register a new backbone */
+ goto claim_free_ref;
+
+ bat_dbg(DBG_BLA, bat_priv,
+ "bla_add_claim(): changing ownership for %pM, vid %d\n",
+ mac, vid);
+
+ claim->backbone_gw->crc ^=
+ crc16(0, claim->addr, ETH_ALEN);
+ backbone_gw_free_ref(claim->backbone_gw);
+
+ }
+ /* set (new) backbone gw */
+ atomic_inc(&backbone_gw->refcount);
+ claim->backbone_gw = backbone_gw;
+
+ backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
+ backbone_gw->lasttime = jiffies;
+
+claim_free_ref:
+ claim_free_ref(claim);
+}
+
+/* Delete a claim from the claim hash which has the
+ * given mac address and vid.
+ */
+static void bla_del_claim(struct bat_priv *bat_priv, const uint8_t *mac,
+ const short vid)
+{
+ struct claim search_claim, *claim;
+
+ memcpy(search_claim.addr, mac, ETH_ALEN);
+ search_claim.vid = vid;
+ claim = claim_hash_find(bat_priv, &search_claim);
+ if (!claim)
+ return;
+
+ bat_dbg(DBG_BLA, bat_priv, "bla_del_claim(): %pM, vid %d\n", mac, vid);
+
+ hash_remove(bat_priv->claim_hash, compare_claim, choose_claim, claim);
+ claim_free_ref(claim); /* reference from the hash is gone */
+
+ claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
+
+ /* don't need the reference from hash_find() anymore */
+ claim_free_ref(claim);
+}
+
+/* check for ANNOUNCE frame, return 1 if handled */
+static int handle_announce(struct bat_priv *bat_priv,
+ uint8_t *an_addr, uint8_t *backbone_addr, short vid)
+{
+ struct backbone_gw *backbone_gw;
+ uint16_t crc;
+
+ if (memcmp(an_addr, announce_mac, 4) != 0)
+ return 0;
+
+ backbone_gw = bla_get_backbone_gw(bat_priv, backbone_addr, vid);
+
+ if (unlikely(!backbone_gw))
+ return 1;
+
+
+ /* handle as ANNOUNCE frame */
+ backbone_gw->lasttime = jiffies;
+ crc = ntohs(*((uint16_t *)(&an_addr[4])));
+
+ bat_dbg(DBG_BLA, bat_priv,
+ "handle_announce(): ANNOUNCE vid %d (sent by %pM)... CRC = %04x\n",
+ vid, backbone_gw->orig, crc);
+
+ if (backbone_gw->crc != crc) {
+ bat_dbg(DBG_BLA, backbone_gw->bat_priv,
+ "handle_announce(): CRC FAILED for %pM/%d (my = %04x, sent = %04x)\n",
+ backbone_gw->orig, backbone_gw->vid, backbone_gw->crc,
+ crc);
+
+ bla_send_request(backbone_gw);
+ } else {
+ /* if we have sent a request and the crc was OK,
+ * we can allow traffic again.
+ */
+ if (atomic_read(&backbone_gw->request_sent)) {
+ atomic_dec(&backbone_gw->bat_priv->bla_num_requests);
+ atomic_set(&backbone_gw->request_sent, 0);
+ }
+ }
+
+ backbone_gw_free_ref(backbone_gw);
+ return 1;
+}
+
+/* check for REQUEST frame, return 1 if handled */
+static int handle_request(struct bat_priv *bat_priv,
+ struct hard_iface *primary_if,
+ uint8_t *backbone_addr,
+ struct ethhdr *ethhdr, short vid)
+{
+ /* check for REQUEST frame */
+ if (!compare_eth(backbone_addr, ethhdr->h_dest))
+ return 0;
+
+ /* sanity check, this should not happen on a normal switch,
+ * we ignore it in this case.
+ */
+ if (!compare_eth(ethhdr->h_dest, primary_if->net_dev->dev_addr))
+ return 1;
+
+ bat_dbg(DBG_BLA, bat_priv,
+ "handle_request(): REQUEST vid %d (sent by %pM)...\n",
+ vid, ethhdr->h_source);
+
+ bla_answer_request(bat_priv, primary_if, vid);
+ return 1;
+}
+
+/* check for UNCLAIM frame, return 1 if handled */
+static int handle_unclaim(struct bat_priv *bat_priv,
+ struct hard_iface *primary_if,
+ uint8_t *backbone_addr,
+ uint8_t *claim_addr, short vid)
+{
+ struct backbone_gw *backbone_gw;
+
+ /* unclaim in any case if it is our own */
+ if (primary_if && compare_eth(backbone_addr,
+ primary_if->net_dev->dev_addr))
+ bla_send_claim(bat_priv, claim_addr, vid, CLAIM_TYPE_DEL);
+
+ backbone_gw = backbone_hash_find(bat_priv, backbone_addr, vid);
+
+ if (!backbone_gw)
+ return 1;
+
+ /* this must be an UNCLAIM frame */
+ bat_dbg(DBG_BLA, bat_priv,
+ "handle_unclaim(): UNCLAIM %pM on vid %d (sent by %pM)...\n",
+ claim_addr, vid, backbone_gw->orig);
+
+ bla_del_claim(bat_priv, claim_addr, vid);
+ backbone_gw_free_ref(backbone_gw);
+ return 1;
+}
+
+/* check for CLAIM frame, return 1 if handled */
+static int handle_claim(struct bat_priv *bat_priv,
+ struct hard_iface *primary_if, uint8_t *backbone_addr,
+ uint8_t *claim_addr, short vid)
+{
+ struct backbone_gw *backbone_gw;
+
+ /* register the gateway if not yet available, and add the claim. */
+
+ backbone_gw = bla_get_backbone_gw(bat_priv, backbone_addr, vid);
+
+ if (unlikely(!backbone_gw))
+ return 1;
+
+ /* this must be a CLAIM frame */
+ bla_add_claim(bat_priv, claim_addr, vid, backbone_gw);
+ if (compare_eth(backbone_addr, primary_if->net_dev->dev_addr))
+ bla_send_claim(bat_priv, claim_addr, vid, CLAIM_TYPE_ADD);
+
+ /* TODO: we could call something like tt_local_del() here. */
+
+ backbone_gw_free_ref(backbone_gw);
+ return 1;
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @hw_src: the Hardware source in the ARP Header
+ * @hw_dst: the Hardware destination in the ARP Header
+ * @ethhdr: pointer to the Ethernet header of the claim frame
+ *
+ * checks if it is a claim packet and if its on the same group.
+ * This function also applies the group ID of the sender
+ * if it is in the same mesh.
+ *
+ * returns:
+ * 2 - if it is a claim packet and on the same group
+ * 1 - if is a claim packet from another group
+ * 0 - if it is not a claim packet
+ */
+static int check_claim_group(struct bat_priv *bat_priv,
+ struct hard_iface *primary_if,
+ uint8_t *hw_src, uint8_t *hw_dst,
+ struct ethhdr *ethhdr)
+{
+ uint8_t *backbone_addr;
+ struct orig_node *orig_node;
+ struct bla_claim_dst *bla_dst, *bla_dst_own;
+
+ bla_dst = (struct bla_claim_dst *)hw_dst;
+ bla_dst_own = &bat_priv->claim_dest;
+
+ /* check if it is a claim packet in general */
+ if (memcmp(bla_dst->magic, bla_dst_own->magic,
+ sizeof(bla_dst->magic)) != 0)
+ return 0;
+
+ /* if announcement packet, use the source,
+ * otherwise assume it is in the hw_src
+ */
+ switch (bla_dst->type) {
+ case CLAIM_TYPE_ADD:
+ backbone_addr = hw_src;
+ break;
+ case CLAIM_TYPE_REQUEST:
+ case CLAIM_TYPE_ANNOUNCE:
+ case CLAIM_TYPE_DEL:
+ backbone_addr = ethhdr->h_source;
+ break;
+ default:
+ return 0;
+ }
+
+ /* don't accept claim frames from ourselves */
+ if (compare_eth(backbone_addr, primary_if->net_dev->dev_addr))
+ return 0;
+
+ /* if its already the same group, it is fine. */
+ if (bla_dst->group == bla_dst_own->group)
+ return 2;
+
+ /* lets see if this originator is in our mesh */
+ orig_node = orig_hash_find(bat_priv, backbone_addr);
+
+ /* dont accept claims from gateways which are not in
+ * the same mesh or group.
+ */
+ if (!orig_node)
+ return 1;
+
+ /* if our mesh friends mac is bigger, use it for ourselves. */
+ if (ntohs(bla_dst->group) > ntohs(bla_dst_own->group)) {
+ bat_dbg(DBG_BLA, bat_priv,
+ "taking other backbones claim group: %04x\n",
+ ntohs(bla_dst->group));
+ bla_dst_own->group = bla_dst->group;
+ }
+
+ orig_node_free_ref(orig_node);
+
+ return 2;
+}
+
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the frame to be checked
+ *
+ * Check if this is a claim frame, and process it accordingly.
+ *
+ * returns 1 if it was a claim frame, otherwise return 0 to
+ * tell the callee that it can use the frame on its own.
+ */
+static int bla_process_claim(struct bat_priv *bat_priv,
+ struct hard_iface *primary_if,
+ struct sk_buff *skb)
+{
+ struct ethhdr *ethhdr;
+ struct vlan_ethhdr *vhdr;
+ struct arphdr *arphdr;
+ uint8_t *hw_src, *hw_dst;
+ struct bla_claim_dst *bla_dst;
+ uint16_t proto;
+ int headlen;
+ short vid = -1;
+ int ret;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) {
+ vhdr = (struct vlan_ethhdr *)ethhdr;
+ vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
+ proto = ntohs(vhdr->h_vlan_encapsulated_proto);
+ headlen = sizeof(*vhdr);
+ } else {
+ proto = ntohs(ethhdr->h_proto);
+ headlen = ETH_HLEN;
+ }
+
+ if (proto != ETH_P_ARP)
+ return 0; /* not a claim frame */
+
+ /* this must be a ARP frame. check if it is a claim. */
+
+ if (unlikely(!pskb_may_pull(skb, headlen + arp_hdr_len(skb->dev))))
+ return 0;
+
+ /* pskb_may_pull() may have modified the pointers, get ethhdr again */
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+ arphdr = (struct arphdr *)((uint8_t *)ethhdr + headlen);
+
+ /* Check whether the ARP frame carries a valid
+ * IP information
+ */
+
+ if (arphdr->ar_hrd != htons(ARPHRD_ETHER))
+ return 0;
+ if (arphdr->ar_pro != htons(ETH_P_IP))
+ return 0;
+ if (arphdr->ar_hln != ETH_ALEN)
+ return 0;
+ if (arphdr->ar_pln != 4)
+ return 0;
+
+ hw_src = (uint8_t *)arphdr + sizeof(struct arphdr);
+ hw_dst = hw_src + ETH_ALEN + 4;
+ bla_dst = (struct bla_claim_dst *)hw_dst;
+
+ /* check if it is a claim frame. */
+ ret = check_claim_group(bat_priv, primary_if, hw_src, hw_dst, ethhdr);
+ if (ret == 1)
+ bat_dbg(DBG_BLA, bat_priv,
+ "bla_process_claim(): received a claim frame from another group. From: %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",
+ ethhdr->h_source, vid, hw_src, hw_dst);
+
+ if (ret < 2)
+ return ret;
+
+ /* become a backbone gw ourselves on this vlan if not happened yet */
+ bla_update_own_backbone_gw(bat_priv, primary_if, vid);
+
+ /* check for the different types of claim frames ... */
+ switch (bla_dst->type) {
+ case CLAIM_TYPE_ADD:
+ if (handle_claim(bat_priv, primary_if, hw_src,
+ ethhdr->h_source, vid))
+ return 1;
+ break;
+ case CLAIM_TYPE_DEL:
+ if (handle_unclaim(bat_priv, primary_if,
+ ethhdr->h_source, hw_src, vid))
+ return 1;
+ break;
+
+ case CLAIM_TYPE_ANNOUNCE:
+ if (handle_announce(bat_priv, hw_src, ethhdr->h_source, vid))
+ return 1;
+ break;
+ case CLAIM_TYPE_REQUEST:
+ if (handle_request(bat_priv, primary_if, hw_src, ethhdr, vid))
+ return 1;
+ break;
+ }
+
+ bat_dbg(DBG_BLA, bat_priv,
+ "bla_process_claim(): ERROR - this looks like a claim frame, but is useless. eth src %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",
+ ethhdr->h_source, vid, hw_src, hw_dst);
+ return 1;
+}
+
+/* Check when we last heard from other nodes, and remove them in case of
+ * a time out, or clean all backbone gws if now is set.
+ */
+static void bla_purge_backbone_gw(struct bat_priv *bat_priv, int now)
+{
+ struct backbone_gw *backbone_gw;
+ struct hlist_node *node, *node_tmp;
+ struct hlist_head *head;
+ struct hashtable_t *hash;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
+ int i;
+
+ hash = bat_priv->backbone_hash;
+ if (!hash)
+ return;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(backbone_gw, node, node_tmp,
+ head, hash_entry) {
+ if (now)
+ goto purge_now;
+ if (!has_timed_out(backbone_gw->lasttime,
+ BLA_BACKBONE_TIMEOUT))
+ continue;
+
+ bat_dbg(DBG_BLA, backbone_gw->bat_priv,
+ "bla_purge_backbone_gw(): backbone gw %pM timed out\n",
+ backbone_gw->orig);
+
+purge_now:
+ /* don't wait for the pending request anymore */
+ if (atomic_read(&backbone_gw->request_sent))
+ atomic_dec(&bat_priv->bla_num_requests);
+
+ bla_del_backbone_claims(backbone_gw);
+
+ hlist_del_rcu(node);
+ backbone_gw_free_ref(backbone_gw);
+ }
+ spin_unlock_bh(list_lock);
+ }
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @primary_if: the selected primary interface, may be NULL if now is set
+ * @now: whether the whole hash shall be wiped now
+ *
+ * Check when we heard last time from our own claims, and remove them in case of
+ * a time out, or clean all claims if now is set
+ */
+static void bla_purge_claims(struct bat_priv *bat_priv,
+ struct hard_iface *primary_if, int now)
+{
+ struct claim *claim;
+ struct hlist_node *node;
+ struct hlist_head *head;
+ struct hashtable_t *hash;
+ int i;
+
+ hash = bat_priv->claim_hash;
+ if (!hash)
+ return;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(claim, node, head, hash_entry) {
+ if (now)
+ goto purge_now;
+ if (!compare_eth(claim->backbone_gw->orig,
+ primary_if->net_dev->dev_addr))
+ continue;
+ if (!has_timed_out(claim->lasttime,
+ BLA_CLAIM_TIMEOUT))
+ continue;
+
+ bat_dbg(DBG_BLA, bat_priv,
+ "bla_purge_claims(): %pM, vid %d, time out\n",
+ claim->addr, claim->vid);
+
+purge_now:
+ handle_unclaim(bat_priv, primary_if,
+ claim->backbone_gw->orig,
+ claim->addr, claim->vid);
+ }
+ rcu_read_unlock();
+ }
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @primary_if: the new selected primary_if
+ * @oldif: the old primary interface, may be NULL
+ *
+ * Update the backbone gateways when the own orig address changes.
+ *
+ */
+void bla_update_orig_address(struct bat_priv *bat_priv,
+ struct hard_iface *primary_if,
+ struct hard_iface *oldif)
+{
+ struct backbone_gw *backbone_gw;
+ struct hlist_node *node;
+ struct hlist_head *head;
+ struct hashtable_t *hash;
+ int i;
+
+ /* reset bridge loop avoidance group id */
+ bat_priv->claim_dest.group =
+ htons(crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN));
+
+ if (!oldif) {
+ bla_purge_claims(bat_priv, NULL, 1);
+ bla_purge_backbone_gw(bat_priv, 1);
+ return;
+ }
+
+ hash = bat_priv->backbone_hash;
+ if (!hash)
+ return;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(backbone_gw, node, head, hash_entry) {
+ /* own orig still holds the old value. */
+ if (!compare_eth(backbone_gw->orig,
+ oldif->net_dev->dev_addr))
+ continue;
+
+ memcpy(backbone_gw->orig,
+ primary_if->net_dev->dev_addr, ETH_ALEN);
+ /* send an announce frame so others will ask for our
+ * claims and update their tables.
+ */
+ bla_send_announce(bat_priv, backbone_gw);
+ }
+ rcu_read_unlock();
+ }
+}
+
+
+
+/* (re)start the timer */
+static void bla_start_timer(struct bat_priv *bat_priv)
+{
+ INIT_DELAYED_WORK(&bat_priv->bla_work, bla_periodic_work);
+ queue_delayed_work(bat_event_workqueue, &bat_priv->bla_work,
+ msecs_to_jiffies(BLA_PERIOD_LENGTH));
+}
+
+/* periodic work to do:
+ * * purge structures when they are too old
+ * * send announcements
+ */
+static void bla_periodic_work(struct work_struct *work)
+{
+ struct delayed_work *delayed_work =
+ container_of(work, struct delayed_work, work);
+ struct bat_priv *bat_priv =
+ container_of(delayed_work, struct bat_priv, bla_work);
+ struct hlist_node *node;
+ struct hlist_head *head;
+ struct backbone_gw *backbone_gw;
+ struct hashtable_t *hash;
+ struct hard_iface *primary_if;
+ int i;
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ bla_purge_claims(bat_priv, primary_if, 0);
+ bla_purge_backbone_gw(bat_priv, 0);
+
+ if (!atomic_read(&bat_priv->bridge_loop_avoidance))
+ goto out;
+
+ hash = bat_priv->backbone_hash;
+ if (!hash)
+ goto out;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(backbone_gw, node, head, hash_entry) {
+ if (!compare_eth(backbone_gw->orig,
+ primary_if->net_dev->dev_addr))
+ continue;
+
+ backbone_gw->lasttime = jiffies;
+
+ bla_send_announce(bat_priv, backbone_gw);
+ }
+ rcu_read_unlock();
+ }
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+
+ bla_start_timer(bat_priv);
+}
+
+/* initialize all bla structures */
+int bla_init(struct bat_priv *bat_priv)
+{
+ int i;
+ uint8_t claim_dest[ETH_ALEN] = {0xff, 0x43, 0x05, 0x00, 0x00, 0x00};
+ struct hard_iface *primary_if;
+
+ bat_dbg(DBG_BLA, bat_priv, "bla hash registering\n");
+
+ /* setting claim destination address */
+ memcpy(&bat_priv->claim_dest.magic, claim_dest, 3);
+ bat_priv->claim_dest.type = 0;
+ primary_if = primary_if_get_selected(bat_priv);
+ if (primary_if) {
+ bat_priv->claim_dest.group =
+ htons(crc16(0, primary_if->net_dev->dev_addr,
+ ETH_ALEN));
+ hardif_free_ref(primary_if);
+ } else {
+ bat_priv->claim_dest.group = 0; /* will be set later */
+ }
+
+ /* initialize the duplicate list */
+ for (i = 0; i < DUPLIST_SIZE; i++)
+ bat_priv->bcast_duplist[i].entrytime =
+ jiffies - msecs_to_jiffies(DUPLIST_TIMEOUT);
+ bat_priv->bcast_duplist_curr = 0;
+
+ if (bat_priv->claim_hash)
+ return 1;
+
+ bat_priv->claim_hash = hash_new(128);
+ bat_priv->backbone_hash = hash_new(32);
+
+ if (!bat_priv->claim_hash || !bat_priv->backbone_hash)
+ return -1;
+
+ bat_dbg(DBG_BLA, bat_priv, "bla hashes initialized\n");
+
+ bla_start_timer(bat_priv);
+ return 1;
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @bcast_packet: originator mac address
+ * @hdr_size: maximum length of the frame
+ *
+ * check if it is on our broadcast list. Another gateway might
+ * have sent the same packet because it is connected to the same backbone,
+ * so we have to remove this duplicate.
+ *
+ * This is performed by checking the CRC, which will tell us
+ * with a good chance that it is the same packet. If it is furthermore
+ * sent by another host, drop it. We allow equal packets from
+ * the same host however as this might be intended.
+ *
+ **/
+
+int bla_check_bcast_duplist(struct bat_priv *bat_priv,
+ struct bcast_packet *bcast_packet,
+ int hdr_size)
+{
+ int i, length, curr;
+ uint8_t *content;
+ uint16_t crc;
+ struct bcast_duplist_entry *entry;
+
+ length = hdr_size - sizeof(*bcast_packet);
+ content = (uint8_t *)bcast_packet;
+ content += sizeof(*bcast_packet);
+
+ /* calculate the crc ... */
+ crc = crc16(0, content, length);
+
+ for (i = 0 ; i < DUPLIST_SIZE; i++) {
+ curr = (bat_priv->bcast_duplist_curr + i) % DUPLIST_SIZE;
+ entry = &bat_priv->bcast_duplist[curr];
+
+ /* we can stop searching if the entry is too old ;
+ * later entries will be even older
+ */
+ if (has_timed_out(entry->entrytime, DUPLIST_TIMEOUT))
+ break;
+
+ if (entry->crc != crc)
+ continue;
+
+ if (compare_eth(entry->orig, bcast_packet->orig))
+ continue;
+
+ /* this entry seems to match: same crc, not too old,
+ * and from another gw. therefore return 1 to forbid it.
+ */
+ return 1;
+ }
+ /* not found, add a new entry (overwrite the oldest entry) */
+ curr = (bat_priv->bcast_duplist_curr + DUPLIST_SIZE - 1) % DUPLIST_SIZE;
+ entry = &bat_priv->bcast_duplist[curr];
+ entry->crc = crc;
+ entry->entrytime = jiffies;
+ memcpy(entry->orig, bcast_packet->orig, ETH_ALEN);
+ bat_priv->bcast_duplist_curr = curr;
+
+ /* allow it, its the first occurence. */
+ return 0;
+}
+
+
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig: originator mac address
+ *
+ * check if the originator is a gateway for any VLAN ID.
+ *
+ * returns 1 if it is found, 0 otherwise
+ *
+ */
+
+int bla_is_backbone_gw_orig(struct bat_priv *bat_priv, uint8_t *orig)
+{
+ struct hashtable_t *hash = bat_priv->backbone_hash;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct backbone_gw *backbone_gw;
+ int i;
+
+ if (!atomic_read(&bat_priv->bridge_loop_avoidance))
+ return 0;
+
+ if (!hash)
+ return 0;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(backbone_gw, node, head, hash_entry) {
+ if (compare_eth(backbone_gw->orig, orig)) {
+ rcu_read_unlock();
+ return 1;
+ }
+ }
+ rcu_read_unlock();
+ }
+
+ return 0;
+}
+
+
+/**
+ * @skb: the frame to be checked
+ * @orig_node: the orig_node of the frame
+ * @hdr_size: maximum length of the frame
+ *
+ * bla_is_backbone_gw inspects the skb for the VLAN ID and returns 1
+ * if the orig_node is also a gateway on the soft interface, otherwise it
+ * returns 0.
+ *
+ */
+int bla_is_backbone_gw(struct sk_buff *skb,
+ struct orig_node *orig_node, int hdr_size)
+{
+ struct ethhdr *ethhdr;
+ struct vlan_ethhdr *vhdr;
+ struct backbone_gw *backbone_gw;
+ short vid = -1;
+
+ if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance))
+ return 0;
+
+ /* first, find out the vid. */
+ if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
+ return 0;
+
+ ethhdr = (struct ethhdr *)(((uint8_t *)skb->data) + hdr_size);
+
+ if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) {
+ if (!pskb_may_pull(skb, hdr_size + sizeof(struct vlan_ethhdr)))
+ return 0;
+
+ vhdr = (struct vlan_ethhdr *)(((uint8_t *)skb->data) +
+ hdr_size);
+ vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
+ }
+
+ /* see if this originator is a backbone gw for this VLAN */
+
+ backbone_gw = backbone_hash_find(orig_node->bat_priv,
+ orig_node->orig, vid);
+ if (!backbone_gw)
+ return 0;
+
+ backbone_gw_free_ref(backbone_gw);
+ return 1;
+}
+
+/* free all bla structures (for softinterface free or module unload) */
+void bla_free(struct bat_priv *bat_priv)
+{
+ struct hard_iface *primary_if;
+
+ cancel_delayed_work_sync(&bat_priv->bla_work);
+ primary_if = primary_if_get_selected(bat_priv);
+
+ if (bat_priv->claim_hash) {
+ bla_purge_claims(bat_priv, primary_if, 1);
+ hash_destroy(bat_priv->claim_hash);
+ bat_priv->claim_hash = NULL;
+ }
+ if (bat_priv->backbone_hash) {
+ bla_purge_backbone_gw(bat_priv, 1);
+ hash_destroy(bat_priv->backbone_hash);
+ bat_priv->backbone_hash = NULL;
+ }
+ if (primary_if)
+ hardif_free_ref(primary_if);
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the frame to be checked
+ * @vid: the VLAN ID of the frame
+ *
+ * bla_rx avoidance checks if:
+ * * we have to race for a claim
+ * * if the frame is allowed on the LAN
+ *
+ * in these cases, the skb is further handled by this function and
+ * returns 1, otherwise it returns 0 and the caller shall further
+ * process the skb.
+ *
+ */
+int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
+{
+ struct ethhdr *ethhdr;
+ struct claim search_claim, *claim = NULL;
+ struct hard_iface *primary_if;
+ int ret;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto handled;
+
+ if (!atomic_read(&bat_priv->bridge_loop_avoidance))
+ goto allow;
+
+
+ if (unlikely(atomic_read(&bat_priv->bla_num_requests)))
+ /* don't allow broadcasts while requests are in flight */
+ if (is_multicast_ether_addr(ethhdr->h_dest))
+ goto handled;
+
+ memcpy(search_claim.addr, ethhdr->h_source, ETH_ALEN);
+ search_claim.vid = vid;
+ claim = claim_hash_find(bat_priv, &search_claim);
+
+ if (!claim) {
+ /* possible optimization: race for a claim */
+ /* No claim exists yet, claim it for us!
+ */
+ handle_claim(bat_priv, primary_if,
+ primary_if->net_dev->dev_addr,
+ ethhdr->h_source, vid);
+ goto allow;
+ }
+
+ /* if it is our own claim ... */
+ if (compare_eth(claim->backbone_gw->orig,
+ primary_if->net_dev->dev_addr)) {
+ /* ... allow it in any case */
+ claim->lasttime = jiffies;
+ goto allow;
+ }
+
+ /* if it is a broadcast ... */
+ if (is_multicast_ether_addr(ethhdr->h_dest)) {
+ /* ... drop it. the responsible gateway is in charge. */
+ goto handled;
+ } else {
+ /* seems the client considers us as its best gateway.
+ * send a claim and update the claim table
+ * immediately.
+ */
+ handle_claim(bat_priv, primary_if,
+ primary_if->net_dev->dev_addr,
+ ethhdr->h_source, vid);
+ goto allow;
+ }
+allow:
+ bla_update_own_backbone_gw(bat_priv, primary_if, vid);
+ ret = 0;
+ goto out;
+
+handled:
+ kfree_skb(skb);
+ ret = 1;
+
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ if (claim)
+ claim_free_ref(claim);
+ return ret;
+}
+
+/**
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the frame to be checked
+ * @vid: the VLAN ID of the frame
+ *
+ * bla_tx checks if:
+ * * a claim was received which has to be processed
+ * * the frame is allowed on the mesh
+ *
+ * in these cases, the skb is further handled by this function and
+ * returns 1, otherwise it returns 0 and the caller shall further
+ * process the skb.
+ *
+ */
+int bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
+{
+ struct ethhdr *ethhdr;
+ struct claim search_claim, *claim = NULL;
+ struct hard_iface *primary_if;
+ int ret = 0;
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ if (!atomic_read(&bat_priv->bridge_loop_avoidance))
+ goto allow;
+
+ /* in VLAN case, the mac header might not be set. */
+ skb_reset_mac_header(skb);
+
+ if (bla_process_claim(bat_priv, primary_if, skb))
+ goto handled;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ if (unlikely(atomic_read(&bat_priv->bla_num_requests)))
+ /* don't allow broadcasts while requests are in flight */
+ if (is_multicast_ether_addr(ethhdr->h_dest))
+ goto handled;
+
+ memcpy(search_claim.addr, ethhdr->h_source, ETH_ALEN);
+ search_claim.vid = vid;
+
+ claim = claim_hash_find(bat_priv, &search_claim);
+
+ /* if no claim exists, allow it. */
+ if (!claim)
+ goto allow;
+
+ /* check if we are responsible. */
+ if (compare_eth(claim->backbone_gw->orig,
+ primary_if->net_dev->dev_addr)) {
+ /* if yes, the client has roamed and we have
+ * to unclaim it.
+ */
+ handle_unclaim(bat_priv, primary_if,
+ primary_if->net_dev->dev_addr,
+ ethhdr->h_source, vid);
+ goto allow;
+ }
+
+ /* check if it is a multicast/broadcast frame */
+ if (is_multicast_ether_addr(ethhdr->h_dest)) {
+ /* drop it. the responsible gateway has forwarded it into
+ * the backbone network.
+ */
+ goto handled;
+ } else {
+ /* we must allow it. at least if we are
+ * responsible for the DESTINATION.
+ */
+ goto allow;
+ }
+allow:
+ bla_update_own_backbone_gw(bat_priv, primary_if, vid);
+ ret = 0;
+ goto out;
+handled:
+ ret = 1;
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ if (claim)
+ claim_free_ref(claim);
+ return ret;
+}
+
+int bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
+{
+ struct net_device *net_dev = (struct net_device *)seq->private;
+ struct bat_priv *bat_priv = netdev_priv(net_dev);
+ struct hashtable_t *hash = bat_priv->claim_hash;
+ struct claim *claim;
+ struct hard_iface *primary_if;
+ struct hlist_node *node;
+ struct hlist_head *head;
+ uint32_t i;
+ bool is_own;
+ int ret = 0;
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if) {
+ ret = seq_printf(seq,
+ "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
+ net_dev->name);
+ goto out;
+ }
+
+ if (primary_if->if_status != IF_ACTIVE) {
+ ret = seq_printf(seq,
+ "BATMAN mesh %s disabled - primary interface not active\n",
+ net_dev->name);
+ goto out;
+ }
+
+ seq_printf(seq,
+ "Claims announced for the mesh %s (orig %pM, group id %04x)\n",
+ net_dev->name, primary_if->net_dev->dev_addr,
+ ntohs(bat_priv->claim_dest.group));
+ seq_printf(seq, " %-17s %-5s %-17s [o] (%-4s)\n",
+ "Client", "VID", "Originator", "CRC");
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(claim, node, head, hash_entry) {
+ is_own = compare_eth(claim->backbone_gw->orig,
+ primary_if->net_dev->dev_addr);
+ seq_printf(seq, " * %pM on % 5d by %pM [%c] (%04x)\n",
+ claim->addr, claim->vid,
+ claim->backbone_gw->orig,
+ (is_own ? 'x' : ' '),
+ claim->backbone_gw->crc);
+ }
+ rcu_read_unlock();
+ }
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ return ret;
+}
diff --git a/net/batman-adv/bridge_loop_avoidance.h b/net/batman-adv/bridge_loop_avoidance.h
new file mode 100644
index 000000000000..4a8e4fc766bc
--- /dev/null
+++ b/net/batman-adv/bridge_loop_avoidance.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 B.A.T.M.A.N. contributors:
+ *
+ * Simon Wunderlich
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#ifndef _NET_BATMAN_ADV_BLA_H_
+#define _NET_BATMAN_ADV_BLA_H_
+
+#ifdef CONFIG_BATMAN_ADV_BLA
+int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid);
+int bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid);
+int bla_is_backbone_gw(struct sk_buff *skb,
+ struct orig_node *orig_node, int hdr_size);
+int bla_claim_table_seq_print_text(struct seq_file *seq, void *offset);
+int bla_is_backbone_gw_orig(struct bat_priv *bat_priv, uint8_t *orig);
+int bla_check_bcast_duplist(struct bat_priv *bat_priv,
+ struct bcast_packet *bcast_packet, int hdr_size);
+void bla_update_orig_address(struct bat_priv *bat_priv,
+ struct hard_iface *primary_if,
+ struct hard_iface *oldif);
+int bla_init(struct bat_priv *bat_priv);
+void bla_free(struct bat_priv *bat_priv);
+
+#define BLA_CRC_INIT 0
+#else /* ifdef CONFIG_BATMAN_ADV_BLA */
+
+static inline int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb,
+ short vid)
+{
+ return 0;
+}
+
+static inline int bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb,
+ short vid)
+{
+ return 0;
+}
+
+static inline int bla_is_backbone_gw(struct sk_buff *skb,
+ struct orig_node *orig_node,
+ int hdr_size)
+{
+ return 0;
+}
+
+static inline int bla_claim_table_seq_print_text(struct seq_file *seq,
+ void *offset)
+{
+ return 0;
+}
+
+static inline int bla_is_backbone_gw_orig(struct bat_priv *bat_priv,
+ uint8_t *orig)
+{
+ return 0;
+}
+
+static inline int bla_check_bcast_duplist(struct bat_priv *bat_priv,
+ struct bcast_packet *bcast_packet,
+ int hdr_size)
+{
+ return 0;
+}
+
+static inline void bla_update_orig_address(struct bat_priv *bat_priv,
+ struct hard_iface *primary_if,
+ struct hard_iface *oldif)
+{
+}
+
+static inline int bla_init(struct bat_priv *bat_priv)
+{
+ return 1;
+}
+
+static inline void bla_free(struct bat_priv *bat_priv)
+{
+}
+
+#endif /* ifdef CONFIG_BATMAN_ADV_BLA */
+
+#endif /* ifndef _NET_BATMAN_ADV_BLA_H_ */
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 377897701a85..47c79d724ba3 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -28,6 +28,7 @@
#include "bat_sysfs.h"
#include "originator.h"
#include "hash.h"
+#include "bridge_loop_avoidance.h"
#include <linux/if_arp.h>
@@ -107,7 +108,8 @@ out:
return hard_iface;
}
-static void primary_if_update_addr(struct bat_priv *bat_priv)
+static void primary_if_update_addr(struct bat_priv *bat_priv,
+ struct hard_iface *oldif)
{
struct vis_packet *vis_packet;
struct hard_iface *primary_if;
@@ -122,6 +124,7 @@ static void primary_if_update_addr(struct bat_priv *bat_priv)
memcpy(vis_packet->sender_orig,
primary_if->net_dev->dev_addr, ETH_ALEN);
+ bla_update_orig_address(bat_priv, primary_if, oldif);
out:
if (primary_if)
hardif_free_ref(primary_if);
@@ -140,14 +143,15 @@ static void primary_if_select(struct bat_priv *bat_priv,
curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1);
rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
- if (curr_hard_iface)
- hardif_free_ref(curr_hard_iface);
-
if (!new_hard_iface)
- return;
+ goto out;
- bat_priv->bat_algo_ops->bat_ogm_init_primary(new_hard_iface);
- primary_if_update_addr(bat_priv);
+ bat_priv->bat_algo_ops->bat_primary_iface_set(new_hard_iface);
+ primary_if_update_addr(bat_priv, curr_hard_iface);
+
+out:
+ if (curr_hard_iface)
+ hardif_free_ref(curr_hard_iface);
}
static bool hardif_is_iface_up(const struct hard_iface *hard_iface)
@@ -300,22 +304,17 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
if (!softif_is_valid(soft_iface)) {
pr_err("Can't create batman mesh interface %s: already exists as regular interface\n",
soft_iface->name);
- dev_put(soft_iface);
ret = -EINVAL;
- goto err;
+ goto err_dev;
}
hard_iface->soft_iface = soft_iface;
bat_priv = netdev_priv(hard_iface->soft_iface);
- bat_priv->bat_algo_ops->bat_ogm_init(hard_iface);
-
- if (!hard_iface->packet_buff) {
- bat_err(hard_iface->soft_iface,
- "Can't add interface packet (%s): out of memory\n",
- hard_iface->net_dev->name);
+ ret = bat_priv->bat_algo_ops->bat_iface_enable(hard_iface);
+ if (ret < 0) {
ret = -ENOMEM;
- goto err;
+ goto err_dev;
}
hard_iface->if_num = bat_priv->num_ifaces;
@@ -328,7 +327,6 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
hard_iface->batman_adv_ptype.dev = hard_iface->net_dev;
dev_add_pack(&hard_iface->batman_adv_ptype);
- atomic_set(&hard_iface->seqno, 1);
atomic_set(&hard_iface->frag_seqno, 1);
bat_info(hard_iface->soft_iface, "Adding interface: %s\n",
hard_iface->net_dev->name);
@@ -360,6 +358,8 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
out:
return 0;
+err_dev:
+ dev_put(soft_iface);
err:
hardif_free_ref(hard_iface);
return ret;
@@ -394,8 +394,7 @@ void hardif_disable_interface(struct hard_iface *hard_iface)
hardif_free_ref(new_if);
}
- kfree(hard_iface->packet_buff);
- hard_iface->packet_buff = NULL;
+ bat_priv->bat_algo_ops->bat_iface_disable(hard_iface);
hard_iface->if_status = IF_NOT_IN_USE;
/* delete all references to this hard_iface */
@@ -447,6 +446,13 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
check_known_mac_addr(hard_iface->net_dev);
list_add_tail_rcu(&hard_iface->list, &hardif_list);
+ /**
+ * This can't be called via a bat_priv callback because
+ * we have no bat_priv yet.
+ */
+ atomic_set(&hard_iface->seqno, 1);
+ hard_iface->packet_buff = NULL;
+
return hard_iface;
free_if:
@@ -531,7 +537,7 @@ static int hard_if_event(struct notifier_block *this,
goto hardif_put;
if (hard_iface == primary_if)
- primary_if_update_addr(bat_priv);
+ primary_if_update_addr(bat_priv, NULL);
break;
default:
break;
@@ -568,8 +574,7 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
goto err_free;
/* expect a valid ethernet header here. */
- if (unlikely(skb->mac_len != sizeof(struct ethhdr) ||
- !skb_mac_header(skb)))
+ if (unlikely(skb->mac_len != ETH_HLEN || !skb_mac_header(skb)))
goto err_free;
if (!hard_iface->soft_iface)
@@ -598,7 +603,7 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
switch (batman_ogm_packet->header.packet_type) {
/* batman originator packet */
- case BAT_OGM:
+ case BAT_IV_OGM:
ret = recv_bat_ogm_packet(skb, hard_iface);
break;
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c
index b87518edcef9..2e98a57f3407 100644
--- a/net/batman-adv/icmp_socket.c
+++ b/net/batman-adv/icmp_socket.c
@@ -175,13 +175,13 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
if (len >= sizeof(struct icmp_packet_rr))
packet_len = sizeof(struct icmp_packet_rr);
- skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr));
+ skb = dev_alloc_skb(packet_len + ETH_HLEN);
if (!skb) {
len = -ENOMEM;
goto out;
}
- skb_reserve(skb, sizeof(struct ethhdr));
+ skb_reserve(skb, ETH_HLEN);
icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len);
if (copy_from_user(icmp_packet, buff, packet_len)) {
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 6d51caaf8cec..791327219531 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -30,6 +30,7 @@
#include "translation-table.h"
#include "hard-interface.h"
#include "gateway_client.h"
+#include "bridge_loop_avoidance.h"
#include "vis.h"
#include "hash.h"
#include "bat_algo.h"
@@ -96,13 +97,10 @@ int mesh_init(struct net_device *soft_iface)
spin_lock_init(&bat_priv->gw_list_lock);
spin_lock_init(&bat_priv->vis_hash_lock);
spin_lock_init(&bat_priv->vis_list_lock);
- spin_lock_init(&bat_priv->softif_neigh_lock);
- spin_lock_init(&bat_priv->softif_neigh_vid_lock);
INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
INIT_HLIST_HEAD(&bat_priv->gw_list);
- INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids);
INIT_LIST_HEAD(&bat_priv->tt_changes_list);
INIT_LIST_HEAD(&bat_priv->tt_req_list);
INIT_LIST_HEAD(&bat_priv->tt_roam_list);
@@ -118,6 +116,9 @@ int mesh_init(struct net_device *soft_iface)
if (vis_init(bat_priv) < 1)
goto err;
+ if (bla_init(bat_priv) < 1)
+ goto err;
+
atomic_set(&bat_priv->gw_reselect, 0);
atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
goto end;
@@ -145,7 +146,7 @@ void mesh_free(struct net_device *soft_iface)
tt_free(bat_priv);
- softif_neigh_purge(bat_priv);
+ bla_free(bat_priv);
atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
}
@@ -207,8 +208,9 @@ int bat_algo_register(struct bat_algo_ops *bat_algo_ops)
}
/* all algorithms must implement all ops (for now) */
- if (!bat_algo_ops->bat_ogm_init ||
- !bat_algo_ops->bat_ogm_init_primary ||
+ if (!bat_algo_ops->bat_iface_enable ||
+ !bat_algo_ops->bat_iface_disable ||
+ !bat_algo_ops->bat_primary_iface_set ||
!bat_algo_ops->bat_ogm_update_mac ||
!bat_algo_ops->bat_ogm_schedule ||
!bat_algo_ops->bat_ogm_emit ||
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 94fa1c2393a6..d9832acf558d 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -65,7 +65,7 @@
#define NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */
-#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
+#define NUM_WORDS BITS_TO_LONGS(TQ_LOCAL_WINDOW_SIZE)
#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
@@ -80,8 +80,12 @@
#define MAX_AGGREGATION_BYTES 512
#define MAX_AGGREGATION_MS 100
-#define SOFTIF_NEIGH_TIMEOUT 180000 /* 3 minutes */
+#define BLA_PERIOD_LENGTH 10000 /* 10 seconds */
+#define BLA_BACKBONE_TIMEOUT (BLA_PERIOD_LENGTH * 3)
+#define BLA_CLAIM_TIMEOUT (BLA_PERIOD_LENGTH * 10)
+#define DUPLIST_SIZE 16
+#define DUPLIST_TIMEOUT 500 /* 500 ms */
/* don't reset again within 30 seconds */
#define RESET_PROTECTION_MS 30000
#define EXPECTED_SEQNO_RANGE 65536
@@ -119,7 +123,8 @@ enum dbg_level {
DBG_BATMAN = 1 << 0,
DBG_ROUTES = 1 << 1, /* route added / changed / deleted */
DBG_TT = 1 << 2, /* translation table operations */
- DBG_ALL = 7
+ DBG_BLA = 1 << 3, /* bridge loop avoidance */
+ DBG_ALL = 15
};
/* Kernel headers */
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 43c0a4f1399e..ce4969885894 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -28,6 +28,7 @@
#include "hard-interface.h"
#include "unicast.h"
#include "soft-interface.h"
+#include "bridge_loop_avoidance.h"
static void purge_orig(struct work_struct *work);
@@ -375,8 +376,6 @@ static void _purge_orig(struct bat_priv *bat_priv)
gw_node_purge(bat_priv);
gw_election(bat_priv);
-
- softif_neigh_purge(bat_priv);
}
static void purge_orig(struct work_struct *work)
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index 441f3db1bd91..f54969c61a1e 100644
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@ -25,7 +25,7 @@
#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
enum bat_packettype {
- BAT_OGM = 0x01,
+ BAT_IV_OGM = 0x01,
BAT_ICMP = 0x02,
BAT_UNICAST = 0x03,
BAT_BCAST = 0x04,
@@ -38,7 +38,7 @@ enum bat_packettype {
/* this file is included by batctl which needs these defines */
#define COMPAT_VERSION 14
-enum batman_flags {
+enum batman_iv_flags {
PRIMARIES_FIRST_HOP = 1 << 4,
VIS_SERVER = 1 << 5,
DIRECTLINK = 1 << 6
@@ -90,6 +90,23 @@ enum tt_client_flags {
TT_CLIENT_PENDING = 1 << 10
};
+/* claim frame types for the bridge loop avoidance */
+enum bla_claimframe {
+ CLAIM_TYPE_ADD = 0x00,
+ CLAIM_TYPE_DEL = 0x01,
+ CLAIM_TYPE_ANNOUNCE = 0x02,
+ CLAIM_TYPE_REQUEST = 0x03
+};
+
+/* the destination hardware field in the ARP frame is used to
+ * transport the claim type and the group id
+ */
+struct bla_claim_dst {
+ uint8_t magic[3]; /* FF:43:05 */
+ uint8_t type; /* bla_claimframe */
+ uint16_t group; /* group id */
+} __packed;
+
struct batman_header {
uint8_t packet_type;
uint8_t version; /* batman version field */
@@ -100,8 +117,8 @@ struct batman_ogm_packet {
struct batman_header header;
uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
uint32_t seqno;
- uint8_t orig[6];
- uint8_t prev_sender[6];
+ uint8_t orig[ETH_ALEN];
+ uint8_t prev_sender[ETH_ALEN];
uint8_t gw_flags; /* flags related to gateway class */
uint8_t tq;
uint8_t tt_num_changes;
@@ -109,13 +126,13 @@ struct batman_ogm_packet {
uint16_t tt_crc;
} __packed;
-#define BATMAN_OGM_LEN sizeof(struct batman_ogm_packet)
+#define BATMAN_OGM_HLEN sizeof(struct batman_ogm_packet)
struct icmp_packet {
struct batman_header header;
uint8_t msg_type; /* see ICMP message types above */
- uint8_t dst[6];
- uint8_t orig[6];
+ uint8_t dst[ETH_ALEN];
+ uint8_t orig[ETH_ALEN];
uint16_t seqno;
uint8_t uid;
uint8_t reserved;
@@ -128,8 +145,8 @@ struct icmp_packet {
struct icmp_packet_rr {
struct batman_header header;
uint8_t msg_type; /* see ICMP message types above */
- uint8_t dst[6];
- uint8_t orig[6];
+ uint8_t dst[ETH_ALEN];
+ uint8_t orig[ETH_ALEN];
uint16_t seqno;
uint8_t uid;
uint8_t rr_cur;
@@ -139,16 +156,16 @@ struct icmp_packet_rr {
struct unicast_packet {
struct batman_header header;
uint8_t ttvn; /* destination translation table version number */
- uint8_t dest[6];
+ uint8_t dest[ETH_ALEN];
} __packed;
struct unicast_frag_packet {
struct batman_header header;
uint8_t ttvn; /* destination translation table version number */
- uint8_t dest[6];
+ uint8_t dest[ETH_ALEN];
uint8_t flags;
uint8_t align;
- uint8_t orig[6];
+ uint8_t orig[ETH_ALEN];
uint16_t seqno;
} __packed;
@@ -156,7 +173,7 @@ struct bcast_packet {
struct batman_header header;
uint8_t reserved;
uint32_t seqno;
- uint8_t orig[6];
+ uint8_t orig[ETH_ALEN];
} __packed;
struct vis_packet {
@@ -165,9 +182,9 @@ struct vis_packet {
uint32_t seqno; /* sequence number */
uint8_t entries; /* number of entries behind this struct */
uint8_t reserved;
- uint8_t vis_orig[6]; /* originator that announces its neighbors */
- uint8_t target_orig[6]; /* who should receive this packet */
- uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
+ uint8_t vis_orig[ETH_ALEN]; /* originator reporting its neighbors */
+ uint8_t target_orig[ETH_ALEN]; /* who should receive this packet */
+ uint8_t sender_orig[ETH_ALEN]; /* who sent or forwarded this packet */
} __packed;
struct tt_query_packet {
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 7f8e15899417..ff560863bc74 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -29,6 +29,10 @@
#include "originator.h"
#include "vis.h"
#include "unicast.h"
+#include "bridge_loop_avoidance.h"
+
+static int route_unicast_packet(struct sk_buff *skb,
+ struct hard_iface *recv_if);
void slide_own_bcast_window(struct hard_iface *hard_iface)
{
@@ -52,7 +56,7 @@ void slide_own_bcast_window(struct hard_iface *hard_iface)
bit_get_packet(bat_priv, word, 1, 0);
orig_node->bcast_own_sum[hard_iface->if_num] =
- bit_packet_count(word);
+ bitmap_weight(word, TQ_LOCAL_WINDOW_SIZE);
spin_unlock_bh(&orig_node->ogm_cnt_lock);
}
rcu_read_unlock();
@@ -250,7 +254,7 @@ int recv_bat_ogm_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
struct ethhdr *ethhdr;
/* drop packet if it has not necessary minimum size */
- if (unlikely(!pskb_may_pull(skb, BATMAN_OGM_LEN)))
+ if (unlikely(!pskb_may_pull(skb, BATMAN_OGM_HLEN)))
return NET_RX_DROP;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
@@ -309,7 +313,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
goto out;
/* create a copy of the skb, if needed, to modify it. */
- if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
+ if (skb_cow(skb, ETH_HLEN) < 0)
goto out;
icmp_packet = (struct icmp_packet_rr *)skb->data;
@@ -364,7 +368,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
goto out;
/* create a copy of the skb, if needed, to modify it. */
- if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
+ if (skb_cow(skb, ETH_HLEN) < 0)
goto out;
icmp_packet = (struct icmp_packet *)skb->data;
@@ -450,7 +454,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
goto out;
/* create a copy of the skb, if needed, to modify it. */
- if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
+ if (skb_cow(skb, ETH_HLEN) < 0)
goto out;
icmp_packet = (struct icmp_packet_rr *)skb->data;
@@ -669,6 +673,13 @@ int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
if (!is_my_mac(roam_adv_packet->dst))
return route_unicast_packet(skb, recv_if);
+ /* check if it is a backbone gateway. we don't accept
+ * roaming advertisement from it, as it has the same
+ * entries as we have.
+ */
+ if (bla_is_backbone_gw_orig(bat_priv, roam_adv_packet->src))
+ goto out;
+
orig_node = orig_hash_find(bat_priv, roam_adv_packet->src);
if (!orig_node)
goto out;
@@ -798,7 +809,7 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size)
return 0;
}
-int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
+static int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
{
struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
struct orig_node *orig_node = NULL;
@@ -830,7 +841,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
goto out;
/* create a copy of the skb, if needed, to modify it. */
- if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
+ if (skb_cow(skb, ETH_HLEN) < 0)
goto out;
unicast_packet = (struct unicast_packet *)skb->data;
@@ -1047,8 +1058,8 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
spin_lock_bh(&orig_node->bcast_seqno_lock);
/* check whether the packet is a duplicate */
- if (get_bit_status(orig_node->bcast_bits, orig_node->last_bcast_seqno,
- ntohl(bcast_packet->seqno)))
+ if (bat_test_bit(orig_node->bcast_bits, orig_node->last_bcast_seqno,
+ ntohl(bcast_packet->seqno)))
goto spin_unlock;
seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno;
@@ -1065,9 +1076,19 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
spin_unlock_bh(&orig_node->bcast_seqno_lock);
+ /* check whether this has been sent by another originator before */
+ if (bla_check_bcast_duplist(bat_priv, bcast_packet, hdr_size))
+ goto out;
+
/* rebroadcast packet */
add_bcast_packet_to_list(bat_priv, skb, 1);
+ /* don't hand the broadcast up if it is from an originator
+ * from the same backbone.
+ */
+ if (bla_is_backbone_gw(skb, orig_node, hdr_size))
+ goto out;
+
/* broadcast for me */
interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
ret = NET_RX_SUCCESS;
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h
index 92ac100d83da..3d729cb17113 100644
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@ -25,7 +25,6 @@
void slide_own_bcast_window(struct hard_iface *hard_iface);
void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
struct neigh_node *neigh_node);
-int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if);
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index af7a6741a685..7c66b6121fa6 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -51,7 +51,7 @@ int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
}
/* push to the ethernet header. */
- if (my_skb_head_push(skb, sizeof(*ethhdr)) < 0)
+ if (my_skb_head_push(skb, ETH_HLEN) < 0)
goto send_skb_err;
skb_reset_mac_header(skb);
@@ -87,7 +87,7 @@ static void realloc_packet_buffer(struct hard_iface *hard_iface,
/* keep old buffer if kmalloc should fail */
if (new_buff) {
memcpy(new_buff, hard_iface->packet_buff,
- BATMAN_OGM_LEN);
+ BATMAN_OGM_HLEN);
kfree(hard_iface->packet_buff);
hard_iface->packet_buff = new_buff;
@@ -101,13 +101,13 @@ static int prepare_packet_buffer(struct bat_priv *bat_priv,
{
int new_len;
- new_len = BATMAN_OGM_LEN +
+ new_len = BATMAN_OGM_HLEN +
tt_len((uint8_t)atomic_read(&bat_priv->tt_local_changes));
/* if we have too many changes for one packet don't send any
* and wait for the tt table request which will be fragmented */
if (new_len > hard_iface->soft_iface->mtu)
- new_len = BATMAN_OGM_LEN;
+ new_len = BATMAN_OGM_HLEN;
realloc_packet_buffer(hard_iface, new_len);
@@ -117,14 +117,14 @@ static int prepare_packet_buffer(struct bat_priv *bat_priv,
atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX);
return tt_changes_fill_buffer(bat_priv,
- hard_iface->packet_buff + BATMAN_OGM_LEN,
- hard_iface->packet_len - BATMAN_OGM_LEN);
+ hard_iface->packet_buff + BATMAN_OGM_HLEN,
+ hard_iface->packet_len - BATMAN_OGM_HLEN);
}
static int reset_packet_buffer(struct bat_priv *bat_priv,
struct hard_iface *hard_iface)
{
- realloc_packet_buffer(hard_iface, BATMAN_OGM_LEN);
+ realloc_packet_buffer(hard_iface, BATMAN_OGM_HLEN);
return 0;
}
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index a5590f4193f1..6e2530b02043 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -36,6 +36,7 @@
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include "unicast.h"
+#include "bridge_loop_avoidance.h"
static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
@@ -73,439 +74,6 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len)
return 0;
}
-static void softif_neigh_free_ref(struct softif_neigh *softif_neigh)
-{
- if (atomic_dec_and_test(&softif_neigh->refcount))
- kfree_rcu(softif_neigh, rcu);
-}
-
-static void softif_neigh_vid_free_rcu(struct rcu_head *rcu)
-{
- struct softif_neigh_vid *softif_neigh_vid;
- struct softif_neigh *softif_neigh;
- struct hlist_node *node, *node_tmp;
- struct bat_priv *bat_priv;
-
- softif_neigh_vid = container_of(rcu, struct softif_neigh_vid, rcu);
- bat_priv = softif_neigh_vid->bat_priv;
-
- spin_lock_bh(&bat_priv->softif_neigh_lock);
- hlist_for_each_entry_safe(softif_neigh, node, node_tmp,
- &softif_neigh_vid->softif_neigh_list, list) {
- hlist_del_rcu(&softif_neigh->list);
- softif_neigh_free_ref(softif_neigh);
- }
- spin_unlock_bh(&bat_priv->softif_neigh_lock);
-
- kfree(softif_neigh_vid);
-}
-
-static void softif_neigh_vid_free_ref(struct softif_neigh_vid *softif_neigh_vid)
-{
- if (atomic_dec_and_test(&softif_neigh_vid->refcount))
- call_rcu(&softif_neigh_vid->rcu, softif_neigh_vid_free_rcu);
-}
-
-static struct softif_neigh_vid *softif_neigh_vid_get(struct bat_priv *bat_priv,
- short vid)
-{
- struct softif_neigh_vid *softif_neigh_vid;
- struct hlist_node *node;
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(softif_neigh_vid, node,
- &bat_priv->softif_neigh_vids, list) {
- if (softif_neigh_vid->vid != vid)
- continue;
-
- if (!atomic_inc_not_zero(&softif_neigh_vid->refcount))
- continue;
-
- goto out;
- }
-
- softif_neigh_vid = kzalloc(sizeof(*softif_neigh_vid), GFP_ATOMIC);
- if (!softif_neigh_vid)
- goto out;
-
- softif_neigh_vid->vid = vid;
- softif_neigh_vid->bat_priv = bat_priv;
-
- /* initialize with 2 - caller decrements counter by one */
- atomic_set(&softif_neigh_vid->refcount, 2);
- INIT_HLIST_HEAD(&softif_neigh_vid->softif_neigh_list);
- INIT_HLIST_NODE(&softif_neigh_vid->list);
- spin_lock_bh(&bat_priv->softif_neigh_vid_lock);
- hlist_add_head_rcu(&softif_neigh_vid->list,
- &bat_priv->softif_neigh_vids);
- spin_unlock_bh(&bat_priv->softif_neigh_vid_lock);
-
-out:
- rcu_read_unlock();
- return softif_neigh_vid;
-}
-
-static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
- const uint8_t *addr, short vid)
-{
- struct softif_neigh_vid *softif_neigh_vid;
- struct softif_neigh *softif_neigh = NULL;
- struct hlist_node *node;
-
- softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
- if (!softif_neigh_vid)
- goto out;
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(softif_neigh, node,
- &softif_neigh_vid->softif_neigh_list,
- list) {
- if (!compare_eth(softif_neigh->addr, addr))
- continue;
-
- if (!atomic_inc_not_zero(&softif_neigh->refcount))
- continue;
-
- softif_neigh->last_seen = jiffies;
- goto unlock;
- }
-
- softif_neigh = kzalloc(sizeof(*softif_neigh), GFP_ATOMIC);
- if (!softif_neigh)
- goto unlock;
-
- memcpy(softif_neigh->addr, addr, ETH_ALEN);
- softif_neigh->last_seen = jiffies;
- /* initialize with 2 - caller decrements counter by one */
- atomic_set(&softif_neigh->refcount, 2);
-
- INIT_HLIST_NODE(&softif_neigh->list);
- spin_lock_bh(&bat_priv->softif_neigh_lock);
- hlist_add_head_rcu(&softif_neigh->list,
- &softif_neigh_vid->softif_neigh_list);
- spin_unlock_bh(&bat_priv->softif_neigh_lock);
-
-unlock:
- rcu_read_unlock();
-out:
- if (softif_neigh_vid)
- softif_neigh_vid_free_ref(softif_neigh_vid);
- return softif_neigh;
-}
-
-static struct softif_neigh *softif_neigh_get_selected(
- struct softif_neigh_vid *softif_neigh_vid)
-{
- struct softif_neigh *softif_neigh;
-
- rcu_read_lock();
- softif_neigh = rcu_dereference(softif_neigh_vid->softif_neigh);
-
- if (softif_neigh && !atomic_inc_not_zero(&softif_neigh->refcount))
- softif_neigh = NULL;
-
- rcu_read_unlock();
- return softif_neigh;
-}
-
-static struct softif_neigh *softif_neigh_vid_get_selected(
- struct bat_priv *bat_priv,
- short vid)
-{
- struct softif_neigh_vid *softif_neigh_vid;
- struct softif_neigh *softif_neigh = NULL;
-
- softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
- if (!softif_neigh_vid)
- goto out;
-
- softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
-out:
- if (softif_neigh_vid)
- softif_neigh_vid_free_ref(softif_neigh_vid);
- return softif_neigh;
-}
-
-static void softif_neigh_vid_select(struct bat_priv *bat_priv,
- struct softif_neigh *new_neigh,
- short vid)
-{
- struct softif_neigh_vid *softif_neigh_vid;
- struct softif_neigh *curr_neigh;
-
- softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
- if (!softif_neigh_vid)
- goto out;
-
- spin_lock_bh(&bat_priv->softif_neigh_lock);
-
- if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount))
- new_neigh = NULL;
-
- curr_neigh = rcu_dereference_protected(softif_neigh_vid->softif_neigh,
- 1);
- rcu_assign_pointer(softif_neigh_vid->softif_neigh, new_neigh);
-
- if ((curr_neigh) && (!new_neigh))
- bat_dbg(DBG_ROUTES, bat_priv,
- "Removing mesh exit point on vid: %d (prev: %pM).\n",
- vid, curr_neigh->addr);
- else if ((curr_neigh) && (new_neigh))
- bat_dbg(DBG_ROUTES, bat_priv,
- "Changing mesh exit point on vid: %d from %pM to %pM.\n",
- vid, curr_neigh->addr, new_neigh->addr);
- else if ((!curr_neigh) && (new_neigh))
- bat_dbg(DBG_ROUTES, bat_priv,
- "Setting mesh exit point on vid: %d to %pM.\n",
- vid, new_neigh->addr);
-
- if (curr_neigh)
- softif_neigh_free_ref(curr_neigh);
-
- spin_unlock_bh(&bat_priv->softif_neigh_lock);
-
-out:
- if (softif_neigh_vid)
- softif_neigh_vid_free_ref(softif_neigh_vid);
-}
-
-static void softif_neigh_vid_deselect(struct bat_priv *bat_priv,
- struct softif_neigh_vid *softif_neigh_vid)
-{
- struct softif_neigh *curr_neigh;
- struct softif_neigh *softif_neigh = NULL, *softif_neigh_tmp;
- struct hard_iface *primary_if = NULL;
- struct hlist_node *node;
-
- primary_if = primary_if_get_selected(bat_priv);
- if (!primary_if)
- goto out;
-
- /* find new softif_neigh immediately to avoid temporary loops */
- rcu_read_lock();
- curr_neigh = rcu_dereference(softif_neigh_vid->softif_neigh);
-
- hlist_for_each_entry_rcu(softif_neigh_tmp, node,
- &softif_neigh_vid->softif_neigh_list,
- list) {
- if (softif_neigh_tmp == curr_neigh)
- continue;
-
- /* we got a neighbor but its mac is 'bigger' than ours */
- if (memcmp(primary_if->net_dev->dev_addr,
- softif_neigh_tmp->addr, ETH_ALEN) < 0)
- continue;
-
- if (!atomic_inc_not_zero(&softif_neigh_tmp->refcount))
- continue;
-
- softif_neigh = softif_neigh_tmp;
- goto unlock;
- }
-
-unlock:
- rcu_read_unlock();
-out:
- softif_neigh_vid_select(bat_priv, softif_neigh, softif_neigh_vid->vid);
-
- if (primary_if)
- hardif_free_ref(primary_if);
- if (softif_neigh)
- softif_neigh_free_ref(softif_neigh);
-}
-
-int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
-{
- struct net_device *net_dev = (struct net_device *)seq->private;
- struct bat_priv *bat_priv = netdev_priv(net_dev);
- struct softif_neigh_vid *softif_neigh_vid;
- struct softif_neigh *softif_neigh;
- struct hard_iface *primary_if;
- struct hlist_node *node, *node_tmp;
- struct softif_neigh *curr_softif_neigh;
- int ret = 0, last_seen_secs, last_seen_msecs;
-
- primary_if = primary_if_get_selected(bat_priv);
- if (!primary_if) {
- ret = seq_printf(seq,
- "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
- net_dev->name);
- goto out;
- }
-
- if (primary_if->if_status != IF_ACTIVE) {
- ret = seq_printf(seq,
- "BATMAN mesh %s disabled - primary interface not active\n",
- net_dev->name);
- goto out;
- }
-
- seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name);
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(softif_neigh_vid, node,
- &bat_priv->softif_neigh_vids, list) {
- seq_printf(seq, " %-15s %s on vid: %d\n",
- "Originator", "last-seen", softif_neigh_vid->vid);
-
- curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
-
- hlist_for_each_entry_rcu(softif_neigh, node_tmp,
- &softif_neigh_vid->softif_neigh_list,
- list) {
- last_seen_secs = jiffies_to_msecs(jiffies -
- softif_neigh->last_seen) / 1000;
- last_seen_msecs = jiffies_to_msecs(jiffies -
- softif_neigh->last_seen) % 1000;
- seq_printf(seq, "%s %pM %3i.%03is\n",
- curr_softif_neigh == softif_neigh
- ? "=>" : " ", softif_neigh->addr,
- last_seen_secs, last_seen_msecs);
- }
-
- if (curr_softif_neigh)
- softif_neigh_free_ref(curr_softif_neigh);
-
- seq_printf(seq, "\n");
- }
- rcu_read_unlock();
-
-out:
- if (primary_if)
- hardif_free_ref(primary_if);
- return ret;
-}
-
-void softif_neigh_purge(struct bat_priv *bat_priv)
-{
- struct softif_neigh *softif_neigh, *curr_softif_neigh;
- struct softif_neigh_vid *softif_neigh_vid;
- struct hlist_node *node, *node_tmp, *node_tmp2;
- int do_deselect;
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(softif_neigh_vid, node,
- &bat_priv->softif_neigh_vids, list) {
- if (!atomic_inc_not_zero(&softif_neigh_vid->refcount))
- continue;
-
- curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
- do_deselect = 0;
-
- spin_lock_bh(&bat_priv->softif_neigh_lock);
- hlist_for_each_entry_safe(softif_neigh, node_tmp, node_tmp2,
- &softif_neigh_vid->softif_neigh_list,
- list) {
- if ((!has_timed_out(softif_neigh->last_seen,
- SOFTIF_NEIGH_TIMEOUT)) &&
- (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE))
- continue;
-
- if (curr_softif_neigh == softif_neigh) {
- bat_dbg(DBG_ROUTES, bat_priv,
- "Current mesh exit point on vid: %d '%pM' vanished.\n",
- softif_neigh_vid->vid,
- softif_neigh->addr);
- do_deselect = 1;
- }
-
- hlist_del_rcu(&softif_neigh->list);
- softif_neigh_free_ref(softif_neigh);
- }
- spin_unlock_bh(&bat_priv->softif_neigh_lock);
-
- /* soft_neigh_vid_deselect() needs to acquire the
- * softif_neigh_lock */
- if (do_deselect)
- softif_neigh_vid_deselect(bat_priv, softif_neigh_vid);
-
- if (curr_softif_neigh)
- softif_neigh_free_ref(curr_softif_neigh);
-
- softif_neigh_vid_free_ref(softif_neigh_vid);
- }
- rcu_read_unlock();
-
- spin_lock_bh(&bat_priv->softif_neigh_vid_lock);
- hlist_for_each_entry_safe(softif_neigh_vid, node, node_tmp,
- &bat_priv->softif_neigh_vids, list) {
- if (!hlist_empty(&softif_neigh_vid->softif_neigh_list))
- continue;
-
- hlist_del_rcu(&softif_neigh_vid->list);
- softif_neigh_vid_free_ref(softif_neigh_vid);
- }
- spin_unlock_bh(&bat_priv->softif_neigh_vid_lock);
-
-}
-
-static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
- short vid)
-{
- struct bat_priv *bat_priv = netdev_priv(dev);
- struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
- struct batman_ogm_packet *batman_ogm_packet;
- struct softif_neigh *softif_neigh = NULL;
- struct hard_iface *primary_if = NULL;
- struct softif_neigh *curr_softif_neigh = NULL;
-
- if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
- batman_ogm_packet = (struct batman_ogm_packet *)
- (skb->data + ETH_HLEN + VLAN_HLEN);
- else
- batman_ogm_packet = (struct batman_ogm_packet *)
- (skb->data + ETH_HLEN);
-
- if (batman_ogm_packet->header.version != COMPAT_VERSION)
- goto out;
-
- if (batman_ogm_packet->header.packet_type != BAT_OGM)
- goto out;
-
- if (!(batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
- goto out;
-
- if (is_my_mac(batman_ogm_packet->orig))
- goto out;
-
- softif_neigh = softif_neigh_get(bat_priv, batman_ogm_packet->orig, vid);
- if (!softif_neigh)
- goto out;
-
- curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
- if (curr_softif_neigh == softif_neigh)
- goto out;
-
- primary_if = primary_if_get_selected(bat_priv);
- if (!primary_if)
- goto out;
-
- /* we got a neighbor but its mac is 'bigger' than ours */
- if (memcmp(primary_if->net_dev->dev_addr,
- softif_neigh->addr, ETH_ALEN) < 0)
- goto out;
-
- /* close own batX device and use softif_neigh as exit node */
- if (!curr_softif_neigh) {
- softif_neigh_vid_select(bat_priv, softif_neigh, vid);
- goto out;
- }
-
- /* switch to new 'smallest neighbor' */
- if (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0)
- softif_neigh_vid_select(bat_priv, softif_neigh, vid);
-
-out:
- kfree_skb(skb);
- if (softif_neigh)
- softif_neigh_free_ref(softif_neigh);
- if (curr_softif_neigh)
- softif_neigh_free_ref(curr_softif_neigh);
- if (primary_if)
- hardif_free_ref(primary_if);
- return;
-}
-
static int interface_open(struct net_device *dev)
{
netif_start_queue(dev);
@@ -562,10 +130,11 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
struct hard_iface *primary_if = NULL;
struct bcast_packet *bcast_packet;
struct vlan_ethhdr *vhdr;
- struct softif_neigh *curr_softif_neigh = NULL;
+ static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00,
+ 0x00};
unsigned int header_len = 0;
int data_len = skb->len, ret;
- short vid = -1;
+ short vid __maybe_unused = -1;
bool do_bcast = false;
if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
@@ -583,21 +152,21 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
/* fall through */
case ETH_P_BATMAN:
- softif_batman_recv(skb, soft_iface, vid);
- goto end;
+ goto dropped;
}
- /**
- * if we have a another chosen mesh exit node in range
- * it will transport the packets to the mesh
- */
- curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
- if (curr_softif_neigh)
+ if (bla_tx(bat_priv, skb, vid))
goto dropped;
/* Register the client MAC in the transtable */
tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
+ /* don't accept stp packets. STP does not help in meshes.
+ * better use the bridge loop avoidance ...
+ */
+ if (compare_eth(ethhdr->h_dest, stp_addr))
+ goto dropped;
+
if (is_multicast_ether_addr(ethhdr->h_dest)) {
do_bcast = true;
@@ -675,8 +244,6 @@ dropped:
dropped_freed:
bat_priv->stats.tx_dropped++;
end:
- if (curr_softif_neigh)
- softif_neigh_free_ref(curr_softif_neigh);
if (primary_if)
hardif_free_ref(primary_if);
return NETDEV_TX_OK;
@@ -687,12 +254,9 @@ void interface_rx(struct net_device *soft_iface,
int hdr_size)
{
struct bat_priv *bat_priv = netdev_priv(soft_iface);
- struct unicast_packet *unicast_packet;
struct ethhdr *ethhdr;
struct vlan_ethhdr *vhdr;
- struct softif_neigh *curr_softif_neigh = NULL;
- short vid = -1;
- int ret;
+ short vid __maybe_unused = -1;
/* check if enough space is available for pulling, and pull */
if (!pskb_may_pull(skb, hdr_size))
@@ -716,30 +280,6 @@ void interface_rx(struct net_device *soft_iface,
goto dropped;
}
- /**
- * if we have a another chosen mesh exit node in range
- * it will transport the packets to the non-mesh network
- */
- curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
- if (curr_softif_neigh) {
- skb_push(skb, hdr_size);
- unicast_packet = (struct unicast_packet *)skb->data;
-
- if ((unicast_packet->header.packet_type != BAT_UNICAST) &&
- (unicast_packet->header.packet_type != BAT_UNICAST_FRAG))
- goto dropped;
-
- skb_reset_mac_header(skb);
-
- memcpy(unicast_packet->dest,
- curr_softif_neigh->addr, ETH_ALEN);
- ret = route_unicast_packet(skb, recv_if);
- if (ret == NET_RX_DROP)
- goto dropped;
-
- goto out;
- }
-
/* skb->dev & skb->pkt_type are set here */
if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
goto dropped;
@@ -752,21 +292,25 @@ void interface_rx(struct net_device *soft_iface,
/* skb->ip_summed = CHECKSUM_UNNECESSARY;*/
bat_priv->stats.rx_packets++;
- bat_priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr);
+ bat_priv->stats.rx_bytes += skb->len + ETH_HLEN;
soft_iface->last_rx = jiffies;
if (is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
goto dropped;
+ /* Let the bridge loop avoidance check the packet. If will
+ * not handle it, we can safely push it up.
+ */
+ if (bla_rx(bat_priv, skb, vid))
+ goto out;
+
netif_rx(skb);
goto out;
dropped:
kfree_skb(skb);
out:
- if (curr_softif_neigh)
- softif_neigh_free_ref(curr_softif_neigh);
return;
}
@@ -828,13 +372,14 @@ struct net_device *softif_create(const char *name)
atomic_set(&bat_priv->aggregated_ogms, 1);
atomic_set(&bat_priv->bonding, 0);
+ atomic_set(&bat_priv->bridge_loop_avoidance, 0);
atomic_set(&bat_priv->ap_isolation, 0);
atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
atomic_set(&bat_priv->gw_mode, GW_MODE_OFF);
atomic_set(&bat_priv->gw_sel_class, 20);
atomic_set(&bat_priv->gw_bandwidth, 41);
atomic_set(&bat_priv->orig_interval, 1000);
- atomic_set(&bat_priv->hop_penalty, 10);
+ atomic_set(&bat_priv->hop_penalty, 30);
atomic_set(&bat_priv->log_level, 0);
atomic_set(&bat_priv->fragmentation, 1);
atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN);
@@ -845,6 +390,7 @@ struct net_device *softif_create(const char *name)
atomic_set(&bat_priv->ttvn, 0);
atomic_set(&bat_priv->tt_local_changes, 0);
atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
+ atomic_set(&bat_priv->bla_num_requests, 0);
bat_priv->tt_buff = NULL;
bat_priv->tt_buff_len = 0;
diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h
index 756eab5b8dd4..020300673884 100644
--- a/net/batman-adv/soft-interface.h
+++ b/net/batman-adv/soft-interface.h
@@ -23,8 +23,6 @@
#define _NET_BATMAN_ADV_SOFT_INTERFACE_H_
int my_skb_head_push(struct sk_buff *skb, unsigned int len);
-int softif_neigh_seq_print_text(struct seq_file *seq, void *offset);
-void softif_neigh_purge(struct bat_priv *bat_priv);
void interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, struct hard_iface *recv_if,
int hdr_size);
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 1f8692127840..a38d315d3cd6 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -27,13 +27,14 @@
#include "hash.h"
#include "originator.h"
#include "routing.h"
+#include "bridge_loop_avoidance.h"
#include <linux/crc16.h>
-static void _tt_global_del(struct bat_priv *bat_priv,
- struct tt_global_entry *tt_global_entry,
- const char *message);
+static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
+ struct orig_node *orig_node);
static void tt_purge(struct work_struct *work);
+static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry);
/* returns 1 if they are the same mac addr */
static int compare_tt(const struct hlist_node *node, const void *data2)
@@ -123,17 +124,31 @@ static void tt_global_entry_free_rcu(struct rcu_head *rcu)
tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
common);
- if (tt_global_entry->orig_node)
- orig_node_free_ref(tt_global_entry->orig_node);
-
kfree(tt_global_entry);
}
static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
{
- if (atomic_dec_and_test(&tt_global_entry->common.refcount))
+ if (atomic_dec_and_test(&tt_global_entry->common.refcount)) {
+ tt_global_del_orig_list(tt_global_entry);
call_rcu(&tt_global_entry->common.rcu,
tt_global_entry_free_rcu);
+ }
+}
+
+static void tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
+{
+ struct tt_orig_list_entry *orig_entry;
+
+ orig_entry = container_of(rcu, struct tt_orig_list_entry, rcu);
+ atomic_dec(&orig_entry->orig_node->tt_size);
+ orig_node_free_ref(orig_entry->orig_node);
+ kfree(orig_entry);
+}
+
+static void tt_orig_list_entry_free_ref(struct tt_orig_list_entry *orig_entry)
+{
+ call_rcu(&orig_entry->rcu, tt_orig_list_entry_free_rcu);
}
static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
@@ -182,6 +197,9 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
struct bat_priv *bat_priv = netdev_priv(soft_iface);
struct tt_local_entry *tt_local_entry = NULL;
struct tt_global_entry *tt_global_entry = NULL;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct tt_orig_list_entry *orig_entry;
int hash_added;
tt_local_entry = tt_local_hash_find(bat_priv, addr);
@@ -232,14 +250,21 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
/* Check whether it is a roaming! */
if (tt_global_entry) {
- /* This node is probably going to update its tt table */
- tt_global_entry->orig_node->tt_poss_change = true;
- /* The global entry has to be marked as ROAMING and has to be
- * kept for consistency purpose */
+ /* These node are probably going to update their tt table */
+ head = &tt_global_entry->orig_list;
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(orig_entry, node, head, list) {
+ orig_entry->orig_node->tt_poss_change = true;
+
+ send_roam_adv(bat_priv, tt_global_entry->common.addr,
+ orig_entry->orig_node);
+ }
+ rcu_read_unlock();
+ /* The global entry has to be marked as ROAMING and
+ * has to be kept for consistency purpose
+ */
tt_global_entry->common.flags |= TT_CLIENT_ROAM;
tt_global_entry->roam_at = jiffies;
- send_roam_adv(bat_priv, tt_global_entry->common.addr,
- tt_global_entry->orig_node);
}
out:
if (tt_local_entry)
@@ -490,33 +515,76 @@ static void tt_changes_list_free(struct bat_priv *bat_priv)
spin_unlock_bh(&bat_priv->tt_changes_list_lock);
}
+/* find out if an orig_node is already in the list of a tt_global_entry.
+ * returns 1 if found, 0 otherwise
+ */
+static bool tt_global_entry_has_orig(const struct tt_global_entry *entry,
+ const struct orig_node *orig_node)
+{
+ struct tt_orig_list_entry *tmp_orig_entry;
+ const struct hlist_head *head;
+ struct hlist_node *node;
+ bool found = false;
+
+ rcu_read_lock();
+ head = &entry->orig_list;
+ hlist_for_each_entry_rcu(tmp_orig_entry, node, head, list) {
+ if (tmp_orig_entry->orig_node == orig_node) {
+ found = true;
+ break;
+ }
+ }
+ rcu_read_unlock();
+ return found;
+}
+
+static void tt_global_add_orig_entry(struct tt_global_entry *tt_global_entry,
+ struct orig_node *orig_node,
+ int ttvn)
+{
+ struct tt_orig_list_entry *orig_entry;
+
+ orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC);
+ if (!orig_entry)
+ return;
+
+ INIT_HLIST_NODE(&orig_entry->list);
+ atomic_inc(&orig_node->refcount);
+ atomic_inc(&orig_node->tt_size);
+ orig_entry->orig_node = orig_node;
+ orig_entry->ttvn = ttvn;
+
+ spin_lock_bh(&tt_global_entry->list_lock);
+ hlist_add_head_rcu(&orig_entry->list,
+ &tt_global_entry->orig_list);
+ spin_unlock_bh(&tt_global_entry->list_lock);
+}
+
/* caller must hold orig_node refcount */
int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
bool wifi)
{
- struct tt_global_entry *tt_global_entry;
- struct orig_node *orig_node_tmp;
+ struct tt_global_entry *tt_global_entry = NULL;
int ret = 0;
int hash_added;
tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
if (!tt_global_entry) {
- tt_global_entry =
- kmalloc(sizeof(*tt_global_entry),
- GFP_ATOMIC);
+ tt_global_entry = kzalloc(sizeof(*tt_global_entry),
+ GFP_ATOMIC);
if (!tt_global_entry)
goto out;
memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN);
+
tt_global_entry->common.flags = NO_FLAGS;
- atomic_set(&tt_global_entry->common.refcount, 2);
- /* Assign the new orig_node */
- atomic_inc(&orig_node->refcount);
- tt_global_entry->orig_node = orig_node;
- tt_global_entry->ttvn = ttvn;
tt_global_entry->roam_at = 0;
+ atomic_set(&tt_global_entry->common.refcount, 2);
+
+ INIT_HLIST_HEAD(&tt_global_entry->orig_list);
+ spin_lock_init(&tt_global_entry->list_lock);
hash_added = hash_add(bat_priv->tt_global_hash, compare_tt,
choose_orig, &tt_global_entry->common,
@@ -527,19 +595,27 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
tt_global_entry_free_ref(tt_global_entry);
goto out_remove;
}
- atomic_inc(&orig_node->tt_size);
+
+ tt_global_add_orig_entry(tt_global_entry, orig_node, ttvn);
} else {
- if (tt_global_entry->orig_node != orig_node) {
- atomic_dec(&tt_global_entry->orig_node->tt_size);
- orig_node_tmp = tt_global_entry->orig_node;
- atomic_inc(&orig_node->refcount);
- tt_global_entry->orig_node = orig_node;
- orig_node_free_ref(orig_node_tmp);
- atomic_inc(&orig_node->tt_size);
+ /* there is already a global entry, use this one. */
+
+ /* If there is the TT_CLIENT_ROAM flag set, there is only one
+ * originator left in the list and we previously received a
+ * delete + roaming change for this originator.
+ *
+ * We should first delete the old originator before adding the
+ * new one.
+ */
+ if (tt_global_entry->common.flags & TT_CLIENT_ROAM) {
+ tt_global_del_orig_list(tt_global_entry);
+ tt_global_entry->common.flags &= ~TT_CLIENT_ROAM;
+ tt_global_entry->roam_at = 0;
}
- tt_global_entry->common.flags = NO_FLAGS;
- tt_global_entry->ttvn = ttvn;
- tt_global_entry->roam_at = 0;
+
+ if (!tt_global_entry_has_orig(tt_global_entry, orig_node))
+ tt_global_add_orig_entry(tt_global_entry, orig_node,
+ ttvn);
}
if (wifi)
@@ -560,6 +636,34 @@ out:
return ret;
}
+/* print all orig nodes who announce the address for this global entry.
+ * it is assumed that the caller holds rcu_read_lock();
+ */
+static void tt_global_print_entry(struct tt_global_entry *tt_global_entry,
+ struct seq_file *seq)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct tt_orig_list_entry *orig_entry;
+ struct tt_common_entry *tt_common_entry;
+ uint16_t flags;
+ uint8_t last_ttvn;
+
+ tt_common_entry = &tt_global_entry->common;
+
+ head = &tt_global_entry->orig_list;
+
+ hlist_for_each_entry_rcu(orig_entry, node, head, list) {
+ flags = tt_common_entry->flags;
+ last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
+ seq_printf(seq, " * %pM (%3u) via %pM (%3u) [%c%c]\n",
+ tt_global_entry->common.addr, orig_entry->ttvn,
+ orig_entry->orig_node->orig, last_ttvn,
+ (flags & TT_CLIENT_ROAM ? 'R' : '.'),
+ (flags & TT_CLIENT_WIFI ? 'W' : '.'));
+ }
+}
+
int tt_global_seq_print_text(struct seq_file *seq, void *offset)
{
struct net_device *net_dev = (struct net_device *)seq->private;
@@ -603,18 +707,7 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
tt_global_entry = container_of(tt_common_entry,
struct tt_global_entry,
common);
- seq_printf(seq,
- " * %pM (%3u) via %pM (%3u) [%c%c]\n",
- tt_global_entry->common.addr,
- tt_global_entry->ttvn,
- tt_global_entry->orig_node->orig,
- (uint8_t) atomic_read(
- &tt_global_entry->orig_node->
- last_ttvn),
- (tt_global_entry->common.flags &
- TT_CLIENT_ROAM ? 'R' : '.'),
- (tt_global_entry->common.flags &
- TT_CLIENT_WIFI ? 'W' : '.'));
+ tt_global_print_entry(tt_global_entry, seq);
}
rcu_read_unlock();
}
@@ -624,59 +717,150 @@ out:
return ret;
}
-static void _tt_global_del(struct bat_priv *bat_priv,
- struct tt_global_entry *tt_global_entry,
- const char *message)
+/* deletes the orig list of a tt_global_entry */
+static void tt_global_del_orig_list(struct tt_global_entry *tt_global_entry)
{
- if (!tt_global_entry)
- goto out;
+ struct hlist_head *head;
+ struct hlist_node *node, *safe;
+ struct tt_orig_list_entry *orig_entry;
- bat_dbg(DBG_TT, bat_priv,
- "Deleting global tt entry %pM (via %pM): %s\n",
- tt_global_entry->common.addr, tt_global_entry->orig_node->orig,
- message);
+ spin_lock_bh(&tt_global_entry->list_lock);
+ head = &tt_global_entry->orig_list;
+ hlist_for_each_entry_safe(orig_entry, node, safe, head, list) {
+ hlist_del_rcu(node);
+ tt_orig_list_entry_free_ref(orig_entry);
+ }
+ spin_unlock_bh(&tt_global_entry->list_lock);
- atomic_dec(&tt_global_entry->orig_node->tt_size);
+}
+
+static void tt_global_del_orig_entry(struct bat_priv *bat_priv,
+ struct tt_global_entry *tt_global_entry,
+ struct orig_node *orig_node,
+ const char *message)
+{
+ struct hlist_head *head;
+ struct hlist_node *node, *safe;
+ struct tt_orig_list_entry *orig_entry;
+
+ spin_lock_bh(&tt_global_entry->list_lock);
+ head = &tt_global_entry->orig_list;
+ hlist_for_each_entry_safe(orig_entry, node, safe, head, list) {
+ if (orig_entry->orig_node == orig_node) {
+ bat_dbg(DBG_TT, bat_priv,
+ "Deleting %pM from global tt entry %pM: %s\n",
+ orig_node->orig, tt_global_entry->common.addr,
+ message);
+ hlist_del_rcu(node);
+ tt_orig_list_entry_free_ref(orig_entry);
+ }
+ }
+ spin_unlock_bh(&tt_global_entry->list_lock);
+}
+
+static void tt_global_del_struct(struct bat_priv *bat_priv,
+ struct tt_global_entry *tt_global_entry,
+ const char *message)
+{
+ bat_dbg(DBG_TT, bat_priv,
+ "Deleting global tt entry %pM: %s\n",
+ tt_global_entry->common.addr, message);
hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig,
tt_global_entry->common.addr);
-out:
- if (tt_global_entry)
- tt_global_entry_free_ref(tt_global_entry);
+ tt_global_entry_free_ref(tt_global_entry);
+
}
-void tt_global_del(struct bat_priv *bat_priv,
- struct orig_node *orig_node, const unsigned char *addr,
- const char *message, bool roaming)
+/* If the client is to be deleted, we check if it is the last origantor entry
+ * within tt_global entry. If yes, we set the TT_CLIENT_ROAM flag and the timer,
+ * otherwise we simply remove the originator scheduled for deletion.
+ */
+static void tt_global_del_roaming(struct bat_priv *bat_priv,
+ struct tt_global_entry *tt_global_entry,
+ struct orig_node *orig_node,
+ const char *message)
+{
+ bool last_entry = true;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct tt_orig_list_entry *orig_entry;
+
+ /* no local entry exists, case 1:
+ * Check if this is the last one or if other entries exist.
+ */
+
+ rcu_read_lock();
+ head = &tt_global_entry->orig_list;
+ hlist_for_each_entry_rcu(orig_entry, node, head, list) {
+ if (orig_entry->orig_node != orig_node) {
+ last_entry = false;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ if (last_entry) {
+ /* its the last one, mark for roaming. */
+ tt_global_entry->common.flags |= TT_CLIENT_ROAM;
+ tt_global_entry->roam_at = jiffies;
+ } else
+ /* there is another entry, we can simply delete this
+ * one and can still use the other one.
+ */
+ tt_global_del_orig_entry(bat_priv, tt_global_entry,
+ orig_node, message);
+}
+
+
+
+static void tt_global_del(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ const unsigned char *addr,
+ const char *message, bool roaming)
{
struct tt_global_entry *tt_global_entry = NULL;
struct tt_local_entry *tt_local_entry = NULL;
tt_global_entry = tt_global_hash_find(bat_priv, addr);
- if (!tt_global_entry || tt_global_entry->orig_node != orig_node)
+ if (!tt_global_entry)
goto out;
- if (!roaming)
- goto out_del;
+ if (!roaming) {
+ tt_global_del_orig_entry(bat_priv, tt_global_entry, orig_node,
+ message);
+
+ if (hlist_empty(&tt_global_entry->orig_list))
+ tt_global_del_struct(bat_priv, tt_global_entry,
+ message);
+
+ goto out;
+ }
/* if we are deleting a global entry due to a roam
* event, there are two possibilities:
- * 1) the client roamed from node A to node B => we mark
+ * 1) the client roamed from node A to node B => if there
+ * is only one originator left for this client, we mark
* it with TT_CLIENT_ROAM, we start a timer and we
* wait for node B to claim it. In case of timeout
* the entry is purged.
+ *
+ * If there are other originators left, we directly delete
+ * the originator.
* 2) the client roamed to us => we can directly delete
* the global entry, since it is useless now. */
+
tt_local_entry = tt_local_hash_find(bat_priv,
tt_global_entry->common.addr);
- if (!tt_local_entry) {
- tt_global_entry->common.flags |= TT_CLIENT_ROAM;
- tt_global_entry->roam_at = jiffies;
- goto out;
- }
+ if (tt_local_entry) {
+ /* local entry exists, case 2: client roamed to us. */
+ tt_global_del_orig_list(tt_global_entry);
+ tt_global_del_struct(bat_priv, tt_global_entry, message);
+ } else
+ /* no local entry exists, case 1: check for roaming */
+ tt_global_del_roaming(bat_priv, tt_global_entry, orig_node,
+ message);
-out_del:
- _tt_global_del(bat_priv, tt_global_entry, message);
out:
if (tt_global_entry)
@@ -709,11 +893,14 @@ void tt_global_del_orig(struct bat_priv *bat_priv,
tt_global_entry = container_of(tt_common_entry,
struct tt_global_entry,
common);
- if (tt_global_entry->orig_node == orig_node) {
+
+ tt_global_del_orig_entry(bat_priv, tt_global_entry,
+ orig_node, message);
+
+ if (hlist_empty(&tt_global_entry->orig_list)) {
bat_dbg(DBG_TT, bat_priv,
- "Deleting global tt entry %pM (via %pM): %s\n",
+ "Deleting global tt entry %pM: %s\n",
tt_global_entry->common.addr,
- tt_global_entry->orig_node->orig,
message);
hlist_del_rcu(node);
tt_global_entry_free_ref(tt_global_entry);
@@ -754,7 +941,7 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv)
bat_dbg(DBG_TT, bat_priv,
"Deleting global tt entry (%pM): Roaming timeout\n",
tt_global_entry->common.addr);
- atomic_dec(&tt_global_entry->orig_node->tt_size);
+
hlist_del_rcu(node);
tt_global_entry_free_ref(tt_global_entry);
}
@@ -817,6 +1004,11 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv,
struct tt_local_entry *tt_local_entry = NULL;
struct tt_global_entry *tt_global_entry = NULL;
struct orig_node *orig_node = NULL;
+ struct neigh_node *router = NULL;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct tt_orig_list_entry *orig_entry;
+ int best_tq;
if (src && atomic_read(&bat_priv->ap_isolation)) {
tt_local_entry = tt_local_hash_find(bat_priv, src);
@@ -833,11 +1025,25 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv,
if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
goto out;
- if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
- goto out;
+ best_tq = 0;
- orig_node = tt_global_entry->orig_node;
+ rcu_read_lock();
+ head = &tt_global_entry->orig_list;
+ hlist_for_each_entry_rcu(orig_entry, node, head, list) {
+ router = orig_node_get_router(orig_entry->orig_node);
+ if (!router)
+ continue;
+ if (router->tq_avg > best_tq) {
+ orig_node = orig_entry->orig_node;
+ best_tq = router->tq_avg;
+ }
+ neigh_node_free_ref(router);
+ }
+ /* found anything? */
+ if (orig_node && !atomic_inc_not_zero(&orig_node->refcount))
+ orig_node = NULL;
+ rcu_read_unlock();
out:
if (tt_global_entry)
tt_global_entry_free_ref(tt_global_entry);
@@ -848,7 +1054,8 @@ out:
}
/* Calculates the checksum of the local table of a given orig_node */
-uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
+static uint16_t tt_global_crc(struct bat_priv *bat_priv,
+ struct orig_node *orig_node)
{
uint16_t total = 0, total_one;
struct hashtable_t *hash = bat_priv->tt_global_hash;
@@ -868,20 +1075,26 @@ uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
tt_global_entry = container_of(tt_common_entry,
struct tt_global_entry,
common);
- if (compare_eth(tt_global_entry->orig_node,
- orig_node)) {
- /* Roaming clients are in the global table for
- * consistency only. They don't have to be
- * taken into account while computing the
- * global crc */
- if (tt_common_entry->flags & TT_CLIENT_ROAM)
- continue;
- total_one = 0;
- for (j = 0; j < ETH_ALEN; j++)
- total_one = crc16_byte(total_one,
- tt_common_entry->addr[j]);
- total ^= total_one;
- }
+ /* Roaming clients are in the global table for
+ * consistency only. They don't have to be
+ * taken into account while computing the
+ * global crc
+ */
+ if (tt_global_entry->common.flags & TT_CLIENT_ROAM)
+ continue;
+
+ /* find out if this global entry is announced by this
+ * originator
+ */
+ if (!tt_global_entry_has_orig(tt_global_entry,
+ orig_node))
+ continue;
+
+ total_one = 0;
+ for (j = 0; j < ETH_ALEN; j++)
+ total_one = crc16_byte(total_one,
+ tt_global_entry->common.addr[j]);
+ total ^= total_one;
}
rcu_read_unlock();
}
@@ -936,8 +1149,10 @@ static void tt_req_list_free(struct bat_priv *bat_priv)
spin_unlock_bh(&bat_priv->tt_req_list_lock);
}
-void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
- const unsigned char *tt_buff, uint8_t tt_num_changes)
+static void tt_save_orig_buffer(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ const unsigned char *tt_buff,
+ uint8_t tt_num_changes)
{
uint16_t tt_buff_len = tt_len(tt_num_changes);
@@ -1020,7 +1235,7 @@ static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
common);
- return (tt_global_entry->orig_node == orig_node);
+ return tt_global_entry_has_orig(tt_global_entry, orig_node);
}
static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
@@ -1124,7 +1339,7 @@ static int send_tt_request(struct bat_priv *bat_priv,
memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
tt_request->header.ttl = TTL;
tt_request->ttvn = ttvn;
- tt_request->tt_data = tt_crc;
+ tt_request->tt_data = htons(tt_crc);
tt_request->flags = TT_REQUEST;
if (full_table)
@@ -1401,10 +1616,15 @@ out:
bool send_tt_response(struct bat_priv *bat_priv,
struct tt_query_packet *tt_request)
{
- if (is_my_mac(tt_request->dst))
+ if (is_my_mac(tt_request->dst)) {
+ /* don't answer backbone gws! */
+ if (bla_is_backbone_gw_orig(bat_priv, tt_request->src))
+ return true;
+
return send_my_tt_response(bat_priv, tt_request);
- else
+ } else {
return send_other_tt_response(bat_priv, tt_request);
+ }
}
static void _tt_update_changes(struct bat_priv *bat_priv,
@@ -1508,6 +1728,10 @@ void handle_tt_response(struct bat_priv *bat_priv,
tt_response->src, tt_response->ttvn, tt_response->tt_data,
(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
+ /* we should have never asked a backbone gw */
+ if (bla_is_backbone_gw_orig(bat_priv, tt_response->src))
+ goto out;
+
orig_node = orig_hash_find(bat_priv, tt_response->src);
if (!orig_node)
goto out;
@@ -1627,8 +1851,8 @@ unlock:
return ret;
}
-void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
- struct orig_node *orig_node)
+static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
+ struct orig_node *orig_node)
{
struct neigh_node *neigh_node = NULL;
struct sk_buff *skb = NULL;
@@ -1796,6 +2020,8 @@ void tt_commit_changes(struct bat_priv *bat_priv)
/* Increment the TTVN only once per OGM interval */
atomic_inc(&bat_priv->ttvn);
+ bat_dbg(DBG_TT, bat_priv, "Local changes committed, updating to ttvn %u\n",
+ (uint8_t)atomic_read(&bat_priv->ttvn));
bat_priv->tt_poss_change = false;
}
@@ -1836,6 +2062,10 @@ void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
bool full_table = true;
+ /* don't care about a backbone gateways updates. */
+ if (bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
+ return;
+
/* orig table not initialised AND first diff is in the OGM OR the ttvn
* increased by one -> we can apply the attached changes */
if ((!orig_node->tt_initialised && ttvn == 1) ||
@@ -1873,6 +2103,7 @@ void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
} else {
/* if we missed more than one change or our tables are not
* in sync anymore -> request fresh tt data */
+
if (!orig_node->tt_initialised || ttvn != orig_ttvn ||
orig_node->tt_crc != tt_crc) {
request_table:
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h
index c753633b1da1..bfebe26edd8e 100644
--- a/net/batman-adv/translation-table.h
+++ b/net/batman-adv/translation-table.h
@@ -39,23 +39,15 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
int tt_global_seq_print_text(struct seq_file *seq, void *offset);
void tt_global_del_orig(struct bat_priv *bat_priv,
struct orig_node *orig_node, const char *message);
-void tt_global_del(struct bat_priv *bat_priv,
- struct orig_node *orig_node, const unsigned char *addr,
- const char *message, bool roaming);
struct orig_node *transtable_search(struct bat_priv *bat_priv,
const uint8_t *src, const uint8_t *addr);
-void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
- const unsigned char *tt_buff, uint8_t tt_num_changes);
uint16_t tt_local_crc(struct bat_priv *bat_priv);
-uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node);
void tt_free(struct bat_priv *bat_priv);
bool send_tt_response(struct bat_priv *bat_priv,
struct tt_query_packet *tt_request);
bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr);
void handle_tt_response(struct bat_priv *bat_priv,
struct tt_query_packet *tt_response);
-void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
- struct orig_node *orig_node);
void tt_commit_changes(struct bat_priv *bat_priv);
bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst);
void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 302efb523475..2f4848b776a7 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -27,7 +27,7 @@
#include "packet.h"
#include "bitarray.h"
-#define BAT_HEADER_LEN (sizeof(struct ethhdr) + \
+#define BAT_HEADER_LEN (ETH_HLEN + \
((sizeof(struct unicast_packet) > sizeof(struct bcast_packet) ? \
sizeof(struct unicast_packet) : \
sizeof(struct bcast_packet))))
@@ -90,7 +90,7 @@ struct orig_node {
bool tt_poss_change;
uint32_t last_real_seqno;
uint8_t last_ttl;
- unsigned long bcast_bits[NUM_WORDS];
+ DECLARE_BITMAP(bcast_bits, TQ_LOCAL_WINDOW_SIZE);
uint32_t last_bcast_seqno;
struct hlist_head neigh_list;
struct list_head frag_list;
@@ -132,7 +132,7 @@ struct neigh_node {
uint8_t last_ttl;
struct list_head bonding_list;
unsigned long last_valid;
- unsigned long real_bits[NUM_WORDS];
+ DECLARE_BITMAP(real_bits, TQ_LOCAL_WINDOW_SIZE);
atomic_t refcount;
struct rcu_head rcu;
struct orig_node *orig_node;
@@ -140,6 +140,13 @@ struct neigh_node {
spinlock_t tq_lock; /* protects: tq_recv, tq_index */
};
+#ifdef CONFIG_BATMAN_ADV_BLA
+struct bcast_duplist_entry {
+ uint8_t orig[ETH_ALEN];
+ uint16_t crc;
+ unsigned long entrytime;
+};
+#endif
struct bat_priv {
atomic_t mesh_state;
@@ -148,6 +155,7 @@ struct bat_priv {
atomic_t bonding; /* boolean */
atomic_t fragmentation; /* boolean */
atomic_t ap_isolation; /* boolean */
+ atomic_t bridge_loop_avoidance; /* boolean */
atomic_t vis_mode; /* VIS_TYPE_* */
atomic_t gw_mode; /* GW_MODE_* */
atomic_t gw_sel_class; /* uint */
@@ -161,6 +169,7 @@ struct bat_priv {
atomic_t ttvn; /* translation table version number */
atomic_t tt_ogm_append_cnt;
atomic_t tt_local_changes; /* changes registered in a OGM interval */
+ atomic_t bla_num_requests; /* number of bla requests in flight */
/* The tt_poss_change flag is used to detect an ongoing roaming phase.
* If true, then I received a Roaming_adv and I have to inspect every
* packet directed to me to check whether I am still the true
@@ -174,15 +183,23 @@ struct bat_priv {
struct hlist_head forw_bat_list;
struct hlist_head forw_bcast_list;
struct hlist_head gw_list;
- struct hlist_head softif_neigh_vids;
struct list_head tt_changes_list; /* tracks changes in a OGM int */
struct list_head vis_send_list;
struct hashtable_t *orig_hash;
struct hashtable_t *tt_local_hash;
struct hashtable_t *tt_global_hash;
+#ifdef CONFIG_BATMAN_ADV_BLA
+ struct hashtable_t *claim_hash;
+ struct hashtable_t *backbone_hash;
+#endif
struct list_head tt_req_list; /* list of pending tt_requests */
struct list_head tt_roam_list;
struct hashtable_t *vis_hash;
+#ifdef CONFIG_BATMAN_ADV_BLA
+ struct bcast_duplist_entry bcast_duplist[DUPLIST_SIZE];
+ int bcast_duplist_curr;
+ struct bla_claim_dst claim_dest;
+#endif
spinlock_t forw_bat_list_lock; /* protects forw_bat_list */
spinlock_t forw_bcast_list_lock; /* protects */
spinlock_t tt_changes_list_lock; /* protects tt_changes */
@@ -191,8 +208,6 @@ struct bat_priv {
spinlock_t gw_list_lock; /* protects gw_list and curr_gw */
spinlock_t vis_hash_lock; /* protects vis_hash */
spinlock_t vis_list_lock; /* protects vis_info::recv_list */
- spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */
- spinlock_t softif_neigh_vid_lock; /* protects soft-interface vid list */
atomic_t num_local_tt;
/* Checksum of the local table, recomputed before sending a new OGM */
atomic_t tt_crc;
@@ -202,6 +217,7 @@ struct bat_priv {
struct delayed_work tt_work;
struct delayed_work orig_work;
struct delayed_work vis_work;
+ struct delayed_work bla_work;
struct gw_node __rcu *curr_gw; /* rcu protected pointer */
atomic_t gw_reselect;
struct hard_iface __rcu *primary_if; /* rcu protected pointer */
@@ -239,10 +255,41 @@ struct tt_local_entry {
struct tt_global_entry {
struct tt_common_entry common;
+ struct hlist_head orig_list;
+ spinlock_t list_lock; /* protects the list */
+ unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */
+};
+
+struct tt_orig_list_entry {
struct orig_node *orig_node;
uint8_t ttvn;
- unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */
+ struct rcu_head rcu;
+ struct hlist_node list;
+};
+
+#ifdef CONFIG_BATMAN_ADV_BLA
+struct backbone_gw {
+ uint8_t orig[ETH_ALEN];
+ short vid; /* used VLAN ID */
+ struct hlist_node hash_entry;
+ struct bat_priv *bat_priv;
+ unsigned long lasttime; /* last time we heard of this backbone gw */
+ atomic_t request_sent;
+ atomic_t refcount;
+ struct rcu_head rcu;
+ uint16_t crc; /* crc checksum over all claims */
+};
+
+struct claim {
+ uint8_t addr[ETH_ALEN];
+ short vid;
+ struct backbone_gw *backbone_gw;
+ unsigned long lasttime; /* last time we heard of claim (locals only) */
+ struct rcu_head rcu;
+ atomic_t refcount;
+ struct hlist_node hash_entry;
};
+#endif
struct tt_change_node {
struct list_head list;
@@ -327,31 +374,15 @@ struct recvlist_node {
uint8_t mac[ETH_ALEN];
};
-struct softif_neigh_vid {
- struct hlist_node list;
- struct bat_priv *bat_priv;
- short vid;
- atomic_t refcount;
- struct softif_neigh __rcu *softif_neigh;
- struct rcu_head rcu;
- struct hlist_head softif_neigh_list;
-};
-
-struct softif_neigh {
- struct hlist_node list;
- uint8_t addr[ETH_ALEN];
- unsigned long last_seen;
- atomic_t refcount;
- struct rcu_head rcu;
-};
-
struct bat_algo_ops {
struct hlist_node list;
char *name;
- /* init OGM when hard-interface is enabled */
- void (*bat_ogm_init)(struct hard_iface *hard_iface);
- /* init primary OGM when primary interface is selected */
- void (*bat_ogm_init_primary)(struct hard_iface *hard_iface);
+ /* init routing info when hard-interface is enabled */
+ int (*bat_iface_enable)(struct hard_iface *hard_iface);
+ /* de-init routing info when hard-interface is disabled */
+ void (*bat_iface_disable)(struct hard_iface *hard_iface);
+ /* called when primary interface is selected / changed */
+ void (*bat_primary_iface_set)(struct hard_iface *hard_iface);
/* init mac addresses of the OGM belonging to this hard-interface */
void (*bat_ogm_update_mac)(struct hard_iface *hard_iface);
/* prepare a new outgoing OGM for the send queue */
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index c4a5b8cafada..cec216fb77c7 100644
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@ -434,12 +434,12 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
return NULL;
info->skb_packet = dev_alloc_skb(sizeof(*packet) + vis_info_len +
- sizeof(struct ethhdr));
+ ETH_HLEN);
if (!info->skb_packet) {
kfree(info);
return NULL;
}
- skb_reserve(info->skb_packet, sizeof(struct ethhdr));
+ skb_reserve(info->skb_packet, ETH_HLEN);
packet = (struct vis_packet *)skb_put(info->skb_packet, sizeof(*packet)
+ vis_info_len);
@@ -894,11 +894,11 @@ int vis_init(struct bat_priv *bat_priv)
bat_priv->my_vis_info->skb_packet = dev_alloc_skb(sizeof(*packet) +
MAX_VIS_PACKET_SIZE +
- sizeof(struct ethhdr));
+ ETH_HLEN);
if (!bat_priv->my_vis_info->skb_packet)
goto free_info;
- skb_reserve(bat_priv->my_vis_info->skb_packet, sizeof(struct ethhdr));
+ skb_reserve(bat_priv->my_vis_info->skb_packet, ETH_HLEN);
packet = (struct vis_packet *)skb_put(bat_priv->my_vis_info->skb_packet,
sizeof(*packet));
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index ba829de84423..d6e5929458b1 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -317,6 +317,9 @@ static const struct net_device_ops br_netdev_ops = {
.ndo_add_slave = br_add_slave,
.ndo_del_slave = br_del_slave,
.ndo_fix_features = br_fix_features,
+ .ndo_fdb_add = br_fdb_add,
+ .ndo_fdb_del = br_fdb_delete,
+ .ndo_fdb_dump = br_fdb_dump,
};
static void br_dev_free(struct net_device *dev)
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 5ba0c844d508..5945c54bc2de 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -487,14 +487,14 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
ndm->ndm_ifindex = fdb->dst ? fdb->dst->dev->ifindex : br->dev->ifindex;
ndm->ndm_state = fdb_to_nud(fdb);
- NLA_PUT(skb, NDA_LLADDR, ETH_ALEN, &fdb->addr);
-
+ if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->addr))
+ goto nla_put_failure;
ci.ndm_used = jiffies_to_clock_t(now - fdb->used);
ci.ndm_confirmed = 0;
ci.ndm_updated = jiffies_to_clock_t(now - fdb->updated);
ci.ndm_refcnt = 0;
- NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
-
+ if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
+ goto nla_put_failure;
return nlmsg_end(skb, nlh);
nla_put_failure:
@@ -535,44 +535,38 @@ errout:
}
/* Dump information about entries, in response to GETNEIGH */
-int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
+int br_fdb_dump(struct sk_buff *skb,
+ struct netlink_callback *cb,
+ struct net_device *dev,
+ int idx)
{
- struct net *net = sock_net(skb->sk);
- struct net_device *dev;
- int idx = 0;
-
- rcu_read_lock();
- for_each_netdev_rcu(net, dev) {
- struct net_bridge *br = netdev_priv(dev);
- int i;
+ struct net_bridge *br = netdev_priv(dev);
+ int i;
- if (!(dev->priv_flags & IFF_EBRIDGE))
- continue;
+ if (!(dev->priv_flags & IFF_EBRIDGE))
+ goto out;
- for (i = 0; i < BR_HASH_SIZE; i++) {
- struct hlist_node *h;
- struct net_bridge_fdb_entry *f;
-
- hlist_for_each_entry_rcu(f, h, &br->hash[i], hlist) {
- if (idx < cb->args[0])
- goto skip;
+ for (i = 0; i < BR_HASH_SIZE; i++) {
+ struct hlist_node *h;
+ struct net_bridge_fdb_entry *f;
- if (fdb_fill_info(skb, br, f,
- NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq,
- RTM_NEWNEIGH,
- NLM_F_MULTI) < 0)
- break;
+ hlist_for_each_entry_rcu(f, h, &br->hash[i], hlist) {
+ if (idx < cb->args[0])
+ goto skip;
+
+ if (fdb_fill_info(skb, br, f,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWNEIGH,
+ NLM_F_MULTI) < 0)
+ break;
skip:
- ++idx;
- }
+ ++idx;
}
}
- rcu_read_unlock();
- cb->args[0] = idx;
-
- return skb->len;
+out:
+ return idx;
}
/* Update (create or replace) forwarding database entry */
@@ -614,43 +608,11 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
}
/* Add new permanent fdb entry with RTM_NEWNEIGH */
-int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+int br_fdb_add(struct ndmsg *ndm, struct net_device *dev,
+ unsigned char *addr, u16 nlh_flags)
{
- struct net *net = sock_net(skb->sk);
- struct ndmsg *ndm;
- struct nlattr *tb[NDA_MAX+1];
- struct net_device *dev;
struct net_bridge_port *p;
- const __u8 *addr;
- int err;
-
- ASSERT_RTNL();
- err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
- if (err < 0)
- return err;
-
- ndm = nlmsg_data(nlh);
- if (ndm->ndm_ifindex == 0) {
- pr_info("bridge: RTM_NEWNEIGH with invalid ifindex\n");
- return -EINVAL;
- }
-
- dev = __dev_get_by_index(net, ndm->ndm_ifindex);
- if (dev == NULL) {
- pr_info("bridge: RTM_NEWNEIGH with unknown ifindex\n");
- return -ENODEV;
- }
-
- if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) {
- pr_info("bridge: RTM_NEWNEIGH with invalid address\n");
- return -EINVAL;
- }
-
- addr = nla_data(tb[NDA_LLADDR]);
- if (!is_valid_ether_addr(addr)) {
- pr_info("bridge: RTM_NEWNEIGH with invalid ether address\n");
- return -EINVAL;
- }
+ int err = 0;
if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) {
pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state);
@@ -670,14 +632,14 @@ int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
rcu_read_unlock();
} else {
spin_lock_bh(&p->br->hash_lock);
- err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags);
+ err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags);
spin_unlock_bh(&p->br->hash_lock);
}
return err;
}
-static int fdb_delete_by_addr(struct net_bridge_port *p, const u8 *addr)
+static int fdb_delete_by_addr(struct net_bridge_port *p, u8 *addr)
{
struct net_bridge *br = p->br;
struct hlist_head *head = &br->hash[br_mac_hash(addr)];
@@ -692,40 +654,12 @@ static int fdb_delete_by_addr(struct net_bridge_port *p, const u8 *addr)
}
/* Remove neighbor entry with RTM_DELNEIGH */
-int br_fdb_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+int br_fdb_delete(struct ndmsg *ndm, struct net_device *dev,
+ unsigned char *addr)
{
- struct net *net = sock_net(skb->sk);
- struct ndmsg *ndm;
struct net_bridge_port *p;
- struct nlattr *llattr;
- const __u8 *addr;
- struct net_device *dev;
int err;
- ASSERT_RTNL();
- if (nlmsg_len(nlh) < sizeof(*ndm))
- return -EINVAL;
-
- ndm = nlmsg_data(nlh);
- if (ndm->ndm_ifindex == 0) {
- pr_info("bridge: RTM_DELNEIGH with invalid ifindex\n");
- return -EINVAL;
- }
-
- dev = __dev_get_by_index(net, ndm->ndm_ifindex);
- if (dev == NULL) {
- pr_info("bridge: RTM_DELNEIGH with unknown ifindex\n");
- return -ENODEV;
- }
-
- llattr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_LLADDR);
- if (llattr == NULL || nla_len(llattr) != ETH_ALEN) {
- pr_info("bridge: RTM_DELNEIGH with invalid address\n");
- return -EINVAL;
- }
-
- addr = nla_data(llattr);
-
p = br_port_get_rtnl(dev);
if (p == NULL) {
pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n",
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 61f65344e711..aab8470707c4 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -34,7 +34,7 @@ static inline int should_deliver(const struct net_bridge_port *p,
p->state == BR_STATE_FORWARDING);
}
-static inline unsigned packet_length(const struct sk_buff *skb)
+static inline unsigned int packet_length(const struct sk_buff *skb)
{
return skb->len - (skb->protocol == htons(ETH_P_8021Q) ? VLAN_HLEN : 0);
}
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 27ca25ed7021..708e84f31888 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -36,6 +36,8 @@
#define mlock_dereference(X, br) \
rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
+static void br_multicast_start_querier(struct net_bridge *br);
+
#if IS_ENABLED(CONFIG_IPV6)
static inline int ipv6_is_transient_multicast(const struct in6_addr *addr)
{
@@ -512,8 +514,8 @@ static struct net_bridge_mdb_entry *br_multicast_get_group(
struct net_bridge_mdb_htable *mdb;
struct net_bridge_mdb_entry *mp;
struct hlist_node *p;
- unsigned count = 0;
- unsigned max;
+ unsigned int count = 0;
+ unsigned int max;
int elasticity;
int err;
@@ -740,6 +742,21 @@ static void br_multicast_local_router_expired(unsigned long data)
{
}
+static void br_multicast_querier_expired(unsigned long data)
+{
+ struct net_bridge_port *port = (void *)data;
+ struct net_bridge *br = port->br;
+
+ spin_lock(&br->multicast_lock);
+ if (!netif_running(br->dev) || br->multicast_disabled)
+ goto out;
+
+ br_multicast_start_querier(br);
+
+out:
+ spin_unlock(&br->multicast_lock);
+}
+
static void __br_multicast_send_query(struct net_bridge *br,
struct net_bridge_port *port,
struct br_ip *ip)
@@ -766,6 +783,7 @@ static void br_multicast_send_query(struct net_bridge *br,
struct br_ip br_group;
if (!netif_running(br->dev) || br->multicast_disabled ||
+ !br->multicast_querier ||
timer_pending(&br->multicast_querier_timer))
return;
@@ -1281,8 +1299,8 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
struct sk_buff *skb2 = skb;
const struct iphdr *iph;
struct igmphdr *ih;
- unsigned len;
- unsigned offset;
+ unsigned int len;
+ unsigned int offset;
int err;
/* We treat OOM as packet loss for now. */
@@ -1382,7 +1400,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
u8 icmp6_type;
u8 nexthdr;
__be16 frag_off;
- unsigned len;
+ unsigned int len;
int offset;
int err;
@@ -1548,6 +1566,7 @@ void br_multicast_init(struct net_bridge *br)
br->hash_max = 512;
br->multicast_router = 1;
+ br->multicast_querier = 0;
br->multicast_last_member_count = 2;
br->multicast_startup_query_count = 2;
@@ -1562,7 +1581,7 @@ void br_multicast_init(struct net_bridge *br)
setup_timer(&br->multicast_router_timer,
br_multicast_local_router_expired, 0);
setup_timer(&br->multicast_querier_timer,
- br_multicast_local_router_expired, 0);
+ br_multicast_querier_expired, 0);
setup_timer(&br->multicast_query_timer, br_multicast_query_expired,
(unsigned long)br);
}
@@ -1689,9 +1708,23 @@ unlock:
return err;
}
-int br_multicast_toggle(struct net_bridge *br, unsigned long val)
+static void br_multicast_start_querier(struct net_bridge *br)
{
struct net_bridge_port *port;
+
+ br_multicast_open(br);
+
+ list_for_each_entry(port, &br->port_list, list) {
+ if (port->state == BR_STATE_DISABLED ||
+ port->state == BR_STATE_BLOCKING)
+ continue;
+
+ __br_multicast_enable_port(port);
+ }
+}
+
+int br_multicast_toggle(struct net_bridge *br, unsigned long val)
+{
int err = 0;
struct net_bridge_mdb_htable *mdb;
@@ -1721,14 +1754,7 @@ rollback:
goto rollback;
}
- br_multicast_open(br);
- list_for_each_entry(port, &br->port_list, list) {
- if (port->state == BR_STATE_DISABLED ||
- port->state == BR_STATE_BLOCKING)
- continue;
-
- __br_multicast_enable_port(port);
- }
+ br_multicast_start_querier(br);
unlock:
spin_unlock_bh(&br->multicast_lock);
@@ -1736,6 +1762,24 @@ unlock:
return err;
}
+int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
+{
+ val = !!val;
+
+ spin_lock_bh(&br->multicast_lock);
+ if (br->multicast_querier == val)
+ goto unlock;
+
+ br->multicast_querier = val;
+ if (val)
+ br_multicast_start_querier(br);
+
+unlock:
+ spin_unlock_bh(&br->multicast_lock);
+
+ return 0;
+}
+
int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
{
int err = -ENOENT;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index dec4f3817133..9d4f09c3520f 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -1008,12 +1008,6 @@ static ctl_table brnf_table[] = {
},
{ }
};
-
-static struct ctl_path brnf_path[] = {
- { .procname = "net", },
- { .procname = "bridge", },
- { }
-};
#endif
int __init br_netfilter_init(void)
@@ -1030,7 +1024,7 @@ int __init br_netfilter_init(void)
return ret;
}
#ifdef CONFIG_SYSCTL
- brnf_sysctl_header = register_sysctl_paths(brnf_path, brnf_table);
+ brnf_sysctl_header = register_net_sysctl(&init_net, "net/bridge", brnf_table);
if (brnf_sysctl_header == NULL) {
printk(KERN_WARNING
"br_netfilter: can't register to sysctl.\n");
@@ -1047,7 +1041,7 @@ void br_netfilter_fini(void)
{
nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
#ifdef CONFIG_SYSCTL
- unregister_sysctl_table(brnf_sysctl_header);
+ unregister_net_sysctl_table(brnf_sysctl_header);
#endif
dst_entries_destroy(&fake_dst_ops);
}
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index a1daf8227ed1..2080485515f1 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -60,20 +60,17 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
hdr->ifi_flags = dev_get_flags(dev);
hdr->ifi_change = 0;
- NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
- NLA_PUT_U32(skb, IFLA_MASTER, br->dev->ifindex);
- NLA_PUT_U32(skb, IFLA_MTU, dev->mtu);
- NLA_PUT_U8(skb, IFLA_OPERSTATE, operstate);
-
- if (dev->addr_len)
- NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
-
- if (dev->ifindex != dev->iflink)
- NLA_PUT_U32(skb, IFLA_LINK, dev->iflink);
-
- if (event == RTM_NEWLINK)
- NLA_PUT_U8(skb, IFLA_PROTINFO, port->state);
-
+ if (nla_put_string(skb, IFLA_IFNAME, dev->name) ||
+ nla_put_u32(skb, IFLA_MASTER, br->dev->ifindex) ||
+ nla_put_u32(skb, IFLA_MTU, dev->mtu) ||
+ nla_put_u8(skb, IFLA_OPERSTATE, operstate) ||
+ (dev->addr_len &&
+ nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) ||
+ (dev->ifindex != dev->iflink &&
+ nla_put_u32(skb, IFLA_LINK, dev->iflink)) ||
+ (event == RTM_NEWLINK &&
+ nla_put_u8(skb, IFLA_PROTINFO, port->state)))
+ goto nla_put_failure;
return nlmsg_end(skb, nlh);
nla_put_failure:
@@ -91,7 +88,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
int err = -ENOBUFS;
br_debug(port->br, "port %u(%s) event %d\n",
- (unsigned)port->port_no, port->dev->name, event);
+ (unsigned int)port->port_no, port->dev->name, event);
skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC);
if (skb == NULL)
@@ -235,18 +232,6 @@ int __init br_netlink_init(void)
br_rtm_setlink, NULL, NULL);
if (err)
goto err3;
- err = __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH,
- br_fdb_add, NULL, NULL);
- if (err)
- goto err3;
- err = __rtnl_register(PF_BRIDGE, RTM_DELNEIGH,
- br_fdb_delete, NULL, NULL);
- if (err)
- goto err3;
- err = __rtnl_register(PF_BRIDGE, RTM_GETNEIGH,
- NULL, br_fdb_dump, NULL);
- if (err)
- goto err3;
return 0;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index e1d882257877..1a8ad4fb9a6b 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -224,6 +224,7 @@ struct net_bridge
unsigned char multicast_router;
u8 multicast_disabled:1;
+ u8 multicast_querier:1;
u32 hash_elasticity;
u32 hash_max;
@@ -359,9 +360,18 @@ extern int br_fdb_insert(struct net_bridge *br,
extern void br_fdb_update(struct net_bridge *br,
struct net_bridge_port *source,
const unsigned char *addr);
-extern int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb);
-extern int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
-extern int br_fdb_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
+
+extern int br_fdb_delete(struct ndmsg *ndm,
+ struct net_device *dev,
+ unsigned char *addr);
+extern int br_fdb_add(struct ndmsg *nlh,
+ struct net_device *dev,
+ unsigned char *addr,
+ u16 nlh_flags);
+extern int br_fdb_dump(struct sk_buff *skb,
+ struct netlink_callback *cb,
+ struct net_device *dev,
+ int idx);
/* br_forward.c */
extern void br_deliver(const struct net_bridge_port *to,
@@ -417,6 +427,7 @@ extern int br_multicast_set_router(struct net_bridge *br, unsigned long val);
extern int br_multicast_set_port_router(struct net_bridge_port *p,
unsigned long val);
extern int br_multicast_toggle(struct net_bridge *br, unsigned long val);
+extern int br_multicast_set_querier(struct net_bridge *br, unsigned long val);
extern int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val);
static inline bool br_multicast_is_router(struct net_bridge *br)
diff --git a/net/bridge/br_private_stp.h b/net/bridge/br_private_stp.h
index 05ed9bc7e426..0c0fe36e7aa9 100644
--- a/net/bridge/br_private_stp.h
+++ b/net/bridge/br_private_stp.h
@@ -29,10 +29,9 @@
#define BR_MIN_PATH_COST 1
#define BR_MAX_PATH_COST 65535
-struct br_config_bpdu
-{
- unsigned topology_change:1;
- unsigned topology_change_ack:1;
+struct br_config_bpdu {
+ unsigned int topology_change:1;
+ unsigned int topology_change_ack:1;
bridge_id root;
int root_path_cost;
bridge_id bridge_id;
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index 8c836d96ba76..af9a12099ba4 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -32,7 +32,7 @@ static const char *const br_port_state_names[] = {
void br_log_state(const struct net_bridge_port *p)
{
br_info(p->br, "port %u(%s) entered %s state\n",
- (unsigned) p->port_no, p->dev->name,
+ (unsigned int) p->port_no, p->dev->name,
br_port_state_names[p->state]);
}
@@ -478,7 +478,7 @@ void br_received_tcn_bpdu(struct net_bridge_port *p)
{
if (br_is_designated_port(p)) {
br_info(p->br, "port %u(%s) received tcn bpdu\n",
- (unsigned) p->port_no, p->dev->name);
+ (unsigned int) p->port_no, p->dev->name);
br_topology_change_detection(p->br);
br_topology_change_acknowledge(p);
diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c
index 58de2a0f9975..a6747e673426 100644
--- a/net/bridge/br_stp_timer.c
+++ b/net/bridge/br_stp_timer.c
@@ -56,7 +56,7 @@ static void br_message_age_timer_expired(unsigned long arg)
return;
br_info(br, "port %u(%s) neighbor %.2x%.2x.%pM lost\n",
- (unsigned) p->port_no, p->dev->name,
+ (unsigned int) p->port_no, p->dev->name,
id->prio[0], id->prio[1], &id->addr);
/*
@@ -84,7 +84,7 @@ static void br_forward_delay_timer_expired(unsigned long arg)
struct net_bridge *br = p->br;
br_debug(br, "port %u(%s) forward delay timer\n",
- (unsigned) p->port_no, p->dev->name);
+ (unsigned int) p->port_no, p->dev->name);
spin_lock(&br->lock);
if (p->state == BR_STATE_LISTENING) {
p->state = BR_STATE_LEARNING;
@@ -131,7 +131,7 @@ static void br_hold_timer_expired(unsigned long arg)
struct net_bridge_port *p = (struct net_bridge_port *) arg;
br_debug(p->br, "port %u(%s) hold timer expired\n",
- (unsigned) p->port_no, p->dev->name);
+ (unsigned int) p->port_no, p->dev->name);
spin_lock(&p->br->lock);
if (p->config_pending)
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index c236c0e43984..c5c059333eab 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -297,7 +297,7 @@ static ssize_t store_group_addr(struct device *d,
const char *buf, size_t len)
{
struct net_bridge *br = to_bridge(d);
- unsigned new_addr[6];
+ unsigned int new_addr[6];
int i;
if (!capable(CAP_NET_ADMIN))
@@ -379,6 +379,23 @@ static ssize_t store_multicast_snooping(struct device *d,
static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR,
show_multicast_snooping, store_multicast_snooping);
+static ssize_t show_multicast_querier(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct net_bridge *br = to_bridge(d);
+ return sprintf(buf, "%d\n", br->multicast_querier);
+}
+
+static ssize_t store_multicast_querier(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return store_bridge_parm(d, buf, len, br_multicast_set_querier);
+}
+static DEVICE_ATTR(multicast_querier, S_IRUGO | S_IWUSR,
+ show_multicast_querier, store_multicast_querier);
+
static ssize_t show_hash_elasticity(struct device *d,
struct device_attribute *attr, char *buf)
{
@@ -702,6 +719,7 @@ static struct attribute *bridge_attrs[] = {
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
&dev_attr_multicast_router.attr,
&dev_attr_multicast_snooping.attr,
+ &dev_attr_multicast_querier.attr,
&dev_attr_hash_elasticity.attr,
&dev_attr_hash_max.attr,
&dev_attr_multicast_last_member_count.attr,
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 5016fa57b623..0dccdb3c7d26 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -19,7 +19,7 @@
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/caif/caif_socket.h>
-#include <linux/atomic.h>
+#include <linux/pkt_sched.h>
#include <net/sock.h>
#include <net/tcp_states.h>
#include <net/caif/caif_layer.h>
@@ -130,7 +130,7 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
- (unsigned)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) {
+ (unsigned int)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) {
if (net_ratelimit())
pr_debug("sending flow OFF (queue len = %d %d)\n",
atomic_read(&cf_sk->sk.sk_rmem_alloc),
@@ -505,6 +505,7 @@ static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk,
pkt = cfpkt_fromnative(CAIF_DIR_OUT, skb);
memset(skb->cb, 0, sizeof(struct caif_payload_info));
+ cfpkt_set_prio(pkt, cf_sk->sk.sk_priority);
if (cf_sk->layer.dn == NULL) {
kfree_skb(skb);
@@ -1062,6 +1063,18 @@ static int caif_create(struct net *net, struct socket *sock, int protocol,
/* Store the protocol */
sk->sk_protocol = (unsigned char) protocol;
+ /* Initialize default priority for well-known cases */
+ switch (protocol) {
+ case CAIFPROTO_AT:
+ sk->sk_priority = TC_PRIO_CONTROL;
+ break;
+ case CAIFPROTO_RFM:
+ sk->sk_priority = TC_PRIO_INTERACTIVE_BULK;
+ break;
+ default:
+ sk->sk_priority = TC_PRIO_BESTEFFORT;
+ }
+
/*
* Lock in order to try to stop someone from opening the socket
* too early.
@@ -1081,7 +1094,6 @@ static int caif_create(struct net *net, struct socket *sock, int protocol,
set_rx_flow_on(cf_sk);
/* Set default options on configuration */
- cf_sk->sk.sk_priority = CAIF_PRIO_NORMAL;
cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY;
cf_sk->conn_req.protocol = protocol;
release_sock(&cf_sk->sk);
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index 5cf52225692e..047cd0eec022 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -9,6 +9,7 @@
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/pkt_sched.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfpkt.h>
#include <net/caif/cfctrl.h>
@@ -189,6 +190,7 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
cfctrl->serv.dev_info.id = physlinkid;
cfpkt_addbdy(pkt, CFCTRL_CMD_ENUM);
cfpkt_addbdy(pkt, physlinkid);
+ cfpkt_set_prio(pkt, TC_PRIO_CONTROL);
dn->transmit(dn, pkt);
}
@@ -281,6 +283,7 @@ int cfctrl_linkup_request(struct cflayer *layer,
* might arrive with the newly allocated channel ID.
*/
cfpkt_info(pkt)->dev_info->id = param->phyid;
+ cfpkt_set_prio(pkt, TC_PRIO_CONTROL);
ret =
dn->transmit(dn, pkt);
if (ret < 0) {
@@ -314,6 +317,7 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY);
cfpkt_addbdy(pkt, channelid);
init_info(cfpkt_info(pkt), cfctrl);
+ cfpkt_set_prio(pkt, TC_PRIO_CONTROL);
ret =
dn->transmit(dn, pkt);
#ifndef CAIF_NO_LOOP
diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c
index e335ba859b97..863dedd91bb6 100644
--- a/net/caif/cfpkt_skbuff.c
+++ b/net/caif/cfpkt_skbuff.c
@@ -381,6 +381,7 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos)
memcpy(skb2->data, split, len2nd);
skb2->tail += len2nd;
skb2->len += len2nd;
+ skb2->priority = skb->priority;
return skb_to_pkt(skb2);
}
@@ -394,3 +395,9 @@ struct caif_payload_info *cfpkt_info(struct cfpkt *pkt)
return (struct caif_payload_info *)&pkt_to_skb(pkt)->cb;
}
EXPORT_SYMBOL(cfpkt_info);
+
+void cfpkt_set_prio(struct cfpkt *pkt, int prio)
+{
+ pkt_to_skb(pkt)->priority = prio;
+}
+EXPORT_SYMBOL(cfpkt_set_prio);
diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c
index 4aa33d4496b6..dd485f6128e8 100644
--- a/net/caif/cfsrvl.c
+++ b/net/caif/cfsrvl.c
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/pkt_sched.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfsrvl.h>
#include <net/caif/cfpkt.h>
@@ -120,6 +121,7 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
info->channel_id = service->layer.id;
info->hdr_len = 1;
info->dev_info = &service->dev_info;
+ cfpkt_set_prio(pkt, TC_PRIO_CONTROL);
return layr->dn->transmit(layr->dn, pkt);
}
case CAIF_MODEMCMD_FLOW_OFF_REQ:
@@ -140,6 +142,7 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
info->channel_id = service->layer.id;
info->hdr_len = 1;
info->dev_info = &service->dev_info;
+ cfpkt_set_prio(pkt, TC_PRIO_CONTROL);
return layr->dn->transmit(layr->dn, pkt);
}
default:
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
index d09340e1523f..69771c04ba8f 100644
--- a/net/caif/chnl_net.c
+++ b/net/caif/chnl_net.c
@@ -424,14 +424,14 @@ static int ipcaif_fill_info(struct sk_buff *skb, const struct net_device *dev)
struct chnl_net *priv;
u8 loop;
priv = netdev_priv(dev);
- NLA_PUT_U32(skb, IFLA_CAIF_IPV4_CONNID,
- priv->conn_req.sockaddr.u.dgm.connection_id);
- NLA_PUT_U32(skb, IFLA_CAIF_IPV6_CONNID,
- priv->conn_req.sockaddr.u.dgm.connection_id);
+ if (nla_put_u32(skb, IFLA_CAIF_IPV4_CONNID,
+ priv->conn_req.sockaddr.u.dgm.connection_id) ||
+ nla_put_u32(skb, IFLA_CAIF_IPV6_CONNID,
+ priv->conn_req.sockaddr.u.dgm.connection_id))
+ goto nla_put_failure;
loop = priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP;
- NLA_PUT_U8(skb, IFLA_CAIF_LOOPBACK, loop);
-
-
+ if (nla_put_u8(skb, IFLA_CAIF_LOOPBACK, loop))
+ goto nla_put_failure;
return 0;
nla_put_failure:
return -EMSGSIZE;
diff --git a/net/can/gw.c b/net/can/gw.c
index 3d79b127881e..b41acf25668f 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -66,7 +66,7 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
MODULE_ALIAS("can-gw");
-HLIST_HEAD(cgw_list);
+static HLIST_HEAD(cgw_list);
static struct notifier_block notifier;
static struct kmem_cache *cgw_cache __read_mostly;
diff --git a/net/ceph/auth_x.h b/net/ceph/auth_x.h
index e02da7a5c5a1..f459e93b774f 100644
--- a/net/ceph/auth_x.h
+++ b/net/ceph/auth_x.h
@@ -13,7 +13,7 @@
*/
struct ceph_x_ticket_handler {
struct rb_node node;
- unsigned service;
+ unsigned int service;
struct ceph_crypto_key session_key;
struct ceph_timespec validity;
@@ -27,7 +27,7 @@ struct ceph_x_ticket_handler {
struct ceph_x_authorizer {
struct ceph_buffer *buf;
- unsigned service;
+ unsigned int service;
u64 nonce;
char reply_buf[128]; /* big enough for encrypted blob */
};
@@ -38,7 +38,7 @@ struct ceph_x_info {
bool starting;
u64 server_challenge;
- unsigned have_keys;
+ unsigned int have_keys;
struct rb_root ticket_handlers;
struct ceph_x_authorizer auth_authorizer;
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index cc913193d992..a776f751edbf 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -441,8 +441,8 @@ EXPORT_SYMBOL(ceph_client_id);
* create a fresh client instance
*/
struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private,
- unsigned supported_features,
- unsigned required_features)
+ unsigned int supported_features,
+ unsigned int required_features)
{
struct ceph_client *client;
struct ceph_entity_addr *myaddr = NULL;
diff --git a/net/ceph/ceph_hash.c b/net/ceph/ceph_hash.c
index 0a1b53bce76d..67bb1f11e613 100644
--- a/net/ceph/ceph_hash.c
+++ b/net/ceph/ceph_hash.c
@@ -20,7 +20,7 @@
c = c - a; c = c - b; c = c ^ (b >> 15); \
} while (0)
-unsigned ceph_str_hash_rjenkins(const char *str, unsigned length)
+unsigned int ceph_str_hash_rjenkins(const char *str, unsigned int length)
{
const unsigned char *k = (const unsigned char *)str;
__u32 a, b, c; /* the internal state */
@@ -81,7 +81,7 @@ unsigned ceph_str_hash_rjenkins(const char *str, unsigned length)
/*
* linux dcache hash
*/
-unsigned ceph_str_hash_linux(const char *str, unsigned length)
+unsigned int ceph_str_hash_linux(const char *str, unsigned int length)
{
unsigned long hash = 0;
unsigned char c;
@@ -94,7 +94,7 @@ unsigned ceph_str_hash_linux(const char *str, unsigned length)
}
-unsigned ceph_str_hash(int type, const char *s, unsigned len)
+unsigned int ceph_str_hash(int type, const char *s, unsigned int len)
{
switch (type) {
case CEPH_STR_HASH_LINUX:
diff --git a/net/ceph/crush/mapper.c b/net/ceph/crush/mapper.c
index b79747c4b645..854ac53f56cd 100644
--- a/net/ceph/crush/mapper.c
+++ b/net/ceph/crush/mapper.c
@@ -68,8 +68,8 @@ int crush_find_rule(struct crush_map *map, int ruleset, int type, int size)
static int bucket_perm_choose(struct crush_bucket *bucket,
int x, int r)
{
- unsigned pr = r % bucket->size;
- unsigned i, s;
+ unsigned int pr = r % bucket->size;
+ unsigned int i, s;
/* start a new permutation if @x has changed */
if (bucket->perm_x != x || bucket->perm_n == 0) {
@@ -100,13 +100,13 @@ static int bucket_perm_choose(struct crush_bucket *bucket,
for (i = 0; i < bucket->perm_n; i++)
dprintk(" perm_choose have %d: %d\n", i, bucket->perm[i]);
while (bucket->perm_n <= pr) {
- unsigned p = bucket->perm_n;
+ unsigned int p = bucket->perm_n;
/* no point in swapping the final entry */
if (p < bucket->size - 1) {
i = crush_hash32_3(bucket->hash, x, bucket->id, p) %
(bucket->size - p);
if (i) {
- unsigned t = bucket->perm[p + i];
+ unsigned int t = bucket->perm[p + i];
bucket->perm[p + i] = bucket->perm[p];
bucket->perm[p] = t;
}
diff --git a/net/ceph/debugfs.c b/net/ceph/debugfs.c
index 27d4ea315d12..54b531a01121 100644
--- a/net/ceph/debugfs.c
+++ b/net/ceph/debugfs.c
@@ -94,9 +94,9 @@ static int monc_show(struct seq_file *s, void *p)
mutex_lock(&monc->mutex);
if (monc->have_mdsmap)
- seq_printf(s, "have mdsmap %u\n", (unsigned)monc->have_mdsmap);
+ seq_printf(s, "have mdsmap %u\n", (unsigned int)monc->have_mdsmap);
if (monc->have_osdmap)
- seq_printf(s, "have osdmap %u\n", (unsigned)monc->have_osdmap);
+ seq_printf(s, "have osdmap %u\n", (unsigned int)monc->have_osdmap);
if (monc->want_next_osdmap)
seq_printf(s, "want next osdmap\n");
@@ -146,7 +146,7 @@ static int osdc_show(struct seq_file *s, void *pp)
if (req->r_reassert_version.epoch)
seq_printf(s, "\t%u'%llu",
- (unsigned)le32_to_cpu(req->r_reassert_version.epoch),
+ (unsigned int)le32_to_cpu(req->r_reassert_version.epoch),
le64_to_cpu(req->r_reassert_version.version));
else
seq_printf(s, "\t");
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index f0993af2ae4d..36fa6bf68498 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -699,7 +699,7 @@ static int prepare_write_connect(struct ceph_messenger *msgr,
struct ceph_connection *con,
int include_banner)
{
- unsigned global_seq = get_global_seq(con->msgr, 0);
+ unsigned int global_seq = get_global_seq(con->msgr, 0);
int proto;
switch (con->peer_name.type) {
@@ -816,7 +816,7 @@ static void iter_bio_next(struct bio **bio_iter, int *seg)
static int write_partial_msg_pages(struct ceph_connection *con)
{
struct ceph_msg *msg = con->out_msg;
- unsigned data_len = le32_to_cpu(msg->hdr.data_len);
+ unsigned int data_len = le32_to_cpu(msg->hdr.data_len);
size_t len;
bool do_datacrc = !con->msgr->nocrc;
int ret;
@@ -1554,7 +1554,7 @@ static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
static int read_partial_message_pages(struct ceph_connection *con,
struct page **pages,
- unsigned data_len, bool do_datacrc)
+ unsigned int data_len, bool do_datacrc)
{
void *p;
int ret;
@@ -1587,7 +1587,7 @@ static int read_partial_message_pages(struct ceph_connection *con,
#ifdef CONFIG_BLOCK
static int read_partial_message_bio(struct ceph_connection *con,
struct bio **bio_iter, int *bio_seg,
- unsigned data_len, bool do_datacrc)
+ unsigned int data_len, bool do_datacrc)
{
struct bio_vec *bv = bio_iovec_idx(*bio_iter, *bio_seg);
void *p;
@@ -1629,7 +1629,7 @@ static int read_partial_message(struct ceph_connection *con)
struct ceph_msg *m = con->in_msg;
int ret;
int to, left;
- unsigned front_len, middle_len, data_len;
+ unsigned int front_len, middle_len, data_len;
bool do_datacrc = !con->msgr->nocrc;
int skip;
u64 seq;
@@ -2345,9 +2345,9 @@ void ceph_con_revoke_message(struct ceph_connection *con, struct ceph_msg *msg)
{
mutex_lock(&con->mutex);
if (con->in_msg && con->in_msg == msg) {
- unsigned front_len = le32_to_cpu(con->in_hdr.front_len);
- unsigned middle_len = le32_to_cpu(con->in_hdr.middle_len);
- unsigned data_len = le32_to_cpu(con->in_hdr.data_len);
+ unsigned int front_len = le32_to_cpu(con->in_hdr.front_len);
+ unsigned int middle_len = le32_to_cpu(con->in_hdr.middle_len);
+ unsigned int data_len = le32_to_cpu(con->in_hdr.data_len);
/* skip rest of message */
dout("con_revoke_pages %p msg %p revoked\n", con, msg);
diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
index 1845cde26227..10d6008d31f2 100644
--- a/net/ceph/mon_client.c
+++ b/net/ceph/mon_client.c
@@ -168,7 +168,7 @@ static bool __sub_expired(struct ceph_mon_client *monc)
*/
static void __schedule_delayed(struct ceph_mon_client *monc)
{
- unsigned delay;
+ unsigned int delay;
if (monc->cur_mon < 0 || __sub_expired(monc))
delay = 10 * HZ;
@@ -184,7 +184,7 @@ static void __schedule_delayed(struct ceph_mon_client *monc)
static void __send_subscribe(struct ceph_mon_client *monc)
{
dout("__send_subscribe sub_sent=%u exp=%u want_osd=%d\n",
- (unsigned)monc->sub_sent, __sub_expired(monc),
+ (unsigned int)monc->sub_sent, __sub_expired(monc),
monc->want_next_osdmap);
if ((__sub_expired(monc) && !monc->sub_sent) ||
monc->want_next_osdmap == 1) {
@@ -201,7 +201,7 @@ static void __send_subscribe(struct ceph_mon_client *monc)
if (monc->want_next_osdmap) {
dout("__send_subscribe to 'osdmap' %u\n",
- (unsigned)monc->have_osdmap);
+ (unsigned int)monc->have_osdmap);
ceph_encode_string(&p, end, "osdmap", 6);
i = p;
i->have = cpu_to_le64(monc->have_osdmap);
@@ -211,7 +211,7 @@ static void __send_subscribe(struct ceph_mon_client *monc)
}
if (monc->want_mdsmap) {
dout("__send_subscribe to 'mdsmap' %u+\n",
- (unsigned)monc->have_mdsmap);
+ (unsigned int)monc->have_mdsmap);
ceph_encode_string(&p, end, "mdsmap", 6);
i = p;
i->have = cpu_to_le64(monc->have_mdsmap);
@@ -236,7 +236,7 @@ static void __send_subscribe(struct ceph_mon_client *monc)
static void handle_subscribe_ack(struct ceph_mon_client *monc,
struct ceph_msg *msg)
{
- unsigned seconds;
+ unsigned int seconds;
struct ceph_mon_subscribe_ack *h = msg->front.iov_base;
if (msg->front.iov_len < sizeof(*h))
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index 5e254055c910..1b0ef3c4d393 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -1214,7 +1214,7 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg,
}
if (!req->r_got_reply) {
- unsigned bytes;
+ unsigned int bytes;
req->r_result = le32_to_cpu(rhead->result);
bytes = le32_to_cpu(msg->hdr.data_len);
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index 29ad46ec9dcf..56e561a69004 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -38,7 +38,7 @@ done:
/* maps */
-static int calc_bits_of(unsigned t)
+static int calc_bits_of(unsigned int t)
{
int b = 0;
while (t) {
@@ -154,7 +154,7 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
magic = ceph_decode_32(p);
if (magic != CRUSH_MAGIC) {
pr_err("crush_decode magic %x != current %x\n",
- (unsigned)magic, (unsigned)CRUSH_MAGIC);
+ (unsigned int)magic, (unsigned int)CRUSH_MAGIC);
goto bad;
}
c->max_buckets = ceph_decode_32(p);
@@ -460,7 +460,7 @@ static void __remove_pg_pool(struct rb_root *root, struct ceph_pg_pool_info *pi)
static int __decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi)
{
- unsigned n, m;
+ unsigned int n, m;
ceph_decode_copy(p, &pi->v, sizeof(pi->v));
calc_pg_masks(pi);
@@ -970,7 +970,7 @@ void ceph_calc_file_object_mapping(struct ceph_file_layout *layout,
objsetno = stripeno / su_per_object;
*ono = objsetno * sc + stripepos;
- dout("objset %u * sc %u = ono %u\n", objsetno, sc, (unsigned)*ono);
+ dout("objset %u * sc %u = ono %u\n", objsetno, sc, (unsigned int)*ono);
/* *oxoff = *off % layout->fl_stripe_unit; # offset in su */
t = off;
@@ -998,12 +998,12 @@ int ceph_calc_object_layout(struct ceph_object_layout *ol,
struct ceph_file_layout *fl,
struct ceph_osdmap *osdmap)
{
- unsigned num, num_mask;
+ unsigned int num, num_mask;
struct ceph_pg pgid;
s32 preferred = (s32)le32_to_cpu(fl->fl_pg_preferred);
int poolid = le32_to_cpu(fl->fl_pg_pool);
struct ceph_pg_pool_info *pool;
- unsigned ps;
+ unsigned int ps;
BUG_ON(!osdmap);
@@ -1045,7 +1045,7 @@ static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
struct ceph_pg_mapping *pg;
struct ceph_pg_pool_info *pool;
int ruleno;
- unsigned poolid, ps, pps, t;
+ unsigned int poolid, ps, pps, t;
int preferred;
poolid = le32_to_cpu(pgid.pool);
diff --git a/net/compat.c b/net/compat.c
index e055708b8ec9..e240441a2317 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -741,13 +741,13 @@ static unsigned char nas[21] = {
};
#undef AL
-asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags)
+asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
{
return sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
}
asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
- unsigned vlen, unsigned int flags)
+ unsigned int vlen, unsigned int flags)
{
return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
flags | MSG_CMSG_COMPAT);
@@ -758,20 +758,20 @@ asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, uns
return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
}
-asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned flags)
+asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned int flags)
{
return sys_recv(fd, buf, len, flags | MSG_CMSG_COMPAT);
}
asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
- unsigned flags, struct sockaddr __user *addr,
+ unsigned int flags, struct sockaddr __user *addr,
int __user *addrlen)
{
return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
}
asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
- unsigned vlen, unsigned int flags,
+ unsigned int vlen, unsigned int flags,
struct compat_timespec __user *timeout)
{
int datagrams;
diff --git a/net/core/datagram.c b/net/core/datagram.c
index e4fbfd6e2bd4..ae6acf6a3dea 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -65,7 +65,7 @@ static inline int connection_based(struct sock *sk)
return sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM;
}
-static int receiver_wake_function(wait_queue_t *wait, unsigned mode, int sync,
+static int receiver_wake_function(wait_queue_t *wait, unsigned int mode, int sync,
void *key)
{
unsigned long bits = (unsigned long)key;
@@ -158,7 +158,7 @@ out_noerr:
* quite explicitly by POSIX 1003.1g, don't change them without having
* the standard around please.
*/
-struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
+struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
int *peeked, int *off, int *err)
{
struct sk_buff *skb;
@@ -216,7 +216,7 @@ no_packet:
}
EXPORT_SYMBOL(__skb_recv_datagram);
-struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
+struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned int flags,
int noblock, int *err)
{
int peeked, off = 0;
diff --git a/net/core/dev.c b/net/core/dev.c
index 9bb8f87c4cda..501f3cc703dd 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -208,7 +208,8 @@ static inline void dev_base_seq_inc(struct net *net)
static inline struct hlist_head *dev_name_hash(struct net *net, const char *name)
{
- unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
+ unsigned int hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
+
return &net->dev_name_head[hash_32(hash, NETDEV_HASHBITS)];
}
@@ -3541,10 +3542,13 @@ gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb)
break;
case GRO_DROP:
- case GRO_MERGED_FREE:
kfree_skb(skb);
break;
+ case GRO_MERGED_FREE:
+ consume_skb(skb);
+ break;
+
case GRO_HELD:
case GRO_MERGED:
break;
@@ -4618,9 +4622,9 @@ void dev_set_rx_mode(struct net_device *dev)
*
* Get the combination of flag bits exported through APIs to userspace.
*/
-unsigned dev_get_flags(const struct net_device *dev)
+unsigned int dev_get_flags(const struct net_device *dev)
{
- unsigned flags;
+ unsigned int flags;
flags = (dev->flags & ~(IFF_PROMISC |
IFF_ALLMULTI |
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index 626698f0db8b..c4cc2bc49f06 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -21,12 +21,35 @@
* General list handling functions
*/
+static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
+ unsigned char *addr, int addr_len,
+ unsigned char addr_type, bool global)
+{
+ struct netdev_hw_addr *ha;
+ int alloc_size;
+
+ alloc_size = sizeof(*ha);
+ if (alloc_size < L1_CACHE_BYTES)
+ alloc_size = L1_CACHE_BYTES;
+ ha = kmalloc(alloc_size, GFP_ATOMIC);
+ if (!ha)
+ return -ENOMEM;
+ memcpy(ha->addr, addr, addr_len);
+ ha->type = addr_type;
+ ha->refcount = 1;
+ ha->global_use = global;
+ ha->synced = false;
+ list_add_tail_rcu(&ha->list, &list->list);
+ list->count++;
+
+ return 0;
+}
+
static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
unsigned char *addr, int addr_len,
unsigned char addr_type, bool global)
{
struct netdev_hw_addr *ha;
- int alloc_size;
if (addr_len > MAX_ADDR_LEN)
return -EINVAL;
@@ -46,21 +69,7 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
}
}
-
- alloc_size = sizeof(*ha);
- if (alloc_size < L1_CACHE_BYTES)
- alloc_size = L1_CACHE_BYTES;
- ha = kmalloc(alloc_size, GFP_ATOMIC);
- if (!ha)
- return -ENOMEM;
- memcpy(ha->addr, addr, addr_len);
- ha->type = addr_type;
- ha->refcount = 1;
- ha->global_use = global;
- ha->synced = false;
- list_add_tail_rcu(&ha->list, &list->list);
- list->count++;
- return 0;
+ return __hw_addr_create_ex(list, addr, addr_len, addr_type, global);
}
static int __hw_addr_add(struct netdev_hw_addr_list *list, unsigned char *addr,
@@ -377,6 +386,34 @@ EXPORT_SYMBOL(dev_addr_del_multiple);
*/
/**
+ * dev_uc_add_excl - Add a global secondary unicast address
+ * @dev: device
+ * @addr: address to add
+ */
+int dev_uc_add_excl(struct net_device *dev, unsigned char *addr)
+{
+ struct netdev_hw_addr *ha;
+ int err;
+
+ netif_addr_lock_bh(dev);
+ list_for_each_entry(ha, &dev->uc.list, list) {
+ if (!memcmp(ha->addr, addr, dev->addr_len) &&
+ ha->type == NETDEV_HW_ADDR_T_UNICAST) {
+ err = -EEXIST;
+ goto out;
+ }
+ }
+ err = __hw_addr_create_ex(&dev->uc, addr, dev->addr_len,
+ NETDEV_HW_ADDR_T_UNICAST, true);
+ if (!err)
+ __dev_set_rx_mode(dev);
+out:
+ netif_addr_unlock_bh(dev);
+ return err;
+}
+EXPORT_SYMBOL(dev_uc_add_excl);
+
+/**
* dev_uc_add - Add a secondary unicast address
* @dev: device
* @addr: address to add
@@ -501,6 +538,34 @@ EXPORT_SYMBOL(dev_uc_init);
* Multicast list handling functions
*/
+/**
+ * dev_mc_add_excl - Add a global secondary multicast address
+ * @dev: device
+ * @addr: address to add
+ */
+int dev_mc_add_excl(struct net_device *dev, unsigned char *addr)
+{
+ struct netdev_hw_addr *ha;
+ int err;
+
+ netif_addr_lock_bh(dev);
+ list_for_each_entry(ha, &dev->mc.list, list) {
+ if (!memcmp(ha->addr, addr, dev->addr_len) &&
+ ha->type == NETDEV_HW_ADDR_T_MULTICAST) {
+ err = -EEXIST;
+ goto out;
+ }
+ }
+ err = __hw_addr_create_ex(&dev->mc, addr, dev->addr_len,
+ NETDEV_HW_ADDR_T_MULTICAST, true);
+ if (!err)
+ __dev_set_rx_mode(dev);
+out:
+ netif_addr_unlock_bh(dev);
+ return err;
+}
+EXPORT_SYMBOL(dev_mc_add_excl);
+
static int __dev_mc_add(struct net_device *dev, unsigned char *addr,
bool global)
{
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 6d6d7d25caaa..beacdd93cd8f 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -17,6 +17,8 @@
#include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
+#include <linux/net_tstamp.h>
+#include <linux/phy.h>
#include <linux/bitops.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
@@ -36,6 +38,17 @@ u32 ethtool_op_get_link(struct net_device *dev)
}
EXPORT_SYMBOL(ethtool_op_get_link);
+int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
+{
+ info->so_timestamping =
+ SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+ info->phc_index = -1;
+ return 0;
+}
+EXPORT_SYMBOL(ethtool_op_get_ts_info);
+
/* Handlers for each ethtool command */
#define ETHTOOL_DEV_FEATURE_WORDS ((NETDEV_FEATURE_COUNT + 31) / 32)
@@ -1278,6 +1291,40 @@ out:
return ret;
}
+static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr)
+{
+ int err = 0;
+ struct ethtool_ts_info info;
+ const struct ethtool_ops *ops = dev->ethtool_ops;
+ struct phy_device *phydev = dev->phydev;
+
+ memset(&info, 0, sizeof(info));
+ info.cmd = ETHTOOL_GET_TS_INFO;
+
+ if (phydev && phydev->drv && phydev->drv->ts_info) {
+
+ err = phydev->drv->ts_info(phydev, &info);
+
+ } else if (dev->ethtool_ops && dev->ethtool_ops->get_ts_info) {
+
+ err = ops->get_ts_info(dev, &info);
+
+ } else {
+ info.so_timestamping =
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+ info.phc_index = -1;
+ }
+
+ if (err)
+ return err;
+
+ if (copy_to_user(useraddr, &info, sizeof(info)))
+ err = -EFAULT;
+
+ return err;
+}
+
/* The main entry point in this file. Called from net/core/dev.c */
int dev_ethtool(struct net *net, struct ifreq *ifr)
@@ -1295,11 +1342,13 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
return -EFAULT;
if (!dev->ethtool_ops) {
- /* ETHTOOL_GDRVINFO does not require any driver support.
- * It is also unprivileged and does not change anything,
- * so we can take a shortcut to it. */
+ /* A few commands do not require any driver support,
+ * are unprivileged, and do not change anything, so we
+ * can take a shortcut to them. */
if (ethcmd == ETHTOOL_GDRVINFO)
return ethtool_get_drvinfo(dev, useraddr);
+ else if (ethcmd == ETHTOOL_GET_TS_INFO)
+ return ethtool_get_ts_info(dev, useraddr);
else
return -EOPNOTSUPP;
}
@@ -1330,6 +1379,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_GRXCLSRULE:
case ETHTOOL_GRXCLSRLALL:
case ETHTOOL_GFEATURES:
+ case ETHTOOL_GET_TS_INFO:
break;
default:
if (!capable(CAP_NET_ADMIN))
@@ -1496,6 +1546,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_GET_DUMP_DATA:
rc = ethtool_get_dump_data(dev, useraddr);
break;
+ case ETHTOOL_GET_TS_INFO:
+ rc = ethtool_get_ts_info(dev, useraddr);
+ break;
default:
rc = -EOPNOTSUPP;
}
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index c02e63c908da..72cceb79d0d4 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -542,7 +542,8 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
frh = nlmsg_data(nlh);
frh->family = ops->family;
frh->table = rule->table;
- NLA_PUT_U32(skb, FRA_TABLE, rule->table);
+ if (nla_put_u32(skb, FRA_TABLE, rule->table))
+ goto nla_put_failure;
frh->res1 = 0;
frh->res2 = 0;
frh->action = rule->action;
@@ -553,31 +554,28 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
frh->flags |= FIB_RULE_UNRESOLVED;
if (rule->iifname[0]) {
- NLA_PUT_STRING(skb, FRA_IIFNAME, rule->iifname);
-
+ if (nla_put_string(skb, FRA_IIFNAME, rule->iifname))
+ goto nla_put_failure;
if (rule->iifindex == -1)
frh->flags |= FIB_RULE_IIF_DETACHED;
}
if (rule->oifname[0]) {
- NLA_PUT_STRING(skb, FRA_OIFNAME, rule->oifname);
-
+ if (nla_put_string(skb, FRA_OIFNAME, rule->oifname))
+ goto nla_put_failure;
if (rule->oifindex == -1)
frh->flags |= FIB_RULE_OIF_DETACHED;
}
- if (rule->pref)
- NLA_PUT_U32(skb, FRA_PRIORITY, rule->pref);
-
- if (rule->mark)
- NLA_PUT_U32(skb, FRA_FWMARK, rule->mark);
-
- if (rule->mark_mask || rule->mark)
- NLA_PUT_U32(skb, FRA_FWMASK, rule->mark_mask);
-
- if (rule->target)
- NLA_PUT_U32(skb, FRA_GOTO, rule->target);
-
+ if ((rule->pref &&
+ nla_put_u32(skb, FRA_PRIORITY, rule->pref)) ||
+ (rule->mark &&
+ nla_put_u32(skb, FRA_FWMARK, rule->mark)) ||
+ ((rule->mark_mask || rule->mark) &&
+ nla_put_u32(skb, FRA_FWMASK, rule->mark_mask)) ||
+ (rule->target &&
+ nla_put_u32(skb, FRA_GOTO, rule->target)))
+ goto nla_put_failure;
if (ops->fill(rule, skb, frh) < 0)
goto nla_put_failure;
diff --git a/net/core/filter.c b/net/core/filter.c
index 6f755cca4520..47a5f055e7f3 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -317,6 +317,9 @@ load_b:
case BPF_S_ANC_CPU:
A = raw_smp_processor_id();
continue;
+ case BPF_S_ANC_ALU_XOR_X:
+ A ^= X;
+ continue;
case BPF_S_ANC_NLATTR: {
struct nlattr *nla;
@@ -528,7 +531,7 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
* Compare this with conditional jumps below,
* where offsets are limited. --ANK (981016)
*/
- if (ftest->k >= (unsigned)(flen-pc-1))
+ if (ftest->k >= (unsigned int)(flen-pc-1))
return -EINVAL;
break;
case BPF_S_JMP_JEQ_K:
@@ -561,6 +564,7 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
ANCILLARY(HATYPE);
ANCILLARY(RXHASH);
ANCILLARY(CPU);
+ ANCILLARY(ALU_XOR_X);
}
}
ftest->code = code;
@@ -589,6 +593,67 @@ void sk_filter_release_rcu(struct rcu_head *rcu)
}
EXPORT_SYMBOL(sk_filter_release_rcu);
+static int __sk_prepare_filter(struct sk_filter *fp)
+{
+ int err;
+
+ fp->bpf_func = sk_run_filter;
+
+ err = sk_chk_filter(fp->insns, fp->len);
+ if (err)
+ return err;
+
+ bpf_jit_compile(fp);
+ return 0;
+}
+
+/**
+ * sk_unattached_filter_create - create an unattached filter
+ * @fprog: the filter program
+ * @sk: the socket to use
+ *
+ * Create a filter independent ofr any socket. We first run some
+ * sanity checks on it to make sure it does not explode on us later.
+ * If an error occurs or there is insufficient memory for the filter
+ * a negative errno code is returned. On success the return is zero.
+ */
+int sk_unattached_filter_create(struct sk_filter **pfp,
+ struct sock_fprog *fprog)
+{
+ struct sk_filter *fp;
+ unsigned int fsize = sizeof(struct sock_filter) * fprog->len;
+ int err;
+
+ /* Make sure new filter is there and in the right amounts. */
+ if (fprog->filter == NULL)
+ return -EINVAL;
+
+ fp = kmalloc(fsize + sizeof(*fp), GFP_KERNEL);
+ if (!fp)
+ return -ENOMEM;
+ memcpy(fp->insns, fprog->filter, fsize);
+
+ atomic_set(&fp->refcnt, 1);
+ fp->len = fprog->len;
+
+ err = __sk_prepare_filter(fp);
+ if (err)
+ goto free_mem;
+
+ *pfp = fp;
+ return 0;
+free_mem:
+ kfree(fp);
+ return err;
+}
+EXPORT_SYMBOL_GPL(sk_unattached_filter_create);
+
+void sk_unattached_filter_destroy(struct sk_filter *fp)
+{
+ sk_filter_release(fp);
+}
+EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy);
+
/**
* sk_attach_filter - attach a socket filter
* @fprog: the filter program
@@ -619,16 +684,13 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
atomic_set(&fp->refcnt, 1);
fp->len = fprog->len;
- fp->bpf_func = sk_run_filter;
- err = sk_chk_filter(fp->insns, fp->len);
+ err = __sk_prepare_filter(fp);
if (err) {
sk_filter_uncharge(sk, fp);
return err;
}
- bpf_jit_compile(fp);
-
old_fp = rcu_dereference_protected(sk->sk_filter,
sock_owned_by_user(sk));
rcu_assign_pointer(sk->sk_filter, fp);
diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c
index 0452eb27a272..ddedf211e588 100644
--- a/net/core/gen_stats.c
+++ b/net/core/gen_stats.c
@@ -27,7 +27,8 @@
static inline int
gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size)
{
- NLA_PUT(d->skb, type, size, buf);
+ if (nla_put(d->skb, type, size, buf))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/core/kmap_skb.h b/net/core/kmap_skb.h
deleted file mode 100644
index 52d0a4459041..000000000000
--- a/net/core/kmap_skb.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <linux/highmem.h>
-
-static inline void *kmap_skb_frag(const skb_frag_t *frag)
-{
-#ifdef CONFIG_HIGHMEM
- BUG_ON(in_irq());
-
- local_bh_disable();
-#endif
- return kmap_atomic(skb_frag_page(frag));
-}
-
-static inline void kunmap_skb_frag(void *vaddr)
-{
- kunmap_atomic(vaddr);
-#ifdef CONFIG_HIGHMEM
- local_bh_enable();
-#endif
-}
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 0a68045782d1..fadaa819b854 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -890,7 +890,7 @@ static void neigh_timer_handler(unsigned long arg)
{
unsigned long now, next;
struct neighbour *neigh = (struct neighbour *)arg;
- unsigned state;
+ unsigned int state;
int notify = 0;
write_lock(&neigh->lock);
@@ -1500,7 +1500,7 @@ static void neigh_parms_destroy(struct neigh_parms *parms)
static struct lock_class_key neigh_table_proxy_queue_class;
-void neigh_table_init_no_netlink(struct neigh_table *tbl)
+static void neigh_table_init_no_netlink(struct neigh_table *tbl)
{
unsigned long now = jiffies;
unsigned long phsize;
@@ -1538,7 +1538,6 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
tbl->last_flush = now;
tbl->last_rand = now + tbl->parms.reachable_time * 20;
}
-EXPORT_SYMBOL(neigh_table_init_no_netlink);
void neigh_table_init(struct neigh_table *tbl)
{
@@ -1768,29 +1767,29 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
if (nest == NULL)
return -ENOBUFS;
- if (parms->dev)
- NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
-
- NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
- NLA_PUT_U32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes);
- /* approximative value for deprecated QUEUE_LEN (in packets) */
- NLA_PUT_U32(skb, NDTPA_QUEUE_LEN,
- DIV_ROUND_UP(parms->queue_len_bytes,
- SKB_TRUESIZE(ETH_FRAME_LEN)));
- NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
- NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
- NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
- NLA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes);
- NLA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time);
- NLA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME,
- parms->base_reachable_time);
- NLA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime);
- NLA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time);
- NLA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time);
- NLA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay);
- NLA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay);
- NLA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime);
-
+ if ((parms->dev &&
+ nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
+ nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) ||
+ nla_put_u32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes) ||
+ /* approximative value for deprecated QUEUE_LEN (in packets) */
+ nla_put_u32(skb, NDTPA_QUEUE_LEN,
+ DIV_ROUND_UP(parms->queue_len_bytes,
+ SKB_TRUESIZE(ETH_FRAME_LEN))) ||
+ nla_put_u32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen) ||
+ nla_put_u32(skb, NDTPA_APP_PROBES, parms->app_probes) ||
+ nla_put_u32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes) ||
+ nla_put_u32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes) ||
+ nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) ||
+ nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
+ parms->base_reachable_time) ||
+ nla_put_msecs(skb, NDTPA_GC_STALETIME, parms->gc_staletime) ||
+ nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
+ parms->delay_probe_time) ||
+ nla_put_msecs(skb, NDTPA_RETRANS_TIME, parms->retrans_time) ||
+ nla_put_msecs(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay) ||
+ nla_put_msecs(skb, NDTPA_PROXY_DELAY, parms->proxy_delay) ||
+ nla_put_msecs(skb, NDTPA_LOCKTIME, parms->locktime))
+ goto nla_put_failure;
return nla_nest_end(skb, nest);
nla_put_failure:
@@ -1815,12 +1814,12 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
ndtmsg->ndtm_pad1 = 0;
ndtmsg->ndtm_pad2 = 0;
- NLA_PUT_STRING(skb, NDTA_NAME, tbl->id);
- NLA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval);
- NLA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1);
- NLA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2);
- NLA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3);
-
+ if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
+ nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval) ||
+ nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
+ nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
+ nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
+ goto nla_put_failure;
{
unsigned long now = jiffies;
unsigned int flush_delta = now - tbl->last_flush;
@@ -1841,7 +1840,8 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
rcu_read_unlock_bh();
- NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);
+ if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
+ goto nla_put_failure;
}
{
@@ -1866,7 +1866,8 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
ndst.ndts_forced_gc_runs += st->forced_gc_runs;
}
- NLA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst);
+ if (nla_put(skb, NDTA_STATS, sizeof(ndst), &ndst))
+ goto nla_put_failure;
}
BUG_ON(tbl->parms.dev);
@@ -2137,7 +2138,8 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
ndm->ndm_type = neigh->type;
ndm->ndm_ifindex = neigh->dev->ifindex;
- NLA_PUT(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key);
+ if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
+ goto nla_put_failure;
read_lock_bh(&neigh->lock);
ndm->ndm_state = neigh->nud_state;
@@ -2157,8 +2159,9 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
read_unlock_bh(&neigh->lock);
- NLA_PUT_U32(skb, NDA_PROBES, atomic_read(&neigh->probes));
- NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
+ if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
+ nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
+ goto nla_put_failure;
return nlmsg_end(skb, nlh);
@@ -2187,7 +2190,8 @@ static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
ndm->ndm_ifindex = pn->dev->ifindex;
ndm->ndm_state = NUD_NONE;
- NLA_PUT(skb, NDA_DST, tbl->key_len, pn->key);
+ if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
+ goto nla_put_failure;
return nlmsg_end(skb, nlh);
@@ -2795,7 +2799,6 @@ enum {
static struct neigh_sysctl_table {
struct ctl_table_header *sysctl_header;
struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
- char *dev_name;
} neigh_sysctl_template __read_mostly = {
.neigh_vars = {
[NEIGH_VAR_MCAST_PROBE] = {
@@ -2921,19 +2924,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
{
struct neigh_sysctl_table *t;
const char *dev_name_source = NULL;
-
-#define NEIGH_CTL_PATH_ROOT 0
-#define NEIGH_CTL_PATH_PROTO 1
-#define NEIGH_CTL_PATH_NEIGH 2
-#define NEIGH_CTL_PATH_DEV 3
-
- struct ctl_path neigh_path[] = {
- { .procname = "net", },
- { .procname = "proto", },
- { .procname = "neigh", },
- { .procname = "default", },
- { },
- };
+ char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
if (!t)
@@ -2961,7 +2952,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
} else {
- dev_name_source = neigh_path[NEIGH_CTL_PATH_DEV].procname;
+ dev_name_source = "default";
t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = (int *)(p + 1);
t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = (int *)(p + 1) + 1;
t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = (int *)(p + 1) + 2;
@@ -2984,23 +2975,16 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].extra1 = dev;
}
- t->dev_name = kstrdup(dev_name_source, GFP_KERNEL);
- if (!t->dev_name)
- goto free;
-
- neigh_path[NEIGH_CTL_PATH_DEV].procname = t->dev_name;
- neigh_path[NEIGH_CTL_PATH_PROTO].procname = p_name;
-
+ snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
+ p_name, dev_name_source);
t->sysctl_header =
- register_net_sysctl_table(neigh_parms_net(p), neigh_path, t->neigh_vars);
+ register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
if (!t->sysctl_header)
- goto free_procname;
+ goto free;
p->sysctl_table = t;
return 0;
-free_procname:
- kfree(t->dev_name);
free:
kfree(t);
err:
@@ -3013,8 +2997,7 @@ void neigh_sysctl_unregister(struct neigh_parms *p)
if (p->sysctl_table) {
struct neigh_sysctl_table *t = p->sysctl_table;
p->sysctl_table = NULL;
- unregister_sysctl_table(t->sysctl_header);
- kfree(t->dev_name);
+ unregister_net_sysctl_table(t->sysctl_header);
kfree(t);
}
}
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 495586232aa1..fdf9e61d0651 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -74,15 +74,14 @@ static ssize_t netdev_store(struct device *dev, struct device_attribute *attr,
int (*set)(struct net_device *, unsigned long))
{
struct net_device *net = to_net_dev(dev);
- char *endp;
unsigned long new;
int ret = -EINVAL;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- new = simple_strtoul(buf, &endp, 0);
- if (endp == buf)
+ ret = kstrtoul(buf, 0, &new);
+ if (ret)
goto err;
if (!rtnl_trylock())
@@ -232,7 +231,7 @@ NETDEVICE_SHOW(flags, fmt_hex);
static int change_flags(struct net_device *net, unsigned long new_flags)
{
- return dev_change_flags(net, (unsigned) new_flags);
+ return dev_change_flags(net, (unsigned int) new_flags);
}
static ssize_t store_flags(struct device *dev, struct device_attribute *attr,
@@ -582,7 +581,7 @@ static ssize_t store_rps_map(struct netdev_rx_queue *queue,
return err;
}
- map = kzalloc(max_t(unsigned,
+ map = kzalloc(max_t(unsigned int,
RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES),
GFP_KERNEL);
if (!map) {
@@ -903,7 +902,7 @@ static ssize_t bql_set_hold_time(struct netdev_queue *queue,
const char *buf, size_t len)
{
struct dql *dql = &queue->dql;
- unsigned value;
+ unsigned int value;
int err;
err = kstrtouint(buf, 10, &value);
@@ -1107,7 +1106,7 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
return err;
}
- new_dev_maps = kzalloc(max_t(unsigned,
+ new_dev_maps = kzalloc(max_t(unsigned int,
XPS_DEV_MAPS_SIZE, L1_CACHE_BYTES), GFP_KERNEL);
if (!new_dev_maps) {
free_cpumask_var(mask);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 4d8ce93cd503..ffb5d382f241 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -320,7 +320,7 @@ struct pktgen_dev {
(see RFC 3260, sec. 4) */
/* MPLS */
- unsigned nr_labels; /* Depth of stack, 0 = no MPLS */
+ unsigned int nr_labels; /* Depth of stack, 0 = no MPLS */
__be32 labels[MAX_MPLS_LABELS];
/* VLAN/SVLAN (802.1Q/Q-in-Q) */
@@ -373,10 +373,10 @@ struct pktgen_dev {
*/
char odevname[32];
struct flow_state *flows;
- unsigned cflows; /* Concurrent flows (config) */
- unsigned lflow; /* Flow length (config) */
- unsigned nflows; /* accumulated flows (stats) */
- unsigned curfl; /* current sequenced flow (state)*/
+ unsigned int cflows; /* Concurrent flows (config) */
+ unsigned int lflow; /* Flow length (config) */
+ unsigned int nflows; /* accumulated flows (stats) */
+ unsigned int curfl; /* current sequenced flow (state)*/
u16 queue_map_min;
u16 queue_map_max;
@@ -592,7 +592,7 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
pkt_dev->src_mac_count, pkt_dev->dst_mac_count);
if (pkt_dev->nr_labels) {
- unsigned i;
+ unsigned int i;
seq_printf(seq, " mpls: ");
for (i = 0; i < pkt_dev->nr_labels; i++)
seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
@@ -812,7 +812,7 @@ done_str:
static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
{
- unsigned n = 0;
+ unsigned int n = 0;
char c;
ssize_t i = 0;
int len;
@@ -1510,7 +1510,7 @@ static ssize_t pktgen_if_write(struct file *file,
}
if (!strcmp(name, "mpls")) {
- unsigned n, cnt;
+ unsigned int n, cnt;
len = get_labels(&user_buffer[i], pkt_dev);
if (len < 0)
@@ -2324,7 +2324,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
}
if (pkt_dev->flags & F_MPLS_RND) {
- unsigned i;
+ unsigned int i;
for (i = 0; i < pkt_dev->nr_labels; i++)
if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
@@ -2550,7 +2550,7 @@ err:
static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
{
- unsigned i;
+ unsigned int i;
for (i = 0; i < pkt_dev->nr_labels; i++)
*mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 90430b776ece..b442d35bbc8b 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -35,7 +35,9 @@
#include <linux/security.h>
#include <linux/mutex.h>
#include <linux/if_addr.h>
+#include <linux/if_bridge.h>
#include <linux/pci.h>
+#include <linux/etherdevice.h>
#include <asm/uaccess.h>
@@ -552,7 +554,7 @@ void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data
}
EXPORT_SYMBOL(__rta_fill);
-int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo)
+int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned int group, int echo)
{
struct sock *rtnl = net->rtnl;
int err = 0;
@@ -607,7 +609,8 @@ int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics)
for (i = 0; i < RTAX_MAX; i++) {
if (metrics[i]) {
valid++;
- NLA_PUT_U32(skb, i+1, metrics[i]);
+ if (nla_put_u32(skb, i+1, metrics[i]))
+ goto nla_put_failure;
}
}
@@ -782,6 +785,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
+ nla_total_size(4) /* IFLA_MTU */
+ nla_total_size(4) /* IFLA_LINK */
+ nla_total_size(4) /* IFLA_MASTER */
+ + nla_total_size(4) /* IFLA_PROMISCUITY */
+ nla_total_size(1) /* IFLA_OPERSTATE */
+ nla_total_size(1) /* IFLA_LINKMODE */
+ nla_total_size(ext_filter_mask
@@ -807,7 +811,8 @@ static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)
vf_port = nla_nest_start(skb, IFLA_VF_PORT);
if (!vf_port)
goto nla_put_failure;
- NLA_PUT_U32(skb, IFLA_PORT_VF, vf);
+ if (nla_put_u32(skb, IFLA_PORT_VF, vf))
+ goto nla_put_failure;
err = dev->netdev_ops->ndo_get_vf_port(dev, vf, skb);
if (err == -EMSGSIZE)
goto nla_put_failure;
@@ -891,25 +896,23 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
ifm->ifi_flags = dev_get_flags(dev);
ifm->ifi_change = change;
- NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
- NLA_PUT_U32(skb, IFLA_TXQLEN, dev->tx_queue_len);
- NLA_PUT_U8(skb, IFLA_OPERSTATE,
- netif_running(dev) ? dev->operstate : IF_OPER_DOWN);
- NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode);
- NLA_PUT_U32(skb, IFLA_MTU, dev->mtu);
- NLA_PUT_U32(skb, IFLA_GROUP, dev->group);
-
- if (dev->ifindex != dev->iflink)
- NLA_PUT_U32(skb, IFLA_LINK, dev->iflink);
-
- if (dev->master)
- NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex);
-
- if (dev->qdisc)
- NLA_PUT_STRING(skb, IFLA_QDISC, dev->qdisc->ops->id);
-
- if (dev->ifalias)
- NLA_PUT_STRING(skb, IFLA_IFALIAS, dev->ifalias);
+ if (nla_put_string(skb, IFLA_IFNAME, dev->name) ||
+ nla_put_u32(skb, IFLA_TXQLEN, dev->tx_queue_len) ||
+ nla_put_u8(skb, IFLA_OPERSTATE,
+ netif_running(dev) ? dev->operstate : IF_OPER_DOWN) ||
+ nla_put_u8(skb, IFLA_LINKMODE, dev->link_mode) ||
+ nla_put_u32(skb, IFLA_MTU, dev->mtu) ||
+ nla_put_u32(skb, IFLA_GROUP, dev->group) ||
+ nla_put_u32(skb, IFLA_PROMISCUITY, dev->promiscuity) ||
+ (dev->ifindex != dev->iflink &&
+ nla_put_u32(skb, IFLA_LINK, dev->iflink)) ||
+ (dev->master &&
+ nla_put_u32(skb, IFLA_MASTER, dev->master->ifindex)) ||
+ (dev->qdisc &&
+ nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) ||
+ (dev->ifalias &&
+ nla_put_string(skb, IFLA_IFALIAS, dev->ifalias)))
+ goto nla_put_failure;
if (1) {
struct rtnl_link_ifmap map = {
@@ -920,12 +923,14 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
.dma = dev->dma,
.port = dev->if_port,
};
- NLA_PUT(skb, IFLA_MAP, sizeof(map), &map);
+ if (nla_put(skb, IFLA_MAP, sizeof(map), &map))
+ goto nla_put_failure;
}
if (dev->addr_len) {
- NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
- NLA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast);
+ if (nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr) ||
+ nla_put(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast))
+ goto nla_put_failure;
}
attr = nla_reserve(skb, IFLA_STATS,
@@ -942,8 +947,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
goto nla_put_failure;
copy_rtnl_link_stats64(nla_data(attr), stats);
- if (dev->dev.parent && (ext_filter_mask & RTEXT_FILTER_VF))
- NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent));
+ if (dev->dev.parent && (ext_filter_mask & RTEXT_FILTER_VF) &&
+ nla_put_u32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent)))
+ goto nla_put_failure;
if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent
&& (ext_filter_mask & RTEXT_FILTER_VF)) {
@@ -986,12 +992,13 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
nla_nest_cancel(skb, vfinfo);
goto nla_put_failure;
}
- NLA_PUT(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac);
- NLA_PUT(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan);
- NLA_PUT(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate),
- &vf_tx_rate);
- NLA_PUT(skb, IFLA_VF_SPOOFCHK, sizeof(vf_spoofchk),
- &vf_spoofchk);
+ if (nla_put(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac) ||
+ nla_put(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan) ||
+ nla_put(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate),
+ &vf_tx_rate) ||
+ nla_put(skb, IFLA_VF_SPOOFCHK, sizeof(vf_spoofchk),
+ &vf_spoofchk))
+ goto nla_put_failure;
nla_nest_end(skb, vf);
}
nla_nest_end(skb, vfinfo);
@@ -1113,6 +1120,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_PORT_SELF] = { .type = NLA_NESTED },
[IFLA_AF_SPEC] = { .type = NLA_NESTED },
[IFLA_EXT_MASK] = { .type = NLA_U32 },
+ [IFLA_PROMISCUITY] = { .type = NLA_U32 },
};
EXPORT_SYMBOL(ifla_policy);
@@ -1634,14 +1642,14 @@ struct net_device *rtnl_create_link(struct net *src_net, struct net *net,
int err;
struct net_device *dev;
unsigned int num_queues = 1;
- unsigned int real_num_queues = 1;
if (ops->get_tx_queues) {
- err = ops->get_tx_queues(src_net, tb, &num_queues,
- &real_num_queues);
- if (err)
+ err = ops->get_tx_queues(src_net, tb);
+ if (err < 0)
goto err;
+ num_queues = err;
}
+
err = -ENOMEM;
dev = alloc_netdev_mq(ops->priv_size, ifname, ops->setup, num_queues);
if (!dev)
@@ -1947,7 +1955,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
-void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
+void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change)
{
struct net *net = dev_net(dev);
struct sk_buff *skb;
@@ -1972,6 +1980,267 @@ errout:
rtnl_set_sk_err(net, RTNLGRP_LINK, err);
}
+static int nlmsg_populate_fdb_fill(struct sk_buff *skb,
+ struct net_device *dev,
+ u8 *addr, u32 pid, u32 seq,
+ int type, unsigned int flags)
+{
+ struct nlmsghdr *nlh;
+ struct ndmsg *ndm;
+
+ nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), NLM_F_MULTI);
+ if (!nlh)
+ return -EMSGSIZE;
+
+ ndm = nlmsg_data(nlh);
+ ndm->ndm_family = AF_BRIDGE;
+ ndm->ndm_pad1 = 0;
+ ndm->ndm_pad2 = 0;
+ ndm->ndm_flags = flags;
+ ndm->ndm_type = 0;
+ ndm->ndm_ifindex = dev->ifindex;
+ ndm->ndm_state = NUD_PERMANENT;
+
+ if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr))
+ goto nla_put_failure;
+
+ return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+}
+
+static inline size_t rtnl_fdb_nlmsg_size(void)
+{
+ return NLMSG_ALIGN(sizeof(struct ndmsg)) + nla_total_size(ETH_ALEN);
+}
+
+static void rtnl_fdb_notify(struct net_device *dev, u8 *addr, int type)
+{
+ struct net *net = dev_net(dev);
+ struct sk_buff *skb;
+ int err = -ENOBUFS;
+
+ skb = nlmsg_new(rtnl_fdb_nlmsg_size(), GFP_ATOMIC);
+ if (!skb)
+ goto errout;
+
+ err = nlmsg_populate_fdb_fill(skb, dev, addr, 0, 0, type, NTF_SELF);
+ if (err < 0) {
+ kfree_skb(skb);
+ goto errout;
+ }
+
+ rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
+ return;
+errout:
+ rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
+}
+
+static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ struct net *net = sock_net(skb->sk);
+ struct net_device *master = NULL;
+ struct ndmsg *ndm;
+ struct nlattr *tb[NDA_MAX+1];
+ struct net_device *dev;
+ u8 *addr;
+ int err;
+
+ err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
+ if (err < 0)
+ return err;
+
+ ndm = nlmsg_data(nlh);
+ if (ndm->ndm_ifindex == 0) {
+ pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid ifindex\n");
+ return -EINVAL;
+ }
+
+ dev = __dev_get_by_index(net, ndm->ndm_ifindex);
+ if (dev == NULL) {
+ pr_info("PF_BRIDGE: RTM_NEWNEIGH with unknown ifindex\n");
+ return -ENODEV;
+ }
+
+ if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) {
+ pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid address\n");
+ return -EINVAL;
+ }
+
+ addr = nla_data(tb[NDA_LLADDR]);
+ if (!is_valid_ether_addr(addr)) {
+ pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid ether address\n");
+ return -EINVAL;
+ }
+
+ err = -EOPNOTSUPP;
+
+ /* Support fdb on master device the net/bridge default case */
+ if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) &&
+ (dev->priv_flags & IFF_BRIDGE_PORT)) {
+ master = dev->master;
+ err = master->netdev_ops->ndo_fdb_add(ndm, dev, addr,
+ nlh->nlmsg_flags);
+ if (err)
+ goto out;
+ else
+ ndm->ndm_flags &= ~NTF_MASTER;
+ }
+
+ /* Embedded bridge, macvlan, and any other device support */
+ if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_add) {
+ err = dev->netdev_ops->ndo_fdb_add(ndm, dev, addr,
+ nlh->nlmsg_flags);
+
+ if (!err) {
+ rtnl_fdb_notify(dev, addr, RTM_NEWNEIGH);
+ ndm->ndm_flags &= ~NTF_SELF;
+ }
+ }
+out:
+ return err;
+}
+
+static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ struct net *net = sock_net(skb->sk);
+ struct ndmsg *ndm;
+ struct nlattr *llattr;
+ struct net_device *dev;
+ int err = -EINVAL;
+ __u8 *addr;
+
+ if (nlmsg_len(nlh) < sizeof(*ndm))
+ return -EINVAL;
+
+ ndm = nlmsg_data(nlh);
+ if (ndm->ndm_ifindex == 0) {
+ pr_info("PF_BRIDGE: RTM_DELNEIGH with invalid ifindex\n");
+ return -EINVAL;
+ }
+
+ dev = __dev_get_by_index(net, ndm->ndm_ifindex);
+ if (dev == NULL) {
+ pr_info("PF_BRIDGE: RTM_DELNEIGH with unknown ifindex\n");
+ return -ENODEV;
+ }
+
+ llattr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_LLADDR);
+ if (llattr == NULL || nla_len(llattr) != ETH_ALEN) {
+ pr_info("PF_BRIGDE: RTM_DELNEIGH with invalid address\n");
+ return -EINVAL;
+ }
+
+ addr = nla_data(llattr);
+ err = -EOPNOTSUPP;
+
+ /* Support fdb on master device the net/bridge default case */
+ if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) &&
+ (dev->priv_flags & IFF_BRIDGE_PORT)) {
+ struct net_device *master = dev->master;
+
+ if (master->netdev_ops->ndo_fdb_del)
+ err = master->netdev_ops->ndo_fdb_del(ndm, dev, addr);
+
+ if (err)
+ goto out;
+ else
+ ndm->ndm_flags &= ~NTF_MASTER;
+ }
+
+ /* Embedded bridge, macvlan, and any other device support */
+ if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) {
+ err = dev->netdev_ops->ndo_fdb_del(ndm, dev, addr);
+
+ if (!err) {
+ rtnl_fdb_notify(dev, addr, RTM_DELNEIGH);
+ ndm->ndm_flags &= ~NTF_SELF;
+ }
+ }
+out:
+ return err;
+}
+
+static int nlmsg_populate_fdb(struct sk_buff *skb,
+ struct netlink_callback *cb,
+ struct net_device *dev,
+ int *idx,
+ struct netdev_hw_addr_list *list)
+{
+ struct netdev_hw_addr *ha;
+ int err;
+ u32 pid, seq;
+
+ pid = NETLINK_CB(cb->skb).pid;
+ seq = cb->nlh->nlmsg_seq;
+
+ list_for_each_entry(ha, &list->list, list) {
+ if (*idx < cb->args[0])
+ goto skip;
+
+ err = nlmsg_populate_fdb_fill(skb, dev, ha->addr,
+ pid, seq, 0, NTF_SELF);
+ if (err < 0)
+ return err;
+skip:
+ *idx += 1;
+ }
+ return 0;
+}
+
+/**
+ * ndo_dflt_fdb_dump: default netdevice operation to dump an FDB table.
+ * @nlh: netlink message header
+ * @dev: netdevice
+ *
+ * Default netdevice operation to dump the existing unicast address list.
+ * Returns zero on success.
+ */
+int ndo_dflt_fdb_dump(struct sk_buff *skb,
+ struct netlink_callback *cb,
+ struct net_device *dev,
+ int idx)
+{
+ int err;
+
+ netif_addr_lock_bh(dev);
+ err = nlmsg_populate_fdb(skb, cb, dev, &idx, &dev->uc);
+ if (err)
+ goto out;
+ nlmsg_populate_fdb(skb, cb, dev, &idx, &dev->mc);
+out:
+ netif_addr_unlock_bh(dev);
+ return idx;
+}
+EXPORT_SYMBOL(ndo_dflt_fdb_dump);
+
+static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int idx = 0;
+ struct net *net = sock_net(skb->sk);
+ struct net_device *dev;
+
+ rcu_read_lock();
+ for_each_netdev_rcu(net, dev) {
+ if (dev->priv_flags & IFF_BRIDGE_PORT) {
+ struct net_device *master = dev->master;
+ const struct net_device_ops *ops = master->netdev_ops;
+
+ if (ops->ndo_fdb_dump)
+ idx = ops->ndo_fdb_dump(skb, cb, dev, idx);
+ }
+
+ if (dev->netdev_ops->ndo_fdb_dump)
+ idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx);
+ }
+ rcu_read_unlock();
+
+ cb->args[0] = idx;
+ return skb->len;
+}
+
/* Protected by RTNL sempahore. */
static struct rtattr **rta_buf;
static int rtattr_max;
@@ -2042,7 +2311,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
struct rtattr *attr = (void *)nlh + NLMSG_ALIGN(min_len);
while (RTA_OK(attr, attrlen)) {
- unsigned flavor = attr->rta_type;
+ unsigned int flavor = attr->rta_type;
if (flavor) {
if (flavor > rta_max[sz_idx])
return -EINVAL;
@@ -2144,5 +2413,9 @@ void __init rtnetlink_init(void)
rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all, NULL);
rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all, NULL);
+
+ rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, rtnl_fdb_add, NULL, NULL);
+ rtnl_register(PF_BRIDGE, RTM_DELNEIGH, rtnl_fdb_del, NULL, NULL);
+ rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, NULL);
}
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index e59840010d45..aaf4abc4417d 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -67,8 +67,7 @@
#include <asm/uaccess.h>
#include <trace/events/skb.h>
-
-#include "kmap_skb.h"
+#include <linux/highmem.h>
static struct kmem_cache *skbuff_head_cache __read_mostly;
static struct kmem_cache *skbuff_fclone_cache __read_mostly;
@@ -707,10 +706,10 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
}
return -ENOMEM;
}
- vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
+ vaddr = kmap_atomic(skb_frag_page(f));
memcpy(page_address(page),
vaddr + f->page_offset, skb_frag_size(f));
- kunmap_skb_frag(vaddr);
+ kunmap_atomic(vaddr);
page->private = (unsigned long)head;
head = page;
}
@@ -1275,7 +1274,7 @@ drop_pages:
return -ENOMEM;
nfrag->next = frag->next;
- kfree_skb(frag);
+ consume_skb(frag);
frag = nfrag;
*fragp = frag;
}
@@ -1487,21 +1486,22 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
+ skb_frag_t *f = &skb_shinfo(skb)->frags[i];
WARN_ON(start > offset + len);
- end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
+ end = start + skb_frag_size(f);
if ((copy = end - offset) > 0) {
u8 *vaddr;
if (copy > len)
copy = len;
- vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
+ vaddr = kmap_atomic(skb_frag_page(f));
memcpy(to,
- vaddr + skb_shinfo(skb)->frags[i].page_offset+
- offset - start, copy);
- kunmap_skb_frag(vaddr);
+ vaddr + f->page_offset + offset - start,
+ copy);
+ kunmap_atomic(vaddr);
if ((len -= copy) == 0)
return 0;
@@ -1547,9 +1547,9 @@ static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
put_page(spd->pages[i]);
}
-static inline struct page *linear_to_page(struct page *page, unsigned int *len,
- unsigned int *offset,
- struct sk_buff *skb, struct sock *sk)
+static struct page *linear_to_page(struct page *page, unsigned int *len,
+ unsigned int *offset,
+ struct sk_buff *skb, struct sock *sk)
{
struct page *p = sk->sk_sndmsg_page;
unsigned int off;
@@ -1565,6 +1565,9 @@ new_page:
} else {
unsigned int mlen;
+ /* If we are the only user of the page, we can reset offset */
+ if (page_count(p) == 1)
+ sk->sk_sndmsg_off = 0;
off = sk->sk_sndmsg_off;
mlen = PAGE_SIZE - off;
if (mlen < 64 && mlen < *len) {
@@ -1578,36 +1581,48 @@ new_page:
memcpy(page_address(p) + off, page_address(page) + *offset, *len);
sk->sk_sndmsg_off += *len;
*offset = off;
- get_page(p);
return p;
}
+static bool spd_can_coalesce(const struct splice_pipe_desc *spd,
+ struct page *page,
+ unsigned int offset)
+{
+ return spd->nr_pages &&
+ spd->pages[spd->nr_pages - 1] == page &&
+ (spd->partial[spd->nr_pages - 1].offset +
+ spd->partial[spd->nr_pages - 1].len == offset);
+}
+
/*
* Fill page/offset/length into spd, if it can hold more pages.
*/
-static inline int spd_fill_page(struct splice_pipe_desc *spd,
- struct pipe_inode_info *pipe, struct page *page,
- unsigned int *len, unsigned int offset,
- struct sk_buff *skb, int linear,
- struct sock *sk)
+static bool spd_fill_page(struct splice_pipe_desc *spd,
+ struct pipe_inode_info *pipe, struct page *page,
+ unsigned int *len, unsigned int offset,
+ struct sk_buff *skb, int linear,
+ struct sock *sk)
{
- if (unlikely(spd->nr_pages == pipe->buffers))
- return 1;
+ if (unlikely(spd->nr_pages == MAX_SKB_FRAGS))
+ return true;
if (linear) {
page = linear_to_page(page, len, &offset, skb, sk);
if (!page)
- return 1;
- } else
- get_page(page);
-
+ return true;
+ }
+ if (spd_can_coalesce(spd, page, offset)) {
+ spd->partial[spd->nr_pages - 1].len += *len;
+ return false;
+ }
+ get_page(page);
spd->pages[spd->nr_pages] = page;
spd->partial[spd->nr_pages].len = *len;
spd->partial[spd->nr_pages].offset = offset;
spd->nr_pages++;
- return 0;
+ return false;
}
static inline void __segment_seek(struct page **page, unsigned int *poff,
@@ -1624,20 +1639,20 @@ static inline void __segment_seek(struct page **page, unsigned int *poff,
*plen -= off;
}
-static inline int __splice_segment(struct page *page, unsigned int poff,
- unsigned int plen, unsigned int *off,
- unsigned int *len, struct sk_buff *skb,
- struct splice_pipe_desc *spd, int linear,
- struct sock *sk,
- struct pipe_inode_info *pipe)
+static bool __splice_segment(struct page *page, unsigned int poff,
+ unsigned int plen, unsigned int *off,
+ unsigned int *len, struct sk_buff *skb,
+ struct splice_pipe_desc *spd, int linear,
+ struct sock *sk,
+ struct pipe_inode_info *pipe)
{
if (!*len)
- return 1;
+ return true;
/* skip this segment if already processed */
if (*off >= plen) {
*off -= plen;
- return 0;
+ return false;
}
/* ignore any bits we already processed */
@@ -1653,23 +1668,23 @@ static inline int __splice_segment(struct page *page, unsigned int poff,
flen = min_t(unsigned int, flen, PAGE_SIZE - poff);
if (spd_fill_page(spd, pipe, page, &flen, poff, skb, linear, sk))
- return 1;
+ return true;
__segment_seek(&page, &poff, &plen, flen);
*len -= flen;
} while (*len && plen);
- return 0;
+ return false;
}
/*
- * Map linear and fragment data from the skb to spd. It reports failure if the
+ * Map linear and fragment data from the skb to spd. It reports true if the
* pipe is full or if we already spliced the requested length.
*/
-static int __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
- unsigned int *offset, unsigned int *len,
- struct splice_pipe_desc *spd, struct sock *sk)
+static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
+ unsigned int *offset, unsigned int *len,
+ struct splice_pipe_desc *spd, struct sock *sk)
{
int seg;
@@ -1680,7 +1695,7 @@ static int __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
(unsigned long) skb->data & (PAGE_SIZE - 1),
skb_headlen(skb),
offset, len, skb, spd, 1, sk, pipe))
- return 1;
+ return true;
/*
* then map the fragments
@@ -1691,10 +1706,10 @@ static int __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
if (__splice_segment(skb_frag_page(f),
f->page_offset, skb_frag_size(f),
offset, len, skb, spd, 0, sk, pipe))
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/*
@@ -1707,8 +1722,8 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
struct pipe_inode_info *pipe, unsigned int tlen,
unsigned int flags)
{
- struct partial_page partial[PIPE_DEF_BUFFERS];
- struct page *pages[PIPE_DEF_BUFFERS];
+ struct partial_page partial[MAX_SKB_FRAGS];
+ struct page *pages[MAX_SKB_FRAGS];
struct splice_pipe_desc spd = {
.pages = pages,
.partial = partial,
@@ -1720,9 +1735,6 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
struct sock *sk = skb->sk;
int ret = 0;
- if (splice_grow_spd(pipe, &spd))
- return -ENOMEM;
-
/*
* __skb_splice_bits() only fails if the output has no room left,
* so no point in going over the frag_list for the error case.
@@ -1758,7 +1770,6 @@ done:
lock_sock(sk);
}
- splice_shrink_spd(pipe, &spd);
return ret;
}
@@ -1806,10 +1817,10 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
if (copy > len)
copy = len;
- vaddr = kmap_skb_frag(frag);
+ vaddr = kmap_atomic(skb_frag_page(frag));
memcpy(vaddr + frag->page_offset + offset - start,
from, copy);
- kunmap_skb_frag(vaddr);
+ kunmap_atomic(vaddr);
if ((len -= copy) == 0)
return 0;
@@ -1869,21 +1880,21 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
WARN_ON(start > offset + len);
- end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
+ end = start + skb_frag_size(frag);
if ((copy = end - offset) > 0) {
__wsum csum2;
u8 *vaddr;
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
if (copy > len)
copy = len;
- vaddr = kmap_skb_frag(frag);
+ vaddr = kmap_atomic(skb_frag_page(frag));
csum2 = csum_partial(vaddr + frag->page_offset +
offset - start, copy, 0);
- kunmap_skb_frag(vaddr);
+ kunmap_atomic(vaddr);
csum = csum_block_add(csum, csum2, pos);
if (!(len -= copy))
return csum;
@@ -1955,12 +1966,12 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
if (copy > len)
copy = len;
- vaddr = kmap_skb_frag(frag);
+ vaddr = kmap_atomic(skb_frag_page(frag));
csum2 = csum_partial_copy_nocheck(vaddr +
frag->page_offset +
offset - start, to,
copy, 0);
- kunmap_skb_frag(vaddr);
+ kunmap_atomic(vaddr);
csum = csum_block_add(csum, csum2, pos);
if (!(len -= copy))
return csum;
@@ -2480,7 +2491,7 @@ next_skb:
if (abs_offset < block_limit) {
if (!st->frag_data)
- st->frag_data = kmap_skb_frag(frag);
+ st->frag_data = kmap_atomic(skb_frag_page(frag));
*data = (u8 *) st->frag_data + frag->page_offset +
(abs_offset - st->stepped_offset);
@@ -2489,7 +2500,7 @@ next_skb:
}
if (st->frag_data) {
- kunmap_skb_frag(st->frag_data);
+ kunmap_atomic(st->frag_data);
st->frag_data = NULL;
}
@@ -2498,7 +2509,7 @@ next_skb:
}
if (st->frag_data) {
- kunmap_skb_frag(st->frag_data);
+ kunmap_atomic(st->frag_data);
st->frag_data = NULL;
}
@@ -2526,7 +2537,7 @@ EXPORT_SYMBOL(skb_seq_read);
void skb_abort_seq_read(struct skb_seq_state *st)
{
if (st->frag_data)
- kunmap_skb_frag(st->frag_data);
+ kunmap_atomic(st->frag_data);
}
EXPORT_SYMBOL(skb_abort_seq_read);
@@ -3166,7 +3177,7 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
int len = skb->len;
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
- (unsigned)sk->sk_rcvbuf)
+ (unsigned int)sk->sk_rcvbuf)
return -ENOMEM;
skb_orphan(skb);
diff --git a/net/core/sock.c b/net/core/sock.c
index b2e14c07d920..0431aaf7473a 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -389,7 +389,7 @@ int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested)
skb->dev = NULL;
- if (sk_rcvqueues_full(sk, skb)) {
+ if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf)) {
atomic_inc(&sk->sk_drops);
goto discard_and_relse;
}
@@ -406,7 +406,7 @@ int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested)
rc = sk_backlog_rcv(sk, skb);
mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_);
- } else if (sk_add_backlog(sk, skb)) {
+ } else if (sk_add_backlog(sk, skb, sk->sk_rcvbuf)) {
bh_unlock_sock(sk);
atomic_inc(&sk->sk_drops);
goto discard_and_relse;
@@ -561,7 +561,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
sock_valbool_flag(sk, SOCK_DBG, valbool);
break;
case SO_REUSEADDR:
- sk->sk_reuse = valbool;
+ sk->sk_reuse = (valbool ? SK_CAN_REUSE : SK_NO_REUSE);
break;
case SO_TYPE:
case SO_PROTOCOL:
@@ -1534,7 +1534,7 @@ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force,
*/
void *sock_kmalloc(struct sock *sk, int size, gfp_t priority)
{
- if ((unsigned)size <= sysctl_optmem_max &&
+ if ((unsigned int)size <= sysctl_optmem_max &&
atomic_read(&sk->sk_omem_alloc) + size < sysctl_optmem_max) {
void *mem;
/* First do the add, to avoid the race if kmalloc
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 0c2850874254..a7c36845b123 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -14,6 +14,7 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/kmemleak.h>
#include <net/ip.h>
#include <net/sock.h>
@@ -202,12 +203,6 @@ static struct ctl_table netns_core_table[] = {
{ }
};
-__net_initdata struct ctl_path net_core_path[] = {
- { .procname = "net", },
- { .procname = "core", },
- { },
-};
-
static __net_init int sysctl_core_net_init(struct net *net)
{
struct ctl_table *tbl;
@@ -223,8 +218,7 @@ static __net_init int sysctl_core_net_init(struct net *net)
tbl[0].data = &net->core.sysctl_somaxconn;
}
- net->core.sysctl_hdr = register_net_sysctl_table(net,
- net_core_path, tbl);
+ net->core.sysctl_hdr = register_net_sysctl(net, "net/core", tbl);
if (net->core.sysctl_hdr == NULL)
goto err_reg;
@@ -254,10 +248,7 @@ static __net_initdata struct pernet_operations sysctl_core_ops = {
static __init int sysctl_core_init(void)
{
- static struct ctl_table empty[1];
-
- register_sysctl_paths(net_core_path, empty);
- register_net_sysctl_rotable(net_core_path, net_core_table);
+ register_net_sysctl(&init_net, "net/core", net_core_table);
return register_pernet_subsys(&sysctl_core_ops);
}
diff --git a/net/core/utils.c b/net/core/utils.c
index dc3c3faff2f4..39895a65e54a 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -58,14 +58,11 @@ __be32 in_aton(const char *str)
int i;
l = 0;
- for (i = 0; i < 4; i++)
- {
+ for (i = 0; i < 4; i++) {
l <<= 8;
- if (*str != '\0')
- {
+ if (*str != '\0') {
val = 0;
- while (*str != '\0' && *str != '.' && *str != '\n')
- {
+ while (*str != '\0' && *str != '.' && *str != '\n') {
val *= 10;
val += *str - '0';
str++;
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
index d86053002c16..8dfa1da7c40d 100644
--- a/net/dcb/dcbnl.c
+++ b/net/dcb/dcbnl.c
@@ -178,6 +178,7 @@ static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = {
[DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)},
[DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)},
[DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED},
+ [DCB_ATTR_IEEE_MAXRATE] = {.len = sizeof(struct ieee_maxrate)},
};
static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = {
@@ -1205,13 +1206,15 @@ static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb,
if (!app)
goto nla_put_failure;
- if (app_info_type)
- NLA_PUT(skb, app_info_type, sizeof(info), &info);
-
- for (i = 0; i < app_count; i++)
- NLA_PUT(skb, app_entry_type, sizeof(struct dcb_app),
- &table[i]);
+ if (app_info_type &&
+ nla_put(skb, app_info_type, sizeof(info), &info))
+ goto nla_put_failure;
+ for (i = 0; i < app_count; i++) {
+ if (nla_put(skb, app_entry_type, sizeof(struct dcb_app),
+ &table[i]))
+ goto nla_put_failure;
+ }
nla_nest_end(skb, app);
}
err = 0;
@@ -1230,8 +1233,8 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
int dcbx;
int err = -EMSGSIZE;
- NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
-
+ if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name))
+ goto nla_put_failure;
ieee = nla_nest_start(skb, DCB_ATTR_IEEE);
if (!ieee)
goto nla_put_failure;
@@ -1239,15 +1242,28 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
if (ops->ieee_getets) {
struct ieee_ets ets;
err = ops->ieee_getets(netdev, &ets);
- if (!err)
- NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets);
+ if (!err &&
+ nla_put(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets))
+ goto nla_put_failure;
+ }
+
+ if (ops->ieee_getmaxrate) {
+ struct ieee_maxrate maxrate;
+ err = ops->ieee_getmaxrate(netdev, &maxrate);
+ if (!err) {
+ err = nla_put(skb, DCB_ATTR_IEEE_MAXRATE,
+ sizeof(maxrate), &maxrate);
+ if (err)
+ goto nla_put_failure;
+ }
}
if (ops->ieee_getpfc) {
struct ieee_pfc pfc;
err = ops->ieee_getpfc(netdev, &pfc);
- if (!err)
- NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc);
+ if (!err &&
+ nla_put(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc))
+ goto nla_put_failure;
}
app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE);
@@ -1278,15 +1294,17 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
if (ops->ieee_peer_getets) {
struct ieee_ets ets;
err = ops->ieee_peer_getets(netdev, &ets);
- if (!err)
- NLA_PUT(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets);
+ if (!err &&
+ nla_put(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets))
+ goto nla_put_failure;
}
if (ops->ieee_peer_getpfc) {
struct ieee_pfc pfc;
err = ops->ieee_peer_getpfc(netdev, &pfc);
- if (!err)
- NLA_PUT(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc);
+ if (!err &&
+ nla_put(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc))
+ goto nla_put_failure;
}
if (ops->peer_getappinfo && ops->peer_getapptable) {
@@ -1340,10 +1358,11 @@ static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0,
&prio, &pgid, &tc_pct, &up_map);
- NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_PGID, pgid);
- NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
- NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
- NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct);
+ if (nla_put_u8(skb, DCB_TC_ATTR_PARAM_PGID, pgid) ||
+ nla_put_u8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map) ||
+ nla_put_u8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio) ||
+ nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct))
+ goto nla_put_failure;
nla_nest_end(skb, tc_nest);
}
@@ -1356,7 +1375,8 @@ static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
else
ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0,
&tc_pct);
- NLA_PUT_U8(skb, i, tc_pct);
+ if (nla_put_u8(skb, i, tc_pct))
+ goto nla_put_failure;
}
nla_nest_end(skb, pg);
return 0;
@@ -1373,8 +1393,8 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
int dcbx, i, err = -EMSGSIZE;
u8 value;
- NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
-
+ if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name))
+ goto nla_put_failure;
cee = nla_nest_start(skb, DCB_ATTR_CEE);
if (!cee)
goto nla_put_failure;
@@ -1401,7 +1421,8 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value);
- NLA_PUT_U8(skb, i, value);
+ if (nla_put_u8(skb, i, value))
+ goto nla_put_failure;
}
nla_nest_end(skb, pfc_nest);
}
@@ -1454,8 +1475,9 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX;
i++)
- if (!ops->getfeatcfg(netdev, i, &value))
- NLA_PUT_U8(skb, i, value);
+ if (!ops->getfeatcfg(netdev, i, &value) &&
+ nla_put_u8(skb, i, value))
+ goto nla_put_failure;
nla_nest_end(skb, feat);
}
@@ -1464,15 +1486,17 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
if (ops->cee_peer_getpg) {
struct cee_pg pg;
err = ops->cee_peer_getpg(netdev, &pg);
- if (!err)
- NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg);
+ if (!err &&
+ nla_put(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg))
+ goto nla_put_failure;
}
if (ops->cee_peer_getpfc) {
struct cee_pfc pfc;
err = ops->cee_peer_getpfc(netdev, &pfc);
- if (!err)
- NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc);
+ if (!err &&
+ nla_put(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc))
+ goto nla_put_failure;
}
if (ops->peer_getappinfo && ops->peer_getapptable) {
@@ -1589,6 +1613,14 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
goto err;
}
+ if (ieee[DCB_ATTR_IEEE_MAXRATE] && ops->ieee_setmaxrate) {
+ struct ieee_maxrate *maxrate =
+ nla_data(ieee[DCB_ATTR_IEEE_MAXRATE]);
+ err = ops->ieee_setmaxrate(netdev, maxrate);
+ if (err)
+ goto err;
+ }
+
if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
err = ops->ieee_setpfc(netdev, pfc);
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index 70bfaf2d1965..8c67bedf85b0 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -100,7 +100,7 @@ static void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hc)
DCCP_BUG_ON(hc->tx_t_ipi == 0);
ccid3_pr_debug("t_ipi=%u, s=%u, X=%u\n", hc->tx_t_ipi,
- hc->tx_s, (unsigned)(hc->tx_x >> 6));
+ hc->tx_s, (unsigned int)(hc->tx_x >> 6));
}
static u32 ccid3_hc_tx_idle_rtt(struct ccid3_hc_tx_sock *hc, ktime_t now)
@@ -153,9 +153,9 @@ static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp)
if (hc->tx_x != old_x) {
ccid3_pr_debug("X_prev=%u, X_now=%u, X_calc=%u, "
- "X_recv=%u\n", (unsigned)(old_x >> 6),
- (unsigned)(hc->tx_x >> 6), hc->tx_x_calc,
- (unsigned)(hc->tx_x_recv >> 6));
+ "X_recv=%u\n", (unsigned int)(old_x >> 6),
+ (unsigned int)(hc->tx_x >> 6), hc->tx_x_calc,
+ (unsigned int)(hc->tx_x_recv >> 6));
ccid3_update_send_interval(hc);
}
@@ -425,8 +425,8 @@ done_computing_x:
"p=%u, X_calc=%u, X_recv=%u, X=%u\n",
dccp_role(sk), sk, hc->tx_rtt, r_sample,
hc->tx_s, hc->tx_p, hc->tx_x_calc,
- (unsigned)(hc->tx_x_recv >> 6),
- (unsigned)(hc->tx_x >> 6));
+ (unsigned int)(hc->tx_x_recv >> 6),
+ (unsigned int)(hc->tx_x >> 6));
/* unschedule no feedback timer */
sk_stop_timer(sk, &hc->tx_no_feedback_timer);
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index 29d6bb629a6c..9040be049d8c 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -75,7 +75,7 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
* state, about 60 seconds */
/* RFC 1122, 4.2.3.1 initial RTO value */
-#define DCCP_TIMEOUT_INIT ((unsigned)(3 * HZ))
+#define DCCP_TIMEOUT_INIT ((unsigned int)(3 * HZ))
/*
* The maximum back-off value for retransmissions. This is needed for
@@ -84,7 +84,7 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
* - feature-negotiation retransmission (sec. 6.6.3),
* - Acks in client-PARTOPEN state (sec. 8.1.5).
*/
-#define DCCP_RTO_MAX ((unsigned)(64 * HZ))
+#define DCCP_RTO_MAX ((unsigned int)(64 * HZ))
/*
* RTT sampling: sanity bounds and fallback RTT value from RFC 4340, section 3.4
@@ -287,9 +287,9 @@ extern struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
extern int dccp_child_process(struct sock *parent, struct sock *child,
struct sk_buff *skb);
extern int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
- struct dccp_hdr *dh, unsigned len);
+ struct dccp_hdr *dh, unsigned int len);
extern int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
- const struct dccp_hdr *dh, const unsigned len);
+ const struct dccp_hdr *dh, const unsigned int len);
extern int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized);
extern void dccp_destroy_sock(struct sock *sk);
diff --git a/net/dccp/input.c b/net/dccp/input.c
index 51d5fe5fffba..bc93a333931e 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -285,7 +285,7 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb)
}
static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
- const struct dccp_hdr *dh, const unsigned len)
+ const struct dccp_hdr *dh, const unsigned int len)
{
struct dccp_sock *dp = dccp_sk(sk);
@@ -366,7 +366,7 @@ discard:
}
int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
- const struct dccp_hdr *dh, const unsigned len)
+ const struct dccp_hdr *dh, const unsigned int len)
{
if (dccp_check_seqno(sk, skb))
goto discard;
@@ -388,7 +388,7 @@ EXPORT_SYMBOL_GPL(dccp_rcv_established);
static int dccp_rcv_request_sent_state_process(struct sock *sk,
struct sk_buff *skb,
const struct dccp_hdr *dh,
- const unsigned len)
+ const unsigned int len)
{
/*
* Step 4: Prepare sequence numbers in REQUEST
@@ -521,7 +521,7 @@ unable_to_proceed:
static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
struct sk_buff *skb,
const struct dccp_hdr *dh,
- const unsigned len)
+ const unsigned int len)
{
struct dccp_sock *dp = dccp_sk(sk);
u32 sample = dp->dccps_options_received.dccpor_timestamp_echo;
@@ -572,7 +572,7 @@ static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
}
int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
- struct dccp_hdr *dh, unsigned len)
+ struct dccp_hdr *dh, unsigned int len)
{
struct dccp_sock *dp = dccp_sk(sk);
struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index caf6e1734b62..07f5579ca756 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -574,6 +574,11 @@ static void dccp_v4_reqsk_destructor(struct request_sock *req)
kfree(inet_rsk(req)->opt);
}
+void dccp_syn_ack_timeout(struct sock *sk, struct request_sock *req)
+{
+}
+EXPORT_SYMBOL(dccp_syn_ack_timeout);
+
static struct request_sock_ops dccp_request_sock_ops __read_mostly = {
.family = PF_INET,
.obj_size = sizeof(struct dccp_request_sock),
@@ -581,6 +586,7 @@ static struct request_sock_ops dccp_request_sock_ops __read_mostly = {
.send_ack = dccp_reqsk_send_ack,
.destructor = dccp_v4_reqsk_destructor,
.send_reset = dccp_v4_ctl_send_reset,
+ .syn_ack_timeout = dccp_syn_ack_timeout,
};
int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 4dc588f520e0..fa9512d86f3b 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -343,6 +343,7 @@ static struct request_sock_ops dccp6_request_sock_ops = {
.send_ack = dccp_reqsk_send_ack,
.destructor = dccp_v6_reqsk_destructor,
.send_reset = dccp_v6_ctl_send_reset,
+ .syn_ack_timeout = dccp_syn_ack_timeout,
};
static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
@@ -579,7 +580,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
newnp->pktoptions = NULL;
if (ireq6->pktopts != NULL) {
newnp->pktoptions = skb_clone(ireq6->pktopts, GFP_ATOMIC);
- kfree_skb(ireq6->pktopts);
+ consume_skb(ireq6->pktopts);
ireq6->pktopts = NULL;
if (newnp->pktoptions)
skb_set_owner_r(newnp->pktoptions, newsk);
diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c
index 42348824ee31..607ab71b5a0c 100644
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -98,18 +98,11 @@ static struct ctl_table dccp_default_table[] = {
{ }
};
-static struct ctl_path dccp_path[] = {
- { .procname = "net", },
- { .procname = "dccp", },
- { .procname = "default", },
- { }
-};
-
static struct ctl_table_header *dccp_table_header;
int __init dccp_sysctl_init(void)
{
- dccp_table_header = register_sysctl_paths(dccp_path,
+ dccp_table_header = register_net_sysctl(&init_net, "net/dccp/default",
dccp_default_table);
return dccp_table_header != NULL ? 0 : -ENOMEM;
@@ -118,7 +111,7 @@ int __init dccp_sysctl_init(void)
void dccp_sysctl_exit(void)
{
if (dccp_table_header != NULL) {
- unregister_sysctl_table(dccp_table_header);
+ unregister_net_sysctl_table(dccp_table_header);
dccp_table_header = NULL;
}
}
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 4136987d94da..2ba1a2814c24 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -250,7 +250,7 @@ static void dn_unhash_sock_bh(struct sock *sk)
static struct hlist_head *listen_hash(struct sockaddr_dn *addr)
{
int i;
- unsigned hash = addr->sdn_objnum;
+ unsigned int hash = addr->sdn_objnum;
if (hash == 0) {
hash = addr->sdn_objnamel;
@@ -1844,9 +1844,9 @@ static inline int dn_queue_too_long(struct dn_scp *scp, struct sk_buff_head *que
* inclusion (or not) of the two 16 bit acknowledgement fields so it doesn't
* make much practical difference.
*/
-unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu)
+unsigned int dn_mss_from_pmtu(struct net_device *dev, int mtu)
{
- unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER;
+ unsigned int mss = 230 - DN_MAX_NSP_DATA_HEADER;
if (dev) {
struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
mtu -= LL_RESERVED_SPACE(dev);
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index c00e3077988c..f3924ab1e019 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -209,15 +209,7 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *
struct dn_dev_sysctl_table *t;
int i;
-#define DN_CTL_PATH_DEV 3
-
- struct ctl_path dn_ctl_path[] = {
- { .procname = "net", },
- { .procname = "decnet", },
- { .procname = "conf", },
- { /* to be set */ },
- { },
- };
+ char path[sizeof("net/decnet/conf/") + IFNAMSIZ];
t = kmemdup(&dn_dev_sysctl, sizeof(*t), GFP_KERNEL);
if (t == NULL)
@@ -228,15 +220,12 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *
t->dn_dev_vars[i].data = ((char *)parms) + offset;
}
- if (dev) {
- dn_ctl_path[DN_CTL_PATH_DEV].procname = dev->name;
- } else {
- dn_ctl_path[DN_CTL_PATH_DEV].procname = parms->name;
- }
+ snprintf(path, sizeof(path), "net/decnet/conf/%s",
+ dev? dev->name : parms->name);
t->dn_dev_vars[0].extra1 = (void *)dev;
- t->sysctl_header = register_sysctl_paths(dn_ctl_path, t->dn_dev_vars);
+ t->sysctl_header = register_net_sysctl(&init_net, path, t->dn_dev_vars);
if (t->sysctl_header == NULL)
kfree(t);
else
@@ -248,7 +237,7 @@ static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
if (parms->sysctl) {
struct dn_dev_sysctl_table *t = parms->sysctl;
parms->sysctl = NULL;
- unregister_sysctl_table(t->sysctl_header);
+ unregister_net_sysctl_table(t->sysctl_header);
kfree(t);
}
}
@@ -694,13 +683,13 @@ static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
ifm->ifa_scope = ifa->ifa_scope;
ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
- if (ifa->ifa_address)
- NLA_PUT_LE16(skb, IFA_ADDRESS, ifa->ifa_address);
- if (ifa->ifa_local)
- NLA_PUT_LE16(skb, IFA_LOCAL, ifa->ifa_local);
- if (ifa->ifa_label[0])
- NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
-
+ if ((ifa->ifa_address &&
+ nla_put_le16(skb, IFA_ADDRESS, ifa->ifa_address)) ||
+ (ifa->ifa_local &&
+ nla_put_le16(skb, IFA_LOCAL, ifa->ifa_local)) ||
+ (ifa->ifa_label[0] &&
+ nla_put_string(skb, IFA_LABEL, ifa->ifa_label)))
+ goto nla_put_failure;
return nlmsg_end(skb, nlh);
nla_put_failure:
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
index 9e885f180b60..65a8cd7891fe 100644
--- a/net/decnet/dn_fib.c
+++ b/net/decnet/dn_fib.c
@@ -302,11 +302,12 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
struct rtattr *attr = RTA_DATA(rta->rta_mx);
while(RTA_OK(attr, attrlen)) {
- unsigned flavour = attr->rta_type;
+ unsigned int flavour = attr->rta_type;
+
if (flavour) {
if (flavour > RTAX_MAX)
goto err_inval;
- fi->fib_metrics[flavour-1] = *(unsigned*)RTA_DATA(attr);
+ fi->fib_metrics[flavour-1] = *(unsigned int *)RTA_DATA(attr);
}
attr = RTA_NEXT(attr, attrlen);
}
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
index f6544b2c91b0..58084f37151e 100644
--- a/net/decnet/dn_nsp_in.c
+++ b/net/decnet/dn_nsp_in.c
@@ -588,7 +588,7 @@ static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig
number of warnings when compiling with -W --ANK
*/
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
- (unsigned)sk->sk_rcvbuf) {
+ (unsigned int)sk->sk_rcvbuf) {
err = -ENOMEM;
goto out;
}
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index e446e85e64a6..b952f88d9c1f 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -209,7 +209,7 @@ static void dn_nsp_rtt(struct sock *sk, long rtt)
*
* Returns: The number of times the packet has been sent previously
*/
-static inline unsigned dn_nsp_clone_and_send(struct sk_buff *skb,
+static inline unsigned int dn_nsp_clone_and_send(struct sk_buff *skb,
gfp_t gfp)
{
struct dn_skb_cb *cb = DN_SKB_CB(skb);
@@ -240,7 +240,7 @@ void dn_nsp_output(struct sock *sk)
{
struct dn_scp *scp = DN_SK(sk);
struct sk_buff *skb;
- unsigned reduce_win = 0;
+ unsigned int reduce_win = 0;
/*
* First we check for otherdata/linkservice messages
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 80a3de4906d3..7e1f8788da19 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -122,7 +122,7 @@ static int dn_route_input(struct sk_buff *);
static void dn_run_flush(unsigned long dummy);
static struct dn_rt_hash_bucket *dn_rt_hash_table;
-static unsigned dn_rt_hash_mask;
+static unsigned int dn_rt_hash_mask;
static struct timer_list dn_route_timer;
static DEFINE_TIMER(dn_rt_flush_timer, dn_run_flush, 0, 0);
@@ -149,13 +149,13 @@ static void dn_dst_destroy(struct dst_entry *dst)
dst_destroy_metrics_generic(dst);
}
-static __inline__ unsigned dn_hash(__le16 src, __le16 dst)
+static __inline__ unsigned int dn_hash(__le16 src, __le16 dst)
{
__u16 tmp = (__u16 __force)(src ^ dst);
tmp ^= (tmp >> 3);
tmp ^= (tmp >> 5);
tmp ^= (tmp >> 10);
- return dn_rt_hash_mask & (unsigned)tmp;
+ return dn_rt_hash_mask & (unsigned int)tmp;
}
static inline void dnrt_free(struct dn_route *rt)
@@ -297,7 +297,7 @@ static inline int compare_keys(struct flowidn *fl1, struct flowidn *fl2)
(fl1->flowidn_iif ^ fl2->flowidn_iif)) == 0;
}
-static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp)
+static int dn_insert_route(struct dn_route *rt, unsigned int hash, struct dn_route **rp)
{
struct dn_route *rth;
struct dn_route __rcu **rthp;
@@ -934,8 +934,8 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowidn *o
struct dn_route *rt = NULL;
struct net_device *dev_out = NULL, *dev;
struct neighbour *neigh = NULL;
- unsigned hash;
- unsigned flags = 0;
+ unsigned int hash;
+ unsigned int flags = 0;
struct dn_fib_res res = { .fi = NULL, .type = RTN_UNICAST };
int err;
int free_res = 0;
@@ -1209,7 +1209,7 @@ e_neighbour:
*/
static int __dn_route_output_key(struct dst_entry **pprt, const struct flowidn *flp, int flags)
{
- unsigned hash = dn_hash(flp->saddr, flp->daddr);
+ unsigned int hash = dn_hash(flp->saddr, flp->daddr);
struct dn_route *rt = NULL;
if (!(flags & MSG_TRYHARD)) {
@@ -1275,7 +1275,7 @@ static int dn_route_input_slow(struct sk_buff *skb)
struct net_device *out_dev = NULL;
struct dn_dev *dn_db;
struct neighbour *neigh = NULL;
- unsigned hash;
+ unsigned int hash;
int flags = 0;
__le16 gateway = 0;
__le16 local_src = 0;
@@ -1490,7 +1490,7 @@ static int dn_route_input(struct sk_buff *skb)
{
struct dn_route *rt;
struct dn_skb_cb *cb = DN_SKB_CB(skb);
- unsigned hash = dn_hash(cb->src, cb->dst);
+ unsigned int hash = dn_hash(cb->src, cb->dst);
if (skb_dst(skb))
return 0;
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c
index f65c9ddaee41..e65f2c856e06 100644
--- a/net/decnet/dn_rules.c
+++ b/net/decnet/dn_rules.c
@@ -177,11 +177,11 @@ static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
return 1;
}
-unsigned dnet_addr_type(__le16 addr)
+unsigned int dnet_addr_type(__le16 addr)
{
struct flowidn fld = { .daddr = addr };
struct dn_fib_res res;
- unsigned ret = RTN_UNICAST;
+ unsigned int ret = RTN_UNICAST;
struct dn_fib_table *tb = dn_fib_get_table(RT_TABLE_LOCAL, 0);
res.r = NULL;
@@ -204,11 +204,11 @@ static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
frh->src_len = r->src_len;
frh->tos = 0;
- if (r->dst_len)
- NLA_PUT_LE16(skb, FRA_DST, r->dst);
- if (r->src_len)
- NLA_PUT_LE16(skb, FRA_SRC, r->src);
-
+ if ((r->dst_len &&
+ nla_put_le16(skb, FRA_DST, r->dst)) ||
+ (r->src_len &&
+ nla_put_le16(skb, FRA_SRC, r->src)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c
index 02e75d11cfbb..a55eeccaa72f 100644
--- a/net/decnet/sysctl_net_decnet.c
+++ b/net/decnet/sysctl_net_decnet.c
@@ -351,20 +351,14 @@ static ctl_table dn_table[] = {
{ }
};
-static struct ctl_path dn_path[] = {
- { .procname = "net", },
- { .procname = "decnet", },
- { }
-};
-
void dn_register_sysctl(void)
{
- dn_table_header = register_sysctl_paths(dn_path, dn_table);
+ dn_table_header = register_net_sysctl(&init_net, "net/decnet", dn_table);
}
void dn_unregister_sysctl(void)
{
- unregister_sysctl_table(dn_table_header);
+ unregister_net_sysctl_table(dn_table_header);
}
#else /* CONFIG_SYSCTL */
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
index c73bba326d70..6f70ea935b0b 100644
--- a/net/dns_resolver/dns_key.c
+++ b/net/dns_resolver/dns_key.c
@@ -38,7 +38,7 @@ MODULE_DESCRIPTION("DNS Resolver");
MODULE_AUTHOR("Wang Lei");
MODULE_LICENSE("GPL");
-unsigned dns_resolver_debug;
+unsigned int dns_resolver_debug;
module_param_named(debug, dns_resolver_debug, uint, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(debug, "DNS Resolver debugging mask");
diff --git a/net/dns_resolver/internal.h b/net/dns_resolver/internal.h
index 189ca9e9b785..17c7886b5b3a 100644
--- a/net/dns_resolver/internal.h
+++ b/net/dns_resolver/internal.h
@@ -31,7 +31,7 @@ extern const struct cred *dns_resolver_cache;
/*
* debug tracing
*/
-extern unsigned dns_resolver_debug;
+extern unsigned int dns_resolver_debug;
#define kdebug(FMT, ...) \
do { \
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 71b5edcee401..fa14ca76b77b 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -617,7 +617,7 @@ static int econet_create(struct net *net, struct socket *sock, int protocol,
if (sk == NULL)
goto out;
- sk->sk_reuse = 1;
+ sk->sk_reuse = SK_CAN_REUSE;
sock->ops = &econet_ops;
sock_init_data(sock, sk);
@@ -1012,7 +1012,7 @@ static int __init aun_udp_initialise(void)
return error;
}
- udpsock->sk->sk_reuse = 1;
+ udpsock->sk->sk_reuse = SK_CAN_REUSE;
udpsock->sk->sk_allocation = GFP_ATOMIC; /* we're going to call it
from interrupts */
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index bf10a311cf1c..5889a6c38a10 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -77,7 +77,7 @@ __setup("ether=", netdev_boot_setup);
*/
int eth_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
- const void *daddr, const void *saddr, unsigned len)
+ const void *daddr, const void *saddr, unsigned int len)
{
struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 368515885368..58c8895716ff 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -371,7 +371,7 @@ err:
static int lowpan_header_create(struct sk_buff *skb,
struct net_device *dev,
unsigned short type, const void *_daddr,
- const void *_saddr, unsigned len)
+ const void *_saddr, unsigned int len)
{
u8 tmp, iphc0, iphc1, *hc06_ptr;
struct ipv6hdr *hdr;
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
index 1b09eaabaac1..6fbb2ad7bb6d 100644
--- a/net/ieee802154/dgram.c
+++ b/net/ieee802154/dgram.c
@@ -44,8 +44,8 @@ struct dgram_sock {
struct ieee802154_addr src_addr;
struct ieee802154_addr dst_addr;
- unsigned bound:1;
- unsigned want_ack:1;
+ unsigned int bound:1;
+ unsigned int want_ack:1;
};
static inline struct dgram_sock *dgram_sk(const struct sock *sk)
@@ -206,7 +206,7 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, size_t size)
{
struct net_device *dev;
- unsigned mtu;
+ unsigned int mtu;
struct sk_buff *skb;
struct dgram_sock *ro = dgram_sk(sk);
int hlen, tlen;
diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c
index adaf46214905..ca92587720f4 100644
--- a/net/ieee802154/nl-mac.c
+++ b/net/ieee802154/nl-mac.c
@@ -63,15 +63,14 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
if (!msg)
return -ENOBUFS;
- NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
- NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
- NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
- dev->dev_addr);
-
- NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
- addr->hwaddr);
-
- NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap);
+ if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
+ nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
+ nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+ dev->dev_addr) ||
+ nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
+ addr->hwaddr) ||
+ nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
+ goto nla_put_failure;
return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
@@ -92,14 +91,13 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
if (!msg)
return -ENOBUFS;
- NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
- NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
- NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
- dev->dev_addr);
-
- NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr);
- NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
-
+ if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
+ nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
+ nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+ dev->dev_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);
nla_put_failure:
@@ -119,20 +117,22 @@ int ieee802154_nl_disassoc_indic(struct net_device *dev,
if (!msg)
return -ENOBUFS;
- NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
- NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
- NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
- dev->dev_addr);
-
- if (addr->addr_type == IEEE802154_ADDR_LONG)
- NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
- addr->hwaddr);
- else
- NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
- addr->short_addr);
-
- NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason);
-
+ if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
+ nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
+ nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+ dev->dev_addr))
+ goto nla_put_failure;
+ if (addr->addr_type == IEEE802154_ADDR_LONG) {
+ if (nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
+ addr->hwaddr))
+ goto nla_put_failure;
+ } else {
+ if (nla_put_u16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
+ addr->short_addr))
+ goto nla_put_failure;
+ }
+ if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
+ goto nla_put_failure;
return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
nla_put_failure:
@@ -151,13 +151,12 @@ int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
if (!msg)
return -ENOBUFS;
- NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
- NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
- NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
- dev->dev_addr);
-
- NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
-
+ if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
+ nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
+ nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+ dev->dev_addr) ||
+ nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
+ goto nla_put_failure;
return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
nla_put_failure:
@@ -177,13 +176,13 @@ int ieee802154_nl_beacon_indic(struct net_device *dev,
if (!msg)
return -ENOBUFS;
- NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
- NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
- NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
- dev->dev_addr);
- NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr);
- NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid);
-
+ if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
+ nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
+ nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+ dev->dev_addr) ||
+ 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);
nla_put_failure:
@@ -204,19 +203,17 @@ int ieee802154_nl_scan_confirm(struct net_device *dev,
if (!msg)
return -ENOBUFS;
- NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
- NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
- NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
- dev->dev_addr);
-
- NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
- NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type);
- NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned);
- NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, page);
-
- if (edl)
- NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl);
-
+ if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
+ nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
+ nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+ dev->dev_addr) ||
+ nla_put_u8(msg, IEEE802154_ATTR_STATUS, status) ||
+ nla_put_u8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type) ||
+ nla_put_u32(msg, IEEE802154_ATTR_CHANNELS, unscanned) ||
+ nla_put_u8(msg, IEEE802154_ATTR_PAGE, page) ||
+ (edl &&
+ nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl)))
+ goto nla_put_failure;
return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
nla_put_failure:
@@ -235,13 +232,12 @@ int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
if (!msg)
return -ENOBUFS;
- NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
- NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
- NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
- dev->dev_addr);
-
- NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
-
+ if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
+ nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
+ nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+ dev->dev_addr) ||
+ nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
+ goto nla_put_failure;
return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
nla_put_failure:
@@ -266,16 +262,16 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid,
phy = ieee802154_mlme_ops(dev)->get_phy(dev);
BUG_ON(!phy);
- NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
- NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
- NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
-
- NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
- dev->dev_addr);
- NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR,
- ieee802154_mlme_ops(dev)->get_short_addr(dev));
- NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID,
- ieee802154_mlme_ops(dev)->get_pan_id(dev));
+ if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
+ nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
+ nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
+ nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+ dev->dev_addr) ||
+ nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR,
+ ieee802154_mlme_ops(dev)->get_short_addr(dev)) ||
+ nla_put_u16(msg, IEEE802154_ATTR_PAN_ID,
+ ieee802154_mlme_ops(dev)->get_pan_id(dev)))
+ goto nla_put_failure;
wpan_phy_put(phy);
return genlmsg_end(msg, hdr);
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c
index c64a38d57aa3..3bdc4303c339 100644
--- a/net/ieee802154/nl-phy.c
+++ b/net/ieee802154/nl-phy.c
@@ -53,18 +53,18 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 pid,
goto out;
mutex_lock(&phy->pib_lock);
- NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
-
- NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, phy->current_page);
- NLA_PUT_U8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel);
+ if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
+ nla_put_u8(msg, IEEE802154_ATTR_PAGE, phy->current_page) ||
+ nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel))
+ goto nla_put_failure;
for (i = 0; i < 32; i++) {
if (phy->channels_supported[i])
buf[pages++] = phy->channels_supported[i] | (i << 27);
}
- if (pages)
- NLA_PUT(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST,
- pages * sizeof(uint32_t), buf);
-
+ if (pages &&
+ nla_put(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST,
+ pages * sizeof(uint32_t), buf))
+ goto nla_put_failure;
mutex_unlock(&phy->pib_lock);
kfree(buf);
return genlmsg_end(msg, hdr);
@@ -245,9 +245,9 @@ static int ieee802154_add_iface(struct sk_buff *skb,
goto dev_unregister;
}
- NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
- NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
-
+ if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
+ nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name))
+ goto nla_put_failure;
dev_put(dev);
wpan_phy_put(phy);
@@ -333,10 +333,9 @@ static int ieee802154_del_iface(struct sk_buff *skb,
rtnl_unlock();
-
- NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
- NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, name);
-
+ if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
+ nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, name))
+ goto nla_put_failure;
wpan_phy_put(phy);
return ieee802154_nl_reply(msg, info);
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c
index f96bae8fd330..50e823927d49 100644
--- a/net/ieee802154/raw.c
+++ b/net/ieee802154/raw.c
@@ -106,7 +106,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t size)
{
struct net_device *dev;
- unsigned mtu;
+ unsigned int mtu;
struct sk_buff *skb;
int hlen, tlen;
int err;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 10e3751466b5..c8f7aee587d1 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -350,7 +350,7 @@ lookup_protocol:
err = 0;
sk->sk_no_check = answer_no_check;
if (INET_PROTOSW_REUSE & answer_flags)
- sk->sk_reuse = 1;
+ sk->sk_reuse = SK_CAN_REUSE;
inet = inet_sk(sk);
inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
@@ -541,7 +541,7 @@ out:
}
EXPORT_SYMBOL(inet_bind);
-int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr,
+int inet_dgram_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags)
{
struct sock *sk = sock->sk;
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index fd508b526014..3a280756dd73 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -77,7 +77,7 @@ static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash,
static int ip_clear_mutable_options(const struct iphdr *iph, __be32 *daddr)
{
- unsigned char * optptr = (unsigned char*)(iph+1);
+ unsigned char *optptr = (unsigned char *)(iph+1);
int l = iph->ihl*4 - sizeof(struct iphdr);
int optlen;
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 18d9b81ecb1a..373b56bf8f49 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1059,7 +1059,7 @@ static int arp_req_set(struct net *net, struct arpreq *r,
neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev);
err = PTR_ERR(neigh);
if (!IS_ERR(neigh)) {
- unsigned state = NUD_STALE;
+ unsigned int state = NUD_STALE;
if (r->arp_flags & ATF_PERM)
state = NUD_PERMANENT;
err = neigh_update(neigh, (r->arp_flags & ATF_COM) ?
@@ -1071,7 +1071,7 @@ static int arp_req_set(struct net *net, struct arpreq *r,
return err;
}
-static unsigned arp_state_to_flags(struct neighbour *neigh)
+static unsigned int arp_state_to_flags(struct neighbour *neigh)
{
if (neigh->nud_state&NUD_PERMANENT)
return ATF_PERM | ATF_COM;
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 6e447ff94dfa..88c9e3f68c78 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1125,7 +1125,7 @@ skip:
}
}
-static inline bool inetdev_valid_mtu(unsigned mtu)
+static inline bool inetdev_valid_mtu(unsigned int mtu)
{
return mtu >= 68;
}
@@ -1266,17 +1266,15 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
ifm->ifa_scope = ifa->ifa_scope;
ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
- if (ifa->ifa_address)
- NLA_PUT_BE32(skb, IFA_ADDRESS, ifa->ifa_address);
-
- if (ifa->ifa_local)
- NLA_PUT_BE32(skb, IFA_LOCAL, ifa->ifa_local);
-
- if (ifa->ifa_broadcast)
- NLA_PUT_BE32(skb, IFA_BROADCAST, ifa->ifa_broadcast);
-
- if (ifa->ifa_label[0])
- NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
+ if ((ifa->ifa_address &&
+ nla_put_be32(skb, IFA_ADDRESS, ifa->ifa_address)) ||
+ (ifa->ifa_local &&
+ nla_put_be32(skb, IFA_LOCAL, ifa->ifa_local)) ||
+ (ifa->ifa_broadcast &&
+ nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
+ (ifa->ifa_label[0] &&
+ nla_put_string(skb, IFA_LABEL, ifa->ifa_label)))
+ goto nla_put_failure;
return nlmsg_end(skb, nlh);
@@ -1587,7 +1585,6 @@ static int ipv4_doint_and_flush(ctl_table *ctl, int write,
static struct devinet_sysctl_table {
struct ctl_table_header *sysctl_header;
struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
- char *dev_name;
} devinet_sysctl = {
.devinet_vars = {
DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
@@ -1629,16 +1626,7 @@ static int __devinet_sysctl_register(struct net *net, char *dev_name,
{
int i;
struct devinet_sysctl_table *t;
-
-#define DEVINET_CTL_PATH_DEV 3
-
- struct ctl_path devinet_ctl_path[] = {
- { .procname = "net", },
- { .procname = "ipv4", },
- { .procname = "conf", },
- { /* to be set */ },
- { },
- };
+ char path[sizeof("net/ipv4/conf/") + IFNAMSIZ];
t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL);
if (!t)
@@ -1650,27 +1638,15 @@ static int __devinet_sysctl_register(struct net *net, char *dev_name,
t->devinet_vars[i].extra2 = net;
}
- /*
- * Make a copy of dev_name, because '.procname' is regarded as const
- * by sysctl and we wouldn't want anyone to change it under our feet
- * (see SIOCSIFNAME).
- */
- t->dev_name = kstrdup(dev_name, GFP_KERNEL);
- if (!t->dev_name)
- goto free;
-
- devinet_ctl_path[DEVINET_CTL_PATH_DEV].procname = t->dev_name;
+ snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name);
- t->sysctl_header = register_net_sysctl_table(net, devinet_ctl_path,
- t->devinet_vars);
+ t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars);
if (!t->sysctl_header)
- goto free_procname;
+ goto free;
p->sysctl = t;
return 0;
-free_procname:
- kfree(t->dev_name);
free:
kfree(t);
out:
@@ -1686,7 +1662,6 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
cnf->sysctl = NULL;
unregister_net_sysctl_table(t->sysctl_header);
- kfree(t->dev_name);
kfree(t);
}
@@ -1716,12 +1691,6 @@ static struct ctl_table ctl_forward_entry[] = {
},
{ },
};
-
-static __net_initdata struct ctl_path net_ipv4_path[] = {
- { .procname = "net", },
- { .procname = "ipv4", },
- { },
-};
#endif
static __net_init int devinet_init_net(struct net *net)
@@ -1767,7 +1736,7 @@ static __net_init int devinet_init_net(struct net *net)
goto err_reg_dflt;
err = -ENOMEM;
- forw_hdr = register_net_sysctl_table(net, net_ipv4_path, tbl);
+ forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
if (forw_hdr == NULL)
goto err_reg_ctl;
net->ipv4.forw_hdr = forw_hdr;
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index cbe3a68507cf..3854411fa37c 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -136,13 +136,13 @@ static void fib_flush(struct net *net)
* Find address type as if only "dev" was present in the system. If
* on_dev is NULL then all interfaces are taken into consideration.
*/
-static inline unsigned __inet_dev_addr_type(struct net *net,
- const struct net_device *dev,
- __be32 addr)
+static inline unsigned int __inet_dev_addr_type(struct net *net,
+ const struct net_device *dev,
+ __be32 addr)
{
struct flowi4 fl4 = { .daddr = addr };
struct fib_result res;
- unsigned ret = RTN_BROADCAST;
+ unsigned int ret = RTN_BROADCAST;
struct fib_table *local_table;
if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
@@ -740,7 +740,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
#define BRD_OK 2
#define BRD0_OK 4
#define BRD1_OK 8
- unsigned ok = 0;
+ unsigned int ok = 0;
int subnet = 0; /* Primary network */
int gone = 1; /* Address is missing */
int same_prefsrc = 0; /* Another primary with same IP */
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 799fc790b3cf..2d043f71ef70 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -221,15 +221,15 @@ static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
frh->src_len = rule4->src_len;
frh->tos = rule4->tos;
- if (rule4->dst_len)
- NLA_PUT_BE32(skb, FRA_DST, rule4->dst);
-
- if (rule4->src_len)
- NLA_PUT_BE32(skb, FRA_SRC, rule4->src);
-
+ if ((rule4->dst_len &&
+ nla_put_be32(skb, FRA_DST, rule4->dst)) ||
+ (rule4->src_len &&
+ nla_put_be32(skb, FRA_SRC, rule4->src)))
+ goto nla_put_failure;
#ifdef CONFIG_IP_ROUTE_CLASSID
- if (rule4->tclassid)
- NLA_PUT_U32(skb, FRA_FLOW, rule4->tclassid);
+ if (rule4->tclassid &&
+ nla_put_u32(skb, FRA_FLOW, rule4->tclassid))
+ goto nla_put_failure;
#endif
return 0;
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 5063fa38ac7b..a8bdf7405433 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -931,33 +931,36 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
rtm->rtm_table = tb_id;
else
rtm->rtm_table = RT_TABLE_COMPAT;
- NLA_PUT_U32(skb, RTA_TABLE, tb_id);
+ if (nla_put_u32(skb, RTA_TABLE, tb_id))
+ goto nla_put_failure;
rtm->rtm_type = type;
rtm->rtm_flags = fi->fib_flags;
rtm->rtm_scope = fi->fib_scope;
rtm->rtm_protocol = fi->fib_protocol;
- if (rtm->rtm_dst_len)
- NLA_PUT_BE32(skb, RTA_DST, dst);
-
- if (fi->fib_priority)
- NLA_PUT_U32(skb, RTA_PRIORITY, fi->fib_priority);
-
+ if (rtm->rtm_dst_len &&
+ nla_put_be32(skb, RTA_DST, dst))
+ goto nla_put_failure;
+ if (fi->fib_priority &&
+ nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority))
+ goto nla_put_failure;
if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0)
goto nla_put_failure;
- if (fi->fib_prefsrc)
- NLA_PUT_BE32(skb, RTA_PREFSRC, fi->fib_prefsrc);
-
+ if (fi->fib_prefsrc &&
+ nla_put_be32(skb, RTA_PREFSRC, fi->fib_prefsrc))
+ goto nla_put_failure;
if (fi->fib_nhs == 1) {
- if (fi->fib_nh->nh_gw)
- NLA_PUT_BE32(skb, RTA_GATEWAY, fi->fib_nh->nh_gw);
-
- if (fi->fib_nh->nh_oif)
- NLA_PUT_U32(skb, RTA_OIF, fi->fib_nh->nh_oif);
+ if (fi->fib_nh->nh_gw &&
+ nla_put_be32(skb, RTA_GATEWAY, fi->fib_nh->nh_gw))
+ goto nla_put_failure;
+ if (fi->fib_nh->nh_oif &&
+ nla_put_u32(skb, RTA_OIF, fi->fib_nh->nh_oif))
+ goto nla_put_failure;
#ifdef CONFIG_IP_ROUTE_CLASSID
- if (fi->fib_nh[0].nh_tclassid)
- NLA_PUT_U32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid);
+ if (fi->fib_nh[0].nh_tclassid &&
+ nla_put_u32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid))
+ goto nla_put_failure;
#endif
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH
@@ -978,11 +981,13 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
rtnh->rtnh_hops = nh->nh_weight - 1;
rtnh->rtnh_ifindex = nh->nh_oif;
- if (nh->nh_gw)
- NLA_PUT_BE32(skb, RTA_GATEWAY, nh->nh_gw);
+ if (nh->nh_gw &&
+ nla_put_be32(skb, RTA_GATEWAY, nh->nh_gw))
+ goto nla_put_failure;
#ifdef CONFIG_IP_ROUTE_CLASSID
- if (nh->nh_tclassid)
- NLA_PUT_U32(skb, RTA_FLOW, nh->nh_tclassid);
+ if (nh->nh_tclassid &&
+ nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid))
+ goto nla_put_failure;
#endif
/* length of rtnetlink header + attributes */
rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *) rtnh;
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 5dfecfd7d5e9..6699f23e6f55 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -344,10 +344,10 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
pip->protocol = IPPROTO_IGMP;
pip->tot_len = 0; /* filled in later */
ip_select_ident(pip, &rt->dst, NULL);
- ((u8*)&pip[1])[0] = IPOPT_RA;
- ((u8*)&pip[1])[1] = 4;
- ((u8*)&pip[1])[2] = 0;
- ((u8*)&pip[1])[3] = 0;
+ ((u8 *)&pip[1])[0] = IPOPT_RA;
+ ((u8 *)&pip[1])[1] = 4;
+ ((u8 *)&pip[1])[2] = 0;
+ ((u8 *)&pip[1])[3] = 0;
skb->transport_header = skb->network_header + sizeof(struct iphdr) + 4;
skb_put(skb, sizeof(*pig));
@@ -688,10 +688,10 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
iph->saddr = fl4.saddr;
iph->protocol = IPPROTO_IGMP;
ip_select_ident(iph, &rt->dst, NULL);
- ((u8*)&iph[1])[0] = IPOPT_RA;
- ((u8*)&iph[1])[1] = 4;
- ((u8*)&iph[1])[2] = 0;
- ((u8*)&iph[1])[3] = 0;
+ ((u8 *)&iph[1])[0] = IPOPT_RA;
+ ((u8 *)&iph[1])[1] = 4;
+ ((u8 *)&iph[1])[2] = 0;
+ ((u8 *)&iph[1])[3] = 0;
ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
ih->type = type;
@@ -774,7 +774,7 @@ static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs)
if (psf->sf_count[MCAST_INCLUDE] ||
pmc->sfcount[MCAST_EXCLUDE] !=
psf->sf_count[MCAST_EXCLUDE])
- continue;
+ break;
if (srcs[i] == psf->sf_inaddr) {
scount++;
break;
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 19d66cefd7d3..95e61596e605 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -42,7 +42,8 @@ EXPORT_SYMBOL(sysctl_local_reserved_ports);
void inet_get_local_port_range(int *low, int *high)
{
- unsigned seq;
+ unsigned int seq;
+
do {
seq = read_seqbegin(&sysctl_local_ports.lock);
@@ -53,7 +54,7 @@ void inet_get_local_port_range(int *low, int *high)
EXPORT_SYMBOL(inet_get_local_port_range);
int inet_csk_bind_conflict(const struct sock *sk,
- const struct inet_bind_bucket *tb)
+ const struct inet_bind_bucket *tb, bool relax)
{
struct sock *sk2;
struct hlist_node *node;
@@ -79,6 +80,14 @@ int inet_csk_bind_conflict(const struct sock *sk,
sk2_rcv_saddr == sk_rcv_saddr(sk))
break;
}
+ if (!relax && reuse && sk2->sk_reuse &&
+ sk2->sk_state != TCP_LISTEN) {
+ const __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2);
+
+ if (!sk2_rcv_saddr || !sk_rcv_saddr(sk) ||
+ sk2_rcv_saddr == sk_rcv_saddr(sk))
+ break;
+ }
}
}
return node != NULL;
@@ -122,12 +131,13 @@ again:
(tb->num_owners < smallest_size || smallest_size == -1)) {
smallest_size = tb->num_owners;
smallest_rover = rover;
- if (atomic_read(&hashinfo->bsockets) > (high - low) + 1) {
+ if (atomic_read(&hashinfo->bsockets) > (high - low) + 1 &&
+ !inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, false)) {
snum = smallest_rover;
goto tb_found;
}
}
- if (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) {
+ if (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, false)) {
snum = rover;
goto tb_found;
}
@@ -172,18 +182,22 @@ have_snum:
goto tb_not_found;
tb_found:
if (!hlist_empty(&tb->owners)) {
+ if (sk->sk_reuse == SK_FORCE_REUSE)
+ goto success;
+
if (tb->fastreuse > 0 &&
sk->sk_reuse && sk->sk_state != TCP_LISTEN &&
smallest_size == -1) {
goto success;
} else {
ret = 1;
- if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) {
+ if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, true)) {
if (sk->sk_reuse && sk->sk_state != TCP_LISTEN &&
smallest_size != -1 && --attempts >= 0) {
spin_unlock(&head->lock);
goto again;
}
+
goto fail_unlock;
}
}
@@ -514,7 +528,7 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
/* Normally all the openreqs are young and become mature
* (i.e. converted to established socket) for first timeout.
- * If synack was not acknowledged for 3 seconds, it means
+ * If synack was not acknowledged for 1 second, it means
* one of the following things: synack was lost, ack was lost,
* rtt is high or nobody planned to ack (i.e. synflood).
* When server is a bit loaded, queue is populated with old
@@ -555,8 +569,7 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
syn_ack_recalc(req, thresh, max_retries,
queue->rskq_defer_accept,
&expire, &resend);
- if (req->rsk_ops->syn_ack_timeout)
- req->rsk_ops->syn_ack_timeout(parent, req);
+ req->rsk_ops->syn_ack_timeout(parent, req);
if (!expire &&
(!resend ||
!req->rsk_ops->rtx_syn_ack(parent, req, NULL) ||
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 984ec656b03b..7880af970208 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -217,7 +217,7 @@ begin:
}
EXPORT_SYMBOL_GPL(__inet_lookup_listener);
-struct sock * __inet_lookup_established(struct net *net,
+struct sock *__inet_lookup_established(struct net *net,
struct inet_hashinfo *hashinfo,
const __be32 saddr, const __be16 sport,
const __be32 daddr, const u16 hnum,
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index 89168c6351ff..543ef6225458 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -263,7 +263,7 @@ rescan:
void inet_twdr_hangman(unsigned long data)
{
struct inet_timewait_death_row *twdr;
- int unsigned need_timer;
+ unsigned int need_timer;
twdr = (struct inet_timewait_death_row *)data;
spin_lock(&twdr->death_lock);
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index 29a07b6c7168..e5c44fc586ab 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -41,7 +41,7 @@
static int ip_forward_finish(struct sk_buff *skb)
{
- struct ip_options * opt = &(IPCB(skb)->opt);
+ struct ip_options *opt = &(IPCB(skb)->opt);
IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
@@ -55,7 +55,7 @@ int ip_forward(struct sk_buff *skb)
{
struct iphdr *iph; /* Our header */
struct rtable *rt; /* Route we use */
- struct ip_options * opt = &(IPCB(skb)->opt);
+ struct ip_options *opt = &(IPCB(skb)->opt);
if (skb_warn_if_lro(skb))
goto drop;
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 3727e234c884..71e5c328176c 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -569,7 +569,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
skb_morph(head, qp->q.fragments);
head->next = qp->q.fragments->next;
- kfree_skb(qp->q.fragments);
+ consume_skb(qp->q.fragments);
qp->q.fragments = head;
}
@@ -782,7 +782,7 @@ static int __net_init ip4_frags_ns_ctl_register(struct net *net)
table[2].data = &net->ipv4.frags.timeout;
}
- hdr = register_net_sysctl_table(net, net_ipv4_ctl_path, table);
+ hdr = register_net_sysctl(net, "net/ipv4", table);
if (hdr == NULL)
goto err_reg;
@@ -807,7 +807,7 @@ static void __net_exit ip4_frags_ns_ctl_unregister(struct net *net)
static void ip4_frags_ctl_register(void)
{
- register_net_sysctl_rotable(net_ipv4_ctl_path, ip4_frags_ctl_table);
+ register_net_sysctl(&init_net, "net/ipv4", ip4_frags_ctl_table);
}
#else
static inline int ip4_frags_ns_ctl_register(struct net *net)
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index b57532d4742c..f49047b79609 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -169,37 +169,56 @@ struct ipgre_net {
/* often modified stats are per cpu, other are shared (netdev->stats) */
struct pcpu_tstats {
- unsigned long rx_packets;
- unsigned long rx_bytes;
- unsigned long tx_packets;
- unsigned long tx_bytes;
-} __attribute__((aligned(4*sizeof(unsigned long))));
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 tx_packets;
+ u64 tx_bytes;
+ struct u64_stats_sync syncp;
+};
-static struct net_device_stats *ipgre_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *ipgre_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *tot)
{
- struct pcpu_tstats sum = { 0 };
int i;
for_each_possible_cpu(i) {
const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
-
- sum.rx_packets += tstats->rx_packets;
- sum.rx_bytes += tstats->rx_bytes;
- sum.tx_packets += tstats->tx_packets;
- sum.tx_bytes += tstats->tx_bytes;
+ u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin_bh(&tstats->syncp);
+ rx_packets = tstats->rx_packets;
+ tx_packets = tstats->tx_packets;
+ rx_bytes = tstats->rx_bytes;
+ tx_bytes = tstats->tx_bytes;
+ } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
+
+ tot->rx_packets += rx_packets;
+ tot->tx_packets += tx_packets;
+ tot->rx_bytes += rx_bytes;
+ tot->tx_bytes += tx_bytes;
}
- dev->stats.rx_packets = sum.rx_packets;
- dev->stats.rx_bytes = sum.rx_bytes;
- dev->stats.tx_packets = sum.tx_packets;
- dev->stats.tx_bytes = sum.tx_bytes;
- return &dev->stats;
+
+ tot->multicast = dev->stats.multicast;
+ tot->rx_crc_errors = dev->stats.rx_crc_errors;
+ tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
+ tot->rx_length_errors = dev->stats.rx_length_errors;
+ tot->rx_errors = dev->stats.rx_errors;
+ tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
+ tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
+ tot->tx_dropped = dev->stats.tx_dropped;
+ tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
+ tot->tx_errors = dev->stats.tx_errors;
+
+ return tot;
}
/* Given src, dst and key, find appropriate for input tunnel. */
-static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
- __be32 remote, __be32 local,
- __be32 key, __be16 gre_proto)
+static struct ip_tunnel *ipgre_tunnel_lookup(struct net_device *dev,
+ __be32 remote, __be32 local,
+ __be32 key, __be16 gre_proto)
{
struct net *net = dev_net(dev);
int link = dev->ifindex;
@@ -464,7 +483,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
*/
const struct iphdr *iph = (const struct iphdr *)skb->data;
- __be16 *p = (__be16*)(skb->data+(iph->ihl<<2));
+ __be16 *p = (__be16 *)(skb->data+(iph->ihl<<2));
int grehlen = (iph->ihl<<2) + 4;
const int type = icmp_hdr(skb)->type;
const int code = icmp_hdr(skb)->code;
@@ -574,7 +593,7 @@ static int ipgre_rcv(struct sk_buff *skb)
iph = ip_hdr(skb);
h = skb->data;
- flags = *(__be16*)h;
+ flags = *(__be16 *)h;
if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {
/* - Version must be 0.
@@ -598,11 +617,11 @@ static int ipgre_rcv(struct sk_buff *skb)
offset += 4;
}
if (flags&GRE_KEY) {
- key = *(__be32*)(h + offset);
+ key = *(__be32 *)(h + offset);
offset += 4;
}
if (flags&GRE_SEQ) {
- seqno = ntohl(*(__be32*)(h + offset));
+ seqno = ntohl(*(__be32 *)(h + offset));
offset += 4;
}
}
@@ -672,8 +691,10 @@ static int ipgre_rcv(struct sk_buff *skb)
}
tstats = this_cpu_ptr(tunnel->dev->tstats);
+ u64_stats_update_begin(&tstats->syncp);
tstats->rx_packets++;
tstats->rx_bytes += skb->len;
+ u64_stats_update_end(&tstats->syncp);
__skb_tunnel_rx(skb, tunnel->dev);
@@ -900,7 +921,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
htons(ETH_P_TEB) : skb->protocol;
if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
- __be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4);
+ __be32 *ptr = (__be32 *)(((u8 *)iph) + tunnel->hlen - 4);
if (tunnel->parms.o_flags&GRE_SEQ) {
++tunnel->o_seqno;
@@ -913,7 +934,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
}
if (tunnel->parms.o_flags&GRE_CSUM) {
*ptr = 0;
- *(__sum16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr));
+ *(__sum16 *)ptr = ip_compute_csum((void *)(iph+1), skb->len - sizeof(struct iphdr));
}
}
@@ -1169,7 +1190,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
{
struct ip_tunnel *t = netdev_priv(dev);
struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
- __be16 *p = (__be16*)(iph+1);
+ __be16 *p = (__be16 *)(iph+1);
memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
p[0] = t->parms.o_flags;
@@ -1253,7 +1274,7 @@ static const struct net_device_ops ipgre_netdev_ops = {
.ndo_start_xmit = ipgre_tunnel_xmit,
.ndo_do_ioctl = ipgre_tunnel_ioctl,
.ndo_change_mtu = ipgre_tunnel_change_mtu,
- .ndo_get_stats = ipgre_get_stats,
+ .ndo_get_stats64 = ipgre_get_stats64,
};
static void ipgre_dev_free(struct net_device *dev)
@@ -1507,7 +1528,7 @@ static const struct net_device_ops ipgre_tap_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = ipgre_tunnel_change_mtu,
- .ndo_get_stats = ipgre_get_stats,
+ .ndo_get_stats64 = ipgre_get_stats64,
};
static void ipgre_tap_setup(struct net_device *dev)
@@ -1654,17 +1675,18 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
struct ip_tunnel *t = netdev_priv(dev);
struct ip_tunnel_parm *p = &t->parms;
- NLA_PUT_U32(skb, IFLA_GRE_LINK, p->link);
- NLA_PUT_BE16(skb, IFLA_GRE_IFLAGS, p->i_flags);
- NLA_PUT_BE16(skb, IFLA_GRE_OFLAGS, p->o_flags);
- NLA_PUT_BE32(skb, IFLA_GRE_IKEY, p->i_key);
- NLA_PUT_BE32(skb, IFLA_GRE_OKEY, p->o_key);
- NLA_PUT_BE32(skb, IFLA_GRE_LOCAL, p->iph.saddr);
- NLA_PUT_BE32(skb, IFLA_GRE_REMOTE, p->iph.daddr);
- NLA_PUT_U8(skb, IFLA_GRE_TTL, p->iph.ttl);
- NLA_PUT_U8(skb, IFLA_GRE_TOS, p->iph.tos);
- NLA_PUT_U8(skb, IFLA_GRE_PMTUDISC, !!(p->iph.frag_off & htons(IP_DF)));
-
+ if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
+ nla_put_be16(skb, IFLA_GRE_IFLAGS, p->i_flags) ||
+ nla_put_be16(skb, IFLA_GRE_OFLAGS, p->o_flags) ||
+ nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
+ nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
+ nla_put_be32(skb, IFLA_GRE_LOCAL, p->iph.saddr) ||
+ nla_put_be32(skb, IFLA_GRE_REMOTE, p->iph.daddr) ||
+ nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) ||
+ nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) ||
+ nla_put_u8(skb, IFLA_GRE_PMTUDISC,
+ !!(p->iph.frag_off & htons(IP_DF))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index a0d0d9d9b870..95722ed0e5bb 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -210,10 +210,10 @@ int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb)
* Simple and stupid 8), but the most efficient way.
*/
-void ip_options_fragment(struct sk_buff * skb)
+void ip_options_fragment(struct sk_buff *skb)
{
unsigned char *optptr = skb_network_header(skb) + sizeof(struct iphdr);
- struct ip_options * opt = &(IPCB(skb)->opt);
+ struct ip_options *opt = &(IPCB(skb)->opt);
int l = opt->optlen;
int optlen;
@@ -248,13 +248,13 @@ void ip_options_fragment(struct sk_buff * skb)
*/
int ip_options_compile(struct net *net,
- struct ip_options * opt, struct sk_buff * skb)
+ struct ip_options *opt, struct sk_buff *skb)
{
int l;
- unsigned char * iph;
- unsigned char * optptr;
+ unsigned char *iph;
+ unsigned char *optptr;
int optlen;
- unsigned char * pp_ptr = NULL;
+ unsigned char *pp_ptr = NULL;
struct rtable *rt = NULL;
if (skb != NULL) {
@@ -413,7 +413,7 @@ int ip_options_compile(struct net *net,
opt->is_changed = 1;
}
} else {
- unsigned overflow = optptr[3]>>4;
+ unsigned int overflow = optptr[3]>>4;
if (overflow == 15) {
pp_ptr = optptr + 3;
goto error;
@@ -473,20 +473,20 @@ EXPORT_SYMBOL(ip_options_compile);
* Undo all the changes done by ip_options_compile().
*/
-void ip_options_undo(struct ip_options * opt)
+void ip_options_undo(struct ip_options *opt)
{
if (opt->srr) {
- unsigned char * optptr = opt->__data+opt->srr-sizeof(struct iphdr);
+ unsigned char *optptr = opt->__data+opt->srr-sizeof(struct iphdr);
memmove(optptr+7, optptr+3, optptr[1]-7);
memcpy(optptr+3, &opt->faddr, 4);
}
if (opt->rr_needaddr) {
- unsigned char * optptr = opt->__data+opt->rr-sizeof(struct iphdr);
+ unsigned char *optptr = opt->__data+opt->rr-sizeof(struct iphdr);
optptr[2] -= 4;
memset(&optptr[optptr[2]-1], 0, 4);
}
if (opt->ts) {
- unsigned char * optptr = opt->__data+opt->ts-sizeof(struct iphdr);
+ unsigned char *optptr = opt->__data+opt->ts-sizeof(struct iphdr);
if (opt->ts_needtime) {
optptr[2] -= 4;
memset(&optptr[optptr[2]-1], 0, 4);
@@ -549,8 +549,8 @@ int ip_options_get(struct net *net, struct ip_options_rcu **optp,
void ip_forward_options(struct sk_buff *skb)
{
- struct ip_options * opt = &(IPCB(skb)->opt);
- unsigned char * optptr;
+ struct ip_options *opt = &(IPCB(skb)->opt);
+ unsigned char *optptr;
struct rtable *rt = skb_rtable(skb);
unsigned char *raw = skb_network_header(skb);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 2fd0fba77124..51c6c672c8aa 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -90,7 +90,7 @@ static void ip_cmsg_recv_opts(struct msghdr *msg, struct sk_buff *skb)
static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
{
unsigned char optbuf[sizeof(struct ip_options) + 40];
- struct ip_options * opt = (struct ip_options *)optbuf;
+ struct ip_options *opt = (struct ip_options *)optbuf;
if (IPCB(skb)->opt.optlen == 0)
return;
@@ -147,7 +147,7 @@ static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
{
struct inet_sock *inet = inet_sk(skb->sk);
- unsigned flags = inet->cmsg_flags;
+ unsigned int flags = inet->cmsg_flags;
/* Ordered by supposed usage frequency */
if (flags & 1)
@@ -1094,7 +1094,7 @@ EXPORT_SYMBOL(compat_ip_setsockopt);
*/
static int do_ip_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen, unsigned flags)
+ char __user *optval, int __user *optlen, unsigned int flags)
{
struct inet_sock *inet = inet_sk(sk);
int val;
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 92ac7e7363a0..f267280d8709 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -1198,7 +1198,7 @@ static int __init ic_dynamic(void)
d = ic_first_dev;
retries = CONF_SEND_RETRIES;
get_random_bytes(&timeout, sizeof(timeout));
- timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM);
+ timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned int) CONF_TIMEOUT_RANDOM);
for (;;) {
/* Track the device we are configuring */
ic_dev_xid = d->xid;
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index ae1413e3f2f8..2d0f99bf61b3 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -144,33 +144,48 @@ static void ipip_dev_free(struct net_device *dev);
/* often modified stats are per cpu, other are shared (netdev->stats) */
struct pcpu_tstats {
- unsigned long rx_packets;
- unsigned long rx_bytes;
- unsigned long tx_packets;
- unsigned long tx_bytes;
-} __attribute__((aligned(4*sizeof(unsigned long))));
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 tx_packets;
+ u64 tx_bytes;
+ struct u64_stats_sync syncp;
+};
-static struct net_device_stats *ipip_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *ipip_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *tot)
{
- struct pcpu_tstats sum = { 0 };
int i;
for_each_possible_cpu(i) {
const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
-
- sum.rx_packets += tstats->rx_packets;
- sum.rx_bytes += tstats->rx_bytes;
- sum.tx_packets += tstats->tx_packets;
- sum.tx_bytes += tstats->tx_bytes;
+ u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin_bh(&tstats->syncp);
+ rx_packets = tstats->rx_packets;
+ tx_packets = tstats->tx_packets;
+ rx_bytes = tstats->rx_bytes;
+ tx_bytes = tstats->tx_bytes;
+ } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
+
+ tot->rx_packets += rx_packets;
+ tot->tx_packets += tx_packets;
+ tot->rx_bytes += rx_bytes;
+ tot->tx_bytes += tx_bytes;
}
- dev->stats.rx_packets = sum.rx_packets;
- dev->stats.rx_bytes = sum.rx_bytes;
- dev->stats.tx_packets = sum.tx_packets;
- dev->stats.tx_bytes = sum.tx_bytes;
- return &dev->stats;
+
+ tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
+ tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
+ tot->tx_dropped = dev->stats.tx_dropped;
+ tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
+ tot->tx_errors = dev->stats.tx_errors;
+ tot->collisions = dev->stats.collisions;
+
+ return tot;
}
-static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
+static struct ip_tunnel *ipip_tunnel_lookup(struct net *net,
__be32 remote, __be32 local)
{
unsigned int h0 = HASH(remote);
@@ -245,7 +260,7 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
rcu_assign_pointer(*tp, t);
}
-static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
+static struct ip_tunnel *ipip_tunnel_locate(struct net *net,
struct ip_tunnel_parm *parms, int create)
{
__be32 remote = parms->iph.daddr;
@@ -404,8 +419,10 @@ static int ipip_rcv(struct sk_buff *skb)
skb->pkt_type = PACKET_HOST;
tstats = this_cpu_ptr(tunnel->dev->tstats);
+ u64_stats_update_begin(&tstats->syncp);
tstats->rx_packets++;
tstats->rx_bytes += skb->len;
+ u64_stats_update_end(&tstats->syncp);
__skb_tunnel_rx(skb, tunnel->dev);
@@ -730,7 +747,7 @@ static const struct net_device_ops ipip_netdev_ops = {
.ndo_start_xmit = ipip_tunnel_xmit,
.ndo_do_ioctl = ipip_tunnel_ioctl,
.ndo_change_mtu = ipip_tunnel_change_mtu,
- .ndo_get_stats = ipip_get_stats,
+ .ndo_get_stats64 = ipip_get_stats64,
};
static void ipip_dev_free(struct net_device *dev)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 960fbfc3e976..5bef604ac0fa 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -2119,15 +2119,16 @@ static int ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
rtm->rtm_src_len = 32;
rtm->rtm_tos = 0;
rtm->rtm_table = mrt->id;
- NLA_PUT_U32(skb, RTA_TABLE, mrt->id);
+ if (nla_put_u32(skb, RTA_TABLE, mrt->id))
+ goto nla_put_failure;
rtm->rtm_type = RTN_MULTICAST;
rtm->rtm_scope = RT_SCOPE_UNIVERSE;
rtm->rtm_protocol = RTPROT_UNSPEC;
rtm->rtm_flags = 0;
- NLA_PUT_BE32(skb, RTA_SRC, c->mfc_origin);
- NLA_PUT_BE32(skb, RTA_DST, c->mfc_mcastgrp);
-
+ if (nla_put_be32(skb, RTA_SRC, c->mfc_origin) ||
+ nla_put_be32(skb, RTA_DST, c->mfc_mcastgrp))
+ goto nla_put_failure;
if (__ipmr_fill_mroute(mrt, skb, c, rtm) < 0)
goto nla_put_failure;
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 4f47e064e262..ed1b36783192 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -12,7 +12,7 @@
#include <net/netfilter/nf_queue.h>
/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
-int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
+int ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type)
{
struct net *net = dev_net(skb_dst(skb)->dev);
const struct iphdr *iph = ip_hdr(skb);
@@ -237,13 +237,3 @@ static void ipv4_netfilter_fini(void)
module_init(ipv4_netfilter_init);
module_exit(ipv4_netfilter_fini);
-
-#ifdef CONFIG_SYSCTL
-struct ctl_path nf_net_ipv4_netfilter_sysctl_path[] = {
- { .procname = "net", },
- { .procname = "ipv4", },
- { .procname = "netfilter", },
- { }
-};
-EXPORT_SYMBOL_GPL(nf_net_ipv4_netfilter_sysctl_path);
-#endif /* CONFIG_SYSCTL */
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index fd7a3f68917f..a3935273869f 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -303,7 +303,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
if (v < 0) {
/* Pop from stack? */
if (v != XT_RETURN) {
- verdict = (unsigned)(-v) - 1;
+ verdict = (unsigned int)(-v) - 1;
break;
}
e = back;
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 94d45e1f8882..09775a1e1348 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -586,7 +586,7 @@ static int __init ip_queue_init(void)
#endif
register_netdevice_notifier(&ipq_dev_notifier);
#ifdef CONFIG_SYSCTL
- ipq_sysctl_header = register_sysctl_paths(net_ipv4_ctl_path, ipq_table);
+ ipq_sysctl_header = register_net_sysctl(&init_net, "net/ipv4", ipq_table);
#endif
status = nf_register_queue_handler(NFPROTO_IPV4, &nfqh);
if (status < 0) {
@@ -597,7 +597,7 @@ static int __init ip_queue_init(void)
cleanup_sysctl:
#ifdef CONFIG_SYSCTL
- unregister_sysctl_table(ipq_sysctl_header);
+ unregister_net_sysctl_table(ipq_sysctl_header);
#endif
unregister_netdevice_notifier(&ipq_dev_notifier);
proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
@@ -618,7 +618,7 @@ static void __exit ip_queue_fini(void)
ipq_flush(NULL, 0);
#ifdef CONFIG_SYSCTL
- unregister_sysctl_table(ipq_sysctl_header);
+ unregister_net_sysctl_table(ipq_sysctl_header);
#endif
unregister_netdevice_notifier(&ipq_dev_notifier);
proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 24e556e83a3b..585b80f3cc68 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -377,7 +377,7 @@ ipt_do_table(struct sk_buff *skb,
if (v < 0) {
/* Pop from stack? */
if (v != XT_RETURN) {
- verdict = (unsigned)(-v) - 1;
+ verdict = (unsigned int)(-v) - 1;
break;
}
if (*stackptr <= origptr) {
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index cf73cc70ed2d..91747d4ebc26 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -311,8 +311,9 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
static int ipv4_tuple_to_nlattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple)
{
- NLA_PUT_BE32(skb, CTA_IP_V4_SRC, tuple->src.u3.ip);
- NLA_PUT_BE32(skb, CTA_IP_V4_DST, tuple->dst.u3.ip);
+ if (nla_put_be32(skb, CTA_IP_V4_SRC, tuple->src.u3.ip) ||
+ nla_put_be32(skb, CTA_IP_V4_DST, tuple->dst.u3.ip))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -364,7 +365,7 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = {
.nla_policy = ipv4_nla_policy,
#endif
#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
- .ctl_table_path = nf_net_ipv4_netfilter_sysctl_path,
+ .ctl_table_path = "net/ipv4/netfilter",
.ctl_table = ip_ct_sysctl_table,
#endif
.me = THIS_MODULE,
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 7cbe9cb261c2..0847e373d33c 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -228,10 +228,10 @@ icmp_error(struct net *net, struct nf_conn *tmpl,
static int icmp_tuple_to_nlattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *t)
{
- NLA_PUT_BE16(skb, CTA_PROTO_ICMP_ID, t->src.u.icmp.id);
- NLA_PUT_U8(skb, CTA_PROTO_ICMP_TYPE, t->dst.u.icmp.type);
- NLA_PUT_U8(skb, CTA_PROTO_ICMP_CODE, t->dst.u.icmp.code);
-
+ if (nla_put_be16(skb, CTA_PROTO_ICMP_ID, t->src.u.icmp.id) ||
+ nla_put_u8(skb, CTA_PROTO_ICMP_TYPE, t->dst.u.icmp.type) ||
+ nla_put_u8(skb, CTA_PROTO_ICMP_CODE, t->dst.u.icmp.code))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -293,8 +293,8 @@ icmp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeout = data;
- NLA_PUT_BE32(skb, CTA_TIMEOUT_ICMP_TIMEOUT, htonl(*timeout / HZ));
-
+ if (nla_put_be32(skb, CTA_TIMEOUT_ICMP_TIMEOUT, htonl(*timeout / HZ)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 57932c43960e..ea4a23813d26 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -283,7 +283,7 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff,
__be32 newip;
u_int16_t port;
char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
- unsigned buflen;
+ unsigned int buflen;
/* Connection will come from reply */
if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip)
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 50009c787bcd..6e930c7174dd 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -51,15 +51,16 @@ static struct ping_table ping_table;
static u16 ping_port_rover;
-static inline int ping_hashfn(struct net *net, unsigned num, unsigned mask)
+static inline int ping_hashfn(struct net *net, unsigned int num, unsigned int mask)
{
int res = (num + net_hash_mix(net)) & mask;
+
pr_debug("hash(%d) = %d\n", num, res);
return res;
}
static inline struct hlist_nulls_head *ping_hashslot(struct ping_table *table,
- struct net *net, unsigned num)
+ struct net *net, unsigned int num)
{
return &table->hash[ping_hashfn(net, num, PING_HTABLE_MASK)];
}
@@ -188,7 +189,8 @@ static void inet_get_ping_group_range_net(struct net *net, gid_t *low,
gid_t *high)
{
gid_t *data = net->ipv4.sysctl_ping_group_range;
- unsigned seq;
+ unsigned int seq;
+
do {
seq = read_seqbegin(&sysctl_local_ports.lock);
@@ -410,7 +412,7 @@ struct pingfakehdr {
__wsum wcheck;
};
-static int ping_getfrag(void *from, char * to,
+static int ping_getfrag(void *from, char *to,
int offset, int fraglen, int odd, struct sk_buff *skb)
{
struct pingfakehdr *pfh = (struct pingfakehdr *)from;
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index bbd604c68e68..4032b818f3e4 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -288,7 +288,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
read_unlock(&raw_v4_hashinfo.lock);
}
-static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
+static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
/* Charge it to the socket. */
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 167ea10b521a..5773f5d9e213 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -109,6 +109,7 @@
#include <net/rtnetlink.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
+#include <linux/kmemleak.h>
#endif
#include <net/secure_seq.h>
@@ -229,7 +230,7 @@ const __u8 ip_tos2prio[16] = {
TC_PRIO_INTERACTIVE_BULK,
ECN_OR_COST(INTERACTIVE_BULK)
};
-
+EXPORT_SYMBOL(ip_tos2prio);
/*
* Route cache.
@@ -296,7 +297,7 @@ static inline void rt_hash_lock_init(void)
#endif
static struct rt_hash_bucket *rt_hash_table __read_mostly;
-static unsigned rt_hash_mask __read_mostly;
+static unsigned int rt_hash_mask __read_mostly;
static unsigned int rt_hash_log __read_mostly;
static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
@@ -1143,7 +1144,7 @@ static int rt_bind_neighbour(struct rtable *rt)
return 0;
}
-static struct rtable *rt_intern_hash(unsigned hash, struct rtable *rt,
+static struct rtable *rt_intern_hash(unsigned int hash, struct rtable *rt,
struct sk_buff *skb, int ifindex)
{
struct rtable *rth, *cand;
@@ -1384,7 +1385,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
}
EXPORT_SYMBOL(__ip_select_ident);
-static void rt_del(unsigned hash, struct rtable *rt)
+static void rt_del(unsigned int hash, struct rtable *rt)
{
struct rtable __rcu **rthp;
struct rtable *aux;
@@ -1538,7 +1539,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
ip_rt_put(rt);
ret = NULL;
} else if (rt->rt_flags & RTCF_REDIRECTED) {
- unsigned hash = rt_hash(rt->rt_key_dst, rt->rt_key_src,
+ unsigned int hash = rt_hash(rt->rt_key_dst, rt->rt_key_src,
rt->rt_oif,
rt_genid(dev_net(dst->dev)));
rt_del(hash, rt);
@@ -2215,9 +2216,9 @@ static int ip_mkroute_input(struct sk_buff *skb,
struct in_device *in_dev,
__be32 daddr, __be32 saddr, u32 tos)
{
- struct rtable* rth = NULL;
+ struct rtable *rth = NULL;
int err;
- unsigned hash;
+ unsigned int hash;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
if (res->fi && res->fi->fib_nhs > 1)
@@ -2255,13 +2256,13 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
struct fib_result res;
struct in_device *in_dev = __in_dev_get_rcu(dev);
struct flowi4 fl4;
- unsigned flags = 0;
+ unsigned int flags = 0;
u32 itag = 0;
- struct rtable * rth;
- unsigned hash;
+ struct rtable *rth;
+ unsigned int hash;
__be32 spec_dst;
int err = -EINVAL;
- struct net * net = dev_net(dev);
+ struct net *net = dev_net(dev);
/* IP on this device is disabled. */
@@ -2433,8 +2434,8 @@ martian_source_keep_err:
int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev, bool noref)
{
- struct rtable * rth;
- unsigned hash;
+ struct rtable *rth;
+ unsigned int hash;
int iif = dev->ifindex;
struct net *net;
int res;
@@ -2972,7 +2973,8 @@ static int rt_fill_info(struct net *net,
r->rtm_src_len = 0;
r->rtm_tos = rt->rt_key_tos;
r->rtm_table = RT_TABLE_MAIN;
- NLA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN);
+ if (nla_put_u32(skb, RTA_TABLE, RT_TABLE_MAIN))
+ goto nla_put_failure;
r->rtm_type = rt->rt_type;
r->rtm_scope = RT_SCOPE_UNIVERSE;
r->rtm_protocol = RTPROT_UNSPEC;
@@ -2980,31 +2982,38 @@ static int rt_fill_info(struct net *net,
if (rt->rt_flags & RTCF_NOTIFY)
r->rtm_flags |= RTM_F_NOTIFY;
- NLA_PUT_BE32(skb, RTA_DST, rt->rt_dst);
-
+ if (nla_put_be32(skb, RTA_DST, rt->rt_dst))
+ goto nla_put_failure;
if (rt->rt_key_src) {
r->rtm_src_len = 32;
- NLA_PUT_BE32(skb, RTA_SRC, rt->rt_key_src);
+ if (nla_put_be32(skb, RTA_SRC, rt->rt_key_src))
+ goto nla_put_failure;
}
- if (rt->dst.dev)
- NLA_PUT_U32(skb, RTA_OIF, rt->dst.dev->ifindex);
+ if (rt->dst.dev &&
+ nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
+ goto nla_put_failure;
#ifdef CONFIG_IP_ROUTE_CLASSID
- if (rt->dst.tclassid)
- NLA_PUT_U32(skb, RTA_FLOW, rt->dst.tclassid);
+ if (rt->dst.tclassid &&
+ nla_put_u32(skb, RTA_FLOW, rt->dst.tclassid))
+ goto nla_put_failure;
#endif
- if (rt_is_input_route(rt))
- NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_spec_dst);
- else if (rt->rt_src != rt->rt_key_src)
- NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_src);
-
- if (rt->rt_dst != rt->rt_gateway)
- NLA_PUT_BE32(skb, RTA_GATEWAY, rt->rt_gateway);
+ if (rt_is_input_route(rt)) {
+ if (nla_put_be32(skb, RTA_PREFSRC, rt->rt_spec_dst))
+ goto nla_put_failure;
+ } else if (rt->rt_src != rt->rt_key_src) {
+ if (nla_put_be32(skb, RTA_PREFSRC, rt->rt_src))
+ goto nla_put_failure;
+ }
+ if (rt->rt_dst != rt->rt_gateway &&
+ nla_put_be32(skb, RTA_GATEWAY, rt->rt_gateway))
+ goto nla_put_failure;
if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
goto nla_put_failure;
- if (rt->rt_mark)
- NLA_PUT_BE32(skb, RTA_MARK, rt->rt_mark);
+ if (rt->rt_mark &&
+ nla_put_be32(skb, RTA_MARK, rt->rt_mark))
+ goto nla_put_failure;
error = rt->dst.error;
if (peer) {
@@ -3045,7 +3054,8 @@ static int rt_fill_info(struct net *net,
}
} else
#endif
- NLA_PUT_U32(skb, RTA_IIF, rt->rt_iif);
+ if (nla_put_u32(skb, RTA_IIF, rt->rt_iif))
+ goto nla_put_failure;
}
if (rtnl_put_cacheinfo(skb, &rt->dst, id, ts, tsage,
@@ -3059,7 +3069,7 @@ nla_put_failure:
return -EMSGSIZE;
}
-static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
+static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
{
struct net *net = sock_net(in_skb->sk);
struct rtmsg *rtm;
@@ -3334,23 +3344,6 @@ static ctl_table ipv4_route_table[] = {
{ }
};
-static struct ctl_table empty[1];
-
-static struct ctl_table ipv4_skeleton[] =
-{
- { .procname = "route",
- .mode = 0555, .child = ipv4_route_table},
- { .procname = "neigh",
- .mode = 0555, .child = empty},
- { }
-};
-
-static __net_initdata struct ctl_path ipv4_path[] = {
- { .procname = "net", },
- { .procname = "ipv4", },
- { },
-};
-
static struct ctl_table ipv4_route_flush_table[] = {
{
.procname = "flush",
@@ -3361,13 +3354,6 @@ static struct ctl_table ipv4_route_flush_table[] = {
{ },
};
-static __net_initdata struct ctl_path ipv4_route_path[] = {
- { .procname = "net", },
- { .procname = "ipv4", },
- { .procname = "route", },
- { },
-};
-
static __net_init int sysctl_route_net_init(struct net *net)
{
struct ctl_table *tbl;
@@ -3380,8 +3366,7 @@ static __net_init int sysctl_route_net_init(struct net *net)
}
tbl[0].extra1 = net;
- net->ipv4.route_hdr =
- register_net_sysctl_table(net, ipv4_route_path, tbl);
+ net->ipv4.route_hdr = register_net_sysctl(net, "net/ipv4/route", tbl);
if (net->ipv4.route_hdr == NULL)
goto err_reg;
return 0;
@@ -3505,6 +3490,6 @@ int __init ip_rt_init(void)
*/
void __init ip_static_sysctl_init(void)
{
- register_sysctl_paths(ipv4_path, ipv4_skeleton);
+ register_net_sysctl(&init_net, "net/ipv4/route", ipv4_route_table);
}
#endif
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 7a7724da9bff..33417f84e07f 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -78,7 +78,7 @@ static int ipv4_local_port_range(ctl_table *table, int write,
static void inet_get_ping_group_range_table(struct ctl_table *table, gid_t *low, gid_t *high)
{
gid_t *data = table->data;
- unsigned seq;
+ unsigned int seq;
do {
seq = read_seqbegin(&sysctl_local_ports.lock);
@@ -768,13 +768,6 @@ static struct ctl_table ipv4_net_table[] = {
{ }
};
-struct ctl_path net_ipv4_ctl_path[] = {
- { .procname = "net", },
- { .procname = "ipv4", },
- { },
-};
-EXPORT_SYMBOL_GPL(net_ipv4_ctl_path);
-
static __net_init int ipv4_sysctl_init_net(struct net *net)
{
struct ctl_table *table;
@@ -815,8 +808,7 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)
tcp_init_mem(net);
- net->ipv4.ipv4_hdr = register_net_sysctl_table(net,
- net_ipv4_ctl_path, table);
+ net->ipv4.ipv4_hdr = register_net_sysctl(net, "net/ipv4", table);
if (net->ipv4.ipv4_hdr == NULL)
goto err_reg;
@@ -857,12 +849,12 @@ static __init int sysctl_ipv4_init(void)
if (!i->procname)
return -EINVAL;
- hdr = register_sysctl_paths(net_ipv4_ctl_path, ipv4_table);
+ hdr = register_net_sysctl(&init_net, "net/ipv4", ipv4_table);
if (hdr == NULL)
return -ENOMEM;
if (register_pernet_subsys(&ipv4_sysctl_ops)) {
- unregister_sysctl_table(hdr);
+ unregister_net_sysctl_table(hdr);
return -ENOMEM;
}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 8bb6adeb62c0..bcc4eab5f251 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -363,6 +363,70 @@ static int retrans_to_secs(u8 retrans, int timeout, int rto_max)
return period;
}
+/* Address-family independent initialization for a tcp_sock.
+ *
+ * NOTE: A lot of things set to zero explicitly by call to
+ * sk_alloc() so need not be done here.
+ */
+void tcp_init_sock(struct sock *sk)
+{
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ struct tcp_sock *tp = tcp_sk(sk);
+
+ skb_queue_head_init(&tp->out_of_order_queue);
+ tcp_init_xmit_timers(sk);
+ tcp_prequeue_init(tp);
+
+ icsk->icsk_rto = TCP_TIMEOUT_INIT;
+ tp->mdev = TCP_TIMEOUT_INIT;
+
+ /* So many TCP implementations out there (incorrectly) count the
+ * initial SYN frame in their delayed-ACK and congestion control
+ * algorithms that we must have the following bandaid to talk
+ * efficiently to them. -DaveM
+ */
+ tp->snd_cwnd = TCP_INIT_CWND;
+
+ /* See draft-stevens-tcpca-spec-01 for discussion of the
+ * initialization of these values.
+ */
+ tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
+ tp->snd_cwnd_clamp = ~0;
+ tp->mss_cache = TCP_MSS_DEFAULT;
+
+ tp->reordering = sysctl_tcp_reordering;
+ icsk->icsk_ca_ops = &tcp_init_congestion_ops;
+
+ sk->sk_state = TCP_CLOSE;
+
+ sk->sk_write_space = sk_stream_write_space;
+ sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
+
+ icsk->icsk_sync_mss = tcp_sync_mss;
+
+ /* TCP Cookie Transactions */
+ if (sysctl_tcp_cookie_size > 0) {
+ /* Default, cookies without s_data_payload. */
+ tp->cookie_values =
+ kzalloc(sizeof(*tp->cookie_values),
+ sk->sk_allocation);
+ if (tp->cookie_values != NULL)
+ kref_init(&tp->cookie_values->kref);
+ }
+ /* Presumed zeroed, in order of appearance:
+ * cookie_in_always, cookie_out_never,
+ * s_data_constant, s_data_in, s_data_out
+ */
+ sk->sk_sndbuf = sysctl_tcp_wmem[1];
+ sk->sk_rcvbuf = sysctl_tcp_rmem[1];
+
+ local_bh_disable();
+ sock_update_memcg(sk);
+ sk_sockets_allocated_inc(sk);
+ local_bh_enable();
+}
+EXPORT_SYMBOL(tcp_init_sock);
+
/*
* Wait for a TCP event.
*
@@ -912,6 +976,39 @@ static inline int select_size(const struct sock *sk, bool sg)
return tmp;
}
+static int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
+{
+ struct sk_buff *skb;
+ struct tcp_skb_cb *cb;
+ struct tcphdr *th;
+
+ skb = alloc_skb(size + sizeof(*th), sk->sk_allocation);
+ if (!skb)
+ goto err;
+
+ th = (struct tcphdr *)skb_put(skb, sizeof(*th));
+ skb_reset_transport_header(skb);
+ memset(th, 0, sizeof(*th));
+
+ if (memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size))
+ goto err_free;
+
+ cb = TCP_SKB_CB(skb);
+
+ TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt;
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + size;
+ TCP_SKB_CB(skb)->ack_seq = tcp_sk(sk)->snd_una - 1;
+
+ tcp_queue_rcv(sk, skb, sizeof(*th));
+
+ return size;
+
+err_free:
+ kfree_skb(skb);
+err:
+ return -ENOMEM;
+}
+
int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t size)
{
@@ -919,7 +1016,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
int iovlen, flags, err, copied;
- int mss_now, size_goal;
+ int mss_now = 0, size_goal;
bool sg;
long timeo;
@@ -933,6 +1030,19 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if ((err = sk_stream_wait_connect(sk, &timeo)) != 0)
goto out_err;
+ if (unlikely(tp->repair)) {
+ if (tp->repair_queue == TCP_RECV_QUEUE) {
+ copied = tcp_send_rcvq(sk, msg, size);
+ goto out;
+ }
+
+ err = -EINVAL;
+ if (tp->repair_queue == TCP_NO_QUEUE)
+ goto out_err;
+
+ /* 'common' sending to sendq */
+ }
+
/* This should be in poll */
clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
@@ -1089,7 +1199,7 @@ new_segment:
if ((seglen -= copy) == 0 && iovlen == 0)
goto out;
- if (skb->len < max || (flags & MSG_OOB))
+ if (skb->len < max || (flags & MSG_OOB) || unlikely(tp->repair))
continue;
if (forced_push(tp)) {
@@ -1102,7 +1212,7 @@ new_segment:
wait_for_sndbuf:
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
wait_for_memory:
- if (copied)
+ if (copied && likely(!tp->repair))
tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
@@ -1113,7 +1223,7 @@ wait_for_memory:
}
out:
- if (copied)
+ if (copied && likely(!tp->repair))
tcp_push(sk, flags, mss_now, tp->nonagle);
release_sock(sk);
return copied;
@@ -1187,6 +1297,24 @@ static int tcp_recv_urg(struct sock *sk, struct msghdr *msg, int len, int flags)
return -EAGAIN;
}
+static int tcp_peek_sndq(struct sock *sk, struct msghdr *msg, int len)
+{
+ struct sk_buff *skb;
+ int copied = 0, err = 0;
+
+ /* XXX -- need to support SO_PEEK_OFF */
+
+ skb_queue_walk(&sk->sk_write_queue, skb) {
+ err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, skb->len);
+ if (err)
+ break;
+
+ copied += skb->len;
+ }
+
+ return err ?: copied;
+}
+
/* Clean up the receive buffer for full frames taken by the user,
* then send an ACK if necessary. COPIED is the number of bytes
* tcp_recvmsg has given to the user so far, it speeds up the
@@ -1432,6 +1560,21 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if (flags & MSG_OOB)
goto recv_urg;
+ if (unlikely(tp->repair)) {
+ err = -EPERM;
+ if (!(flags & MSG_PEEK))
+ goto out;
+
+ if (tp->repair_queue == TCP_SEND_QUEUE)
+ goto recv_sndq;
+
+ err = -EINVAL;
+ if (tp->repair_queue == TCP_NO_QUEUE)
+ goto out;
+
+ /* 'common' recv queue MSG_PEEK-ing */
+ }
+
seq = &tp->copied_seq;
if (flags & MSG_PEEK) {
peek_seq = tp->copied_seq;
@@ -1783,6 +1926,10 @@ out:
recv_urg:
err = tcp_recv_urg(sk, msg, len, flags);
goto out;
+
+recv_sndq:
+ err = tcp_peek_sndq(sk, msg, len);
+ goto out;
}
EXPORT_SYMBOL(tcp_recvmsg);
@@ -1935,7 +2082,9 @@ void tcp_close(struct sock *sk, long timeout)
* advertise a zero window, then kill -9 the FTP client, wheee...
* Note: timeout is always zero in such a case.
*/
- if (data_was_unread) {
+ if (unlikely(tcp_sk(sk)->repair)) {
+ sk->sk_prot->disconnect(sk, 0);
+ } else if (data_was_unread) {
/* Unread data was tossed, zap the connection. */
NET_INC_STATS_USER(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE);
tcp_set_state(sk, TCP_CLOSE);
@@ -2074,6 +2223,8 @@ int tcp_disconnect(struct sock *sk, int flags)
/* ABORT function of RFC793 */
if (old_state == TCP_LISTEN) {
inet_csk_listen_stop(sk);
+ } else if (unlikely(tp->repair)) {
+ sk->sk_err = ECONNABORTED;
} else if (tcp_need_reset(old_state) ||
(tp->snd_nxt != tp->write_seq &&
(1 << old_state) & (TCPF_CLOSING | TCPF_LAST_ACK))) {
@@ -2125,6 +2276,74 @@ int tcp_disconnect(struct sock *sk, int flags)
}
EXPORT_SYMBOL(tcp_disconnect);
+static inline int tcp_can_repair_sock(struct sock *sk)
+{
+ return capable(CAP_NET_ADMIN) &&
+ ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED));
+}
+
+static int tcp_repair_options_est(struct tcp_sock *tp, char __user *optbuf, unsigned int len)
+{
+ /*
+ * Options are stored in CODE:VALUE form where CODE is 8bit and VALUE
+ * fits the respective TCPOLEN_ size
+ */
+
+ while (len > 0) {
+ u8 opcode;
+
+ if (get_user(opcode, optbuf))
+ return -EFAULT;
+
+ optbuf++;
+ len--;
+
+ switch (opcode) {
+ case TCPOPT_MSS: {
+ u16 in_mss;
+
+ if (len < sizeof(in_mss))
+ return -ENODATA;
+ if (get_user(in_mss, optbuf))
+ return -EFAULT;
+
+ tp->rx_opt.mss_clamp = in_mss;
+
+ optbuf += sizeof(in_mss);
+ len -= sizeof(in_mss);
+ break;
+ }
+ case TCPOPT_WINDOW: {
+ u8 wscale;
+
+ if (len < sizeof(wscale))
+ return -ENODATA;
+ if (get_user(wscale, optbuf))
+ return -EFAULT;
+
+ if (wscale > 14)
+ return -EFBIG;
+
+ tp->rx_opt.snd_wscale = wscale;
+
+ optbuf += sizeof(wscale);
+ len -= sizeof(wscale);
+ break;
+ }
+ case TCPOPT_SACK_PERM:
+ tp->rx_opt.sack_ok |= TCP_SACK_SEEN;
+ if (sysctl_tcp_fack)
+ tcp_enable_fack(tp);
+ break;
+ case TCPOPT_TIMESTAMP:
+ tp->rx_opt.tstamp_ok = 1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
/*
* Socket option code for TCP.
*/
@@ -2297,6 +2516,51 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
tp->thin_dupack = val;
break;
+ case TCP_REPAIR:
+ if (!tcp_can_repair_sock(sk))
+ err = -EPERM;
+ else if (val == 1) {
+ tp->repair = 1;
+ sk->sk_reuse = SK_FORCE_REUSE;
+ tp->repair_queue = TCP_NO_QUEUE;
+ } else if (val == 0) {
+ tp->repair = 0;
+ sk->sk_reuse = SK_NO_REUSE;
+ tcp_send_window_probe(sk);
+ } else
+ err = -EINVAL;
+
+ break;
+
+ case TCP_REPAIR_QUEUE:
+ if (!tp->repair)
+ err = -EPERM;
+ else if (val < TCP_QUEUES_NR)
+ tp->repair_queue = val;
+ else
+ err = -EINVAL;
+ break;
+
+ case TCP_QUEUE_SEQ:
+ if (sk->sk_state != TCP_CLOSE)
+ err = -EPERM;
+ else if (tp->repair_queue == TCP_SEND_QUEUE)
+ tp->write_seq = val;
+ else if (tp->repair_queue == TCP_RECV_QUEUE)
+ tp->rcv_nxt = val;
+ else
+ err = -EINVAL;
+ break;
+
+ case TCP_REPAIR_OPTIONS:
+ if (!tp->repair)
+ err = -EINVAL;
+ else if (sk->sk_state == TCP_ESTABLISHED)
+ err = tcp_repair_options_est(tp, optval, optlen);
+ else
+ err = -EPERM;
+ break;
+
case TCP_CORK:
/* When set indicates to always queue non-full frames.
* Later the user clears this option and we transmit
@@ -2530,6 +2794,8 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
val = tp->mss_cache;
if (!val && ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)))
val = tp->rx_opt.user_mss;
+ if (tp->repair)
+ val = tp->rx_opt.mss_clamp;
break;
case TCP_NODELAY:
val = !!(tp->nonagle&TCP_NAGLE_OFF);
@@ -2632,6 +2898,26 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
val = tp->thin_dupack;
break;
+ case TCP_REPAIR:
+ val = tp->repair;
+ break;
+
+ case TCP_REPAIR_QUEUE:
+ if (tp->repair)
+ val = tp->repair_queue;
+ else
+ return -EINVAL;
+ break;
+
+ case TCP_QUEUE_SEQ:
+ if (tp->repair_queue == TCP_SEND_QUEUE)
+ val = tp->write_seq;
+ else if (tp->repair_queue == TCP_RECV_QUEUE)
+ val = tp->rcv_nxt;
+ else
+ return -EINVAL;
+ break;
+
case TCP_USER_TIMEOUT:
val = jiffies_to_msecs(icsk->icsk_user_timeout);
break;
@@ -2675,7 +2961,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
{
struct sk_buff *segs = ERR_PTR(-EINVAL);
struct tcphdr *th;
- unsigned thlen;
+ unsigned int thlen;
unsigned int seq;
__be32 delta;
unsigned int oldlen;
@@ -3033,9 +3319,9 @@ int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
struct scatterlist sg;
const struct tcphdr *tp = tcp_hdr(skb);
struct hash_desc *desc = &hp->md5_desc;
- unsigned i;
- const unsigned head_data_len = skb_headlen(skb) > header_len ?
- skb_headlen(skb) - header_len : 0;
+ unsigned int i;
+ const unsigned int head_data_len = skb_headlen(skb) > header_len ?
+ skb_headlen(skb) - header_len : 0;
const struct skb_shared_info *shi = skb_shinfo(skb);
struct sk_buff *frag_iter;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 3ff364065376..c1c611b385a7 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -175,7 +175,7 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)
static void tcp_incr_quickack(struct sock *sk)
{
struct inet_connection_sock *icsk = inet_csk(sk);
- unsigned quickacks = tcp_sk(sk)->rcv_wnd / (2 * icsk->icsk_ack.rcv_mss);
+ unsigned int quickacks = tcp_sk(sk)->rcv_wnd / (2 * icsk->icsk_ack.rcv_mss);
if (quickacks == 0)
quickacks = 2;
@@ -937,7 +937,7 @@ static void tcp_init_metrics(struct sock *sk)
tcp_set_rto(sk);
reset:
if (tp->srtt == 0) {
- /* RFC2988bis: We've failed to get a valid RTT sample from
+ /* RFC6298: 5.7 We've failed to get a valid RTT sample from
* 3WHS. This is most likely due to retransmission,
* including spurious one. Reset the RTO back to 3secs
* from the more aggressive 1sec to avoid more spurious
@@ -947,7 +947,7 @@ reset:
inet_csk(sk)->icsk_rto = TCP_TIMEOUT_FALLBACK;
}
/* Cut cwnd down to 1 per RFC5681 if SYN or SYN-ACK has been
- * retransmitted. In light of RFC2988bis' more aggressive 1sec
+ * retransmitted. In light of RFC6298 more aggressive 1sec
* initRTO, we only reset cwnd when more than 1 SYN/SYN-ACK
* retransmission has occurred.
*/
@@ -4450,6 +4450,58 @@ static inline int tcp_try_rmem_schedule(struct sock *sk, unsigned int size)
return 0;
}
+/**
+ * tcp_try_coalesce - try to merge skb to prior one
+ * @sk: socket
+ * @to: prior buffer
+ * @from: buffer to add in queue
+ *
+ * Before queueing skb @from after @to, try to merge them
+ * to reduce overall memory use and queue lengths, if cost is small.
+ * Packets in ofo or receive queues can stay a long time.
+ * Better try to coalesce them right now to avoid future collapses.
+ * Returns > 0 value if caller should free @from instead of queueing it
+ */
+static int tcp_try_coalesce(struct sock *sk,
+ struct sk_buff *to,
+ struct sk_buff *from)
+{
+ int len = from->len;
+
+ if (tcp_hdr(from)->fin)
+ return 0;
+ if (len <= skb_tailroom(to)) {
+ BUG_ON(skb_copy_bits(from, 0, skb_put(to, len), len));
+merge:
+ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRCVCOALESCE);
+ TCP_SKB_CB(to)->end_seq = TCP_SKB_CB(from)->end_seq;
+ TCP_SKB_CB(to)->ack_seq = TCP_SKB_CB(from)->ack_seq;
+ return 1;
+ }
+ if (skb_headlen(from) == 0 &&
+ !skb_has_frag_list(to) &&
+ !skb_has_frag_list(from) &&
+ (skb_shinfo(to)->nr_frags +
+ skb_shinfo(from)->nr_frags <= MAX_SKB_FRAGS)) {
+ int delta = from->truesize - ksize(from->head) -
+ SKB_DATA_ALIGN(sizeof(struct sk_buff));
+
+ WARN_ON_ONCE(delta < len);
+ memcpy(skb_shinfo(to)->frags + skb_shinfo(to)->nr_frags,
+ skb_shinfo(from)->frags,
+ skb_shinfo(from)->nr_frags * sizeof(skb_frag_t));
+ skb_shinfo(to)->nr_frags += skb_shinfo(from)->nr_frags;
+ skb_shinfo(from)->nr_frags = 0;
+ to->truesize += delta;
+ atomic_add(delta, &sk->sk_rmem_alloc);
+ sk_mem_charge(sk, delta);
+ to->len += len;
+ to->data_len += len;
+ goto merge;
+ }
+ return 0;
+}
+
static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -4488,23 +4540,11 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
end_seq = TCP_SKB_CB(skb)->end_seq;
if (seq == TCP_SKB_CB(skb1)->end_seq) {
- /* Packets in ofo can stay in queue a long time.
- * Better try to coalesce them right now
- * to avoid future tcp_collapse_ofo_queue(),
- * probably the most expensive function in tcp stack.
- */
- if (skb->len <= skb_tailroom(skb1) && !tcp_hdr(skb)->fin) {
- NET_INC_STATS_BH(sock_net(sk),
- LINUX_MIB_TCPRCVCOALESCE);
- BUG_ON(skb_copy_bits(skb, 0,
- skb_put(skb1, skb->len),
- skb->len));
- TCP_SKB_CB(skb1)->end_seq = end_seq;
- TCP_SKB_CB(skb1)->ack_seq = TCP_SKB_CB(skb)->ack_seq;
+ if (tcp_try_coalesce(sk, skb1, skb) <= 0) {
+ __skb_queue_after(&tp->out_of_order_queue, skb1, skb);
+ } else {
__kfree_skb(skb);
skb = NULL;
- } else {
- __skb_queue_after(&tp->out_of_order_queue, skb1, skb);
}
if (!tp->rx_opt.num_sacks ||
@@ -4625,13 +4665,18 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
}
if (eaten <= 0) {
+ struct sk_buff *tail;
queue_and_out:
if (eaten < 0 &&
tcp_try_rmem_schedule(sk, skb->truesize))
goto drop;
- skb_set_owner_r(skb, sk);
- __skb_queue_tail(&sk->sk_receive_queue, skb);
+ tail = skb_peek_tail(&sk->sk_receive_queue);
+ eaten = tail ? tcp_try_coalesce(sk, tail, skb) : -1;
+ if (eaten <= 0) {
+ skb_set_owner_r(skb, sk);
+ __skb_queue_tail(&sk->sk_receive_queue, skb);
+ }
}
tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
if (skb->len)
@@ -5326,6 +5371,14 @@ discard:
return 0;
}
+void tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen)
+{
+ __skb_pull(skb, hdrlen);
+ __skb_queue_tail(&sk->sk_receive_queue, skb);
+ skb_set_owner_r(skb, sk);
+ tcp_sk(sk)->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+}
+
/*
* TCP receive function for the ESTABLISHED state.
*
@@ -5491,10 +5544,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITS);
/* Bulk data transfer: receiver */
- __skb_pull(skb, tcp_header_len);
- __skb_queue_tail(&sk->sk_receive_queue, skb);
- skb_set_owner_r(skb, sk);
- tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+ tcp_queue_rcv(sk, skb, tcp_header_len);
}
tcp_event_data_recv(sk, skb);
@@ -5560,6 +5610,44 @@ discard:
}
EXPORT_SYMBOL(tcp_rcv_established);
+void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct inet_connection_sock *icsk = inet_csk(sk);
+
+ tcp_set_state(sk, TCP_ESTABLISHED);
+
+ if (skb != NULL)
+ security_inet_conn_established(sk, skb);
+
+ /* Make sure socket is routed, for correct metrics. */
+ icsk->icsk_af_ops->rebuild_header(sk);
+
+ tcp_init_metrics(sk);
+
+ tcp_init_congestion_control(sk);
+
+ /* Prevent spurious tcp_cwnd_restart() on first data
+ * packet.
+ */
+ tp->lsndtime = tcp_time_stamp;
+
+ tcp_init_buffer_space(sk);
+
+ if (sock_flag(sk, SOCK_KEEPOPEN))
+ inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp));
+
+ if (!tp->rx_opt.snd_wscale)
+ __tcp_fast_path_on(tp, tp->snd_wnd);
+ else
+ tp->pred_flags = 0;
+
+ if (!sock_flag(sk, SOCK_DEAD)) {
+ sk->sk_state_change(sk);
+ sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT);
+ }
+}
+
static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
const struct tcphdr *th, unsigned int len)
{
@@ -5692,36 +5780,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
}
smp_mb();
- tcp_set_state(sk, TCP_ESTABLISHED);
-
- security_inet_conn_established(sk, skb);
-
- /* Make sure socket is routed, for correct metrics. */
- icsk->icsk_af_ops->rebuild_header(sk);
-
- tcp_init_metrics(sk);
-
- tcp_init_congestion_control(sk);
-
- /* Prevent spurious tcp_cwnd_restart() on first data
- * packet.
- */
- tp->lsndtime = tcp_time_stamp;
- tcp_init_buffer_space(sk);
-
- if (sock_flag(sk, SOCK_KEEPOPEN))
- inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp));
-
- if (!tp->rx_opt.snd_wscale)
- __tcp_fast_path_on(tp, tp->snd_wnd);
- else
- tp->pred_flags = 0;
-
- if (!sock_flag(sk, SOCK_DEAD)) {
- sk->sk_state_change(sk);
- sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT);
- }
+ tcp_finish_connect(sk, skb);
if (sk->sk_write_pending ||
icsk->icsk_accept_queue.rskq_defer_accept ||
@@ -5735,8 +5795,6 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
*/
inet_csk_schedule_ack(sk);
icsk->icsk_ack.lrcvtime = tcp_time_stamp;
- icsk->icsk_ack.ato = TCP_ATO_MIN;
- tcp_incr_quickack(sk);
tcp_enter_quickack_mode(sk);
inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
TCP_DELACK_MAX, TCP_RTO_MAX);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 0cb86ceb652f..cf97e9821d76 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -138,6 +138,14 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
}
EXPORT_SYMBOL_GPL(tcp_twsk_unique);
+static int tcp_repair_connect(struct sock *sk)
+{
+ tcp_connect_init(sk);
+ tcp_finish_connect(sk, NULL);
+
+ return 0;
+}
+
/* This will initiate an outgoing connection. */
int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
@@ -196,7 +204,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
/* Reset inherited state */
tp->rx_opt.ts_recent = 0;
tp->rx_opt.ts_recent_stamp = 0;
- tp->write_seq = 0;
+ if (likely(!tp->repair))
+ tp->write_seq = 0;
}
if (tcp_death_row.sysctl_tw_recycle &&
@@ -247,7 +256,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sk->sk_gso_type = SKB_GSO_TCPV4;
sk_setup_caps(sk, &rt->dst);
- if (!tp->write_seq)
+ if (!tp->write_seq && likely(!tp->repair))
tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
inet->inet_daddr,
inet->inet_sport,
@@ -255,7 +264,11 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
inet->inet_id = tp->write_seq ^ jiffies;
- err = tcp_connect(sk);
+ if (likely(!tp->repair))
+ err = tcp_connect(sk);
+ else
+ err = tcp_repair_connect(sk);
+
rt = NULL;
if (err)
goto failure;
@@ -1739,7 +1752,8 @@ process:
if (!tcp_prequeue(sk, skb))
ret = tcp_v4_do_rcv(sk, skb);
}
- } else if (unlikely(sk_add_backlog(sk, skb))) {
+ } else if (unlikely(sk_add_backlog(sk, skb,
+ sk->sk_rcvbuf + sk->sk_sndbuf))) {
bh_unlock_sock(sk);
NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);
goto discard_and_relse;
@@ -1875,64 +1889,15 @@ static const struct tcp_sock_af_ops tcp_sock_ipv4_specific = {
static int tcp_v4_init_sock(struct sock *sk)
{
struct inet_connection_sock *icsk = inet_csk(sk);
- struct tcp_sock *tp = tcp_sk(sk);
-
- skb_queue_head_init(&tp->out_of_order_queue);
- tcp_init_xmit_timers(sk);
- tcp_prequeue_init(tp);
- icsk->icsk_rto = TCP_TIMEOUT_INIT;
- tp->mdev = TCP_TIMEOUT_INIT;
-
- /* So many TCP implementations out there (incorrectly) count the
- * initial SYN frame in their delayed-ACK and congestion control
- * algorithms that we must have the following bandaid to talk
- * efficiently to them. -DaveM
- */
- tp->snd_cwnd = TCP_INIT_CWND;
-
- /* See draft-stevens-tcpca-spec-01 for discussion of the
- * initialization of these values.
- */
- tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
- tp->snd_cwnd_clamp = ~0;
- tp->mss_cache = TCP_MSS_DEFAULT;
-
- tp->reordering = sysctl_tcp_reordering;
- icsk->icsk_ca_ops = &tcp_init_congestion_ops;
-
- sk->sk_state = TCP_CLOSE;
-
- sk->sk_write_space = sk_stream_write_space;
- sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
+ tcp_init_sock(sk);
icsk->icsk_af_ops = &ipv4_specific;
- icsk->icsk_sync_mss = tcp_sync_mss;
+
#ifdef CONFIG_TCP_MD5SIG
- tp->af_specific = &tcp_sock_ipv4_specific;
+ tcp_sk(sk)->af_specific = &tcp_sock_ipv4_specific;
#endif
- /* TCP Cookie Transactions */
- if (sysctl_tcp_cookie_size > 0) {
- /* Default, cookies without s_data_payload. */
- tp->cookie_values =
- kzalloc(sizeof(*tp->cookie_values),
- sk->sk_allocation);
- if (tp->cookie_values != NULL)
- kref_init(&tp->cookie_values->kref);
- }
- /* Presumed zeroed, in order of appearance:
- * cookie_in_always, cookie_out_never,
- * s_data_constant, s_data_in, s_data_out
- */
- sk->sk_sndbuf = sysctl_tcp_wmem[1];
- sk->sk_rcvbuf = sysctl_tcp_rmem[1];
-
- local_bh_disable();
- sock_update_memcg(sk);
- sk_sockets_allocated_inc(sk);
- local_bh_enable();
-
return 0;
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 7ac6423117ad..7b7cf3811348 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -563,13 +563,13 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
/* Compute TCP options for SYN packets. This is not the final
* network wire format yet.
*/
-static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
+static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
struct tcp_out_options *opts,
struct tcp_md5sig_key **md5)
{
struct tcp_sock *tp = tcp_sk(sk);
struct tcp_cookie_values *cvp = tp->cookie_values;
- unsigned remaining = MAX_TCP_OPTION_SPACE;
+ unsigned int remaining = MAX_TCP_OPTION_SPACE;
u8 cookie_size = (!tp->rx_opt.cookie_out_never && cvp != NULL) ?
tcp_cookie_size_check(cvp->cookie_desired) :
0;
@@ -663,15 +663,15 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
}
/* Set up TCP options for SYN-ACKs. */
-static unsigned tcp_synack_options(struct sock *sk,
+static unsigned int tcp_synack_options(struct sock *sk,
struct request_sock *req,
- unsigned mss, struct sk_buff *skb,
+ unsigned int mss, struct sk_buff *skb,
struct tcp_out_options *opts,
struct tcp_md5sig_key **md5,
struct tcp_extend_values *xvp)
{
struct inet_request_sock *ireq = inet_rsk(req);
- unsigned remaining = MAX_TCP_OPTION_SPACE;
+ unsigned int remaining = MAX_TCP_OPTION_SPACE;
u8 cookie_plus = (xvp != NULL && !xvp->cookie_out_never) ?
xvp->cookie_plus :
0;
@@ -742,13 +742,13 @@ static unsigned tcp_synack_options(struct sock *sk,
/* Compute TCP options for ESTABLISHED sockets. This is not the
* final wire format yet.
*/
-static unsigned tcp_established_options(struct sock *sk, struct sk_buff *skb,
+static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb,
struct tcp_out_options *opts,
struct tcp_md5sig_key **md5)
{
struct tcp_skb_cb *tcb = skb ? TCP_SKB_CB(skb) : NULL;
struct tcp_sock *tp = tcp_sk(sk);
- unsigned size = 0;
+ unsigned int size = 0;
unsigned int eff_sacks;
#ifdef CONFIG_TCP_MD5SIG
@@ -770,9 +770,9 @@ static unsigned tcp_established_options(struct sock *sk, struct sk_buff *skb,
eff_sacks = tp->rx_opt.num_sacks + tp->rx_opt.dsack;
if (unlikely(eff_sacks)) {
- const unsigned remaining = MAX_TCP_OPTION_SPACE - size;
+ const unsigned int remaining = MAX_TCP_OPTION_SPACE - size;
opts->num_sack_blocks =
- min_t(unsigned, eff_sacks,
+ min_t(unsigned int, eff_sacks,
(remaining - TCPOLEN_SACK_BASE_ALIGNED) /
TCPOLEN_SACK_PERBLOCK);
size += TCPOLEN_SACK_BASE_ALIGNED +
@@ -801,7 +801,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
struct tcp_sock *tp;
struct tcp_skb_cb *tcb;
struct tcp_out_options opts;
- unsigned tcp_options_size, tcp_header_size;
+ unsigned int tcp_options_size, tcp_header_size;
struct tcp_md5sig_key *md5;
struct tcphdr *th;
int err;
@@ -1259,7 +1259,7 @@ unsigned int tcp_current_mss(struct sock *sk)
const struct tcp_sock *tp = tcp_sk(sk);
const struct dst_entry *dst = __sk_dst_get(sk);
u32 mss_now;
- unsigned header_len;
+ unsigned int header_len;
struct tcp_out_options opts;
struct tcp_md5sig_key *md5;
@@ -1390,7 +1390,7 @@ static inline int tcp_minshall_check(const struct tcp_sock *tp)
*/
static inline int tcp_nagle_check(const struct tcp_sock *tp,
const struct sk_buff *skb,
- unsigned mss_now, int nonagle)
+ unsigned int mss_now, int nonagle)
{
return skb->len < mss_now &&
((nonagle & TCP_NAGLE_CORK) ||
@@ -2562,7 +2562,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
EXPORT_SYMBOL(tcp_make_synack);
/* Do all connect socket setups that can be done AF independent. */
-static void tcp_connect_init(struct sock *sk)
+void tcp_connect_init(struct sock *sk)
{
const struct dst_entry *dst = __sk_dst_get(sk);
struct tcp_sock *tp = tcp_sk(sk);
@@ -2617,9 +2617,12 @@ static void tcp_connect_init(struct sock *sk)
tp->snd_una = tp->write_seq;
tp->snd_sml = tp->write_seq;
tp->snd_up = tp->write_seq;
- tp->rcv_nxt = 0;
- tp->rcv_wup = 0;
- tp->copied_seq = 0;
+ tp->snd_nxt = tp->write_seq;
+
+ if (likely(!tp->repair))
+ tp->rcv_nxt = 0;
+ tp->rcv_wup = tp->rcv_nxt;
+ tp->copied_seq = tp->rcv_nxt;
inet_csk(sk)->icsk_rto = TCP_TIMEOUT_INIT;
inet_csk(sk)->icsk_retransmits = 0;
@@ -2642,7 +2645,6 @@ int tcp_connect(struct sock *sk)
/* Reserve space for headers. */
skb_reserve(buff, MAX_TCP_HEADER);
- tp->snd_nxt = tp->write_seq;
tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
TCP_ECN_send_syn(sk, buff);
@@ -2791,6 +2793,15 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent)
return tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC);
}
+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);
+ }
+}
+
/* Initiate keepalive or window probe from timer. */
int tcp_write_wakeup(struct sock *sk)
{
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index a981cdc0a6e9..4526fe68e60e 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -91,7 +91,7 @@ static inline int tcp_probe_avail(void)
* Note: arguments must match tcp_rcv_established()!
*/
static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
- struct tcphdr *th, unsigned len)
+ struct tcphdr *th, unsigned int len)
{
const struct tcp_sock *tp = tcp_sk(sk);
const struct inet_sock *inet = inet_sk(sk);
@@ -138,7 +138,7 @@ static struct jprobe tcp_jprobe = {
.entry = jtcp_rcv_established,
};
-static int tcpprobe_open(struct inode * inode, struct file * file)
+static int tcpprobe_open(struct inode *inode, struct file *file)
{
/* Reset (empty) log */
spin_lock_bh(&tcp_probe.lock);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index fe141052a1be..279fd0846302 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -107,6 +107,7 @@
#include <net/checksum.h>
#include <net/xfrm.h>
#include <trace/events/udp.h>
+#include <linux/static_key.h>
#include "udp_impl.h"
struct udp_table udp_table __read_mostly;
@@ -206,7 +207,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
if (!snum) {
int low, high, remaining;
- unsigned rand;
+ unsigned int rand;
unsigned short first, last;
DECLARE_BITMAP(bitmap, PORTS_PER_CHAIN);
@@ -846,7 +847,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
* Get and verify the address.
*/
if (msg->msg_name) {
- struct sockaddr_in * usin = (struct sockaddr_in *)msg->msg_name;
+ struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name;
if (msg->msg_namelen < sizeof(*usin))
return -EINVAL;
if (usin->sin_family != AF_INET) {
@@ -1379,6 +1380,14 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
+static struct static_key udp_encap_needed __read_mostly;
+void udp_encap_enable(void)
+{
+ if (!static_key_enabled(&udp_encap_needed))
+ static_key_slow_inc(&udp_encap_needed);
+}
+EXPORT_SYMBOL(udp_encap_enable);
+
/* returns:
* -1: error
* 0: success
@@ -1400,7 +1409,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
goto drop;
nf_reset(skb);
- if (up->encap_type) {
+ if (static_key_false(&udp_encap_needed) && up->encap_type) {
int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
/*
@@ -1470,7 +1479,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
goto drop;
- if (sk_rcvqueues_full(sk, skb))
+ if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf))
goto drop;
rc = 0;
@@ -1479,7 +1488,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
bh_lock_sock(sk);
if (!sock_owned_by_user(sk))
rc = __udp_queue_rcv_skb(sk, skb);
- else if (sk_add_backlog(sk, skb)) {
+ else if (sk_add_backlog(sk, skb, sk->sk_rcvbuf)) {
bh_unlock_sock(sk);
goto drop;
}
@@ -1760,6 +1769,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
/* FALLTHROUGH */
case UDP_ENCAP_L2TPINUDP:
up->encap_type = val;
+ udp_encap_enable();
break;
default:
err = -ENOPROTOOPT;
diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h
index aaad650d47d9..5a681e298b90 100644
--- a/net/ipv4/udp_impl.h
+++ b/net/ipv4/udp_impl.h
@@ -25,7 +25,7 @@ extern int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len, int noblock, int flags, int *addr_len);
extern int udp_sendpage(struct sock *sk, struct page *page, int offset,
size_t size, int flags);
-extern int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb);
+extern int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
extern void udp_destroy_sock(struct sock *sk);
#ifdef CONFIG_PROC_FS
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index a0b4c5da8d43..0d3426cb5c4f 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -152,7 +152,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
case IPPROTO_AH:
if (pskb_may_pull(skb, xprth + 8 - skb->data)) {
- __be32 *ah_hdr = (__be32*)xprth;
+ __be32 *ah_hdr = (__be32 *)xprth;
fl4->fl4_ipsec_spi = ah_hdr[1];
}
@@ -298,8 +298,8 @@ void __init xfrm4_init(int rt_max_size)
xfrm4_state_init();
xfrm4_policy_init();
#ifdef CONFIG_SYSCTL
- sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv4_ctl_path,
- xfrm4_policy_table);
+ sysctl_hdr = register_net_sysctl(&init_net, "net/ipv4",
+ xfrm4_policy_table);
#endif
}
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 7d5cb975cc6f..e3b3421f8dad 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -149,7 +149,7 @@ static void addrconf_type_change(struct net_device *dev,
unsigned long event);
static int addrconf_ifdown(struct net_device *dev, int how);
-static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags);
+static void addrconf_dad_start(struct inet6_ifaddr *ifp);
static void addrconf_dad_timer(unsigned long data);
static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
static void addrconf_dad_run(struct inet6_dev *idev);
@@ -336,10 +336,9 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
snmp6_free_dev(idev);
kfree_rcu(idev, rcu);
}
-
EXPORT_SYMBOL(in6_dev_finish_destroy);
-static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
+static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
{
struct inet6_dev *ndev;
@@ -441,7 +440,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
return ndev;
}
-static struct inet6_dev * ipv6_find_idev(struct net_device *dev)
+static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
{
struct inet6_dev *idev;
@@ -929,7 +928,7 @@ retry:
ift->tstamp = tmp_tstamp;
spin_unlock_bh(&ift->lock);
- addrconf_dad_start(ift, 0);
+ addrconf_dad_start(ift);
in6_ifa_put(ift);
in6_dev_put(idev);
out:
@@ -1332,7 +1331,6 @@ int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev)
rcu_read_unlock();
return onlink;
}
-
EXPORT_SYMBOL(ipv6_chk_prefix);
struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr,
@@ -1522,7 +1520,7 @@ static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev)
if (dev->addr_len != ARCNET_ALEN)
return -1;
memset(eui, 0, 7);
- eui[7] = *(u8*)dev->dev_addr;
+ eui[7] = *(u8 *)dev->dev_addr;
return 0;
}
@@ -1667,7 +1665,8 @@ out:
in6_dev_put(idev);
}
-static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) {
+static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr)
+{
int ret = 0;
if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0)
@@ -1908,7 +1907,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
/* Try to figure out our local address for this prefix */
if (pinfo->autoconf && in6_dev->cnf.autoconf) {
- struct inet6_ifaddr * ifp;
+ struct inet6_ifaddr *ifp;
struct in6_addr addr;
int create = 0, update_lft = 0;
@@ -1957,7 +1956,7 @@ ok:
update_lft = create = 1;
ifp->cstamp = jiffies;
- addrconf_dad_start(ifp, RTF_ADDRCONF|RTF_PREFIX_RT);
+ addrconf_dad_start(ifp);
}
if (ifp) {
@@ -2236,7 +2235,7 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p
* that the Optimistic flag should not be set for
* manually configured addresses
*/
- addrconf_dad_start(ifp, 0);
+ addrconf_dad_start(ifp);
in6_ifa_put(ifp);
addrconf_verify(0);
return 0;
@@ -2362,9 +2361,9 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
}
for_each_netdev(net, dev) {
- struct in_device * in_dev = __in_dev_get_rtnl(dev);
+ struct in_device *in_dev = __in_dev_get_rtnl(dev);
if (in_dev && (dev->flags & IFF_UP)) {
- struct in_ifaddr * ifa;
+ struct in_ifaddr *ifa;
int flag = scope;
@@ -2410,7 +2409,7 @@ static void init_loopback(struct net_device *dev)
static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr)
{
- struct inet6_ifaddr * ifp;
+ struct inet6_ifaddr *ifp;
u32 addr_flags = IFA_F_PERMANENT;
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
@@ -2423,7 +2422,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr
ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags);
if (!IS_ERR(ifp)) {
addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
- addrconf_dad_start(ifp, 0);
+ addrconf_dad_start(ifp);
in6_ifa_put(ifp);
}
}
@@ -2431,7 +2430,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr
static void addrconf_dev_config(struct net_device *dev)
{
struct in6_addr addr;
- struct inet6_dev * idev;
+ struct inet6_dev *idev;
ASSERT_RTNL();
@@ -2567,7 +2566,7 @@ static void addrconf_ip6_tnl_config(struct net_device *dev)
}
static int addrconf_notify(struct notifier_block *this, unsigned long event,
- void * data)
+ void *data)
{
struct net_device *dev = (struct net_device *) data;
struct inet6_dev *idev = __in6_dev_get(dev);
@@ -2918,7 +2917,7 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
addrconf_mod_timer(ifp, AC_DAD, rand_num);
}
-static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
+static void addrconf_dad_start(struct inet6_ifaddr *ifp)
{
struct inet6_dev *idev = ifp->idev;
struct net_device *dev = idev->dev;
@@ -3791,7 +3790,7 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb)
return inet6_dump_addr(skb, cb, type);
}
-static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
+static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh,
void *arg)
{
struct net *net = sock_net(in_skb->sk);
@@ -3986,14 +3985,14 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev)
struct nlattr *nla;
struct ifla_cacheinfo ci;
- NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags);
-
+ if (nla_put_u32(skb, IFLA_INET6_FLAGS, idev->if_flags))
+ goto nla_put_failure;
ci.max_reasm_len = IPV6_MAXPLEN;
ci.tstamp = cstamp_delta(idev->tstamp);
ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time);
ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time);
- NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
-
+ if (nla_put(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci))
+ goto nla_put_failure;
nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
if (nla == NULL)
goto nla_put_failure;
@@ -4058,15 +4057,13 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
hdr->ifi_flags = dev_get_flags(dev);
hdr->ifi_change = 0;
- NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
-
- if (dev->addr_len)
- NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
-
- NLA_PUT_U32(skb, IFLA_MTU, dev->mtu);
- if (dev->ifindex != dev->iflink)
- NLA_PUT_U32(skb, IFLA_LINK, dev->iflink);
-
+ if (nla_put_string(skb, IFLA_IFNAME, dev->name) ||
+ (dev->addr_len &&
+ nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) ||
+ nla_put_u32(skb, IFLA_MTU, dev->mtu) ||
+ (dev->ifindex != dev->iflink &&
+ nla_put_u32(skb, IFLA_LINK, dev->iflink)))
+ goto nla_put_failure;
protoinfo = nla_nest_start(skb, IFLA_PROTINFO);
if (protoinfo == NULL)
goto nla_put_failure;
@@ -4179,12 +4176,12 @@ static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev,
if (pinfo->autoconf)
pmsg->prefix_flags |= IF_PREFIX_AUTOCONF;
- NLA_PUT(skb, PREFIX_ADDRESS, sizeof(pinfo->prefix), &pinfo->prefix);
-
+ if (nla_put(skb, PREFIX_ADDRESS, sizeof(pinfo->prefix), &pinfo->prefix))
+ goto nla_put_failure;
ci.preferred_time = ntohl(pinfo->prefered);
ci.valid_time = ntohl(pinfo->valid);
- NLA_PUT(skb, PREFIX_CACHEINFO, sizeof(ci), &ci);
-
+ if (nla_put(skb, PREFIX_CACHEINFO, sizeof(ci), &ci))
+ goto nla_put_failure;
return nlmsg_end(skb, nlh);
nla_put_failure:
@@ -4368,7 +4365,6 @@ static struct addrconf_sysctl_table
{
struct ctl_table_header *sysctl_header;
ctl_table addrconf_vars[DEVCONF_MAX+1];
- char *dev_name;
} addrconf_sysctl __read_mostly = {
.sysctl_header = NULL,
.addrconf_vars = {
@@ -4597,17 +4593,7 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name,
{
int i;
struct addrconf_sysctl_table *t;
-
-#define ADDRCONF_CTL_PATH_DEV 3
-
- struct ctl_path addrconf_ctl_path[] = {
- { .procname = "net", },
- { .procname = "ipv6", },
- { .procname = "conf", },
- { /* to be set */ },
- { },
- };
-
+ char path[sizeof("net/ipv6/conf/") + IFNAMSIZ];
t = kmemdup(&addrconf_sysctl, sizeof(*t), GFP_KERNEL);
if (t == NULL)
@@ -4619,27 +4605,15 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name,
t->addrconf_vars[i].extra2 = net;
}
- /*
- * Make a copy of dev_name, because '.procname' is regarded as const
- * by sysctl and we wouldn't want anyone to change it under our feet
- * (see SIOCSIFNAME).
- */
- t->dev_name = kstrdup(dev_name, GFP_KERNEL);
- if (!t->dev_name)
- goto free;
-
- addrconf_ctl_path[ADDRCONF_CTL_PATH_DEV].procname = t->dev_name;
+ snprintf(path, sizeof(path), "net/ipv6/conf/%s", dev_name);
- t->sysctl_header = register_net_sysctl_table(net, addrconf_ctl_path,
- t->addrconf_vars);
+ t->sysctl_header = register_net_sysctl(net, path, t->addrconf_vars);
if (t->sysctl_header == NULL)
- goto free_procname;
+ goto free;
p->sysctl = t;
return 0;
-free_procname:
- kfree(t->dev_name);
free:
kfree(t);
out:
@@ -4656,7 +4630,6 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p)
t = p->sysctl;
p->sysctl = NULL;
unregister_net_sysctl_table(t->sysctl_header);
- kfree(t->dev_name);
kfree(t);
}
diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c
index 399287e595d7..d051e5f4bf34 100644
--- a/net/ipv6/addrconf_core.c
+++ b/net/ipv6/addrconf_core.c
@@ -8,9 +8,9 @@
#define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16)
-static inline unsigned ipv6_addr_scope2type(unsigned scope)
+static inline unsigned int ipv6_addr_scope2type(unsigned int scope)
{
- switch(scope) {
+ switch (scope) {
case IPV6_ADDR_SCOPE_NODELOCAL:
return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
IPV6_ADDR_LOOPBACK);
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 8ed1b930e75f..0ad046c7ae95 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -180,7 +180,7 @@ lookup_protocol:
err = 0;
sk->sk_no_check = answer_no_check;
if (INET_PROTOSW_REUSE & answer_flags)
- sk->sk_reuse = 1;
+ sk->sk_reuse = SK_CAN_REUSE;
inet = inet_sk(sk);
inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
@@ -1111,11 +1111,6 @@ static int __init inet6_init(void)
if (err)
goto out_sock_register_fail;
-#ifdef CONFIG_SYSCTL
- err = ipv6_static_sysctl_register();
- if (err)
- goto static_sysctl_fail;
-#endif
tcpv6_prot.sysctl_mem = init_net.ipv4.sysctl_tcp_mem;
/*
@@ -1242,10 +1237,6 @@ ipmr_fail:
icmp_fail:
unregister_pernet_subsys(&inet6_net_ops);
register_pernet_fail:
-#ifdef CONFIG_SYSCTL
- ipv6_static_sysctl_unregister();
-static_sysctl_fail:
-#endif
sock_unregister(PF_INET6);
rtnl_unregister_all(PF_INET6);
out_sock_register_fail:
@@ -1272,9 +1263,6 @@ static void __exit inet6_exit(void)
/* Disallow any further netlink messages */
rtnl_unregister_all(PF_INET6);
-#ifdef CONFIG_SYSCTL
- ipv6_sysctl_unregister();
-#endif
udpv6_exit();
udplitev6_exit();
tcpv6_exit();
@@ -1302,9 +1290,6 @@ static void __exit inet6_exit(void)
rawv6_exit();
unregister_pernet_subsys(&inet6_net_ops);
-#ifdef CONFIG_SYSCTL
- ipv6_static_sysctl_unregister();
-#endif
proto_unregister(&rawv6_prot);
proto_unregister(&udplitev6_prot);
proto_unregister(&udpv6_prot);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 76832c8dc89d..7fba35aea06c 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -98,7 +98,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sin.sin_port = usin->sin6_port;
err = ip4_datagram_connect(sk,
- (struct sockaddr*) &sin,
+ (struct sockaddr *) &sin,
sizeof(sin));
ipv4_connected:
@@ -515,10 +515,10 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
u8 nexthdr = ipv6_hdr(skb)->nexthdr;
while (off <= opt->lastopt) {
- unsigned len;
+ unsigned int len;
u8 *ptr = nh + off;
- switch(nexthdr) {
+ switch (nexthdr) {
case IPPROTO_DSTOPTS:
nexthdr = ptr[0];
len = (ptr[1] + 1) << 3;
@@ -827,9 +827,8 @@ int datagram_send_ctl(struct net *net, struct sock *sk,
int tc;
err = -EINVAL;
- if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
goto exit_f;
- }
tc = *(int *)CMSG_DATA(cmsg);
if (tc < -1 || tc > 0xff)
@@ -846,9 +845,8 @@ int datagram_send_ctl(struct net *net, struct sock *sk,
int df;
err = -EINVAL;
- if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
goto exit_f;
- }
df = *(int *)CMSG_DATA(cmsg);
if (df < 0 || df > 1)
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 3d641b6e9b09..aa0a51e64682 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -153,6 +153,7 @@ static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb)
while (len > 0) {
int optlen = nh[off + 1] + 2;
+ int i;
switch (nh[off]) {
case IPV6_TLV_PAD0:
@@ -160,6 +161,21 @@ static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb)
break;
case IPV6_TLV_PADN:
+ /* RFC 2460 states that the purpose of PadN is
+ * to align the containing header to multiples
+ * of 8. 7 is therefore the highest valid value.
+ * See also RFC 4942, Section 2.1.9.5.
+ */
+ if (optlen > 7)
+ goto bad;
+ /* RFC 4942 recommends receiving hosts to
+ * actively check PadN payload to contain
+ * only zeroes.
+ */
+ for (i = 2; i < optlen; i++) {
+ if (nh[off + i] != 0)
+ goto bad;
+ }
break;
default: /* Other TLV code so scan list */
@@ -722,7 +738,6 @@ void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
if (opt->hopopt)
ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
}
-
EXPORT_SYMBOL(ipv6_push_nfrag_opts);
void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
@@ -738,20 +753,19 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
if (opt2) {
- long dif = (char*)opt2 - (char*)opt;
+ long dif = (char *)opt2 - (char *)opt;
memcpy(opt2, opt, opt->tot_len);
if (opt2->hopopt)
- *((char**)&opt2->hopopt) += dif;
+ *((char **)&opt2->hopopt) += dif;
if (opt2->dst0opt)
- *((char**)&opt2->dst0opt) += dif;
+ *((char **)&opt2->dst0opt) += dif;
if (opt2->dst1opt)
- *((char**)&opt2->dst1opt) += dif;
+ *((char **)&opt2->dst1opt) += dif;
if (opt2->srcrt)
- *((char**)&opt2->srcrt) += dif;
+ *((char **)&opt2->srcrt) += dif;
}
return opt2;
}
-
EXPORT_SYMBOL_GPL(ipv6_dup_options);
static int ipv6_renew_option(void *ohdr,
@@ -892,5 +906,4 @@ struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
fl6->daddr = *((struct rt0_hdr *)opt->srcrt)->addr;
return orig;
}
-
EXPORT_SYMBOL_GPL(fl6_update_dst);
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c
index 72957f4a7c6c..7b1a884634d5 100644
--- a/net/ipv6/exthdrs_core.c
+++ b/net/ipv6/exthdrs_core.c
@@ -21,6 +21,7 @@ int ipv6_ext_hdr(u8 nexthdr)
(nexthdr == NEXTHDR_NONE) ||
(nexthdr == NEXTHDR_DEST);
}
+EXPORT_SYMBOL(ipv6_ext_hdr);
/*
* Skip any extension headers. This is used by the ICMP module.
@@ -109,6 +110,4 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
*nexthdrp = nexthdr;
return start;
}
-
-EXPORT_SYMBOL(ipv6_ext_hdr);
EXPORT_SYMBOL(ipv6_skip_exthdr);
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index b6c573152067..0ff1cfd55bc4 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -22,8 +22,7 @@
#include <net/ip6_route.h>
#include <net/netlink.h>
-struct fib6_rule
-{
+struct fib6_rule {
struct fib_rule common;
struct rt6key src;
struct rt6key dst;
@@ -215,14 +214,13 @@ static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
frh->src_len = rule6->src.plen;
frh->tos = rule6->tclass;
- if (rule6->dst.plen)
- NLA_PUT(skb, FRA_DST, sizeof(struct in6_addr),
- &rule6->dst.addr);
-
- if (rule6->src.plen)
- NLA_PUT(skb, FRA_SRC, sizeof(struct in6_addr),
- &rule6->src.addr);
-
+ if ((rule6->dst.plen &&
+ nla_put(skb, FRA_DST, sizeof(struct in6_addr),
+ &rule6->dst.addr)) ||
+ (rule6->src.plen &&
+ nla_put(skb, FRA_SRC, sizeof(struct in6_addr),
+ &rule6->src.addr)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 27ac95a63429..cc079d8d4681 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -498,7 +498,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
err = ip6_append_data(sk, icmpv6_getfrag, &msg,
len + sizeof(struct icmp6hdr),
sizeof(struct icmp6hdr), hlimit,
- np->tclass, NULL, &fl6, (struct rt6_info*)dst,
+ np->tclass, NULL, &fl6, (struct rt6_info *)dst,
MSG_DONTWAIT, np->dontfrag);
if (err) {
ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
@@ -579,7 +579,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl6,
- (struct rt6_info*)dst, MSG_DONTWAIT,
+ (struct rt6_info *)dst, MSG_DONTWAIT,
np->dontfrag);
if (err) {
@@ -950,7 +950,6 @@ int icmpv6_err_convert(u8 type, u8 code, int *err)
return fatal;
}
-
EXPORT_SYMBOL(icmpv6_err_convert);
#ifdef CONFIG_SYSCTL
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 02dd203d9eac..e6cee5292a0b 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -28,7 +28,7 @@
#include <net/inet6_connection_sock.h>
int inet6_csk_bind_conflict(const struct sock *sk,
- const struct inet_bind_bucket *tb)
+ const struct inet_bind_bucket *tb, bool relax)
{
const struct sock *sk2;
const struct hlist_node *node;
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index b7867a1215b1..1dd632971bce 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -705,9 +705,9 @@ static int ip6fl_seq_show(struct seq_file *seq, void *v)
struct ip6_flowlabel *fl = v;
seq_printf(seq,
"%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n",
- (unsigned)ntohl(fl->label),
+ (unsigned int)ntohl(fl->label),
fl->share,
- (unsigned)fl->owner,
+ (int)fl->owner,
atomic_read(&fl->users),
fl->linger/HZ,
(long)(fl->expires - jiffies)/HZ,
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index aa21da6a09cd..5df487c81ed9 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -198,7 +198,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct ip6_tnl_parm *p)
{
const struct in6_addr *remote = &p->raddr;
const struct in6_addr *local = &p->laddr;
- unsigned h = 0;
+ unsigned int h = 0;
int prio = 0;
if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
@@ -954,7 +954,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
if (skb->sk)
skb_set_owner_w(new_skb, skb->sk);
- kfree_skb(skb);
+ consume_skb(skb);
skb = new_skb;
}
skb_dst_drop(skb);
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 8110362e0af5..efc0098b59dd 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -2215,14 +2215,15 @@ static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
rtm->rtm_src_len = 128;
rtm->rtm_tos = 0;
rtm->rtm_table = mrt->id;
- NLA_PUT_U32(skb, RTA_TABLE, mrt->id);
+ if (nla_put_u32(skb, RTA_TABLE, mrt->id))
+ goto nla_put_failure;
rtm->rtm_scope = RT_SCOPE_UNIVERSE;
rtm->rtm_protocol = RTPROT_UNSPEC;
rtm->rtm_flags = 0;
- NLA_PUT(skb, RTA_SRC, 16, &c->mf6c_origin);
- NLA_PUT(skb, RTA_DST, 16, &c->mf6c_mcastgrp);
-
+ if (nla_put(skb, RTA_SRC, 16, &c->mf6c_origin) ||
+ nla_put(skb, RTA_DST, 16, &c->mf6c_mcastgrp))
+ goto nla_put_failure;
if (__ip6mr_fill_mroute(mrt, skb, c, rtm) < 0)
goto nla_put_failure;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 63dd1f89ed7d..ba6d13d1f1e1 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -678,7 +678,6 @@ done:
}
case MCAST_MSFILTER:
{
- extern int sysctl_mld_max_msf;
struct group_filter *gsf;
if (optlen < GROUP_FILTER_SIZE(0))
@@ -943,7 +942,7 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
}
static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen, unsigned flags)
+ char __user *optval, int __user *optlen, unsigned int flags)
{
struct ipv6_pinfo *np = inet6_sk(sk);
int len;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index b2869cab2092..7dfb89f2bae5 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1061,7 +1061,7 @@ static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,
if (psf->sf_count[MCAST_INCLUDE] ||
pmc->mca_sfcount[MCAST_EXCLUDE] !=
psf->sf_count[MCAST_EXCLUDE])
- continue;
+ break;
if (ipv6_addr_equal(&srcs[i], &psf->sf_addr)) {
scount++;
break;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 176b469322ac..35615c6358b8 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -15,6 +15,7 @@
/*
* Changes:
*
+ * Alexey I. Froloff : RFC6106 (DNSSL) support
* Pierre Ynard : export userland ND options
* through netlink (RDNSS support)
* Lars Fenneberg : fixed MTU setting on receipt
@@ -228,7 +229,8 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
{
- return opt->nd_opt_type == ND_OPT_RDNSS;
+ return opt->nd_opt_type == ND_OPT_RDNSS ||
+ opt->nd_opt_type == ND_OPT_DNSSL;
}
static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
@@ -1099,8 +1101,9 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
- NLA_PUT(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
- &ipv6_hdr(ra)->saddr);
+ if (nla_put(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
+ &ipv6_hdr(ra)->saddr))
+ goto nla_put_failure;
nlmsg_end(skb, nlh);
rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index a34c9e4c792c..3ca9303b3a19 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -588,7 +588,7 @@ static int __init ip6_queue_init(void)
#endif
register_netdevice_notifier(&ipq_dev_notifier);
#ifdef CONFIG_SYSCTL
- ipq_sysctl_header = register_sysctl_paths(net_ipv6_ctl_path, ipq_table);
+ ipq_sysctl_header = register_net_sysctl(&init_net, "net/ipv6", ipq_table);
#endif
status = nf_register_queue_handler(NFPROTO_IPV6, &nfqh);
if (status < 0) {
@@ -599,7 +599,7 @@ static int __init ip6_queue_init(void)
cleanup_sysctl:
#ifdef CONFIG_SYSCTL
- unregister_sysctl_table(ipq_sysctl_header);
+ unregister_net_sysctl_table(ipq_sysctl_header);
#endif
unregister_netdevice_notifier(&ipq_dev_notifier);
proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
@@ -621,7 +621,7 @@ static void __exit ip6_queue_fini(void)
ipq_flush(NULL, 0);
#ifdef CONFIG_SYSCTL
- unregister_sysctl_table(ipq_sysctl_header);
+ unregister_net_sysctl_table(ipq_sysctl_header);
#endif
unregister_netdevice_notifier(&ipq_dev_notifier);
proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 9d4e15559319..d4e350f72bbb 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -396,7 +396,7 @@ ip6t_do_table(struct sk_buff *skb,
if (v < 0) {
/* Pop from stack? */
if (v != XT_RETURN) {
- verdict = (unsigned)(-v) - 1;
+ verdict = (unsigned int)(-v) - 1;
break;
}
if (*stackptr <= origptr)
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 4111050a9fc5..fe925e492520 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -278,10 +278,11 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
static int ipv6_tuple_to_nlattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple)
{
- NLA_PUT(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4,
- &tuple->src.u3.ip6);
- NLA_PUT(skb, CTA_IP_V6_DST, sizeof(u_int32_t) * 4,
- &tuple->dst.u3.ip6);
+ if (nla_put(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4,
+ &tuple->src.u3.ip6) ||
+ nla_put(skb, CTA_IP_V6_DST, sizeof(u_int32_t) * 4,
+ &tuple->dst.u3.ip6))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 92cc9f2931ae..3e81904fbbcd 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -234,10 +234,10 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl,
static int icmpv6_tuple_to_nlattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *t)
{
- NLA_PUT_BE16(skb, CTA_PROTO_ICMPV6_ID, t->src.u.icmp.id);
- NLA_PUT_U8(skb, CTA_PROTO_ICMPV6_TYPE, t->dst.u.icmp.type);
- NLA_PUT_U8(skb, CTA_PROTO_ICMPV6_CODE, t->dst.u.icmp.code);
-
+ if (nla_put_be16(skb, CTA_PROTO_ICMPV6_ID, t->src.u.icmp.id) ||
+ nla_put_u8(skb, CTA_PROTO_ICMPV6_TYPE, t->dst.u.icmp.type) ||
+ nla_put_u8(skb, CTA_PROTO_ICMPV6_CODE, t->dst.u.icmp.code))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -300,8 +300,8 @@ icmpv6_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeout = data;
- NLA_PUT_BE32(skb, CTA_TIMEOUT_ICMPV6_TIMEOUT, htonl(*timeout / HZ));
-
+ if (nla_put_be32(skb, CTA_TIMEOUT_ICMPV6_TIMEOUT, htonl(*timeout / HZ)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 38f00b0298d3..48a2be1b7c70 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -626,8 +626,8 @@ int nf_ct_frag6_init(void)
inet_frags_init(&nf_frags);
#ifdef CONFIG_SYSCTL
- nf_ct_frag6_sysctl_header = register_sysctl_paths(nf_net_netfilter_sysctl_path,
- nf_ct_frag6_sysctl_table);
+ nf_ct_frag6_sysctl_header = register_net_sysctl(&init_net, "net/netfilter",
+ nf_ct_frag6_sysctl_table);
if (!nf_ct_frag6_sysctl_header) {
inet_frags_fini(&nf_frags);
return -ENOMEM;
@@ -640,7 +640,7 @@ int nf_ct_frag6_init(void)
void nf_ct_frag6_cleanup(void)
{
#ifdef CONFIG_SYSCTL
- unregister_sysctl_table(nf_ct_frag6_sysctl_header);
+ unregister_net_sysctl_table(nf_ct_frag6_sysctl_header);
nf_ct_frag6_sysctl_header = NULL;
#endif
inet_frags_fini(&nf_frags);
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 9447bd69873a..36e04cff1a85 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -646,7 +646,7 @@ static int __net_init ip6_frags_ns_sysctl_register(struct net *net)
table[2].data = &net->ipv6.frags.timeout;
}
- hdr = register_net_sysctl_table(net, net_ipv6_ctl_path, table);
+ hdr = register_net_sysctl(net, "net/ipv6", table);
if (hdr == NULL)
goto err_reg;
@@ -674,7 +674,7 @@ static struct ctl_table_header *ip6_ctl_header;
static int ip6_frags_sysctl_register(void)
{
- ip6_ctl_header = register_net_sysctl_rotable(net_ipv6_ctl_path,
+ ip6_ctl_header = register_net_sysctl(&init_net, "net/ipv6",
ip6_frags_ctl_table);
return ip6_ctl_header == NULL ? -ENOMEM : 0;
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index bc4888d902b2..0aefc36f74c7 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -82,7 +82,7 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
static struct rt6_info *rt6_add_route_info(struct net *net,
const struct in6_addr *prefix, int prefixlen,
const struct in6_addr *gwaddr, int ifindex,
- unsigned pref);
+ unsigned int pref);
static struct rt6_info *rt6_get_route_info(struct net *net,
const struct in6_addr *prefix, int prefixlen,
const struct in6_addr *gwaddr, int ifindex);
@@ -1887,7 +1887,7 @@ out:
static struct rt6_info *rt6_add_route_info(struct net *net,
const struct in6_addr *prefix, int prefixlen,
const struct in6_addr *gwaddr, int ifindex,
- unsigned pref)
+ unsigned int pref)
{
struct fib6_config cfg = {
.fc_table = RT6_TABLE_INFO,
@@ -2217,10 +2217,9 @@ void rt6_ifdown(struct net *net, struct net_device *dev)
icmp6_clean_all(fib6_ifdown, &adn);
}
-struct rt6_mtu_change_arg
-{
+struct rt6_mtu_change_arg {
struct net_device *dev;
- unsigned mtu;
+ unsigned int mtu;
};
static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
@@ -2262,7 +2261,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
return 0;
}
-void rt6_mtu_change(struct net_device *dev, unsigned mtu)
+void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
{
struct rt6_mtu_change_arg arg = {
.dev = dev,
@@ -2430,7 +2429,8 @@ static int rt6_fill_node(struct net *net,
else
table = RT6_TABLE_UNSPEC;
rtm->rtm_table = table;
- NLA_PUT_U32(skb, RTA_TABLE, table);
+ if (nla_put_u32(skb, RTA_TABLE, table))
+ goto nla_put_failure;
if (rt->rt6i_flags & RTF_REJECT)
rtm->rtm_type = RTN_UNREACHABLE;
else if (rt->rt6i_flags & RTF_LOCAL)
@@ -2453,16 +2453,20 @@ static int rt6_fill_node(struct net *net,
rtm->rtm_flags |= RTM_F_CLONED;
if (dst) {
- NLA_PUT(skb, RTA_DST, 16, dst);
+ if (nla_put(skb, RTA_DST, 16, dst))
+ goto nla_put_failure;
rtm->rtm_dst_len = 128;
} else if (rtm->rtm_dst_len)
- NLA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr);
+ if (nla_put(skb, RTA_DST, 16, &rt->rt6i_dst.addr))
+ goto nla_put_failure;
#ifdef CONFIG_IPV6_SUBTREES
if (src) {
- NLA_PUT(skb, RTA_SRC, 16, src);
+ if (nla_put(skb, RTA_SRC, 16, src))
+ goto nla_put_failure;
rtm->rtm_src_len = 128;
- } else if (rtm->rtm_src_len)
- NLA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr);
+ } else if (rtm->rtm_src_len &&
+ nla_put(skb, RTA_SRC, 16, &rt->rt6i_src.addr))
+ goto nla_put_failure;
#endif
if (iif) {
#ifdef CONFIG_IPV6_MROUTE
@@ -2480,17 +2484,20 @@ static int rt6_fill_node(struct net *net,
}
} else
#endif
- NLA_PUT_U32(skb, RTA_IIF, iif);
+ if (nla_put_u32(skb, RTA_IIF, iif))
+ goto nla_put_failure;
} else if (dst) {
struct in6_addr saddr_buf;
- if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0)
- NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
+ if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
+ nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
+ goto nla_put_failure;
}
if (rt->rt6i_prefsrc.plen) {
struct in6_addr saddr_buf;
saddr_buf = rt->rt6i_prefsrc.addr;
- NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
+ if (nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
+ goto nla_put_failure;
}
if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
@@ -2506,11 +2513,11 @@ static int rt6_fill_node(struct net *net,
}
rcu_read_unlock();
- if (rt->dst.dev)
- NLA_PUT_U32(skb, RTA_OIF, rt->dst.dev->ifindex);
-
- NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric);
-
+ if (rt->dst.dev &&
+ nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
+ goto nla_put_failure;
+ if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
+ goto nla_put_failure;
if (!(rt->rt6i_flags & RTF_EXPIRES))
expires = 0;
else if (rt->dst.expires - jiffies < INT_MAX)
@@ -2615,6 +2622,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb) {
+ dst_release(&rt->dst);
err = -ENOBUFS;
goto errout;
}
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index c4ffd1743528..e5fef943e30a 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -87,35 +87,51 @@ struct sit_net {
/* often modified stats are per cpu, other are shared (netdev->stats) */
struct pcpu_tstats {
- unsigned long rx_packets;
- unsigned long rx_bytes;
- unsigned long tx_packets;
- unsigned long tx_bytes;
-} __attribute__((aligned(4*sizeof(unsigned long))));
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 tx_packets;
+ u64 tx_bytes;
+ struct u64_stats_sync syncp;
+};
-static struct net_device_stats *ipip6_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *ipip6_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *tot)
{
- struct pcpu_tstats sum = { 0 };
int i;
for_each_possible_cpu(i) {
const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
-
- sum.rx_packets += tstats->rx_packets;
- sum.rx_bytes += tstats->rx_bytes;
- sum.tx_packets += tstats->tx_packets;
- sum.tx_bytes += tstats->tx_bytes;
+ u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin_bh(&tstats->syncp);
+ rx_packets = tstats->rx_packets;
+ tx_packets = tstats->tx_packets;
+ rx_bytes = tstats->rx_bytes;
+ tx_bytes = tstats->tx_bytes;
+ } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
+
+ tot->rx_packets += rx_packets;
+ tot->tx_packets += tx_packets;
+ tot->rx_bytes += rx_bytes;
+ tot->tx_bytes += tx_bytes;
}
- dev->stats.rx_packets = sum.rx_packets;
- dev->stats.rx_bytes = sum.rx_bytes;
- dev->stats.tx_packets = sum.tx_packets;
- dev->stats.tx_bytes = sum.tx_bytes;
- return &dev->stats;
+
+ tot->rx_errors = dev->stats.rx_errors;
+ tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
+ tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
+ tot->tx_dropped = dev->stats.tx_dropped;
+ tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
+ tot->tx_errors = dev->stats.tx_errors;
+
+ return tot;
}
+
/*
* Must be invoked with rcu_read_lock
*/
-static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
+static struct ip_tunnel *ipip6_tunnel_lookup(struct net *net,
struct net_device *dev, __be32 remote, __be32 local)
{
unsigned int h0 = HASH(remote);
@@ -691,7 +707,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
goto tx_error;
}
- addr6 = (const struct in6_addr*)&neigh->primary_key;
+ addr6 = (const struct in6_addr *)&neigh->primary_key;
addr_type = ipv6_addr_type(addr6);
if ((addr_type & IPV6_ADDR_UNICAST) &&
@@ -721,7 +737,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
goto tx_error;
}
- addr6 = (const struct in6_addr*)&neigh->primary_key;
+ addr6 = (const struct in6_addr *)&neigh->primary_key;
addr_type = ipv6_addr_type(addr6);
if (addr_type == IPV6_ADDR_ANY) {
@@ -1126,7 +1142,7 @@ static const struct net_device_ops ipip6_netdev_ops = {
.ndo_start_xmit = ipip6_tunnel_xmit,
.ndo_do_ioctl = ipip6_tunnel_ioctl,
.ndo_change_mtu = ipip6_tunnel_change_mtu,
- .ndo_get_stats = ipip6_get_stats,
+ .ndo_get_stats64= ipip6_get_stats64,
};
static void ipip6_dev_free(struct net_device *dev)
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 166a57c47d39..e85c48bd404f 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -16,32 +16,8 @@
#include <net/addrconf.h>
#include <net/inet_frag.h>
-static struct ctl_table empty[1];
-
-static ctl_table ipv6_static_skeleton[] = {
- {
- .procname = "neigh",
- .maxlen = 0,
- .mode = 0555,
- .child = empty,
- },
- { }
-};
-
static ctl_table ipv6_table_template[] = {
{
- .procname = "route",
- .maxlen = 0,
- .mode = 0555,
- .child = ipv6_route_table_template
- },
- {
- .procname = "icmp",
- .maxlen = 0,
- .mode = 0555,
- .child = ipv6_icmp_table_template
- },
- {
.procname = "bindv6only",
.data = &init_net.ipv6.sysctl.bindv6only,
.maxlen = sizeof(int),
@@ -62,13 +38,6 @@ static ctl_table ipv6_rotable[] = {
{ }
};
-struct ctl_path net_ipv6_ctl_path[] = {
- { .procname = "net", },
- { .procname = "ipv6", },
- { },
-};
-EXPORT_SYMBOL_GPL(net_ipv6_ctl_path);
-
static int __net_init ipv6_sysctl_net_init(struct net *net)
{
struct ctl_table *ipv6_table;
@@ -81,28 +50,37 @@ static int __net_init ipv6_sysctl_net_init(struct net *net)
GFP_KERNEL);
if (!ipv6_table)
goto out;
+ ipv6_table[0].data = &net->ipv6.sysctl.bindv6only;
ipv6_route_table = ipv6_route_sysctl_init(net);
if (!ipv6_route_table)
goto out_ipv6_table;
- ipv6_table[0].child = ipv6_route_table;
ipv6_icmp_table = ipv6_icmp_sysctl_init(net);
if (!ipv6_icmp_table)
goto out_ipv6_route_table;
- ipv6_table[1].child = ipv6_icmp_table;
- ipv6_table[2].data = &net->ipv6.sysctl.bindv6only;
-
- net->ipv6.sysctl.table = register_net_sysctl_table(net, net_ipv6_ctl_path,
- ipv6_table);
- if (!net->ipv6.sysctl.table)
+ net->ipv6.sysctl.hdr = register_net_sysctl(net, "net/ipv6", ipv6_table);
+ if (!net->ipv6.sysctl.hdr)
goto out_ipv6_icmp_table;
+ net->ipv6.sysctl.route_hdr =
+ register_net_sysctl(net, "net/ipv6/route", ipv6_route_table);
+ if (!net->ipv6.sysctl.route_hdr)
+ goto out_unregister_ipv6_table;
+
+ net->ipv6.sysctl.icmp_hdr =
+ register_net_sysctl(net, "net/ipv6/icmp", ipv6_icmp_table);
+ if (!net->ipv6.sysctl.icmp_hdr)
+ goto out_unregister_route_table;
+
err = 0;
out:
return err;
-
+out_unregister_route_table:
+ unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr);
+out_unregister_ipv6_table:
+ unregister_net_sysctl_table(net->ipv6.sysctl.hdr);
out_ipv6_icmp_table:
kfree(ipv6_icmp_table);
out_ipv6_route_table:
@@ -118,11 +96,13 @@ static void __net_exit ipv6_sysctl_net_exit(struct net *net)
struct ctl_table *ipv6_route_table;
struct ctl_table *ipv6_icmp_table;
- ipv6_table = net->ipv6.sysctl.table->ctl_table_arg;
- ipv6_route_table = ipv6_table[0].child;
- ipv6_icmp_table = ipv6_table[1].child;
+ ipv6_table = net->ipv6.sysctl.hdr->ctl_table_arg;
+ ipv6_route_table = net->ipv6.sysctl.route_hdr->ctl_table_arg;
+ ipv6_icmp_table = net->ipv6.sysctl.icmp_hdr->ctl_table_arg;
- unregister_net_sysctl_table(net->ipv6.sysctl.table);
+ unregister_net_sysctl_table(net->ipv6.sysctl.icmp_hdr);
+ unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr);
+ unregister_net_sysctl_table(net->ipv6.sysctl.hdr);
kfree(ipv6_table);
kfree(ipv6_route_table);
@@ -140,7 +120,7 @@ int ipv6_sysctl_register(void)
{
int err = -ENOMEM;
- ip6_header = register_net_sysctl_rotable(net_ipv6_ctl_path, ipv6_rotable);
+ ip6_header = register_net_sysctl(&init_net, "net/ipv6", ipv6_rotable);
if (ip6_header == NULL)
goto out;
@@ -160,18 +140,3 @@ void ipv6_sysctl_unregister(void)
unregister_net_sysctl_table(ip6_header);
unregister_pernet_subsys(&ipv6_sysctl_net_ops);
}
-
-static struct ctl_table_header *ip6_base;
-
-int ipv6_static_sysctl_register(void)
-{
- ip6_base = register_sysctl_paths(net_ipv6_ctl_path, ipv6_static_skeleton);
- if (ip6_base == NULL)
- return -ENOMEM;
- return 0;
-}
-
-void ipv6_static_sysctl_unregister(void)
-{
- unregister_net_sysctl_table(ip6_base);
-}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 98256cf72f9d..cdbf292ad208 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1353,7 +1353,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newnp->pktoptions = NULL;
if (treq->pktopts != NULL) {
newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
- kfree_skb(treq->pktopts);
+ consume_skb(treq->pktopts);
treq->pktopts = NULL;
if (newnp->pktoptions)
skb_set_owner_r(newnp->pktoptions, newsk);
@@ -1658,7 +1658,8 @@ process:
if (!tcp_prequeue(sk, skb))
ret = tcp_v6_do_rcv(sk, skb);
}
- } else if (unlikely(sk_add_backlog(sk, skb))) {
+ } else if (unlikely(sk_add_backlog(sk, skb,
+ sk->sk_rcvbuf + sk->sk_sndbuf))) {
bh_unlock_sock(sk);
NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);
goto discard_and_relse;
@@ -1833,64 +1834,15 @@ static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
static int tcp_v6_init_sock(struct sock *sk)
{
struct inet_connection_sock *icsk = inet_csk(sk);
- struct tcp_sock *tp = tcp_sk(sk);
-
- skb_queue_head_init(&tp->out_of_order_queue);
- tcp_init_xmit_timers(sk);
- tcp_prequeue_init(tp);
-
- icsk->icsk_rto = TCP_TIMEOUT_INIT;
- tp->mdev = TCP_TIMEOUT_INIT;
-
- /* So many TCP implementations out there (incorrectly) count the
- * initial SYN frame in their delayed-ACK and congestion control
- * algorithms that we must have the following bandaid to talk
- * efficiently to them. -DaveM
- */
- tp->snd_cwnd = 2;
-
- /* See draft-stevens-tcpca-spec-01 for discussion of the
- * initialization of these values.
- */
- tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
- tp->snd_cwnd_clamp = ~0;
- tp->mss_cache = TCP_MSS_DEFAULT;
-
- tp->reordering = sysctl_tcp_reordering;
- sk->sk_state = TCP_CLOSE;
+ tcp_init_sock(sk);
icsk->icsk_af_ops = &ipv6_specific;
- icsk->icsk_ca_ops = &tcp_init_congestion_ops;
- icsk->icsk_sync_mss = tcp_sync_mss;
- sk->sk_write_space = sk_stream_write_space;
- sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
#ifdef CONFIG_TCP_MD5SIG
- tp->af_specific = &tcp_sock_ipv6_specific;
+ tcp_sk(sk)->af_specific = &tcp_sock_ipv6_specific;
#endif
- /* TCP Cookie Transactions */
- if (sysctl_tcp_cookie_size > 0) {
- /* Default, cookies without s_data_payload. */
- tp->cookie_values =
- kzalloc(sizeof(*tp->cookie_values),
- sk->sk_allocation);
- if (tp->cookie_values != NULL)
- kref_init(&tp->cookie_values->kref);
- }
- /* Presumed zeroed, in order of appearance:
- * cookie_in_always, cookie_out_never,
- * s_data_constant, s_data_in, s_data_out
- */
- sk->sk_sndbuf = sysctl_tcp_wmem[1];
- sk->sk_rcvbuf = sysctl_tcp_rmem[1];
-
- local_bh_disable();
- sock_update_memcg(sk);
- sk_sockets_allocated_inc(sk);
- local_bh_enable();
-
return 0;
}
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 37b0699e95e5..d39bbc9e0622 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -611,14 +611,14 @@ static void flush_stack(struct sock **stack, unsigned int count,
sk = stack[i];
if (skb1) {
- if (sk_rcvqueues_full(sk, skb1)) {
+ if (sk_rcvqueues_full(sk, skb1, sk->sk_rcvbuf)) {
kfree_skb(skb1);
goto drop;
}
bh_lock_sock(sk);
if (!sock_owned_by_user(sk))
udpv6_queue_rcv_skb(sk, skb1);
- else if (sk_add_backlog(sk, skb1)) {
+ else if (sk_add_backlog(sk, skb1, sk->sk_rcvbuf)) {
kfree_skb(skb1);
bh_unlock_sock(sk);
goto drop;
@@ -790,14 +790,14 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
/* deliver */
- if (sk_rcvqueues_full(sk, skb)) {
+ if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf)) {
sock_put(sk);
goto discard;
}
bh_lock_sock(sk);
if (!sock_owned_by_user(sk))
udpv6_queue_rcv_skb(sk, skb);
- else if (sk_add_backlog(sk, skb)) {
+ else if (sk_add_backlog(sk, skb, sk->sk_rcvbuf)) {
atomic_inc(&sk->sk_drops);
bh_unlock_sock(sk);
sock_put(sk);
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 8ea65e032733..8625fba96db9 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -334,8 +334,8 @@ int __init xfrm6_init(void)
goto out_policy;
#ifdef CONFIG_SYSCTL
- sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv6_ctl_path,
- xfrm6_policy_table);
+ sysctl_hdr = register_net_sysctl(&init_net, "net/ipv6",
+ xfrm6_policy_table);
#endif
out:
return ret;
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 4fe1db12d2a3..ee5a7065aacc 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -68,9 +68,9 @@ static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock);
static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly;
-static inline unsigned xfrm6_tunnel_spi_hash_byaddr(const xfrm_address_t *addr)
+static inline unsigned int xfrm6_tunnel_spi_hash_byaddr(const xfrm_address_t *addr)
{
- unsigned h;
+ unsigned int h;
h = (__force u32)(addr->a6[0] ^ addr->a6[1] ^ addr->a6[2] ^ addr->a6[3]);
h ^= h >> 16;
@@ -80,7 +80,7 @@ static inline unsigned xfrm6_tunnel_spi_hash_byaddr(const xfrm_address_t *addr)
return h;
}
-static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi)
+static inline unsigned int xfrm6_tunnel_spi_hash_byspi(u32 spi)
{
return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE;
}
diff --git a/net/ipx/sysctl_net_ipx.c b/net/ipx/sysctl_net_ipx.c
index bd6dca00fb85..ad7c03dedaab 100644
--- a/net/ipx/sysctl_net_ipx.c
+++ b/net/ipx/sysctl_net_ipx.c
@@ -8,6 +8,7 @@
#include <linux/mm.h>
#include <linux/sysctl.h>
+#include <net/net_namespace.h>
#ifndef CONFIG_SYSCTL
#error This file should not be compiled without CONFIG_SYSCTL defined
@@ -27,20 +28,14 @@ static struct ctl_table ipx_table[] = {
{ },
};
-static struct ctl_path ipx_path[] = {
- { .procname = "net", },
- { .procname = "ipx", },
- { }
-};
-
static struct ctl_table_header *ipx_table_header;
void ipx_register_sysctl(void)
{
- ipx_table_header = register_sysctl_paths(ipx_path, ipx_table);
+ ipx_table_header = register_net_sysctl(&init_net, "net/ipx", ipx_table);
}
void ipx_unregister_sysctl(void)
{
- unregister_sysctl_table(ipx_table_header);
+ unregister_net_sysctl_table(ipx_table_header);
}
diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c
index 77c5e6499f8f..d0667d68351d 100644
--- a/net/irda/ircomm/ircomm_tty_ioctl.c
+++ b/net/irda/ircomm/ircomm_tty_ioctl.c
@@ -54,7 +54,7 @@
*/
static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
{
- unsigned cflag, cval;
+ unsigned int cflag, cval;
int baud;
IRDA_DEBUG(2, "%s()\n", __func__ );
diff --git a/net/irda/irsysctl.c b/net/irda/irsysctl.c
index 2615ffc8e785..de73f6496db5 100644
--- a/net/irda/irsysctl.c
+++ b/net/irda/irsysctl.c
@@ -235,12 +235,6 @@ static ctl_table irda_table[] = {
{ }
};
-static struct ctl_path irda_path[] = {
- { .procname = "net", },
- { .procname = "irda", },
- { }
-};
-
static struct ctl_table_header *irda_table_header;
/*
@@ -251,7 +245,7 @@ static struct ctl_table_header *irda_table_header;
*/
int __init irda_sysctl_register(void)
{
- irda_table_header = register_sysctl_paths(irda_path, irda_table);
+ irda_table_header = register_net_sysctl(&init_net, "net/irda", irda_table);
if (!irda_table_header)
return -ENOMEM;
@@ -266,7 +260,7 @@ int __init irda_sysctl_register(void)
*/
void irda_sysctl_unregister(void)
{
- unregister_sysctl_table(irda_table_header);
+ unregister_net_sysctl_table(irda_table_header);
}
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 7e5d927b576f..34e418508a67 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1714,7 +1714,7 @@ static int key_notify_sa_flush(const struct km_event *c)
static int pfkey_flush(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
{
struct net *net = sock_net(sk);
- unsigned proto;
+ unsigned int proto;
struct km_event c;
struct xfrm_audit audit_info;
int err, err2;
@@ -3547,7 +3547,7 @@ static int pfkey_sendmsg(struct kiocb *kiocb,
goto out;
err = -EMSGSIZE;
- if ((unsigned)len > sk->sk_sndbuf - 32)
+ if ((unsigned int)len > sk->sk_sndbuf - 32)
goto out;
err = -ENOBUFS;
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 89ff8c67943e..f6732b6c758b 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1424,6 +1424,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
/* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP;
udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv;
+ udp_encap_enable();
}
sk->sk_user_data = tunnel;
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index a16a48e79fab..09e4a38b4f43 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -54,15 +54,15 @@ struct l2tp_tunnel;
*/
struct l2tp_session_cfg {
enum l2tp_pwtype pw_type;
- unsigned data_seq:2; /* data sequencing level
+ unsigned int data_seq:2; /* data sequencing level
* 0 => none, 1 => IP only,
* 2 => all
*/
- unsigned recv_seq:1; /* expect receive packets with
+ unsigned int recv_seq:1; /* expect receive packets with
* sequence numbers? */
- unsigned send_seq:1; /* send packets with sequence
+ unsigned int send_seq:1; /* send packets with sequence
* numbers? */
- unsigned lns_mode:1; /* behave as LNS? LAC enables
+ unsigned int lns_mode:1; /* behave as LNS? LAC enables
* sequence numbers under
* control of LNS. */
int debug; /* bitmask of debug message
@@ -107,15 +107,15 @@ struct l2tp_session {
char name[32]; /* for logging */
char ifname[IFNAMSIZ];
- unsigned data_seq:2; /* data sequencing level
+ unsigned int data_seq:2; /* data sequencing level
* 0 => none, 1 => IP only,
* 2 => all
*/
- unsigned recv_seq:1; /* expect receive packets with
+ unsigned int recv_seq:1; /* expect receive packets with
* sequence numbers? */
- unsigned send_seq:1; /* send packets with sequence
+ unsigned int send_seq:1; /* send packets with sequence
* numbers? */
- unsigned lns_mode:1; /* behave as LNS? LAC enables
+ unsigned int lns_mode:1; /* behave as LNS? LAC enables
* sequence numbers under
* control of LNS. */
int debug; /* bitmask of debug message
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index 93a41a09458b..bc8c3348f835 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -231,24 +231,28 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 pid, u32 seq, int flags,
if (IS_ERR(hdr))
return PTR_ERR(hdr);
- NLA_PUT_U8(skb, L2TP_ATTR_PROTO_VERSION, tunnel->version);
- NLA_PUT_U32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id);
- NLA_PUT_U32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id);
- NLA_PUT_U32(skb, L2TP_ATTR_DEBUG, tunnel->debug);
- NLA_PUT_U16(skb, L2TP_ATTR_ENCAP_TYPE, tunnel->encap);
+ if (nla_put_u8(skb, L2TP_ATTR_PROTO_VERSION, tunnel->version) ||
+ nla_put_u32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id) ||
+ nla_put_u32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id) ||
+ nla_put_u32(skb, L2TP_ATTR_DEBUG, tunnel->debug) ||
+ nla_put_u16(skb, L2TP_ATTR_ENCAP_TYPE, tunnel->encap))
+ goto nla_put_failure;
nest = nla_nest_start(skb, L2TP_ATTR_STATS);
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT_U64(skb, L2TP_ATTR_TX_PACKETS, tunnel->stats.tx_packets);
- NLA_PUT_U64(skb, L2TP_ATTR_TX_BYTES, tunnel->stats.tx_bytes);
- NLA_PUT_U64(skb, L2TP_ATTR_TX_ERRORS, tunnel->stats.tx_errors);
- NLA_PUT_U64(skb, L2TP_ATTR_RX_PACKETS, tunnel->stats.rx_packets);
- NLA_PUT_U64(skb, L2TP_ATTR_RX_BYTES, tunnel->stats.rx_bytes);
- NLA_PUT_U64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, tunnel->stats.rx_seq_discards);
- NLA_PUT_U64(skb, L2TP_ATTR_RX_OOS_PACKETS, tunnel->stats.rx_oos_packets);
- NLA_PUT_U64(skb, L2TP_ATTR_RX_ERRORS, tunnel->stats.rx_errors);
+ if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, tunnel->stats.tx_packets) ||
+ nla_put_u64(skb, L2TP_ATTR_TX_BYTES, tunnel->stats.tx_bytes) ||
+ nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, tunnel->stats.tx_errors) ||
+ nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, tunnel->stats.rx_packets) ||
+ nla_put_u64(skb, L2TP_ATTR_RX_BYTES, tunnel->stats.rx_bytes) ||
+ nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS,
+ tunnel->stats.rx_seq_discards) ||
+ nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS,
+ tunnel->stats.rx_oos_packets) ||
+ nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, tunnel->stats.rx_errors))
+ goto nla_put_failure;
nla_nest_end(skb, nest);
sk = tunnel->sock;
@@ -259,13 +263,16 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 pid, u32 seq, int flags,
switch (tunnel->encap) {
case L2TP_ENCAPTYPE_UDP:
- NLA_PUT_U16(skb, L2TP_ATTR_UDP_SPORT, ntohs(inet->inet_sport));
- NLA_PUT_U16(skb, L2TP_ATTR_UDP_DPORT, ntohs(inet->inet_dport));
- NLA_PUT_U8(skb, L2TP_ATTR_UDP_CSUM, (sk->sk_no_check != UDP_CSUM_NOXMIT));
+ if (nla_put_u16(skb, L2TP_ATTR_UDP_SPORT, ntohs(inet->inet_sport)) ||
+ nla_put_u16(skb, L2TP_ATTR_UDP_DPORT, ntohs(inet->inet_dport)) ||
+ nla_put_u8(skb, L2TP_ATTR_UDP_CSUM,
+ (sk->sk_no_check != UDP_CSUM_NOXMIT)))
+ goto nla_put_failure;
/* NOBREAK */
case L2TP_ENCAPTYPE_IP:
- NLA_PUT_BE32(skb, L2TP_ATTR_IP_SADDR, inet->inet_saddr);
- NLA_PUT_BE32(skb, L2TP_ATTR_IP_DADDR, inet->inet_daddr);
+ if (nla_put_be32(skb, L2TP_ATTR_IP_SADDR, inet->inet_saddr) ||
+ nla_put_be32(skb, L2TP_ATTR_IP_DADDR, inet->inet_daddr))
+ goto nla_put_failure;
break;
}
@@ -563,43 +570,50 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 pid, u32 seq, int flags
if (IS_ERR(hdr))
return PTR_ERR(hdr);
- NLA_PUT_U32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id);
- NLA_PUT_U32(skb, L2TP_ATTR_SESSION_ID, session->session_id);
- NLA_PUT_U32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id);
- NLA_PUT_U32(skb, L2TP_ATTR_PEER_SESSION_ID, session->peer_session_id);
- NLA_PUT_U32(skb, L2TP_ATTR_DEBUG, session->debug);
- NLA_PUT_U16(skb, L2TP_ATTR_PW_TYPE, session->pwtype);
- NLA_PUT_U16(skb, L2TP_ATTR_MTU, session->mtu);
- if (session->mru)
- NLA_PUT_U16(skb, L2TP_ATTR_MRU, session->mru);
-
- if (session->ifname && session->ifname[0])
- NLA_PUT_STRING(skb, L2TP_ATTR_IFNAME, session->ifname);
- if (session->cookie_len)
- NLA_PUT(skb, L2TP_ATTR_COOKIE, session->cookie_len, &session->cookie[0]);
- if (session->peer_cookie_len)
- NLA_PUT(skb, L2TP_ATTR_PEER_COOKIE, session->peer_cookie_len, &session->peer_cookie[0]);
- NLA_PUT_U8(skb, L2TP_ATTR_RECV_SEQ, session->recv_seq);
- NLA_PUT_U8(skb, L2TP_ATTR_SEND_SEQ, session->send_seq);
- NLA_PUT_U8(skb, L2TP_ATTR_LNS_MODE, session->lns_mode);
+ if (nla_put_u32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id) ||
+ nla_put_u32(skb, L2TP_ATTR_SESSION_ID, session->session_id) ||
+ nla_put_u32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id) ||
+ nla_put_u32(skb, L2TP_ATTR_PEER_SESSION_ID,
+ session->peer_session_id) ||
+ nla_put_u32(skb, L2TP_ATTR_DEBUG, session->debug) ||
+ nla_put_u16(skb, L2TP_ATTR_PW_TYPE, session->pwtype) ||
+ nla_put_u16(skb, L2TP_ATTR_MTU, session->mtu) ||
+ (session->mru &&
+ nla_put_u16(skb, L2TP_ATTR_MRU, session->mru)))
+ goto nla_put_failure;
+
+ if ((session->ifname && session->ifname[0] &&
+ nla_put_string(skb, L2TP_ATTR_IFNAME, session->ifname)) ||
+ (session->cookie_len &&
+ nla_put(skb, L2TP_ATTR_COOKIE, session->cookie_len,
+ &session->cookie[0])) ||
+ (session->peer_cookie_len &&
+ nla_put(skb, L2TP_ATTR_PEER_COOKIE, session->peer_cookie_len,
+ &session->peer_cookie[0])) ||
+ nla_put_u8(skb, L2TP_ATTR_RECV_SEQ, session->recv_seq) ||
+ nla_put_u8(skb, L2TP_ATTR_SEND_SEQ, session->send_seq) ||
+ nla_put_u8(skb, L2TP_ATTR_LNS_MODE, session->lns_mode) ||
#ifdef CONFIG_XFRM
- if ((sk) && (sk->sk_policy[0] || sk->sk_policy[1]))
- NLA_PUT_U8(skb, L2TP_ATTR_USING_IPSEC, 1);
+ (((sk) && (sk->sk_policy[0] || sk->sk_policy[1])) &&
+ nla_put_u8(skb, L2TP_ATTR_USING_IPSEC, 1)) ||
#endif
- if (session->reorder_timeout)
- NLA_PUT_MSECS(skb, L2TP_ATTR_RECV_TIMEOUT, session->reorder_timeout);
-
+ (session->reorder_timeout &&
+ nla_put_msecs(skb, L2TP_ATTR_RECV_TIMEOUT, session->reorder_timeout)))
+ goto nla_put_failure;
nest = nla_nest_start(skb, L2TP_ATTR_STATS);
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT_U64(skb, L2TP_ATTR_TX_PACKETS, session->stats.tx_packets);
- NLA_PUT_U64(skb, L2TP_ATTR_TX_BYTES, session->stats.tx_bytes);
- NLA_PUT_U64(skb, L2TP_ATTR_TX_ERRORS, session->stats.tx_errors);
- NLA_PUT_U64(skb, L2TP_ATTR_RX_PACKETS, session->stats.rx_packets);
- NLA_PUT_U64(skb, L2TP_ATTR_RX_BYTES, session->stats.rx_bytes);
- NLA_PUT_U64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, session->stats.rx_seq_discards);
- NLA_PUT_U64(skb, L2TP_ATTR_RX_OOS_PACKETS, session->stats.rx_oos_packets);
- NLA_PUT_U64(skb, L2TP_ATTR_RX_ERRORS, session->stats.rx_errors);
+ if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, session->stats.tx_packets) ||
+ nla_put_u64(skb, L2TP_ATTR_TX_BYTES, session->stats.tx_bytes) ||
+ nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, session->stats.tx_errors) ||
+ nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, session->stats.rx_packets) ||
+ nla_put_u64(skb, L2TP_ATTR_RX_BYTES, session->stats.rx_bytes) ||
+ nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS,
+ session->stats.rx_seq_discards) ||
+ nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS,
+ session->stats.rx_oos_packets) ||
+ nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, session->stats.rx_errors))
+ goto nla_put_failure;
nla_nest_end(skb, nest);
return genlmsg_end(skb, hdr);
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index b9bef2c75026..17bc85d5b7ba 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -518,7 +518,7 @@ static int llc_ui_listen(struct socket *sock, int backlog)
if (sock_flag(sk, SOCK_ZAPPED))
goto out;
rc = 0;
- if (!(unsigned)backlog) /* BSDism */
+ if (!(unsigned int)backlog) /* BSDism */
backlog = 1;
sk->sk_max_ack_backlog = backlog;
if (sk->sk_state != TCP_LISTEN) {
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index ba137a6a224d..0d0d416dfab6 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -828,7 +828,7 @@ void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb)
else {
dprintk("%s: adding to backlog...\n", __func__);
llc_set_backlog_type(skb, LLC_PACKET);
- if (sk_add_backlog(sk, skb))
+ if (sk_add_backlog(sk, skb, sk->sk_rcvbuf))
goto drop_unlock;
}
out:
diff --git a/net/llc/sysctl_net_llc.c b/net/llc/sysctl_net_llc.c
index e2ebe3586263..d75306b9c2f3 100644
--- a/net/llc/sysctl_net_llc.c
+++ b/net/llc/sysctl_net_llc.c
@@ -7,6 +7,7 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/sysctl.h>
+#include <net/net_namespace.h>
#include <net/llc.h>
#ifndef CONFIG_SYSCTL
@@ -56,48 +57,29 @@ static struct ctl_table llc_station_table[] = {
{ },
};
-static struct ctl_table llc2_dir_timeout_table[] = {
- {
- .procname = "timeout",
- .mode = 0555,
- .child = llc2_timeout_table,
- },
- { },
-};
-
-static struct ctl_table llc_table[] = {
- {
- .procname = "llc2",
- .mode = 0555,
- .child = llc2_dir_timeout_table,
- },
- {
- .procname = "station",
- .mode = 0555,
- .child = llc_station_table,
- },
- { },
-};
-
-static struct ctl_path llc_path[] = {
- { .procname = "net", },
- { .procname = "llc", },
- { }
-};
-
-static struct ctl_table_header *llc_table_header;
+static struct ctl_table_header *llc2_timeout_header;
+static struct ctl_table_header *llc_station_header;
int __init llc_sysctl_init(void)
{
- llc_table_header = register_sysctl_paths(llc_path, llc_table);
+ llc2_timeout_header = register_net_sysctl(&init_net, "net/llc/llc2/timeout", llc2_timeout_table);
+ llc_station_header = register_net_sysctl(&init_net, "net/llc/station", llc_station_table);
- return llc_table_header ? 0 : -ENOMEM;
+ if (!llc2_timeout_header || !llc_station_header) {
+ llc_sysctl_exit();
+ return -ENOMEM;
+ }
+ return 0;
}
void llc_sysctl_exit(void)
{
- if (llc_table_header) {
- unregister_sysctl_table(llc_table_header);
- llc_table_header = NULL;
+ if (llc2_timeout_header) {
+ unregister_net_sysctl_table(llc2_timeout_header);
+ llc2_timeout_header = NULL;
+ }
+ if (llc_station_header) {
+ unregister_net_sysctl_table(llc_station_header);
+ llc_station_header = NULL;
}
}
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 96ddb72760b9..8d249d705980 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -225,6 +225,17 @@ config MAC80211_VERBOSE_MHWMP_DEBUG
Do not select this option.
+config MAC80211_VERBOSE_MESH_SYNC_DEBUG
+ bool "Verbose mesh mesh synchronization debugging"
+ depends on MAC80211_DEBUG_MENU
+ depends on MAC80211_MESH
+ ---help---
+ Selecting this option causes mac80211 to print out very verbose mesh
+ synchronization debugging messages (when mac80211 is taking part in a
+ mesh network).
+
+ Do not select this option.
+
config MAC80211_VERBOSE_TDLS_DEBUG
bool "Verbose TDLS debugging"
depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 1be7a454aa77..3e9d931bba35 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -38,7 +38,8 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
mesh.o \
mesh_pathtbl.o \
mesh_plink.o \
- mesh_hwmp.o
+ mesh_hwmp.o \
+ mesh_sync.o
mac80211-$(CONFIG_PM) += pm.o
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index 64d3ce5ea1a0..a070d4f460ea 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -142,6 +142,18 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
u8 *timer_to_id = ptid - *ptid;
struct sta_info *sta = container_of(timer_to_id, struct sta_info,
timer_to_tid[0]);
+ struct tid_ampdu_rx *tid_rx;
+ unsigned long timeout;
+
+ tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[*ptid]);
+ if (!tid_rx)
+ return;
+
+ timeout = tid_rx->last_rx + TU_TO_JIFFIES(tid_rx->timeout);
+ if (time_is_after_jiffies(timeout)) {
+ mod_timer(&tid_rx->session_timer, timeout);
+ return;
+ }
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
@@ -291,7 +303,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
/* rx timer */
tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
- init_timer(&tid_agg_rx->session_timer);
+ init_timer_deferrable(&tid_agg_rx->session_timer);
/* rx reorder timer */
tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired;
@@ -335,8 +347,10 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
/* activate it for RX */
rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
- if (timeout)
+ if (timeout) {
mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
+ tid_agg_rx->last_rx = jiffies;
+ }
end:
mutex_unlock(&sta->ampdu_mlme.mtx);
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 76be61744198..5b7053c58732 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -286,25 +286,25 @@ static inline int ieee80211_ac_from_tid(int tid)
* a global "agg_queue_stop" refcount.
*/
static void __acquires(agg_queue)
-ieee80211_stop_queue_agg(struct ieee80211_local *local, int tid)
+ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
{
- int queue = ieee80211_ac_from_tid(tid);
+ int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
- if (atomic_inc_return(&local->agg_queue_stop[queue]) == 1)
+ if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1)
ieee80211_stop_queue_by_reason(
- &local->hw, queue,
+ &sdata->local->hw, queue,
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
__acquire(agg_queue);
}
static void __releases(agg_queue)
-ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
+ieee80211_wake_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
{
- int queue = ieee80211_ac_from_tid(tid);
+ int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
- if (atomic_dec_return(&local->agg_queue_stop[queue]) == 0)
+ if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0)
ieee80211_wake_queue_by_reason(
- &local->hw, queue,
+ &sdata->local->hw, queue,
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
__release(agg_queue);
}
@@ -314,13 +314,14 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
* requires a call to ieee80211_agg_splice_finish later
*/
static void __acquires(agg_queue)
-ieee80211_agg_splice_packets(struct ieee80211_local *local,
+ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata,
struct tid_ampdu_tx *tid_tx, u16 tid)
{
- int queue = ieee80211_ac_from_tid(tid);
+ struct ieee80211_local *local = sdata->local;
+ int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
unsigned long flags;
- ieee80211_stop_queue_agg(local, tid);
+ ieee80211_stop_queue_agg(sdata, tid);
if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
" from the pending queue\n", tid))
@@ -336,9 +337,9 @@ ieee80211_agg_splice_packets(struct ieee80211_local *local,
}
static void __releases(agg_queue)
-ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
+ieee80211_agg_splice_finish(struct ieee80211_sub_if_data *sdata, u16 tid)
{
- ieee80211_wake_queue_agg(local, tid);
+ ieee80211_wake_queue_agg(sdata, tid);
}
void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
@@ -376,9 +377,9 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
" tid %d\n", tid);
#endif
spin_lock_bh(&sta->lock);
- ieee80211_agg_splice_packets(local, tid_tx, tid);
+ ieee80211_agg_splice_packets(sdata, tid_tx, tid);
ieee80211_assign_tid_tx(sta, tid, NULL);
- ieee80211_agg_splice_finish(local, tid);
+ ieee80211_agg_splice_finish(sdata, tid);
spin_unlock_bh(&sta->lock);
kfree_rcu(tid_tx, rcu_head);
@@ -417,6 +418,18 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)
u8 *timer_to_id = ptid - *ptid;
struct sta_info *sta = container_of(timer_to_id, struct sta_info,
timer_to_tid[0]);
+ struct tid_ampdu_tx *tid_tx;
+ unsigned long timeout;
+
+ tid_tx = rcu_dereference_protected_tid_tx(sta, *ptid);
+ if (!tid_tx)
+ return;
+
+ timeout = tid_tx->last_tx + TU_TO_JIFFIES(tid_tx->timeout);
+ if (time_is_after_jiffies(timeout)) {
+ mod_timer(&tid_tx->session_timer, timeout);
+ return;
+ }
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
@@ -542,7 +555,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
/* tx timer */
tid_tx->session_timer.function = sta_tx_agg_session_timer_expired;
tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
- init_timer(&tid_tx->session_timer);
+ init_timer_deferrable(&tid_tx->session_timer);
/* assign a dialog token */
sta->ampdu_mlme.dialog_token_allocator++;
@@ -586,14 +599,14 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
*/
spin_lock_bh(&sta->lock);
- ieee80211_agg_splice_packets(local, tid_tx, tid);
+ ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
/*
* Now mark as operational. This will be visible
* in the TX path, and lets it go lock-free in
* the common case.
*/
set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
- ieee80211_agg_splice_finish(local, tid);
+ ieee80211_agg_splice_finish(sta->sdata, tid);
spin_unlock_bh(&sta->lock);
}
@@ -778,12 +791,12 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
* more.
*/
- ieee80211_agg_splice_packets(local, tid_tx, tid);
+ ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
/* future packets must not find the tid_tx struct any more */
ieee80211_assign_tid_tx(sta, tid, NULL);
- ieee80211_agg_splice_finish(local, tid);
+ ieee80211_agg_splice_finish(sta->sdata, tid);
kfree_rcu(tid_tx, rcu_head);
@@ -884,9 +897,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
sta->ampdu_mlme.addba_req_num[tid] = 0;
- if (tid_tx->timeout)
+ if (tid_tx->timeout) {
mod_timer(&tid_tx->session_timer,
TU_TO_EXP_TIME(tid_tx->timeout));
+ tid_tx->last_tx = jiffies;
+ }
} else {
___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 677d65929780..510a745c3108 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -412,6 +412,10 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->llid = le16_to_cpu(sta->llid);
sinfo->plid = le16_to_cpu(sta->plid);
sinfo->plink_state = sta->plink_state;
+ if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
+ sinfo->filled |= STATION_INFO_T_OFFSET;
+ sinfo->t_offset = sta->t_offset;
+ }
#endif
}
@@ -640,6 +644,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
ieee80211_bss_info_change_notify(sdata, changed);
+ netif_carrier_on(dev);
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+ netif_carrier_on(vlan->dev);
+
return 0;
}
@@ -665,7 +673,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata, *vlan;
struct beacon_data *old;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -674,6 +682,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
if (!old)
return -ENOENT;
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+ netif_carrier_off(vlan->dev);
+ netif_carrier_off(dev);
+
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
kfree_rcu(old, rcu_head);
@@ -1235,6 +1247,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
/* now copy the rest of the setup parameters */
ifmsh->mesh_id_len = setup->mesh_id_len;
memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
+ ifmsh->mesh_sp_id = setup->sync_method;
ifmsh->mesh_pp_id = setup->path_sel_proto;
ifmsh->mesh_pm_id = setup->path_metric;
ifmsh->security = IEEE80211_MESH_SEC_NONE;
@@ -1279,6 +1292,9 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
conf->dot11MeshTTL = nconf->element_ttl;
if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask))
conf->auto_open_plinks = nconf->auto_open_plinks;
+ if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask))
+ conf->dot11MeshNbrOffsetMaxNeighbor =
+ nconf->dot11MeshNbrOffsetMaxNeighbor;
if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask))
conf->dot11MeshHWMPmaxPREQretries =
nconf->dot11MeshHWMPmaxPREQretries;
@@ -1437,6 +1453,9 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
if (!local->ops->conf_tx)
return -EOPNOTSUPP;
+ if (local->hw.queues < IEEE80211_NUM_ACS)
+ return -EOPNOTSUPP;
+
memset(&p, 0, sizeof(p));
p.aifs = params->aifs;
p.cw_max = params->cwmax;
@@ -1449,14 +1468,11 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
*/
p.uapsd = false;
- if (params->queue >= local->hw.queues)
- return -EINVAL;
-
- sdata->tx_conf[params->queue] = p;
- if (drv_conf_tx(local, sdata, params->queue, &p)) {
+ sdata->tx_conf[params->ac] = p;
+ if (drv_conf_tx(local, sdata, params->ac, &p)) {
wiphy_debug(local->hw.wiphy,
- "failed to set TX queue parameters for queue %d\n",
- params->queue);
+ "failed to set TX queue parameters for AC %d\n",
+ params->ac);
return -EINVAL;
}
@@ -2090,6 +2106,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
IEEE80211_SKB_CB(skb)->flags = flags;
+ if (flags & IEEE80211_TX_CTL_TX_OFFCHAN)
+ IEEE80211_SKB_CB(skb)->hw_queue =
+ local->hw.offchannel_tx_hw_queue;
+
skb->dev = sdata->dev;
*cookie = (unsigned long) skb;
@@ -2131,6 +2151,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
/* modify cookie to prevent API mismatches */
*cookie ^= 2;
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
+ IEEE80211_SKB_CB(skb)->hw_queue =
+ local->hw.offchannel_tx_hw_queue;
local->hw_roc_skb = skb;
local->hw_roc_skb_for_status = skb;
mutex_unlock(&local->mtx);
@@ -2350,8 +2372,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
tf->u.setup_req.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
- ieee80211_add_srates_ie(&sdata->vif, skb);
- ieee80211_add_ext_srates_ie(&sdata->vif, skb);
+ ieee80211_add_srates_ie(&sdata->vif, skb, false);
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb, false);
ieee80211_tdls_add_ext_capab(skb);
break;
case WLAN_TDLS_SETUP_RESPONSE:
@@ -2364,8 +2386,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
tf->u.setup_resp.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
- ieee80211_add_srates_ie(&sdata->vif, skb);
- ieee80211_add_ext_srates_ie(&sdata->vif, skb);
+ ieee80211_add_srates_ie(&sdata->vif, skb, false);
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb, false);
ieee80211_tdls_add_ext_capab(skb);
break;
case WLAN_TDLS_SETUP_CONFIRM:
@@ -2425,8 +2447,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
mgmt->u.action.u.tdls_discover_resp.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
- ieee80211_add_srates_ie(&sdata->vif, skb);
- ieee80211_add_ext_srates_ie(&sdata->vif, skb);
+ ieee80211_add_srates_ie(&sdata->vif, skb, false);
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb, false);
ieee80211_tdls_add_ext_capab(skb);
break;
default:
@@ -2666,13 +2688,22 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
}
static struct ieee80211_channel *
-ieee80211_wiphy_get_channel(struct wiphy *wiphy)
+ieee80211_wiphy_get_channel(struct wiphy *wiphy,
+ enum nl80211_channel_type *type)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
+ *type = local->_oper_channel_type;
return local->oper_channel;
}
+#ifdef CONFIG_PM
+static void ieee80211_set_wakeup(struct wiphy *wiphy, bool enabled)
+{
+ drv_set_wakeup(wiphy_priv(wiphy), enabled);
+}
+#endif
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -2741,4 +2772,7 @@ struct cfg80211_ops mac80211_config_ops = {
.probe_client = ieee80211_probe_client,
.get_channel = ieee80211_wiphy_get_channel,
.set_noack_map = ieee80211_set_noack_map,
+#ifdef CONFIG_PM
+ .set_wakeup = ieee80211_set_wakeup,
+#endif
};
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index e00ce8c3e28e..c76cf7230c7d 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -135,29 +135,3 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local,
return result;
}
-
-/*
- * ieee80211_get_tx_channel_type returns the channel type we should
- * use for packet transmission, given the channel capability and
- * whatever regulatory flags we have been given.
- */
-enum nl80211_channel_type ieee80211_get_tx_channel_type(
- struct ieee80211_local *local,
- enum nl80211_channel_type channel_type)
-{
- switch (channel_type) {
- case NL80211_CHAN_HT40PLUS:
- if (local->hw.conf.channel->flags &
- IEEE80211_CHAN_NO_HT40PLUS)
- return NL80211_CHAN_HT20;
- break;
- case NL80211_CHAN_HT40MINUS:
- if (local->hw.conf.channel->flags &
- IEEE80211_CHAN_NO_HT40MINUS)
- return NL80211_CHAN_HT20;
- break;
- default:
- break;
- }
- return channel_type;
-}
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 30f99c344847..e7af5227e322 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -424,6 +424,7 @@ static ssize_t ieee80211_if_parse_tsf(
struct ieee80211_local *local = sdata->local;
unsigned long long tsf;
int ret;
+ int tsf_is_delta = 0;
if (strncmp(buf, "reset", 5) == 0) {
if (local->ops->reset_tsf) {
@@ -431,9 +432,20 @@ static ssize_t ieee80211_if_parse_tsf(
wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
}
} else {
+ if (buflen > 10 && buf[1] == '=') {
+ if (buf[0] == '+')
+ tsf_is_delta = 1;
+ else if (buf[0] == '-')
+ tsf_is_delta = -1;
+ else
+ return -EINVAL;
+ buf += 2;
+ }
ret = kstrtoull(buf, 10, &tsf);
if (ret < 0)
return -EINVAL;
+ if (tsf_is_delta)
+ tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf;
if (local->ops->set_tsf) {
drv_set_tsf(local, sdata, tsf);
wiphy_info(local->hw.wiphy,
@@ -499,26 +511,23 @@ IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC);
IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC);
#endif
-
-#define DEBUGFS_ADD(name) \
- debugfs_create_file(#name, 0400, sdata->debugfs.dir, \
- sdata, &name##_ops);
-
#define DEBUGFS_ADD_MODE(name, mode) \
debugfs_create_file(#name, mode, sdata->debugfs.dir, \
sdata, &name##_ops);
-static void add_sta_files(struct ieee80211_sub_if_data *sdata)
+#define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400)
+
+static void add_common_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(drop_unencrypted);
- DEBUGFS_ADD(flags);
- DEBUGFS_ADD(state);
- DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
+}
+static void add_sta_files(struct ieee80211_sub_if_data *sdata)
+{
DEBUGFS_ADD(bssid);
DEBUGFS_ADD(aid);
DEBUGFS_ADD(last_beacon);
@@ -531,15 +540,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_ADD(drop_unencrypted);
- DEBUGFS_ADD(flags);
- DEBUGFS_ADD(state);
- DEBUGFS_ADD(channel_type);
- DEBUGFS_ADD(rc_rateidx_mask_2ghz);
- DEBUGFS_ADD(rc_rateidx_mask_5ghz);
- DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
- DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
-
DEBUGFS_ADD(num_sta_authorized);
DEBUGFS_ADD(num_sta_ps);
DEBUGFS_ADD(dtim_count);
@@ -549,48 +549,14 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_ADD(channel_type);
- DEBUGFS_ADD(rc_rateidx_mask_2ghz);
- DEBUGFS_ADD(rc_rateidx_mask_5ghz);
- DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
- DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
-
DEBUGFS_ADD_MODE(tsf, 0600);
}
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_ADD(drop_unencrypted);
- DEBUGFS_ADD(flags);
- DEBUGFS_ADD(state);
- DEBUGFS_ADD(channel_type);
- DEBUGFS_ADD(rc_rateidx_mask_2ghz);
- DEBUGFS_ADD(rc_rateidx_mask_5ghz);
- DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
- DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
-
DEBUGFS_ADD(peer);
}
-static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
-{
- DEBUGFS_ADD(drop_unencrypted);
- DEBUGFS_ADD(flags);
- DEBUGFS_ADD(state);
- DEBUGFS_ADD(channel_type);
- DEBUGFS_ADD(rc_rateidx_mask_2ghz);
- DEBUGFS_ADD(rc_rateidx_mask_5ghz);
- DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
- DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
-}
-
-static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
-{
- DEBUGFS_ADD(flags);
- DEBUGFS_ADD(state);
- DEBUGFS_ADD(channel_type);
-}
-
#ifdef CONFIG_MAC80211_MESH
static void add_mesh_files(struct ieee80211_sub_if_data *sdata)
@@ -651,6 +617,13 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
if (!sdata->debugfs.dir)
return;
+ DEBUGFS_ADD(flags);
+ DEBUGFS_ADD(state);
+ DEBUGFS_ADD(channel_type);
+
+ if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
+ add_common_files(sdata);
+
switch (sdata->vif.type) {
case NL80211_IFTYPE_MESH_POINT:
#ifdef CONFIG_MAC80211_MESH
@@ -671,12 +644,6 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
case NL80211_IFTYPE_WDS:
add_wds_files(sdata);
break;
- case NL80211_IFTYPE_MONITOR:
- add_monitor_files(sdata);
- break;
- case NL80211_IFTYPE_AP_VLAN:
- add_vlan_files(sdata);
- break;
default:
break;
}
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 832b2da5e4cd..5ccec2c1e9f6 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -63,7 +63,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
int res = scnprintf(buf, sizeof(buf),
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
TEST(PS_DRIVER), TEST(AUTHORIZED),
TEST(SHORT_PREAMBLE),
@@ -71,7 +71,8 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
- TEST(INSERTED), TEST(RATE_CONTROL));
+ TEST(INSERTED), TEST(RATE_CONTROL),
+ TEST(TOFFSET_KNOWN));
#undef TEST
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index af4691fed645..4a0e559cb26b 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -7,7 +7,9 @@
static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)
{
- WARN_ON(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER));
+ WARN(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER),
+ "%s: Failed check-sdata-in-driver check, flags: 0x%x\n",
+ sdata->dev->name, sdata->flags);
}
static inline struct ieee80211_sub_if_data *
@@ -89,6 +91,19 @@ static inline int drv_resume(struct ieee80211_local *local)
trace_drv_return_int(local, ret);
return ret;
}
+
+static inline void drv_set_wakeup(struct ieee80211_local *local,
+ bool enabled)
+{
+ might_sleep();
+
+ if (!local->ops->set_wakeup)
+ return;
+
+ trace_drv_set_wakeup(local, enabled);
+ local->ops->set_wakeup(&local->hw, enabled);
+ trace_drv_return_void(local);
+}
#endif
static inline int drv_add_interface(struct ieee80211_local *local,
@@ -99,7 +114,8 @@ static inline int drv_add_interface(struct ieee80211_local *local,
might_sleep();
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
- sdata->vif.type == NL80211_IFTYPE_MONITOR))
+ (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+ !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))))
return -EINVAL;
trace_drv_add_interface(local, sdata);
@@ -474,8 +490,23 @@ int drv_sta_state(struct ieee80211_local *local,
return ret;
}
+static inline void drv_sta_rc_update(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta, u32 changed)
+{
+ sdata = get_bss_sdata(sdata);
+ check_sdata_in_driver(sdata);
+
+ trace_drv_sta_rc_update(local, sdata, sta, changed);
+ if (local->ops->sta_rc_update)
+ local->ops->sta_rc_update(&local->hw, &sdata->vif,
+ sta, changed);
+
+ trace_drv_return_void(local);
+}
+
static inline int drv_conf_tx(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata, u16 queue,
+ struct ieee80211_sub_if_data *sdata, u16 ac,
const struct ieee80211_tx_queue_params *params)
{
int ret = -EOPNOTSUPP;
@@ -484,10 +515,10 @@ static inline int drv_conf_tx(struct ieee80211_local *local,
check_sdata_in_driver(sdata);
- trace_drv_conf_tx(local, sdata, queue, params);
+ trace_drv_conf_tx(local, sdata, ac, params);
if (local->ops->conf_tx)
ret = local->ops->conf_tx(&local->hw, &sdata->vif,
- queue, params);
+ ac, params);
trace_drv_return_int(local, ret);
return ret;
}
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 21d6f5290a1c..7c0754bed61b 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -171,6 +171,20 @@ DEFINE_EVENT(local_only_evt, drv_resume,
TP_ARGS(local)
);
+TRACE_EVENT(drv_set_wakeup,
+ TP_PROTO(struct ieee80211_local *local, bool enabled),
+ TP_ARGS(local, enabled),
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(bool, enabled)
+ ),
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->enabled = enabled;
+ ),
+ TP_printk(LOCAL_PR_FMT " enabled:%d", LOCAL_PR_ARG, __entry->enabled)
+);
+
DEFINE_EVENT(local_only_evt, drv_stop,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local)
@@ -624,6 +638,34 @@ TRACE_EVENT(drv_sta_state,
)
);
+TRACE_EVENT(drv_sta_rc_update,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta,
+ u32 changed),
+
+ TP_ARGS(local, sdata, sta, changed),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ STA_ENTRY
+ __field(u32, changed)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ STA_ASSIGN;
+ __entry->changed = changed;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " changed: 0x%x",
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->changed
+ )
+);
+
TRACE_EVENT(drv_sta_add,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
@@ -677,15 +719,14 @@ TRACE_EVENT(drv_sta_remove,
TRACE_EVENT(drv_conf_tx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- u16 queue,
- const struct ieee80211_tx_queue_params *params),
+ u16 ac, const struct ieee80211_tx_queue_params *params),
- TP_ARGS(local, sdata, queue, params),
+ TP_ARGS(local, sdata, ac, params),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
- __field(u16, queue)
+ __field(u16, ac)
__field(u16, txop)
__field(u16, cw_min)
__field(u16, cw_max)
@@ -696,7 +737,7 @@ TRACE_EVENT(drv_conf_tx,
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
- __entry->queue = queue;
+ __entry->ac = ac;
__entry->txop = params->txop;
__entry->cw_max = params->cw_max;
__entry->cw_min = params->cw_min;
@@ -705,8 +746,8 @@ TRACE_EVENT(drv_conf_tx,
),
TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT " queue:%d",
- LOCAL_PR_ARG, VIF_PR_ARG, __entry->queue
+ LOCAL_PR_FMT VIF_PR_FMT " AC:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->ac
)
);
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index f25fff7607d8..9b603366943c 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -19,15 +19,6 @@
#include "ieee80211_i.h"
#include "rate.h"
-bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata)
-{
- const __le16 flg = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40);
- if ((sdata->u.mgd.ht_capa_mask.cap_info & flg) &&
- !(sdata->u.mgd.ht_capa.cap_info & flg))
- return true;
- return false;
-}
-
static void __check_htcap_disable(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta_ht_cap *ht_cap,
u16 flag)
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index cef7c29214a8..61cd391c32a3 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -160,16 +160,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
if (channel_type && sband->ht_cap.ht_supported) {
pos = skb_put(skb, 4 +
sizeof(struct ieee80211_ht_cap) +
- sizeof(struct ieee80211_ht_info));
+ sizeof(struct ieee80211_ht_operation));
pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
sband->ht_cap.cap);
- pos = ieee80211_ie_build_ht_info(pos,
- &sband->ht_cap,
- chan,
- channel_type);
+ pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
+ chan, channel_type);
}
- if (local->hw.queues >= 4) {
+ if (local->hw.queues >= IEEE80211_NUM_ACS) {
pos = skb_put(skb, 9);
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = 7; /* len */
@@ -410,7 +408,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
if (elems->supp_rates) {
supp_rates = ieee80211_sta_get_rates(local, elems,
- band);
+ band, NULL);
if (sta) {
u32 prev_rates;
@@ -441,13 +439,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
if (sta && elems->wmm_info)
set_sta_flag(sta, WLAN_STA_WME);
- if (sta && elems->ht_info_elem && elems->ht_cap_elem &&
+ if (sta && elems->ht_operation && elems->ht_cap_elem &&
sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) {
/* we both use HT */
struct ieee80211_sta_ht_cap sta_ht_cap_new;
enum nl80211_channel_type channel_type =
- ieee80211_ht_info_to_channel_type(
- elems->ht_info_elem);
+ ieee80211_ht_oper_to_channel_type(
+ elems->ht_operation);
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems->ht_cap_elem,
@@ -560,7 +558,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
sdata->name, mgmt->bssid);
#endif
ieee80211_sta_join_ibss(sdata, bss);
- supp_rates = ieee80211_sta_get_rates(local, elems, band);
+ supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL);
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
supp_rates, true);
rcu_read_unlock();
@@ -1063,7 +1061,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
4 /* IBSS params */ +
2 + (IEEE80211_MAX_SUPP_RATES - 8) +
2 + sizeof(struct ieee80211_ht_cap) +
- 2 + sizeof(struct ieee80211_ht_info) +
+ 2 + sizeof(struct ieee80211_ht_operation) +
params->ie_len);
if (!skb)
return -ENOMEM;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d9798a307f20..bd7a451b0849 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -52,7 +52,8 @@ struct ieee80211_local;
* increased memory use (about 2 kB of RAM per entry). */
#define IEEE80211_FRAGMENT_MAX 4
-#define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024))
+#define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024))
+#define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x))
#define IEEE80211_DEFAULT_UAPSD_QUEUES \
(IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \
@@ -378,6 +379,7 @@ enum ieee80211_sta_flags {
IEEE80211_STA_UAPSD_ENABLED = BIT(7),
IEEE80211_STA_NULLFUNC_ACKED = BIT(8),
IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9),
+ IEEE80211_STA_DISABLE_40MHZ = BIT(10),
};
struct ieee80211_mgd_auth_data {
@@ -397,7 +399,7 @@ struct ieee80211_mgd_auth_data {
struct ieee80211_mgd_assoc_data {
struct cfg80211_bss *bss;
const u8 *supp_rates;
- const u8 *ht_information_ie;
+ const u8 *ht_operation_ie;
unsigned long timeout;
int tries;
@@ -552,6 +554,24 @@ struct ieee80211_if_ibss {
} state;
};
+/**
+ * struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface
+ *
+ * these declarations define the interface, which enables
+ * vendor-specific mesh synchronization
+ *
+ */
+struct ieee802_11_elems;
+struct ieee80211_mesh_sync_ops {
+ void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata,
+ u16 stype,
+ struct ieee80211_mgmt *mgmt,
+ struct ieee802_11_elems *elems,
+ struct ieee80211_rx_status *rx_status);
+ void (*adjust_tbtt)(struct ieee80211_sub_if_data *sdata);
+ /* add other framework functions here */
+};
+
struct ieee80211_if_mesh {
struct timer_list housekeeping_timer;
struct timer_list mesh_path_timer;
@@ -600,6 +620,11 @@ struct ieee80211_if_mesh {
IEEE80211_MESH_SEC_AUTHED = 0x1,
IEEE80211_MESH_SEC_SECURED = 0x2,
} security;
+ /* Extensible Synchronization Framework */
+ struct ieee80211_mesh_sync_ops *sync_ops;
+ s64 sync_offset_clockdrift_max;
+ spinlock_t sync_offset_lock;
+ bool adjusting_tbtt;
};
#ifdef CONFIG_MAC80211_MESH
@@ -666,12 +691,6 @@ struct ieee80211_sub_if_data {
char name[IFNAMSIZ];
- /*
- * keep track of whether the HT opmode (stored in
- * vif.bss_info.ht_operation_mode) is valid.
- */
- bool ht_opmode_valid;
-
/* to detect idle changes */
bool old_idle;
@@ -691,7 +710,7 @@ struct ieee80211_sub_if_data {
__be16 control_port_protocol;
bool control_port_no_encrypt;
- struct ieee80211_tx_queue_params tx_conf[IEEE80211_MAX_QUEUES];
+ struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
struct work_struct work;
struct sk_buff_head skb_queue;
@@ -761,7 +780,6 @@ enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
- IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE,
};
#ifdef CONFIG_MAC80211_LEDS
@@ -1082,6 +1100,9 @@ struct ieee80211_local {
struct net_device napi_dev;
struct napi_struct napi;
+
+ /* virtual monitor interface */
+ struct ieee80211_sub_if_data __rcu *monitor_sdata;
};
static inline struct ieee80211_sub_if_data *
@@ -1117,7 +1138,7 @@ struct ieee802_11_elems {
u8 *wmm_info;
u8 *wmm_param;
struct ieee80211_ht_cap *ht_cap_elem;
- struct ieee80211_ht_info *ht_info_elem;
+ struct ieee80211_ht_operation *ht_operation;
struct ieee80211_meshconf_ie *mesh_config;
u8 *mesh_id;
u8 *peering;
@@ -1239,6 +1260,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
struct cfg80211_scan_request *req);
void ieee80211_scan_cancel(struct ieee80211_local *local);
+void ieee80211_run_deferred_scan(struct ieee80211_local *local);
ieee80211_rx_result
ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
@@ -1251,9 +1273,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
struct ieee802_11_elems *elems,
struct ieee80211_channel *channel,
bool beacon);
-struct ieee80211_bss *
-ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
- u8 *ssid, u8 ssid_len);
void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_bss *bss);
@@ -1299,7 +1318,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev);
/* HT */
-bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata);
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta_ht_cap *ht_cap);
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
@@ -1383,7 +1401,7 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw)
extern void *mac80211_wiphy_privid; /* for wiphy privid */
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
enum nl80211_iftype type);
-int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
+int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
int rate, int erp, int short_preamble);
void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
struct ieee80211_hdr *hdr, const u8 *tsc,
@@ -1429,13 +1447,17 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason);
void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason);
+void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue);
void ieee80211_add_pending_skb(struct ieee80211_local *local,
struct sk_buff *skb);
-void ieee80211_add_pending_skbs(struct ieee80211_local *local,
- struct sk_buff_head *skbs);
void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
struct sk_buff_head *skbs,
void (*fn)(void *data), void *data);
+static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+ struct sk_buff_head *skbs)
+{
+ ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
+}
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg,
@@ -1460,7 +1482,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
const u8 *supp_rates);
u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
struct ieee802_11_elems *elems,
- enum ieee80211_band band);
+ enum ieee80211_band band, u32 *basic_rates);
int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode);
void ieee80211_recalc_smps(struct ieee80211_local *local);
@@ -1470,10 +1492,9 @@ size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u16 cap);
-u8 *ieee80211_ie_build_ht_info(u8 *pos,
- struct ieee80211_sta_ht_cap *ht_cap,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type);
+u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type);
/* internal work items */
void ieee80211_work_init(struct ieee80211_local *local);
@@ -1501,10 +1522,7 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum nl80211_channel_type chantype);
enum nl80211_channel_type
-ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info);
-enum nl80211_channel_type ieee80211_get_tx_channel_type(
- struct ieee80211_local *local,
- enum nl80211_channel_type channel_type);
+ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper);
#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 401c01f0731e..23d1da376eb3 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -149,6 +149,35 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
return 0;
}
+static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata)
+{
+ int n_queues = sdata->local->hw.queues;
+ int i;
+
+ for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ if (WARN_ON_ONCE(sdata->vif.hw_queue[i] ==
+ IEEE80211_INVAL_HW_QUEUE))
+ return -EINVAL;
+ if (WARN_ON_ONCE(sdata->vif.hw_queue[i] >=
+ n_queues))
+ return -EINVAL;
+ }
+
+ if ((sdata->vif.type != NL80211_IFTYPE_AP) ||
+ !(sdata->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) {
+ sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
+ return 0;
+ }
+
+ if (WARN_ON_ONCE(sdata->vif.cab_queue == IEEE80211_INVAL_HW_QUEUE))
+ return -EINVAL;
+
+ if (WARN_ON_ONCE(sdata->vif.cab_queue >= n_queues))
+ return -EINVAL;
+
+ return 0;
+}
+
void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
const int offset)
{
@@ -169,6 +198,81 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
#undef ADJUST
}
+static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ int i;
+
+ for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
+ sdata->vif.hw_queue[i] = IEEE80211_INVAL_HW_QUEUE;
+ else
+ sdata->vif.hw_queue[i] = i;
+ }
+ sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
+}
+
+static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
+{
+ struct ieee80211_sub_if_data *sdata;
+ int ret;
+
+ if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
+ return 0;
+
+ if (local->monitor_sdata)
+ return 0;
+
+ sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
+ if (!sdata)
+ return -ENOMEM;
+
+ /* set up data */
+ sdata->local = local;
+ sdata->vif.type = NL80211_IFTYPE_MONITOR;
+ snprintf(sdata->name, IFNAMSIZ, "%s-monitor",
+ wiphy_name(local->hw.wiphy));
+
+ ieee80211_set_default_queues(sdata);
+
+ ret = drv_add_interface(local, sdata);
+ if (WARN_ON(ret)) {
+ /* ok .. stupid driver, it asked for this! */
+ kfree(sdata);
+ return ret;
+ }
+
+ ret = ieee80211_check_queues(sdata);
+ if (ret) {
+ kfree(sdata);
+ return ret;
+ }
+
+ rcu_assign_pointer(local->monitor_sdata, sdata);
+
+ return 0;
+}
+
+static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
+ return;
+
+ sdata = rtnl_dereference(local->monitor_sdata);
+
+ if (!sdata)
+ return;
+
+ rcu_assign_pointer(local->monitor_sdata, NULL);
+ synchronize_net();
+
+ drv_remove_interface(local, sdata);
+
+ kfree(sdata);
+}
+
/*
* NOTE: Be very careful when changing this function, it must NOT return
* an error on interface type changes that have been pre-checked, so most
@@ -246,15 +350,18 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
if (!is_valid_ether_addr(dev->dev_addr)) {
- if (!local->open_count)
- drv_stop(local);
- return -EADDRNOTAVAIL;
+ res = -EADDRNOTAVAIL;
+ goto err_stop;
}
}
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
- /* no need to tell driver */
+ /* no need to tell driver, but set carrier */
+ if (rtnl_dereference(sdata->bss->beacon))
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
break;
case NL80211_IFTYPE_MONITOR:
if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
@@ -262,6 +369,12 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
break;
}
+ if (local->monitors == 0 && local->open_count == 0) {
+ res = ieee80211_add_virtual_monitor(local);
+ if (res)
+ goto err_stop;
+ }
+
/* must be before the call to ieee80211_configure_filter */
local->monitors++;
if (local->monitors == 1) {
@@ -276,9 +389,14 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
break;
default:
if (coming_up) {
+ ieee80211_del_virtual_monitor(local);
+
res = drv_add_interface(local, sdata);
if (res)
goto err_stop;
+ res = ieee80211_check_queues(sdata);
+ if (res)
+ goto err_del_interface;
}
if (sdata->vif.type == NL80211_IFTYPE_AP) {
@@ -294,7 +412,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
ieee80211_bss_info_change_notify(sdata, changed);
if (sdata->vif.type == NL80211_IFTYPE_STATION ||
- sdata->vif.type == NL80211_IFTYPE_ADHOC)
+ sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+ sdata->vif.type == NL80211_IFTYPE_AP)
netif_carrier_off(dev);
else
netif_carrier_on(dev);
@@ -366,6 +485,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
sdata->bss = NULL;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
list_del(&sdata->u.vlan.list);
+ /* might already be clear but that doesn't matter */
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
return res;
}
@@ -506,6 +626,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
if (local->monitors == 0) {
local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
+ ieee80211_del_virtual_monitor(local);
}
ieee80211_adjust_monitor_flags(sdata, -1);
@@ -579,6 +700,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
}
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+
+ if (local->monitors == local->open_count && local->monitors > 0)
+ ieee80211_add_virtual_monitor(local);
}
static int ieee80211_stop(struct net_device *dev)
@@ -676,7 +800,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,
struct ieee80211_hdr *hdr;
struct ieee80211_radiotap_header *rtap = (void *)skb->data;
- if (local->hw.queues < 4)
+ if (local->hw.queues < IEEE80211_NUM_ACS)
return 0;
if (skb->len < 4 ||
@@ -970,6 +1094,13 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
if (ret)
type = sdata->vif.type;
+ /*
+ * Ignore return value here, there's not much we can do since
+ * the driver changed the interface type internally already.
+ * The warnings will hopefully make driver authors fix it :-)
+ */
+ ieee80211_check_queues(sdata);
+
ieee80211_setup_sdata(sdata, type);
err = ieee80211_do_open(sdata->dev, false);
@@ -1133,11 +1264,15 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
struct net_device *ndev;
struct ieee80211_sub_if_data *sdata = NULL;
int ret, i;
+ int txqs = 1;
ASSERT_RTNL();
+ if (local->hw.queues >= IEEE80211_NUM_ACS)
+ txqs = IEEE80211_NUM_ACS;
+
ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size,
- name, ieee80211_if_setup, local->hw.queues, 1);
+ name, ieee80211_if_setup, txqs, 1);
if (!ndev)
return -ENOMEM;
dev_net_set(ndev, wiphy_net(local->hw.wiphy));
@@ -1192,6 +1327,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
sizeof(sdata->rc_rateidx_mcs_mask[i]));
}
+ ieee80211_set_default_queues(sdata);
+
/* setup type-dependent data */
ieee80211_setup_sdata(sdata, type);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 16336480c631..ac79d5e8e0d0 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -557,8 +557,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
WIPHY_FLAG_4ADDR_AP |
WIPHY_FLAG_4ADDR_STATION |
WIPHY_FLAG_REPORTS_OBSS |
- WIPHY_FLAG_OFFCHAN_TX |
- WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ WIPHY_FLAG_OFFCHAN_TX;
+
+ if (ops->remain_on_channel)
+ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
wiphy->features = NL80211_FEATURE_SK_TX_STATUS |
NL80211_FEATURE_HT_IBSS;
@@ -589,6 +591,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->hw.max_report_rates = 0;
local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
local->hw.max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
+ local->hw.offchannel_tx_hw_queue = IEEE80211_INVAL_HW_QUEUE;
local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
local->user_power_level = -1;
@@ -685,6 +688,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
WLAN_CIPHER_SUITE_AES_CMAC
};
+ if (hw->flags & IEEE80211_HW_QUEUE_CONTROL &&
+ (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE ||
+ local->hw.offchannel_tx_hw_queue >= local->hw.queues))
+ return -EINVAL;
+
if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns)
#ifdef CONFIG_PM
&& (!local->ops->suspend || !local->ops->resume)
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index e5fbb7cf3562..133c118526fb 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -13,9 +13,6 @@
#include "ieee80211_i.h"
#include "mesh.h"
-#define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01
-#define MESHCONF_CAPAB_FORWARDING 0x08
-
#define TMR_RUNNING_HK 0
#define TMR_RUNNING_MP 1
#define TMR_RUNNING_MPR 2
@@ -69,11 +66,13 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
*
* @ie: information elements of a management frame from the mesh peer
* @sdata: local mesh subif
+ * @basic_rates: BSSBasicRateSet of the peer candidate
*
* This function checks if the mesh configuration of a mesh point matches the
* local mesh configuration, i.e. if both nodes belong to the same mesh network.
*/
-bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata)
+bool mesh_matches_local(struct ieee802_11_elems *ie,
+ struct ieee80211_sub_if_data *sdata, u32 basic_rates)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local;
@@ -97,10 +96,13 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
(ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
goto mismatch;
+ if (sdata->vif.bss_conf.basic_rates != basic_rates)
+ goto mismatch;
+
/* disallow peering with mismatched channel types for now */
- if (ie->ht_info_elem &&
+ if (ie->ht_operation &&
(local->_oper_channel_type !=
- ieee80211_ht_info_to_channel_type(ie->ht_info_elem)))
+ ieee80211_ht_oper_to_channel_type(ie->ht_operation)))
goto mismatch;
return true;
@@ -251,8 +253,10 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
/* Mesh capability */
ifmsh->accepting_plinks = mesh_plink_availables(sdata);
*pos = MESHCONF_CAPAB_FORWARDING;
- *pos++ |= ifmsh->accepting_plinks ?
+ *pos |= ifmsh->accepting_plinks ?
MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
+ *pos++ |= ifmsh->adjusting_tbtt ?
+ MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00;
*pos++ = 0x00;
return 0;
@@ -371,7 +375,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb,
return 0;
}
-int mesh_add_ht_info_ie(struct sk_buff *skb,
+int mesh_add_ht_oper_ie(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
@@ -385,11 +389,11 @@ int mesh_add_ht_info_ie(struct sk_buff *skb,
if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT)
return 0;
- if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_info))
+ if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation))
return -ENOMEM;
- pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_info));
- ieee80211_ie_build_ht_info(pos, ht_cap, channel, channel_type);
+ pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
+ ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type);
return 0;
}
@@ -573,14 +577,21 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
ieee80211_configure_filter(local);
ifmsh->mesh_cc_id = 0; /* Disabled */
- ifmsh->mesh_sp_id = 0; /* Neighbor Offset */
ifmsh->mesh_auth_id = 0; /* Disabled */
+ /* register sync ops from extensible synchronization framework */
+ ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id);
+ ifmsh->adjusting_tbtt = false;
+ ifmsh->sync_offset_clockdrift_max = 0;
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
ieee80211_mesh_root_setup(ifmsh);
ieee80211_queue_work(&local->hw, &sdata->work);
sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
+ sdata->vif.bss_conf.basic_rates =
+ ieee80211_mandatory_rates(sdata->local,
+ sdata->local->hw.conf.channel->band);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED |
+ BSS_CHANGED_BASIC_RATES |
BSS_CHANGED_BEACON_INT);
}
@@ -616,9 +627,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
struct ieee80211_rx_status *rx_status)
{
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee802_11_elems elems;
struct ieee80211_channel *channel;
- u32 supp_rates = 0;
+ u32 supp_rates = 0, basic_rates = 0;
size_t baselen;
int freq;
enum ieee80211_band band = rx_status->band;
@@ -649,11 +661,16 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
return;
+ supp_rates = ieee80211_sta_get_rates(local, &elems,
+ band, &basic_rates);
+
if (elems.mesh_id && elems.mesh_config &&
- mesh_matches_local(&elems, sdata)) {
- supp_rates = ieee80211_sta_get_rates(local, &elems, band);
+ mesh_matches_local(&elems, sdata, basic_rates))
mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems);
- }
+
+ if (ifmsh->sync_ops)
+ ifmsh->sync_ops->rx_bcn_presp(sdata,
+ stype, mgmt, &elems, rx_status);
}
static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
@@ -721,6 +738,9 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags))
ieee80211_mesh_rootpath(sdata);
+
+ if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
+ mesh_sync_adjust_tbtt(sdata);
}
void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
@@ -761,4 +781,5 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
(unsigned long) sdata);
INIT_LIST_HEAD(&ifmsh->preq_queue.list);
spin_lock_init(&ifmsh->mesh_preq_queue_lock);
+ spin_lock_init(&ifmsh->sync_offset_lock);
}
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 8d53b71378e3..4ad738988801 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -19,6 +19,20 @@
/* Data structures */
/**
+ * enum mesh_config_capab_flags - mesh config IE capability flags
+ *
+ * @MESHCONF_CAPAB_ACCEPT_PLINKS: STA is willing to establish
+ * additional mesh peerings with other mesh STAs
+ * @MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs
+ * @MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure is ongoing
+ */
+enum mesh_config_capab_flags {
+ MESHCONF_CAPAB_ACCEPT_PLINKS = BIT(0),
+ MESHCONF_CAPAB_FORWARDING = BIT(3),
+ MESHCONF_CAPAB_TBTT_ADJUSTING = BIT(5),
+};
+
+/**
* enum mesh_path_flags - mac80211 mesh path flags
*
*
@@ -56,12 +70,15 @@ enum mesh_path_flags {
* @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to
* grow
* @MESH_WORK_ROOT: the mesh root station needs to send a frame
+ * @MESH_WORK_DRIFT_ADJUST: time to compensate for clock drift relative to other
+ * mesh nodes
*/
enum mesh_deferred_task_flags {
MESH_WORK_HOUSEKEEPING,
MESH_WORK_GROW_MPATH_TABLE,
MESH_WORK_GROW_MPP_TABLE,
MESH_WORK_ROOT,
+ MESH_WORK_DRIFT_ADJUST,
};
/**
@@ -86,6 +103,7 @@ enum mesh_deferred_task_flags {
* mpath itself. No need to take this lock when adding or removing
* an mpath to a hash bucket on a path table.
* @rann_snd_addr: the RANN sender address
+ * @rann_metric: the aggregated path metric towards the root node
* @is_root: the destination station of this path is a root node
* @is_gate: the destination station of this path is a mesh gate
*
@@ -112,6 +130,7 @@ struct mesh_path {
enum mesh_path_flags flags;
spinlock_t state_lock;
u8 rann_snd_addr[ETH_ALEN];
+ u32 rann_metric;
bool is_root;
bool is_gate;
};
@@ -204,7 +223,7 @@ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
struct ieee80211_sub_if_data *sdata);
bool mesh_matches_local(struct ieee802_11_elems *ie,
- struct ieee80211_sub_if_data *sdata);
+ struct ieee80211_sub_if_data *sdata, u32 basic_rates);
void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
void mesh_mgmt_ies_add(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
@@ -220,7 +239,7 @@ int mesh_add_ds_params_ie(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
int mesh_add_ht_cap_ie(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
-int mesh_add_ht_info_ie(struct sk_buff *skb,
+int mesh_add_ht_oper_ie(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
@@ -232,6 +251,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh);
+struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method);
/* Mesh paths */
int mesh_nexthop_lookup(struct sk_buff *skb,
@@ -325,6 +345,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata);
void mesh_plink_quiesce(struct sta_info *sta);
void mesh_plink_restart(struct sta_info *sta);
+void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
#else
#define mesh_allocated 0
static inline void
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 1c6f3d02aebf..503016f58631 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -86,8 +86,8 @@ static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae)
#define PERR_IE_TARGET_RCODE(x) u16_field_get(x, 13, 0)
#define MSEC_TO_TU(x) (x*1000/1024)
-#define SN_GT(x, y) ((long) (y) - (long) (x) < 0)
-#define SN_LT(x, y) ((long) (x) - (long) (y) < 0)
+#define SN_GT(x, y) ((s32)(y - x) < 0)
+#define SN_LT(x, y) ((s32)(x - y) < 0)
#define net_traversal_jiffies(s) \
msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
@@ -732,11 +732,12 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
struct ieee80211_rann_ie *rann)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
struct mesh_path *mpath;
u8 ttl, flags, hopcount;
u8 *orig_addr;
- u32 orig_sn, metric;
- u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
+ u32 orig_sn, metric, metric_txsta, interval;
bool root_is_gate;
ttl = rann->rann_ttl;
@@ -748,10 +749,11 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
flags = rann->rann_flags;
root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
orig_addr = rann->rann_addr;
- orig_sn = rann->rann_seq;
+ orig_sn = le32_to_cpu(rann->rann_seq);
+ interval = le32_to_cpu(rann->rann_interval);
hopcount = rann->rann_hopcount;
hopcount++;
- metric = rann->rann_metric;
+ metric = le32_to_cpu(rann->rann_metric);
/* Ignore our own RANNs */
if (compare_ether_addr(orig_addr, sdata->vif.addr) == 0)
@@ -761,6 +763,14 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
orig_addr, mgmt->sa, root_is_gate);
rcu_read_lock();
+ sta = sta_info_get(sdata, mgmt->sa);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+
+ metric_txsta = airtime_link_metric_get(local, sta);
+
mpath = mesh_path_lookup(orig_addr, sdata);
if (!mpath) {
mesh_path_add(orig_addr, sdata);
@@ -780,18 +790,21 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
}
- if (mpath->sn < orig_sn && ifmsh->mshcfg.dot11MeshForwarding) {
+ if ((SN_LT(mpath->sn, orig_sn) || (mpath->sn == orig_sn &&
+ metric < mpath->rann_metric)) && ifmsh->mshcfg.dot11MeshForwarding) {
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
cpu_to_le32(orig_sn),
0, NULL, 0, broadcast_addr,
hopcount, ttl, cpu_to_le32(interval),
- cpu_to_le32(metric + mpath->metric),
+ cpu_to_le32(metric + metric_txsta),
0, sdata);
mpath->sn = orig_sn;
+ mpath->rann_metric = metric + metric_txsta;
+ /* Recording RANNs sender address to send individually
+ * addressed PREQs destined for root mesh STA */
+ memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN);
}
- /* Using individually addressed PREQ for root node */
- memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN);
mpath->is_root = true;
if (root_is_gate)
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 49aaefd99635..baa6096c66b4 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -538,6 +538,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
read_lock_bh(&pathtbl_resize_lock);
memcpy(new_mpath->dst, dst, ETH_ALEN);
+ memset(new_mpath->rann_snd_addr, 0xff, ETH_ALEN);
+ new_mpath->is_root = false;
new_mpath->sdata = sdata;
new_mpath->flags = 0;
skb_queue_head_init(&new_mpath->frame_queue);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 4e53c4cbca9e..9c836e774fbd 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -187,7 +187,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
2 + sdata->u.mesh.mesh_id_len +
2 + sizeof(struct ieee80211_meshconf_ie) +
2 + sizeof(struct ieee80211_ht_cap) +
- 2 + sizeof(struct ieee80211_ht_info) +
+ 2 + sizeof(struct ieee80211_ht_operation) +
2 + 8 + /* peering IE */
sdata->u.mesh.ie_len);
if (!skb)
@@ -212,8 +212,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
pos = skb_put(skb, 2);
memcpy(pos + 2, &plid, 2);
}
- if (ieee80211_add_srates_ie(&sdata->vif, skb) ||
- ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
+ if (ieee80211_add_srates_ie(&sdata->vif, skb, true) ||
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) ||
mesh_add_rsn_ie(skb, sdata) ||
mesh_add_meshid_ie(skb, sdata) ||
mesh_add_meshconf_ie(skb, sdata))
@@ -263,7 +263,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
if (action != WLAN_SP_MESH_PEERING_CLOSE) {
if (mesh_add_ht_cap_ie(skb, sdata) ||
- mesh_add_ht_info_ie(skb, sdata))
+ mesh_add_ht_oper_ie(skb, sdata))
return -1;
}
@@ -465,6 +465,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
bool deactivated, matches_local = true;
u8 ie_len;
u8 *baseaddr;
+ u32 rates, basic_rates = 0;
__le16 plid, llid, reason;
#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
static const char *mplstates[] = {
@@ -559,8 +560,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
/* Now we will figure out the appropriate event... */
event = PLINK_UNDEFINED;
+ rates = ieee80211_sta_get_rates(local, &elems,
+ rx_status->band, &basic_rates);
+
if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
- (!mesh_matches_local(&elems, sdata))) {
+ (!mesh_matches_local(&elems, sdata, basic_rates))) {
matches_local = false;
switch (ftype) {
case WLAN_SP_MESH_PEERING_OPEN:
@@ -583,7 +587,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
return;
} else if (!sta) {
/* ftype == WLAN_SP_MESH_PEERING_OPEN */
- u32 rates;
rcu_read_unlock();
@@ -591,8 +594,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
mpl_dbg("Mesh plink error: no more free plinks\n");
return;
}
-
- rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
sta = mesh_plink_alloc(sdata, mgmt->sa, rates, &elems);
if (!sta) {
mpl_dbg("Mesh plink error: plink table full\n");
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c
new file mode 100644
index 000000000000..ff60d6bcc631
--- /dev/null
+++ b/net/mac80211/mesh_sync.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2011-2012, Pavel Zubarev <pavel.zubarev@gmail.com>
+ * Copyright 2011-2012, Marco Porsch <marco.porsch@s2005.tu-chemnitz.de>
+ * Copyright 2011-2012, cozybit Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "ieee80211_i.h"
+#include "mesh.h"
+#include "driver-ops.h"
+
+#ifdef CONFIG_MAC80211_VERBOSE_MESH_SYNC_DEBUG
+#define msync_dbg(fmt, args...) \
+ printk(KERN_DEBUG "Mesh sync (%s): " fmt "\n", sdata->name, ##args)
+#else
+#define msync_dbg(fmt, args...) do { (void)(0); } while (0)
+#endif
+
+/* This is not in the standard. It represents a tolerable tbtt drift below
+ * which we do no TSF adjustment.
+ */
+#define TOFFSET_MINIMUM_ADJUSTMENT 10
+
+/* This is not in the standard. It is a margin added to the
+ * Toffset setpoint to mitigate TSF overcorrection
+ * introduced by TSF adjustment latency.
+ */
+#define TOFFSET_SET_MARGIN 20
+
+/* This is not in the standard. It represents the maximum Toffset jump above
+ * which we'll invalidate the Toffset setpoint and choose a new setpoint. This
+ * could be, for instance, in case a neighbor is restarted and its TSF counter
+ * reset.
+ */
+#define TOFFSET_MAXIMUM_ADJUSTMENT 30000 /* 30 ms */
+
+struct sync_method {
+ u8 method;
+ struct ieee80211_mesh_sync_ops ops;
+};
+
+/**
+ * mesh_peer_tbtt_adjusting - check if an mp is currently adjusting its TBTT
+ *
+ * @ie: information elements of a management frame from the mesh peer
+ */
+static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie)
+{
+ return (ie->mesh_config->meshconf_cap &
+ MESHCONF_CAPAB_TBTT_ADJUSTING) != 0;
+}
+
+void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ /* sdata->vif.bss_conf.beacon_int in 1024us units, 0.04% */
+ u64 beacon_int_fraction = sdata->vif.bss_conf.beacon_int * 1024 / 2500;
+ u64 tsf;
+ u64 tsfdelta;
+
+ spin_lock_bh(&ifmsh->sync_offset_lock);
+
+ if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) {
+ msync_dbg("TBTT : max clockdrift=%lld; adjusting",
+ (long long) ifmsh->sync_offset_clockdrift_max);
+ tsfdelta = -ifmsh->sync_offset_clockdrift_max;
+ ifmsh->sync_offset_clockdrift_max = 0;
+ } else {
+ msync_dbg("TBTT : max clockdrift=%lld; adjusting by %llu",
+ (long long) ifmsh->sync_offset_clockdrift_max,
+ (unsigned long long) beacon_int_fraction);
+ tsfdelta = -beacon_int_fraction;
+ ifmsh->sync_offset_clockdrift_max -= beacon_int_fraction;
+ }
+
+ tsf = drv_get_tsf(local, sdata);
+ if (tsf != -1ULL)
+ drv_set_tsf(local, sdata, tsf + tsfdelta);
+ spin_unlock_bh(&ifmsh->sync_offset_lock);
+}
+
+static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
+ u16 stype,
+ struct ieee80211_mgmt *mgmt,
+ struct ieee802_11_elems *elems,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+ u64 t_t, t_r;
+
+ WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
+
+ /* standard mentions only beacons */
+ if (stype != IEEE80211_STYPE_BEACON)
+ return;
+
+ /* The current tsf is a first approximation for the timestamp
+ * for the received beacon. Further down we try to get a
+ * better value from the rx_status->mactime field if
+ * available. Also we have to call drv_get_tsf() before
+ * entering the rcu-read section.*/
+ t_r = drv_get_tsf(local, sdata);
+
+ rcu_read_lock();
+ sta = sta_info_get(sdata, mgmt->sa);
+ if (!sta)
+ goto no_sync;
+
+ /* check offset sync conditions (13.13.2.2.1)
+ *
+ * TODO also sync to
+ * dot11MeshNbrOffsetMaxNeighbor non-peer non-MBSS neighbors
+ */
+
+ if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) {
+ clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
+ msync_dbg("STA %pM : is adjusting TBTT", sta->sta.addr);
+ goto no_sync;
+ }
+
+ if (rx_status->flag & RX_FLAG_MACTIME_MPDU && rx_status->mactime) {
+ /*
+ * The mactime is defined as the time the first data symbol
+ * of the frame hits the PHY, and the timestamp of the beacon
+ * is defined as "the time that the data symbol containing the
+ * first bit of the timestamp is transmitted to the PHY plus
+ * the transmitting STA's delays through its local PHY from the
+ * MAC-PHY interface to its interface with the WM" (802.11
+ * 11.1.2)
+ *
+ * T_r, in 13.13.2.2.2, is just defined as "the frame reception
+ * time" but we unless we interpret that time to be the same
+ * time of the beacon timestamp, the offset calculation will be
+ * off. Below we adjust t_r to be "the time at which the first
+ * symbol of the timestamp element in the beacon is received".
+ * This correction depends on the rate.
+ *
+ * Based on similar code in ibss.c
+ */
+ int rate;
+
+ if (rx_status->flag & RX_FLAG_HT) {
+ /* TODO:
+ * In principle there could be HT-beacons (Dual Beacon
+ * HT Operation options), but for now ignore them and
+ * just use the primary (i.e. non-HT) beacons for
+ * synchronization.
+ * */
+ goto no_sync;
+ } else
+ rate = local->hw.wiphy->bands[rx_status->band]->
+ bitrates[rx_status->rate_idx].bitrate;
+
+ /* 24 bytes of header * 8 bits/byte *
+ * 10*(100 Kbps)/Mbps / rate (100 Kbps)*/
+ t_r = rx_status->mactime + (24 * 8 * 10 / rate);
+ }
+
+ /* Timing offset calculation (see 13.13.2.2.2) */
+ t_t = le64_to_cpu(mgmt->u.beacon.timestamp);
+ sta->t_offset = t_t - t_r;
+
+ if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
+ s64 t_clockdrift = sta->t_offset_setpoint
+ - sta->t_offset;
+ msync_dbg("STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld",
+ sta->sta.addr,
+ (long long) sta->t_offset,
+ (long long)
+ sta->t_offset_setpoint,
+ (long long) t_clockdrift);
+
+ if (t_clockdrift > TOFFSET_MAXIMUM_ADJUSTMENT ||
+ t_clockdrift < -TOFFSET_MAXIMUM_ADJUSTMENT) {
+ msync_dbg("STA %pM : t_clockdrift=%lld too large, setpoint reset",
+ sta->sta.addr,
+ (long long) t_clockdrift);
+ clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
+ goto no_sync;
+ }
+
+ rcu_read_unlock();
+
+ spin_lock_bh(&ifmsh->sync_offset_lock);
+ if (t_clockdrift >
+ ifmsh->sync_offset_clockdrift_max)
+ ifmsh->sync_offset_clockdrift_max
+ = t_clockdrift;
+ spin_unlock_bh(&ifmsh->sync_offset_lock);
+
+ } else {
+ sta->t_offset_setpoint = sta->t_offset;
+ set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
+ msync_dbg("STA %pM : offset was invalid, "
+ " sta->t_offset=%lld",
+ sta->sta.addr,
+ (long long) sta->t_offset);
+ rcu_read_unlock();
+ }
+ return;
+
+no_sync:
+ rcu_read_unlock();
+}
+
+static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+ WARN_ON(ifmsh->mesh_sp_id
+ != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
+ BUG_ON(!rcu_read_lock_held());
+
+ spin_lock_bh(&ifmsh->sync_offset_lock);
+
+ if (ifmsh->sync_offset_clockdrift_max >
+ TOFFSET_MINIMUM_ADJUSTMENT) {
+ /* Since ajusting the tsf here would
+ * require a possibly blocking call
+ * to the driver tsf setter, we punt
+ * the tsf adjustment to the mesh tasklet
+ */
+ msync_dbg("TBTT : kicking off TBTT "
+ "adjustment with "
+ "clockdrift_max=%lld",
+ ifmsh->sync_offset_clockdrift_max);
+ set_bit(MESH_WORK_DRIFT_ADJUST,
+ &ifmsh->wrkq_flags);
+ } else {
+ msync_dbg("TBTT : max clockdrift=%lld; "
+ "too small to adjust",
+ (long long)
+ ifmsh->sync_offset_clockdrift_max);
+ ifmsh->sync_offset_clockdrift_max = 0;
+ }
+ spin_unlock_bh(&ifmsh->sync_offset_lock);
+}
+
+static const u8 *mesh_get_vendor_oui(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ u8 offset;
+
+ if (!ifmsh->ie || !ifmsh->ie_len)
+ return NULL;
+
+ offset = ieee80211_ie_split_vendor(ifmsh->ie,
+ ifmsh->ie_len, 0);
+
+ if (!offset)
+ return NULL;
+
+ return ifmsh->ie + offset + 2;
+}
+
+static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
+ u16 stype,
+ struct ieee80211_mgmt *mgmt,
+ struct ieee802_11_elems *elems,
+ struct ieee80211_rx_status *rx_status)
+{
+ const u8 *oui;
+
+ WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR);
+ msync_dbg("called mesh_sync_vendor_rx_bcn_presp");
+ oui = mesh_get_vendor_oui(sdata);
+ /* here you would implement the vendor offset tracking for this oui */
+}
+
+static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
+{
+ const u8 *oui;
+
+ WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR);
+ msync_dbg("called mesh_sync_vendor_adjust_tbtt");
+ oui = mesh_get_vendor_oui(sdata);
+ /* here you would implement the vendor tsf adjustment for this oui */
+}
+
+/* global variable */
+static struct sync_method sync_methods[] = {
+ {
+ .method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
+ .ops = {
+ .rx_bcn_presp = &mesh_sync_offset_rx_bcn_presp,
+ .adjust_tbtt = &mesh_sync_offset_adjust_tbtt,
+ }
+ },
+ {
+ .method = IEEE80211_SYNC_METHOD_VENDOR,
+ .ops = {
+ .rx_bcn_presp = &mesh_sync_vendor_rx_bcn_presp,
+ .adjust_tbtt = &mesh_sync_vendor_adjust_tbtt,
+ }
+ },
+};
+
+struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method)
+{
+ struct ieee80211_mesh_sync_ops *ops = NULL;
+ u8 i;
+
+ for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) {
+ if (sync_methods[i].method == method) {
+ ops = &sync_methods[i].ops;
+ break;
+ }
+ }
+ return ops;
+}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index f76da5b3f5c5..c8836fa7d627 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -171,122 +171,64 @@ static int ecw2cw(int ecw)
return (1 << ecw) - 1;
}
-/*
- * ieee80211_enable_ht should be called only after the operating band
- * has been determined as ht configuration depends on the hw's
- * HT abilities for a specific band.
- */
-static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_ht_info *hti,
- const u8 *bssid, u16 ap_ht_cap_flags,
- bool beacon_htcap_ie)
+static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_ht_operation *ht_oper,
+ const u8 *bssid, bool reconfig)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
struct sta_info *sta;
u32 changed = 0;
- int hti_cfreq;
u16 ht_opmode;
- bool enable_ht = true;
- enum nl80211_channel_type prev_chantype;
- enum nl80211_channel_type rx_channel_type = NL80211_CHAN_NO_HT;
- enum nl80211_channel_type tx_channel_type;
+ bool disable_40 = false;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- prev_chantype = sdata->vif.bss_conf.channel_type;
-
- hti_cfreq = ieee80211_channel_to_frequency(hti->control_chan,
- sband->band);
- /* check that channel matches the right operating channel */
- if (local->hw.conf.channel->center_freq != hti_cfreq) {
- /* Some APs mess this up, evidently.
- * Netgear WNDR3700 sometimes reports 4 higher than
- * the actual channel, for instance.
- */
- printk(KERN_DEBUG
- "%s: Wrong control channel in association"
- " response: configured center-freq: %d"
- " hti-cfreq: %d hti->control_chan: %d"
- " band: %d. Disabling HT.\n",
- sdata->name,
- local->hw.conf.channel->center_freq,
- hti_cfreq, hti->control_chan,
- sband->band);
- enable_ht = false;
- }
-
- if (enable_ht) {
- rx_channel_type = NL80211_CHAN_HT20;
-
- if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
- !ieee80111_cfg_override_disables_ht40(sdata) &&
- (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
- (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
- switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
- case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
- rx_channel_type = NL80211_CHAN_HT40PLUS;
- break;
- case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
- rx_channel_type = NL80211_CHAN_HT40MINUS;
- break;
- }
- }
+ switch (sdata->vif.bss_conf.channel_type) {
+ case NL80211_CHAN_HT40PLUS:
+ if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
+ disable_40 = true;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40MINUS)
+ disable_40 = true;
+ break;
+ default:
+ break;
}
- tx_channel_type = ieee80211_get_tx_channel_type(local, rx_channel_type);
-
- if (local->tmp_channel)
- local->tmp_channel_type = rx_channel_type;
+ /* This can change during the lifetime of the BSS */
+ if (!(ht_oper->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
+ disable_40 = true;
- if (!ieee80211_set_channel_type(local, sdata, rx_channel_type)) {
- /* can only fail due to HT40+/- mismatch */
- rx_channel_type = NL80211_CHAN_HT20;
- WARN_ON(!ieee80211_set_channel_type(local, sdata,
- rx_channel_type));
- }
-
- if (beacon_htcap_ie && (prev_chantype != rx_channel_type)) {
- /*
- * Whenever the AP announces the HT mode change that can be
- * 40MHz intolerant or etc., it would be safer to stop tx
- * queues before doing hw config to avoid buffer overflow.
- */
- ieee80211_stop_queues_by_reason(&sdata->local->hw,
- IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
+ mutex_lock(&local->sta_mtx);
+ sta = sta_info_get(sdata, bssid);
- /* flush out all packets */
- synchronize_net();
+ WARN_ON_ONCE(!sta);
- drv_flush(local, false);
- }
+ if (sta && !sta->supports_40mhz)
+ disable_40 = true;
- /* channel_type change automatically detected */
- ieee80211_hw_config(local, 0);
+ if (sta && (!reconfig ||
+ (disable_40 != !!(sta->sta.ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) {
- if (prev_chantype != tx_channel_type) {
- rcu_read_lock();
- sta = sta_info_get(sdata, bssid);
- if (sta)
- rate_control_rate_update(local, sband, sta,
- IEEE80211_RC_HT_CHANGED,
- tx_channel_type);
- rcu_read_unlock();
+ if (disable_40)
+ sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ else
+ sta->sta.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- if (beacon_htcap_ie)
- ieee80211_wake_queues_by_reason(&sdata->local->hw,
- IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
+ rate_control_rate_update(local, sband, sta,
+ IEEE80211_RC_BW_CHANGED);
}
+ mutex_unlock(&local->sta_mtx);
- ht_opmode = le16_to_cpu(hti->operation_mode);
+ ht_opmode = le16_to_cpu(ht_oper->operation_mode);
/* if bss configuration changed store the new one */
- if (sdata->ht_opmode_valid != enable_ht ||
- sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
- prev_chantype != rx_channel_type) {
+ if (!reconfig || (sdata->vif.bss_conf.ht_operation_mode != ht_opmode)) {
changed |= BSS_CHANGED_HT;
sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
- sdata->ht_opmode_valid = enable_ht;
}
return changed;
@@ -316,12 +258,12 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
}
static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb, const u8 *ht_info_ie,
+ struct sk_buff *skb, const u8 *ht_oper_ie,
struct ieee80211_supported_band *sband,
struct ieee80211_channel *channel,
enum ieee80211_smps_mode smps)
{
- struct ieee80211_ht_info *ht_info;
+ struct ieee80211_ht_operation *ht_oper;
u8 *pos;
u32 flags = channel->flags;
u16 cap;
@@ -329,21 +271,21 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
- if (!ht_info_ie)
+ if (!ht_oper_ie)
return;
- if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
+ if (ht_oper_ie[1] < sizeof(struct ieee80211_ht_operation))
return;
memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
ieee80211_apply_htcap_overrides(sdata, &ht_cap);
- ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
+ ht_oper = (struct ieee80211_ht_operation *)(ht_oper_ie + 2);
/* determine capability flags */
cap = ht_cap.cap;
- switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+ switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
@@ -358,6 +300,16 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
break;
}
+ /*
+ * If 40 MHz was disabled associate as though we weren't
+ * capable of 40 MHz -- some broken APs will never fall
+ * back to trying to transmit in 20 MHz.
+ */
+ if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_40MHZ) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+
/* set SM PS mode properly */
cap &= ~IEEE80211_HT_CAP_SM_PS;
switch (smps) {
@@ -557,7 +509,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
}
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
- ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_information_ie,
+ ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_operation_ie,
sband, local->oper_channel, ifmgd->ap_smps);
/* if present, add any custom non-vendor IEs that go after HT */
@@ -1182,7 +1134,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
if (!local->ops->conf_tx)
return;
- if (local->hw.queues < 4)
+ if (local->hw.queues < IEEE80211_NUM_ACS)
return;
if (!wmm_param)
@@ -1435,7 +1387,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.assoc = false;
/* on the next assoc, re-program HT parameters */
- sdata->ht_opmode_valid = false;
memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
@@ -1496,19 +1447,24 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_local *local = sdata->local;
+ mutex_lock(&local->mtx);
if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
- IEEE80211_STA_CONNECTION_POLL)))
- return;
+ IEEE80211_STA_CONNECTION_POLL))) {
+ mutex_unlock(&local->mtx);
+ return;
+ }
ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
IEEE80211_STA_BEACON_POLL);
- mutex_lock(&sdata->local->iflist_mtx);
- ieee80211_recalc_ps(sdata->local, -1);
- mutex_unlock(&sdata->local->iflist_mtx);
+
+ mutex_lock(&local->iflist_mtx);
+ ieee80211_recalc_ps(local, -1);
+ mutex_unlock(&local->iflist_mtx);
if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
- return;
+ goto out;
/*
* We've received a probe response, but are not sure whether
@@ -1520,6 +1476,9 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
mod_timer(&ifmgd->conn_mon_timer,
round_jiffies_up(jiffies +
IEEE80211_CONNECTION_IDLE_TIME));
+out:
+ ieee80211_run_deferred_scan(local);
+ mutex_unlock(&local->mtx);
}
void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
@@ -1567,14 +1526,23 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
ifmgd->nullfunc_failed = false;
ieee80211_send_nullfunc(sdata->local, sdata, 0);
} else {
+ int ssid_len;
+
ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
- ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0,
- (u32) -1, true, false);
+ if (WARN_ON_ONCE(ssid == NULL))
+ ssid_len = 0;
+ else
+ ssid_len = ssid[1];
+
+ ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL,
+ 0, (u32) -1, true, false);
}
ifmgd->probe_send_count++;
ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
run_again(ifmgd, ifmgd->probe_timeout);
+ if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
+ drv_flush(sdata->local, false);
}
static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
@@ -1586,17 +1554,18 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
if (!ieee80211_sdata_running(sdata))
return;
- if (sdata->local->scanning)
- return;
-
- if (sdata->local->tmp_channel)
- return;
-
mutex_lock(&ifmgd->mtx);
if (!ifmgd->associated)
goto out;
+ mutex_lock(&sdata->local->mtx);
+
+ if (sdata->local->tmp_channel || sdata->local->scanning) {
+ mutex_unlock(&sdata->local->mtx);
+ goto out;
+ }
+
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (beacon && net_ratelimit())
printk(KERN_DEBUG "%s: detected beacon loss from AP "
@@ -1623,6 +1592,8 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
else
ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL;
+ mutex_unlock(&sdata->local->mtx);
+
if (already)
goto out;
@@ -1643,6 +1614,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct sk_buff *skb;
const u8 *ssid;
+ int ssid_len;
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
return NULL;
@@ -1653,8 +1625,13 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
return NULL;
ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
+ if (WARN_ON_ONCE(ssid == NULL))
+ ssid_len = 0;
+ else
+ ssid_len = ssid[1];
+
skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid,
- (u32) -1, ssid + 2, ssid[1],
+ (u32) -1, ssid + 2, ssid_len,
NULL, 0, true);
return skb;
@@ -2000,7 +1977,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
u32 changed = 0;
int err;
- u16 ap_ht_cap_flags;
/* AssocResp and ReassocResp have identical structure */
@@ -2051,7 +2027,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems.ht_cap_elem, &sta->sta.ht_cap);
- ap_ht_cap_flags = sta->sta.ht_cap.cap;
+ sta->supports_40mhz =
+ sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
rate_control_rate_init(sta);
@@ -2092,11 +2069,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
ieee80211_set_wmm_default(sdata, false);
changed |= BSS_CHANGED_QOS;
- if (elems.ht_info_elem && elems.wmm_param &&
+ if (elems.ht_operation && elems.wmm_param &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
- changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
- cbss->bssid, ap_ht_cap_flags,
- false);
+ changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
+ cbss->bssid, false);
/* set AID and assoc capability,
* ieee80211_set_associated() will tell the driver */
@@ -2319,7 +2295,7 @@ static const u64 care_about_ies =
(1ULL << WLAN_EID_CHANNEL_SWITCH) |
(1ULL << WLAN_EID_PWR_CONSTRAINT) |
(1ULL << WLAN_EID_HT_CAPABILITY) |
- (1ULL << WLAN_EID_HT_INFORMATION);
+ (1ULL << WLAN_EID_HT_OPERATION);
static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
@@ -2468,11 +2444,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
if (directed_tim) {
if (local->hw.conf.dynamic_ps_timeout > 0) {
- local->hw.conf.flags &= ~IEEE80211_CONF_PS;
- ieee80211_hw_config(local,
- IEEE80211_CONF_CHANGE_PS);
+ if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+ local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+ ieee80211_hw_config(local,
+ IEEE80211_CONF_CHANGE_PS);
+ }
ieee80211_send_nullfunc(local, sdata, 0);
- } else {
+ } else if (!local->pspolling && sdata->u.mgd.powersave) {
local->pspolling = true;
/*
@@ -2504,31 +2482,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
erp_valid, erp_value);
- if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
+ if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) {
- struct sta_info *sta;
struct ieee80211_supported_band *sband;
- u16 ap_ht_cap_flags;
-
- rcu_read_lock();
-
- sta = sta_info_get(sdata, bssid);
- if (WARN_ON(!sta)) {
- rcu_read_unlock();
- return;
- }
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
- elems.ht_cap_elem, &sta->sta.ht_cap);
-
- ap_ht_cap_flags = sta->sta.ht_cap.cap;
-
- rcu_read_unlock();
-
- changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
- bssid, ap_ht_cap_flags, true);
+ changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
+ bssid, true);
}
/* Note: country IE parsing is done for us by cfg80211 */
@@ -3060,6 +3021,11 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta;
bool have_sta = false;
int err;
+ int ht_cfreq;
+ enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+ const u8 *ht_oper_ie;
+ const struct ieee80211_ht_operation *ht_oper = NULL;
+ struct ieee80211_supported_band *sband;
if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data))
return -EINVAL;
@@ -3081,17 +3047,76 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
mutex_unlock(&local->mtx);
/* switch to the right channel */
+ sband = local->hw.wiphy->bands[cbss->channel->band];
+
+ ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ;
+
+ if (sband->ht_cap.ht_supported) {
+ ht_oper_ie = cfg80211_find_ie(WLAN_EID_HT_OPERATION,
+ cbss->information_elements,
+ cbss->len_information_elements);
+ if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper))
+ ht_oper = (void *)(ht_oper_ie + 2);
+ }
+
+ if (ht_oper) {
+ ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
+ cbss->channel->band);
+ /* check that channel matches the right operating channel */
+ if (cbss->channel->center_freq != ht_cfreq) {
+ /*
+ * It's possible that some APs are confused here;
+ * Netgear WNDR3700 sometimes reports 4 higher than
+ * the actual channel in association responses, but
+ * since we look at probe response/beacon data here
+ * it should be OK.
+ */
+ printk(KERN_DEBUG
+ "%s: Wrong control channel: center-freq: %d"
+ " ht-cfreq: %d ht->primary_chan: %d"
+ " band: %d. Disabling HT.\n",
+ sdata->name, cbss->channel->center_freq,
+ ht_cfreq, ht_oper->primary_chan,
+ cbss->channel->band);
+ ht_oper = NULL;
+ }
+ }
+
+ if (ht_oper) {
+ channel_type = NL80211_CHAN_HT20;
+
+ if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+ switch (ht_oper->ht_param &
+ IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ channel_type = NL80211_CHAN_HT40PLUS;
+ break;
+ case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+ channel_type = NL80211_CHAN_HT40MINUS;
+ break;
+ }
+ }
+ }
+
+ if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
+ /* can only fail due to HT40+/- mismatch */
+ channel_type = NL80211_CHAN_HT20;
+ printk(KERN_DEBUG
+ "%s: disabling 40 MHz due to multi-vif mismatch\n",
+ sdata->name);
+ ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
+ WARN_ON(!ieee80211_set_channel_type(local, sdata,
+ channel_type));
+ }
+
local->oper_channel = cbss->channel;
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+ ieee80211_hw_config(local, 0);
if (!have_sta) {
- struct ieee80211_supported_band *sband;
u32 rates = 0, basic_rates = 0;
bool have_higher_than_11mbit;
int min_rate = INT_MAX, min_rate_index = -1;
- sband = sdata->local->hw.wiphy->bands[cbss->channel->band];
-
ieee80211_get_rates(sband, bss->supp_rates,
bss->supp_rates_len,
&rates, &basic_rates,
@@ -3311,7 +3336,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
/* Also disable HT if we don't support it or the AP doesn't use WMM */
sband = local->hw.wiphy->bands[req->bss->channel->band];
if (!sband->ht_cap.ht_supported ||
- local->hw.queues < 4 || !bss->wmm_used)
+ local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used)
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
@@ -3334,11 +3359,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
ifmgd->ap_smps = ifmgd->req_smps;
assoc_data->capability = req->bss->capability;
- assoc_data->wmm = bss->wmm_used && (local->hw.queues >= 4);
+ assoc_data->wmm = bss->wmm_used &&
+ (local->hw.queues >= IEEE80211_NUM_ACS);
assoc_data->supp_rates = bss->supp_rates;
assoc_data->supp_rates_len = bss->supp_rates_len;
- assoc_data->ht_information_ie =
- ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION);
+ assoc_data->ht_operation_ie =
+ ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
if (bss->wmm_used && bss->uapsd_supported &&
(sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index ef8eba1d736d..af1c4e26e965 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -127,6 +127,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
drv_remove_interface(local, sdata);
}
+ sdata = rtnl_dereference(local->monitor_sdata);
+ if (sdata)
+ drv_remove_interface(local, sdata);
+
/* stop hardware - this must stop RX */
if (local->open_count)
ieee80211_stop_device(local);
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index fbb1efdc4d04..6e4fd32c6617 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -17,6 +17,7 @@
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "sta_info.h"
+#include "driver-ops.h"
struct rate_control_ref {
struct ieee80211_local *local;
@@ -63,8 +64,7 @@ static inline void rate_control_rate_init(struct sta_info *sta)
static inline void rate_control_rate_update(struct ieee80211_local *local,
struct ieee80211_supported_band *sband,
- struct sta_info *sta, u32 changed,
- enum nl80211_channel_type oper_chan_type)
+ struct sta_info *sta, u32 changed)
{
struct rate_control_ref *ref = local->rate_ctrl;
struct ieee80211_sta *ista = &sta->sta;
@@ -72,7 +72,8 @@ static inline void rate_control_rate_update(struct ieee80211_local *local,
if (ref && ref->ops->rate_update)
ref->ops->rate_update(ref->priv, sband, ista,
- priv_sta, changed, oper_chan_type);
+ priv_sta, changed);
+ drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
}
static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index b39dda523f39..79633ae06fd6 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -334,14 +334,15 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
static void
-calc_rate_durations(struct ieee80211_local *local, struct minstrel_rate *d,
+calc_rate_durations(enum ieee80211_band band,
+ struct minstrel_rate *d,
struct ieee80211_rate *rate)
{
int erp = !!(rate->flags & IEEE80211_RATE_ERP_G);
- d->perfect_tx_time = ieee80211_frame_duration(local, 1200,
+ d->perfect_tx_time = ieee80211_frame_duration(band, 1200,
rate->bitrate, erp, 1);
- d->ack_time = ieee80211_frame_duration(local, 10,
+ d->ack_time = ieee80211_frame_duration(band, 10,
rate->bitrate, erp, 1);
}
@@ -379,14 +380,14 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
{
struct minstrel_sta_info *mi = priv_sta;
struct minstrel_priv *mp = priv;
- struct ieee80211_local *local = hw_to_local(mp->hw);
struct ieee80211_rate *ctl_rate;
unsigned int i, n = 0;
unsigned int t_slot = 9; /* FIXME: get real slot time */
mi->lowest_rix = rate_lowest_index(sband, sta);
ctl_rate = &sband->bitrates[mi->lowest_rix];
- mi->sp_ack_dur = ieee80211_frame_duration(local, 10, ctl_rate->bitrate,
+ mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10,
+ ctl_rate->bitrate,
!!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1);
for (i = 0; i < sband->n_bitrates; i++) {
@@ -402,7 +403,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
mr->rix = i;
mr->bitrate = sband->bitrates[i].bitrate / 5;
- calc_rate_durations(local, mr, &sband->bitrates[i]);
+ calc_rate_durations(sband->band, mr, &sband->bitrates[i]);
/* calculate maximum number of retransmissions before
* fallback (based on maximum segment size) */
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 16e0b277b9a8..2d1acc6c5445 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -686,14 +686,12 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
static void
minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
- struct ieee80211_sta *sta, void *priv_sta,
- enum nl80211_channel_type oper_chan_type)
+ struct ieee80211_sta *sta, void *priv_sta)
{
struct minstrel_priv *mp = priv;
struct minstrel_ht_sta_priv *msp = priv_sta;
struct minstrel_ht_sta *mi = &msp->ht;
struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
- struct ieee80211_local *local = hw_to_local(mp->hw);
u16 sta_cap = sta->ht_cap.cap;
int n_supported = 0;
int ack_dur;
@@ -712,8 +710,8 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
memset(mi, 0, sizeof(*mi));
mi->stats_update = jiffies;
- ack_dur = ieee80211_frame_duration(local, 10, 60, 1, 1);
- mi->overhead = ieee80211_frame_duration(local, 0, 60, 1, 1) + ack_dur;
+ ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1);
+ mi->overhead = ieee80211_frame_duration(sband->band, 0, 60, 1, 1) + ack_dur;
mi->overhead_rtscts = mi->overhead + 2 * ack_dur;
mi->avg_ampdu_len = MINSTREL_FRAC(1, 1);
@@ -735,10 +733,6 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
- if (oper_chan_type != NL80211_CHAN_HT40MINUS &&
- oper_chan_type != NL80211_CHAN_HT40PLUS)
- sta_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-
smps = (sta_cap & IEEE80211_HT_CAP_SM_PS) >>
IEEE80211_HT_CAP_SM_PS_SHIFT;
@@ -788,17 +782,15 @@ static void
minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta)
{
- struct minstrel_priv *mp = priv;
-
- minstrel_ht_update_caps(priv, sband, sta, priv_sta, mp->hw->conf.channel_type);
+ minstrel_ht_update_caps(priv, sband, sta, priv_sta);
}
static void
minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
- u32 changed, enum nl80211_channel_type oper_chan_type)
+ u32 changed)
{
- minstrel_ht_update_caps(priv, sband, sta, priv_sta, oper_chan_type);
+ minstrel_ht_update_caps(priv, sband, sta, priv_sta);
}
static void *
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index d64e285400aa..7cbb4aad0577 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -794,8 +794,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
/* reset session timer */
if (tid_agg_rx->timeout)
- mod_timer(&tid_agg_rx->session_timer,
- TU_TO_EXP_TIME(tid_agg_rx->timeout));
+ tid_agg_rx->last_rx = jiffies;
/* if this mpdu is fragmented - terminate rx aggregation session */
sc = le16_to_cpu(hdr->seq_ctrl);
@@ -2270,11 +2269,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
sband = rx->local->hw.wiphy->bands[status->band];
- rate_control_rate_update(
- local, sband, rx->sta,
- IEEE80211_RC_SMPS_CHANGED,
- ieee80211_get_tx_channel_type(
- local, local->_oper_channel_type));
+ rate_control_rate_update(local, sband, rx->sta,
+ IEEE80211_RC_SMPS_CHANGED);
goto handled;
}
default:
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index c70e17677135..45f5aa229efd 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -29,20 +29,6 @@
#define IEEE80211_CHANNEL_TIME (HZ / 33)
#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8)
-struct ieee80211_bss *
-ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
- u8 *ssid, u8 ssid_len)
-{
- struct cfg80211_bss *cbss;
-
- cbss = cfg80211_get_bss(local->hw.wiphy,
- ieee80211_get_channel(local->hw.wiphy, freq),
- bssid, ssid, ssid_len, 0, 0);
- if (!cbss)
- return NULL;
- return (void *)cbss->priv;
-}
-
static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
{
struct ieee80211_bss *bss = (void *)cbss->priv;
@@ -387,6 +373,33 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
return 0;
}
+static bool ieee80211_can_scan(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ if (!list_empty(&local->work_list))
+ return false;
+
+ if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+ sdata->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))
+ return false;
+
+ return true;
+}
+
+void ieee80211_run_deferred_scan(struct ieee80211_local *local)
+{
+ lockdep_assert_held(&local->mtx);
+
+ if (!local->scan_req || local->scanning)
+ return;
+
+ if (!ieee80211_can_scan(local, local->scan_sdata))
+ return;
+
+ ieee80211_queue_delayed_work(&local->hw, &local->scan_work,
+ round_jiffies_relative(0));
+}
static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
struct cfg80211_scan_request *req)
@@ -399,7 +412,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
if (local->scan_req)
return -EBUSY;
- if (!list_empty(&local->work_list)) {
+ if (!ieee80211_can_scan(local, sdata)) {
/* wait for the work to finish/time out */
local->scan_req = req;
local->scan_sdata = sdata;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 38137cb5f6f0..7fd7ac48f893 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1195,13 +1195,15 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
ieee80211_is_qos_nullfunc(hdr->frame_control))
qoshdr = ieee80211_get_qos_ctl(hdr);
- /* set EOSP for the frame */
- if (reason == IEEE80211_FRAME_RELEASE_UAPSD &&
- qoshdr && skb_queue_empty(&frames))
- *qoshdr |= IEEE80211_QOS_CTL_EOSP;
-
- info->flags |= IEEE80211_TX_STATUS_EOSP |
- IEEE80211_TX_CTL_REQ_TX_STATUS;
+ /* end service period after last frame */
+ if (skb_queue_empty(&frames)) {
+ if (reason == IEEE80211_FRAME_RELEASE_UAPSD &&
+ qoshdr)
+ *qoshdr |= IEEE80211_QOS_CTL_EOSP;
+
+ info->flags |= IEEE80211_TX_STATUS_EOSP |
+ IEEE80211_TX_CTL_REQ_TX_STATUS;
+ }
if (qoshdr)
tids |= BIT(*qoshdr & IEEE80211_QOS_CTL_TID_MASK);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index ab0576827baf..f75f5d9ac06d 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -55,6 +55,7 @@
* @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame.
* @WLAN_STA_INSERTED: This station is inserted into the hash table.
* @WLAN_STA_RATE_CONTROL: rate control was initialized for this station.
+ * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid.
*/
enum ieee80211_sta_info_flags {
WLAN_STA_AUTH,
@@ -76,6 +77,7 @@ enum ieee80211_sta_info_flags {
WLAN_STA_4ADDR_EVENT,
WLAN_STA_INSERTED,
WLAN_STA_RATE_CONTROL,
+ WLAN_STA_TOFFSET_KNOWN,
};
#define STA_TID_NUM 16
@@ -101,6 +103,7 @@ enum ieee80211_sta_info_flags {
* @dialog_token: dialog token for aggregation session
* @timeout: session timeout value to be filled in ADDBA requests
* @state: session state (see above)
+ * @last_tx: jiffies of last tx activity
* @stop_initiator: initiator of a session stop
* @tx_stop: TX DelBA frame when stopping
* @buf_size: reorder buffer size at receiver
@@ -122,6 +125,7 @@ struct tid_ampdu_tx {
struct timer_list addba_resp_timer;
struct sk_buff_head pending;
unsigned long state;
+ unsigned long last_tx;
u16 timeout;
u8 dialog_token;
u8 stop_initiator;
@@ -139,6 +143,7 @@ struct tid_ampdu_tx {
* @reorder_time: jiffies when skb was added
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
* @reorder_timer: releases expired frames from the reorder buffer.
+ * @last_rx: jiffies of last rx activity
* @head_seq_num: head sequence number in reordering buffer.
* @stored_mpdu_num: number of MPDUs in reordering buffer
* @ssn: Starting Sequence Number expected to be aggregated.
@@ -163,6 +168,7 @@ struct tid_ampdu_rx {
unsigned long *reorder_time;
struct timer_list session_timer;
struct timer_list reorder_timer;
+ unsigned long last_rx;
u16 head_seq_num;
u16 stored_mpdu_num;
u16 ssn;
@@ -264,6 +270,7 @@ struct sta_ampdu_mlme {
* @plink_timeout: timeout of peer link
* @plink_timer: peer link watch timer
* @plink_timer_was_running: used by suspend/resume to restore timers
+ * @t_offset: timing offset relative to this host
* @debugfs: debug filesystem info
* @dead: set to true when sta is unlinked
* @uploaded: set to true when sta is uploaded to the driver
@@ -353,6 +360,8 @@ struct sta_info {
enum nl80211_plink_state plink_state;
u32 plink_timeout;
struct timer_list plink_timer;
+ s64 t_offset;
+ s64 t_offset_setpoint;
#endif
#ifdef CONFIG_MAC80211_DEBUGFS
@@ -365,6 +374,8 @@ struct sta_info {
unsigned int lost_packets;
unsigned int beacon_loss_count;
+ bool supports_40mhz;
+
/* keep last! */
struct ieee80211_sta sta;
};
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 5f8f89e89d6b..05f257aa2e08 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -355,7 +355,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
int rtap_len;
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
- if (info->status.rates[i].idx < 0) {
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+ !(info->flags & IEEE80211_TX_STAT_AMPDU)) {
+ /* just the first aggr frame carry status info */
+ info->status.rates[i].idx = -1;
+ info->status.rates[i].count = 0;
+ break;
+ } else if (info->status.rates[i].idx < 0) {
break;
} else if (i >= hw->max_report_rates) {
/* the HW cannot have attempted that rate */
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 782a60198df4..0abbef952c14 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -159,7 +159,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
/* Time needed to transmit ACK
* (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up
* to closest integer */
- dur = ieee80211_frame_duration(local, 10, rate, erp,
+ dur = ieee80211_frame_duration(sband->band, 10, rate, erp,
tx->sdata->vif.bss_conf.use_short_preamble);
if (next_frag_len) {
@@ -167,7 +167,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
* transmit next fragment plus ACK and 2 x SIFS. */
dur *= 2; /* ACK + SIFS */
/* next fragment */
- dur += ieee80211_frame_duration(local, next_frag_len,
+ dur += ieee80211_frame_duration(sband->band, next_frag_len,
txrate->bitrate, erp,
tx->sdata->vif.bss_conf.use_short_preamble);
}
@@ -230,9 +230,9 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
* changed via debugfs, user needs to reassociate manually to have
* everything in sync.
*/
- if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
- && (ifmgd->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
- && skb_get_queue_mapping(tx->skb) == 0)
+ if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) &&
+ (ifmgd->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) &&
+ skb_get_queue_mapping(tx->skb) == IEEE80211_AC_VO)
return TX_CONTINUE;
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
@@ -400,6 +400,8 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
return TX_CONTINUE;
info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
+ if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
+ info->hw_queue = tx->sdata->vif.cab_queue;
/* device releases frame after DTIM beacon */
if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING))
@@ -1118,8 +1120,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
/* reset session timer */
if (reset_agg_timer && tid_tx->timeout)
- mod_timer(&tid_tx->session_timer,
- TU_TO_EXP_TIME(tid_tx->timeout));
+ tid_tx->last_tx = jiffies;
return queued;
}
@@ -1215,11 +1216,19 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
bool txpending)
{
struct sk_buff *skb, *tmp;
- struct ieee80211_tx_info *info;
unsigned long flags;
skb_queue_walk_safe(skbs, skb, tmp) {
- int q = skb_get_queue_mapping(skb);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int q = info->hw_queue;
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ if (WARN_ON_ONCE(q >= local->hw.queues)) {
+ __skb_unlink(skb, skbs);
+ dev_kfree_skb(skb);
+ continue;
+ }
+#endif
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
if (local->queue_stop_reasons[q] ||
@@ -1241,7 +1250,6 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
- info = IEEE80211_SKB_CB(skb);
info->control.vif = vif;
info->control.sta = sta;
@@ -1284,8 +1292,16 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR:
- sdata = NULL;
- vif = NULL;
+ sdata = rcu_dereference(local->monitor_sdata);
+ if (sdata) {
+ vif = &sdata->vif;
+ info->hw_queue =
+ vif->hw_queue[skb_get_queue_mapping(skb)];
+ } else if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) {
+ dev_kfree_skb(skb);
+ return true;
+ } else
+ vif = NULL;
break;
case NL80211_IFTYPE_AP_VLAN:
sdata = container_of(sdata->bss,
@@ -1400,6 +1416,12 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
tx.channel = local->hw.conf.channel;
info->band = tx.channel->band;
+ /* set up hw_queue value early */
+ if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ||
+ !(local->hw.flags & IEEE80211_HW_QUEUE_CONTROL))
+ info->hw_queue =
+ sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
+
if (!invoke_tx_handlers(&tx))
result = __ieee80211_tx(local, &tx.skbs, led_len,
tx.sta, txpending);
@@ -1468,12 +1490,12 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
if (ieee80211_vif_is_mesh(&sdata->vif) &&
ieee80211_is_data(hdr->frame_control) &&
- !is_multicast_ether_addr(hdr->addr1))
- if (mesh_nexthop_resolve(skb, sdata)) {
- /* skb queued: don't free */
- rcu_read_unlock();
- return;
- }
+ !is_multicast_ether_addr(hdr->addr1) &&
+ mesh_nexthop_resolve(skb, sdata)) {
+ /* skb queued: don't free */
+ rcu_read_unlock();
+ return;
+ }
ieee80211_set_qos_hdr(sdata, skb);
ieee80211_tx(sdata, skb, false);
@@ -1929,7 +1951,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
wme_sta = true;
/* receiver and we are QoS enabled, use a QoS type frame */
- if (wme_sta && local->hw.queues >= 4) {
+ if (wme_sta && local->hw.queues >= IEEE80211_NUM_ACS) {
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
hdrlen += 2;
}
@@ -2170,7 +2192,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
void ieee80211_tx_pending(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *)data;
- struct ieee80211_sub_if_data *sdata;
unsigned long flags;
int i;
bool txok;
@@ -2207,8 +2228,7 @@ void ieee80211_tx_pending(unsigned long data)
}
if (skb_queue_empty(&local->pending[i]))
- list_for_each_entry_rcu(sdata, &local->interfaces, list)
- netif_wake_subqueue(sdata->dev, i);
+ ieee80211_propagate_queue_wake(local, i);
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
@@ -2374,6 +2394,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
IEEE80211_STYPE_BEACON);
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
struct ieee80211_mgmt *mgmt;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 *pos;
int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
sizeof(mgmt->u.beacon);
@@ -2383,6 +2404,10 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
goto out;
#endif
+ if (ifmsh->sync_ops)
+ ifmsh->sync_ops->adjust_tbtt(
+ sdata);
+
skb = dev_alloc_skb(local->tx_headroom +
hdr_len +
2 + /* NULL SSID */
@@ -2390,7 +2415,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2 + 3 + /* DS params */
2 + (IEEE80211_MAX_SUPP_RATES - 8) +
2 + sizeof(struct ieee80211_ht_cap) +
- 2 + sizeof(struct ieee80211_ht_info) +
+ 2 + sizeof(struct ieee80211_ht_operation) +
2 + sdata->u.mesh.mesh_id_len +
2 + sizeof(struct ieee80211_meshconf_ie) +
sdata->u.mesh.ie_len);
@@ -2414,12 +2439,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
*pos++ = WLAN_EID_SSID;
*pos++ = 0x0;
- if (ieee80211_add_srates_ie(&sdata->vif, skb) ||
+ if (ieee80211_add_srates_ie(&sdata->vif, skb, true) ||
mesh_add_ds_params_ie(skb, sdata) ||
- ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) ||
mesh_add_rsn_ie(skb, sdata) ||
mesh_add_ht_cap_ie(skb, sdata) ||
- mesh_add_ht_info_ie(skb, sdata) ||
+ mesh_add_ht_oper_ie(skb, sdata) ||
mesh_add_meshid_ie(skb, sdata) ||
mesh_add_meshconf_ie(skb, sdata) ||
mesh_add_vendor_ies(skb, sdata)) {
@@ -2603,7 +2628,7 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,
pos = skb_put(skb, ie_ssid_len);
*pos++ = WLAN_EID_SSID;
*pos++ = ssid_len;
- if (ssid)
+ if (ssid_len)
memcpy(pos, ssid, ssid_len);
pos += ssid_len;
@@ -2710,11 +2735,13 @@ EXPORT_SYMBOL(ieee80211_get_buffered_bc);
void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int tid)
{
+ int ac = ieee802_1d_to_ac[tid];
+
skb_set_mac_header(skb, 0);
skb_set_network_header(skb, 0);
skb_set_transport_header(skb, 0);
- skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
+ skb_set_queue_mapping(skb, ac);
skb->priority = tid;
/*
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 32f7a3b3d43c..89c1e5b9ba94 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -106,7 +106,7 @@ void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
}
}
-int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
+int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
int rate, int erp, int short_preamble)
{
int dur;
@@ -120,7 +120,7 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
* DIV_ROUND_UP() operations.
*/
- if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) {
+ if (band == IEEE80211_BAND_5GHZ || erp) {
/*
* OFDM:
*
@@ -162,10 +162,10 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
/* Exported duration function for driver use */
__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
+ enum ieee80211_band band,
size_t frame_len,
struct ieee80211_rate *rate)
{
- struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
u16 dur;
int erp;
@@ -179,7 +179,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
erp = rate->flags & IEEE80211_RATE_ERP_G;
}
- dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp,
+ dur = ieee80211_frame_duration(band, frame_len, rate->bitrate, erp,
short_preamble);
return cpu_to_le16(dur);
@@ -198,7 +198,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
u16 dur;
struct ieee80211_supported_band *sband;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[frame_txctl->band];
short_preamble = false;
@@ -213,13 +213,13 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
}
/* CTS duration */
- dur = ieee80211_frame_duration(local, 10, rate->bitrate,
+ dur = ieee80211_frame_duration(sband->band, 10, rate->bitrate,
erp, short_preamble);
/* Data frame duration */
- dur += ieee80211_frame_duration(local, frame_len, rate->bitrate,
+ dur += ieee80211_frame_duration(sband->band, frame_len, rate->bitrate,
erp, short_preamble);
/* ACK duration */
- dur += ieee80211_frame_duration(local, 10, rate->bitrate,
+ dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate,
erp, short_preamble);
return cpu_to_le16(dur);
@@ -239,7 +239,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
u16 dur;
struct ieee80211_supported_band *sband;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[frame_txctl->band];
short_preamble = false;
@@ -253,11 +253,11 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
}
/* Data frame duration */
- dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
+ dur = ieee80211_frame_duration(sband->band, frame_len, rate->bitrate,
erp, short_preamble);
if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) {
/* ACK duration */
- dur += ieee80211_frame_duration(local, 10, rate->bitrate,
+ dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate,
erp, short_preamble);
}
@@ -265,17 +265,45 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_ctstoself_duration);
+void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ int ac;
+
+ if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
+ continue;
+
+ if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE &&
+ local->queue_stop_reasons[sdata->vif.cab_queue] != 0)
+ continue;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ int ac_queue = sdata->vif.hw_queue[ac];
+
+ if (ac_queue == queue ||
+ (sdata->vif.cab_queue == queue &&
+ local->queue_stop_reasons[ac_queue] == 0 &&
+ skb_queue_empty(&local->pending[ac_queue])))
+ netif_wake_subqueue(sdata->dev, ac);
+ }
+ }
+}
+
static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_sub_if_data *sdata;
trace_wake_queue(local, queue, reason);
if (WARN_ON(queue >= hw->queues))
return;
+ if (!test_bit(reason, &local->queue_stop_reasons[queue]))
+ return;
+
__clear_bit(reason, &local->queue_stop_reasons[queue]);
if (local->queue_stop_reasons[queue] != 0)
@@ -284,11 +312,7 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
if (skb_queue_empty(&local->pending[queue])) {
rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
- continue;
- netif_wake_subqueue(sdata->dev, queue);
- }
+ ieee80211_propagate_queue_wake(local, queue);
rcu_read_unlock();
} else
tasklet_schedule(&local->tx_pending_tasklet);
@@ -323,11 +347,21 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
if (WARN_ON(queue >= hw->queues))
return;
+ if (test_bit(reason, &local->queue_stop_reasons[queue]))
+ return;
+
__set_bit(reason, &local->queue_stop_reasons[queue]);
rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces, list)
- netif_stop_subqueue(sdata->dev, queue);
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ int ac;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ if (sdata->vif.hw_queue[ac] == queue ||
+ sdata->vif.cab_queue == queue)
+ netif_stop_subqueue(sdata->dev, ac);
+ }
+ }
rcu_read_unlock();
}
@@ -354,8 +388,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
{
struct ieee80211_hw *hw = &local->hw;
unsigned long flags;
- int queue = skb_get_queue_mapping(skb);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int queue = info->hw_queue;
if (WARN_ON(!info->control.vif)) {
kfree_skb(skb);
@@ -379,10 +413,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
int queue, i;
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- for (i = 0; i < hw->queues; i++)
- __ieee80211_stop_queue(hw, i,
- IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
-
while ((skb = skb_dequeue(skbs))) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -391,7 +421,11 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
continue;
}
- queue = skb_get_queue_mapping(skb);
+ queue = info->hw_queue;
+
+ __ieee80211_stop_queue(hw, queue,
+ IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+
__skb_queue_tail(&local->pending[queue], skb);
}
@@ -404,12 +438,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
-void ieee80211_add_pending_skbs(struct ieee80211_local *local,
- struct sk_buff_head *skbs)
-{
- ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
-}
-
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason)
{
@@ -684,9 +712,9 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
else
elem_parse_failed = true;
break;
- case WLAN_EID_HT_INFORMATION:
- if (elen >= sizeof(struct ieee80211_ht_info))
- elems->ht_info_elem = (void *)pos;
+ case WLAN_EID_HT_OPERATION:
+ if (elen >= sizeof(struct ieee80211_ht_operation))
+ elems->ht_operation = (void *)pos;
else
elem_parse_failed = true;
break;
@@ -775,19 +803,22 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_queue_params qparam;
- int queue;
+ int ac;
bool use_11b;
int aCWmin, aCWmax;
if (!local->ops->conf_tx)
return;
+ if (local->hw.queues < IEEE80211_NUM_ACS)
+ return;
+
memset(&qparam, 0, sizeof(qparam));
use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
- for (queue = 0; queue < local->hw.queues; queue++) {
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
/* Set defaults according to 802.11-2007 Table 7-37 */
aCWmax = 1023;
if (use_11b)
@@ -795,21 +826,21 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
else
aCWmin = 15;
- switch (queue) {
- case 3: /* AC_BK */
+ switch (ac) {
+ case IEEE80211_AC_BK:
qparam.cw_max = aCWmax;
qparam.cw_min = aCWmin;
qparam.txop = 0;
qparam.aifs = 7;
break;
default: /* never happens but let's not leave undefined */
- case 2: /* AC_BE */
+ case IEEE80211_AC_BE:
qparam.cw_max = aCWmax;
qparam.cw_min = aCWmin;
qparam.txop = 0;
qparam.aifs = 3;
break;
- case 1: /* AC_VI */
+ case IEEE80211_AC_VI:
qparam.cw_max = aCWmin;
qparam.cw_min = (aCWmin + 1) / 2 - 1;
if (use_11b)
@@ -818,7 +849,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
qparam.txop = 3008/32;
qparam.aifs = 2;
break;
- case 0: /* AC_VO */
+ case IEEE80211_AC_VO:
qparam.cw_max = (aCWmin + 1) / 2 - 1;
qparam.cw_min = (aCWmin + 1) / 4 - 1;
if (use_11b)
@@ -831,8 +862,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
qparam.uapsd = false;
- sdata->tx_conf[queue] = qparam;
- drv_conf_tx(local, sdata, queue, &qparam);
+ sdata->tx_conf[ac] = qparam;
+ drv_conf_tx(local, sdata, ac, &qparam);
}
/* after reinitialize QoS TX queues setting to default,
@@ -878,10 +909,8 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
int i;
sband = local->hw.wiphy->bands[band];
- if (!sband) {
- WARN_ON(1);
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- }
+ if (WARN_ON(!sband))
+ return 1;
if (band == IEEE80211_BAND_2GHZ)
mandatory_flag = IEEE80211_RATE_MANDATORY_B;
@@ -1106,7 +1135,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
struct ieee802_11_elems *elems,
- enum ieee80211_band band)
+ enum ieee80211_band band, u32 *basic_rates)
{
struct ieee80211_supported_band *sband;
struct ieee80211_rate *bitrates;
@@ -1115,10 +1144,8 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
int i, j;
sband = local->hw.wiphy->bands[band];
- if (!sband) {
- WARN_ON(1);
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- }
+ if (WARN_ON(!sband))
+ return 1;
bitrates = sband->bitrates;
num_rates = sband->n_bitrates;
@@ -1127,15 +1154,25 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
elems->ext_supp_rates_len; i++) {
u8 rate = 0;
int own_rate;
+ bool is_basic;
if (i < elems->supp_rates_len)
rate = elems->supp_rates[i];
else if (elems->ext_supp_rates)
rate = elems->ext_supp_rates
[i - elems->supp_rates_len];
own_rate = 5 * (rate & 0x7f);
- for (j = 0; j < num_rates; j++)
- if (bitrates[j].bitrate == own_rate)
+ is_basic = !!(rate & 0x80);
+
+ if (is_basic && (rate & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
+ continue;
+
+ for (j = 0; j < num_rates; j++) {
+ if (bitrates[j].bitrate == own_rate) {
supp_rates |= BIT(j);
+ if (basic_rates && is_basic)
+ *basic_rates |= BIT(j);
+ }
+ }
}
return supp_rates;
}
@@ -1210,6 +1247,16 @@ int ieee80211_reconfig(struct ieee80211_local *local)
IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
/* add interfaces */
+ sdata = rtnl_dereference(local->monitor_sdata);
+ if (sdata) {
+ res = drv_add_interface(local, sdata);
+ if (WARN_ON(res)) {
+ rcu_assign_pointer(local->monitor_sdata, NULL);
+ synchronize_net();
+ kfree(sdata);
+ }
+ }
+
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_MONITOR &&
@@ -1232,14 +1279,17 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mutex_unlock(&local->sta_mtx);
/* reconfigure tx conf */
- list_for_each_entry(sdata, &local->interfaces, list) {
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
- sdata->vif.type == NL80211_IFTYPE_MONITOR ||
- !ieee80211_sdata_running(sdata))
- continue;
+ if (hw->queues >= IEEE80211_NUM_ACS) {
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+ sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+ !ieee80211_sdata_running(sdata))
+ continue;
- for (i = 0; i < hw->queues; i++)
- drv_conf_tx(local, sdata, i, &sdata->tx_conf[i]);
+ for (i = 0; i < IEEE80211_NUM_ACS; i++)
+ drv_conf_tx(local, sdata, i,
+ &sdata->tx_conf[i]);
+ }
}
/* reconfigure hardware */
@@ -1611,57 +1661,56 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
return pos;
}
-u8 *ieee80211_ie_build_ht_info(u8 *pos,
- struct ieee80211_sta_ht_cap *ht_cap,
+u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
struct ieee80211_channel *channel,
enum nl80211_channel_type channel_type)
{
- struct ieee80211_ht_info *ht_info;
+ struct ieee80211_ht_operation *ht_oper;
/* Build HT Information */
- *pos++ = WLAN_EID_HT_INFORMATION;
- *pos++ = sizeof(struct ieee80211_ht_info);
- ht_info = (struct ieee80211_ht_info *)pos;
- ht_info->control_chan =
+ *pos++ = WLAN_EID_HT_OPERATION;
+ *pos++ = sizeof(struct ieee80211_ht_operation);
+ ht_oper = (struct ieee80211_ht_operation *)pos;
+ ht_oper->primary_chan =
ieee80211_frequency_to_channel(channel->center_freq);
switch (channel_type) {
case NL80211_CHAN_HT40MINUS:
- ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
break;
case NL80211_CHAN_HT40PLUS:
- ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
break;
case NL80211_CHAN_HT20:
default:
- ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
break;
}
if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
- ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
+ ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
/*
* Note: According to 802.11n-2009 9.13.3.1, HT Protection field and
* RIFS Mode are reserved in IBSS mode, therefore keep them at 0
*/
- ht_info->operation_mode = 0x0000;
- ht_info->stbc_param = 0x0000;
+ ht_oper->operation_mode = 0x0000;
+ ht_oper->stbc_param = 0x0000;
/* It seems that Basic MCS set and Supported MCS set
are identical for the first 10 bytes */
- memset(&ht_info->basic_set, 0, 16);
- memcpy(&ht_info->basic_set, &ht_cap->mcs, 10);
+ memset(&ht_oper->basic_set, 0, 16);
+ memcpy(&ht_oper->basic_set, &ht_cap->mcs, 10);
- return pos + sizeof(struct ieee80211_ht_info);
+ return pos + sizeof(struct ieee80211_ht_operation);
}
enum nl80211_channel_type
-ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info)
+ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper)
{
enum nl80211_channel_type channel_type;
- if (!ht_info)
+ if (!ht_oper)
return NL80211_CHAN_NO_HT;
- switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+ switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_NONE:
channel_type = NL80211_CHAN_HT20;
break;
@@ -1678,13 +1727,15 @@ ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info)
return channel_type;
}
-int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
+int ieee80211_add_srates_ie(struct ieee80211_vif *vif,
+ struct sk_buff *skb, bool need_basic)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
int rate;
u8 i, rates, *pos;
+ u32 basic_rates = vif->bss_conf.basic_rates;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
rates = sband->n_bitrates;
@@ -1698,20 +1749,25 @@ int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = rates;
for (i = 0; i < rates; i++) {
+ u8 basic = 0;
+ if (need_basic && basic_rates & BIT(i))
+ basic = 0x80;
rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
+ *pos++ = basic | (u8) (rate / 5);
}
return 0;
}
-int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
+int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif,
+ struct sk_buff *skb, bool need_basic)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
int rate;
u8 i, exrates, *pos;
+ u32 basic_rates = vif->bss_conf.basic_rates;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
exrates = sband->n_bitrates;
@@ -1728,9 +1784,20 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = exrates;
for (i = 8; i < sband->n_bitrates; i++) {
+ u8 basic = 0;
+ if (need_basic && basic_rates & BIT(i))
+ basic = 0x80;
rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
+ *pos++ = basic | (u8) (rate / 5);
}
}
return 0;
}
+
+int ieee80211_ave_rssi(struct ieee80211_vif *vif)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+ return ifmgd->ave_beacon_signal;
+}
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 89511be3111e..c3d643a6536c 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -52,6 +52,26 @@ static int wme_downgrade_ac(struct sk_buff *skb)
}
}
+static u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
+ struct sk_buff *skb)
+{
+ /* in case we are a client verify acm is not set for this ac */
+ while (unlikely(local->wmm_acm & BIT(skb->priority))) {
+ if (wme_downgrade_ac(skb)) {
+ /*
+ * This should not really happen. The AP has marked all
+ * lower ACs to require admission control which is not
+ * a reasonable configuration. Allow the frame to be
+ * transmitted using AC_BK as a workaround.
+ */
+ break;
+ }
+ }
+
+ /* look up which queue to use for frames with this 1d tag */
+ return ieee802_1d_to_ac[skb->priority];
+}
+
/* Indicate which queue to use for this fully formed 802.11 frame */
u16 ieee80211_select_queue_80211(struct ieee80211_local *local,
struct sk_buff *skb,
@@ -59,7 +79,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_local *local,
{
u8 *p;
- if (local->hw.queues < 4)
+ if (local->hw.queues < IEEE80211_NUM_ACS)
return 0;
if (!ieee80211_is_data(hdr->frame_control)) {
@@ -86,9 +106,9 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
const u8 *ra = NULL;
bool qos = false;
- if (local->hw.queues < 4 || skb->len < 6) {
+ if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
skb->priority = 0; /* required for correct WPA/11i MIC */
- return min_t(u16, local->hw.queues - 1, IEEE80211_AC_BE);
+ return 0;
}
rcu_read_lock();
@@ -139,26 +159,6 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
return ieee80211_downgrade_queue(local, skb);
}
-u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
- struct sk_buff *skb)
-{
- /* in case we are a client verify acm is not set for this ac */
- while (unlikely(local->wmm_acm & BIT(skb->priority))) {
- if (wme_downgrade_ac(skb)) {
- /*
- * This should not really happen. The AP has marked all
- * lower ACs to require admission control which is not
- * a reasonable configuration. Allow the frame to be
- * transmitted using AC_BK as a workaround.
- */
- break;
- }
- }
-
- /* look up which queue to use for frames with this 1d tag */
- return ieee802_1d_to_ac[skb->priority];
-}
-
void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index 94edceb617ff..ca80818b7b66 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -22,8 +22,5 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
-u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
- struct sk_buff *skb);
-
#endif /* _WME_H */
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index c6e230efa049..b2650a9d45ff 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -122,9 +122,6 @@ static void ieee80211_work_work(struct work_struct *work)
enum work_action rma;
bool remain_off_channel = false;
- if (local->scanning)
- return;
-
/*
* ieee80211_queue_work() should have picked up most cases,
* here we'll pick the rest.
@@ -134,6 +131,11 @@ static void ieee80211_work_work(struct work_struct *work)
mutex_lock(&local->mtx);
+ if (local->scanning) {
+ mutex_unlock(&local->mtx);
+ return;
+ }
+
ieee80211_recalc_idle(local);
list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
@@ -226,13 +228,8 @@ static void ieee80211_work_work(struct work_struct *work)
run_again(local, jiffies + HZ/2);
}
- if (list_empty(&local->work_list) && local->scan_req &&
- !local->scanning)
- ieee80211_queue_delayed_work(&local->hw,
- &local->scan_work,
- round_jiffies_relative(0));
-
ieee80211_recalc_idle(local);
+ ieee80211_run_deferred_scan(local);
mutex_unlock(&local->mtx);
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index e1b7e051332e..e19f3653db23 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -290,12 +290,3 @@ void __init netfilter_init(void)
if (netfilter_log_init() < 0)
panic("cannot initialize nf_log");
}
-
-#ifdef CONFIG_SYSCTL
-struct ctl_path nf_net_netfilter_sysctl_path[] = {
- { .procname = "net", },
- { .procname = "netfilter", },
- { }
-};
-EXPORT_SYMBOL_GPL(nf_net_netfilter_sysctl_path);
-#endif /* CONFIG_SYSCTL */
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c
index a72a4dff0031..7e1b061aeeba 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ip.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ip.c
@@ -109,8 +109,9 @@ bitmap_ip_list(const struct ip_set *set,
} else
goto nla_put_failure;
}
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
- htonl(map->first_ip + id * map->hosts));
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP,
+ htonl(map->first_ip + id * map->hosts)))
+ goto nla_put_failure;
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, atd);
@@ -194,10 +195,11 @@ bitmap_ip_tlist(const struct ip_set *set,
} else
goto nla_put_failure;
}
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
- htonl(map->first_ip + id * map->hosts));
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(members[id])));
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP,
+ htonl(map->first_ip + id * map->hosts)) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(members[id]))))
+ goto nla_put_failure;
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, adt);
@@ -334,15 +336,16 @@ bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested)
goto nla_put_failure;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip));
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
- if (map->netmask != 32)
- NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
- NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
- NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
- htonl(sizeof(*map) + map->memsize));
- if (with_timeout(map->timeout))
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, htonl(map->first_ip)) ||
+ nla_put_ipaddr4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)) ||
+ (map->netmask != 32 &&
+ nla_put_u8(skb, IPSET_ATTR_NETMASK, map->netmask)) ||
+ nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
+ nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
+ htonl(sizeof(*map) + map->memsize)) ||
+ (with_timeout(map->timeout) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))))
+ goto nla_put_failure;
ipset_nest_end(skb, nested);
return 0;
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
index 81324c12c5be..0bb16c469a89 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
@@ -186,11 +186,12 @@ bitmap_ipmac_list(const struct ip_set *set,
} else
goto nla_put_failure;
}
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
- htonl(map->first_ip + id));
- if (elem->match == MAC_FILLED)
- NLA_PUT(skb, IPSET_ATTR_ETHER, ETH_ALEN,
- elem->ether);
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP,
+ htonl(map->first_ip + id)) ||
+ (elem->match == MAC_FILLED &&
+ nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN,
+ elem->ether)))
+ goto nla_put_failure;
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, atd);
@@ -314,14 +315,16 @@ bitmap_ipmac_tlist(const struct ip_set *set,
} else
goto nla_put_failure;
}
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
- htonl(map->first_ip + id));
- if (elem->match == MAC_FILLED)
- NLA_PUT(skb, IPSET_ATTR_ETHER, ETH_ALEN,
- elem->ether);
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP,
+ htonl(map->first_ip + id)) ||
+ (elem->match == MAC_FILLED &&
+ nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN,
+ elem->ether)))
+ goto nla_put_failure;
timeout = elem->match == MAC_UNSET ? elem->timeout
: ip_set_timeout_get(elem->timeout);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(timeout));
+ if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(timeout)))
+ goto nla_put_failure;
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, atd);
@@ -438,14 +441,16 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb)
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested)
goto nla_put_failure;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip));
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
- NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
- NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
- htonl(sizeof(*map)
- + (map->last_ip - map->first_ip + 1) * map->dsize));
- if (with_timeout(map->timeout))
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, htonl(map->first_ip)) ||
+ nla_put_ipaddr4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)) ||
+ nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
+ nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
+ htonl(sizeof(*map) +
+ ((map->last_ip - map->first_ip + 1) *
+ map->dsize))) ||
+ (with_timeout(map->timeout) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))))
+ goto nla_put_failure;
ipset_nest_end(skb, nested);
return 0;
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c
index 382ec28ba72e..b9f1fce7053b 100644
--- a/net/netfilter/ipset/ip_set_bitmap_port.c
+++ b/net/netfilter/ipset/ip_set_bitmap_port.c
@@ -96,8 +96,9 @@ bitmap_port_list(const struct ip_set *set,
} else
goto nla_put_failure;
}
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
- htons(map->first_port + id));
+ if (nla_put_net16(skb, IPSET_ATTR_PORT,
+ htons(map->first_port + id)))
+ goto nla_put_failure;
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, atd);
@@ -183,10 +184,11 @@ bitmap_port_tlist(const struct ip_set *set,
} else
goto nla_put_failure;
}
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
- htons(map->first_port + id));
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(members[id])));
+ if (nla_put_net16(skb, IPSET_ATTR_PORT,
+ htons(map->first_port + id)) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(members[id]))))
+ goto nla_put_failure;
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, adt);
@@ -320,13 +322,14 @@ bitmap_port_head(struct ip_set *set, struct sk_buff *skb)
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested)
goto nla_put_failure;
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port));
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
- NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
- NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
- htonl(sizeof(*map) + map->memsize));
- if (with_timeout(map->timeout))
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
+ if (nla_put_net16(skb, IPSET_ATTR_PORT, htons(map->first_port)) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port)) ||
+ nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
+ nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
+ htonl(sizeof(*map) + map->memsize)) ||
+ (with_timeout(map->timeout) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))))
+ goto nla_put_failure;
ipset_nest_end(skb, nested);
return 0;
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index e6c1c9605a58..819c342f5b30 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -1092,19 +1092,21 @@ dump_last:
ret = -EMSGSIZE;
goto release_refcount;
}
- NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
- NLA_PUT_STRING(skb, IPSET_ATTR_SETNAME, set->name);
+ if (nla_put_u8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL) ||
+ nla_put_string(skb, IPSET_ATTR_SETNAME, set->name))
+ goto nla_put_failure;
if (dump_flags & IPSET_FLAG_LIST_SETNAME)
goto next_set;
switch (cb->args[2]) {
case 0:
/* Core header data */
- NLA_PUT_STRING(skb, IPSET_ATTR_TYPENAME,
- set->type->name);
- NLA_PUT_U8(skb, IPSET_ATTR_FAMILY,
- set->family);
- NLA_PUT_U8(skb, IPSET_ATTR_REVISION,
- set->revision);
+ if (nla_put_string(skb, IPSET_ATTR_TYPENAME,
+ set->type->name) ||
+ nla_put_u8(skb, IPSET_ATTR_FAMILY,
+ set->family) ||
+ nla_put_u8(skb, IPSET_ATTR_REVISION,
+ set->revision))
+ goto nla_put_failure;
ret = set->variant->head(set, skb);
if (ret < 0)
goto release_refcount;
@@ -1410,11 +1412,12 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb,
IPSET_CMD_HEADER);
if (!nlh2)
goto nlmsg_failure;
- NLA_PUT_U8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
- NLA_PUT_STRING(skb2, IPSET_ATTR_SETNAME, set->name);
- NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, set->type->name);
- NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, set->family);
- NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->revision);
+ if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL) ||
+ nla_put_string(skb2, IPSET_ATTR_SETNAME, set->name) ||
+ nla_put_string(skb2, IPSET_ATTR_TYPENAME, set->type->name) ||
+ nla_put_u8(skb2, IPSET_ATTR_FAMILY, set->family) ||
+ nla_put_u8(skb2, IPSET_ATTR_REVISION, set->revision))
+ goto nla_put_failure;
nlmsg_end(skb2, nlh2);
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
@@ -1469,11 +1472,12 @@ ip_set_type(struct sock *ctnl, struct sk_buff *skb,
IPSET_CMD_TYPE);
if (!nlh2)
goto nlmsg_failure;
- NLA_PUT_U8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
- NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, typename);
- NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, family);
- NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, max);
- NLA_PUT_U8(skb2, IPSET_ATTR_REVISION_MIN, min);
+ if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL) ||
+ nla_put_string(skb2, IPSET_ATTR_TYPENAME, typename) ||
+ nla_put_u8(skb2, IPSET_ATTR_FAMILY, family) ||
+ nla_put_u8(skb2, IPSET_ATTR_REVISION, max) ||
+ nla_put_u8(skb2, IPSET_ATTR_REVISION_MIN, min))
+ goto nla_put_failure;
nlmsg_end(skb2, nlh2);
pr_debug("Send TYPE, nlmsg_len: %u\n", nlh2->nlmsg_len);
@@ -1517,7 +1521,8 @@ ip_set_protocol(struct sock *ctnl, struct sk_buff *skb,
IPSET_CMD_PROTOCOL);
if (!nlh2)
goto nlmsg_failure;
- NLA_PUT_U8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
+ if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL))
+ goto nla_put_failure;
nlmsg_end(skb2, nlh2);
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
@@ -1613,7 +1618,7 @@ static struct nfnetlink_subsystem ip_set_netlink_subsys __read_mostly = {
static int
ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
{
- unsigned *op;
+ unsigned int *op;
void *data;
int copylen = *len, ret = 0;
@@ -1621,7 +1626,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
return -EPERM;
if (optval != SO_IP_SET)
return -EBADF;
- if (*len < sizeof(unsigned))
+ if (*len < sizeof(unsigned int))
return -EINVAL;
data = vmalloc(*len);
@@ -1631,7 +1636,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
ret = -EFAULT;
goto done;
}
- op = (unsigned *) data;
+ op = (unsigned int *) data;
if (*op < IP_SET_OP_VERSION) {
/* Check the version at the beginning of operations */
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c
index 5139dea6019e..507fe93794aa 100644
--- a/net/netfilter/ipset/ip_set_hash_ip.c
+++ b/net/netfilter/ipset/ip_set_hash_ip.c
@@ -81,7 +81,8 @@ hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
static inline bool
hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data)
{
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -94,9 +95,10 @@ hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
const struct hash_ip4_telem *tdata =
(const struct hash_ip4_telem *)data;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout)));
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(tdata->timeout))))
+ goto nla_put_failure;
return 0;
@@ -262,7 +264,8 @@ ip6_netmask(union nf_inet_addr *ip, u8 prefix)
static bool
hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
{
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -275,9 +278,10 @@ hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
const struct hash_ip6_telem *e =
(const struct hash_ip6_telem *)data;
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout)));
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(e->timeout))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c
index 9c27e249c171..68f284c97490 100644
--- a/net/netfilter/ipset/ip_set_hash_ipport.c
+++ b/net/netfilter/ipset/ip_set_hash_ipport.c
@@ -93,9 +93,10 @@ static bool
hash_ipport4_data_list(struct sk_buff *skb,
const struct hash_ipport4_elem *data)
{
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -109,12 +110,12 @@ hash_ipport4_data_tlist(struct sk_buff *skb,
const struct hash_ipport4_telem *tdata =
(const struct hash_ipport4_telem *)data;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout)));
-
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, tdata->port) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(tdata->timeout))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -308,9 +309,10 @@ static bool
hash_ipport6_data_list(struct sk_buff *skb,
const struct hash_ipport6_elem *data)
{
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -324,11 +326,12 @@ hash_ipport6_data_tlist(struct sk_buff *skb,
const struct hash_ipport6_telem *e =
(const struct hash_ipport6_telem *)data;
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout)));
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(e->timeout))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c
index 9134057c0728..1eec4b9e0dca 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportip.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportip.c
@@ -94,10 +94,11 @@ static bool
hash_ipportip4_data_list(struct sk_buff *skb,
const struct hash_ipportip4_elem *data)
{
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
+ nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip2) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -111,13 +112,13 @@ hash_ipportip4_data_tlist(struct sk_buff *skb,
const struct hash_ipportip4_telem *tdata =
(const struct hash_ipportip4_telem *)data;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout)));
-
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
+ nla_put_ipaddr4(skb, IPSET_ATTR_IP2, tdata->ip2) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, tdata->port) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(tdata->timeout))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -319,10 +320,11 @@ static bool
hash_ipportip6_data_list(struct sk_buff *skb,
const struct hash_ipportip6_elem *data)
{
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
+ nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -336,12 +338,13 @@ hash_ipportip6_data_tlist(struct sk_buff *skb,
const struct hash_ipportip6_telem *e =
(const struct hash_ipportip6_telem *)data;
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout)));
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
+ nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(e->timeout))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c
index 5d05e6969862..62d66ecef369 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -124,13 +124,14 @@ hash_ipportnet4_data_list(struct sk_buff *skb,
{
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
+ nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip2) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -145,16 +146,16 @@ hash_ipportnet4_data_tlist(struct sk_buff *skb,
(const struct hash_ipportnet4_telem *)data;
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout)));
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
-
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
+ nla_put_ipaddr4(skb, IPSET_ATTR_IP2, tdata->ip2) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, tdata->port) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(tdata->timeout))) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -436,13 +437,14 @@ hash_ipportnet6_data_list(struct sk_buff *skb,
{
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
+ nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -457,15 +459,16 @@ hash_ipportnet6_data_tlist(struct sk_buff *skb,
(const struct hash_ipportnet6_telem *)data;
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout)));
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
+ nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(e->timeout))) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c
index 7c3d945517cf..6607a814be57 100644
--- a/net/netfilter/ipset/ip_set_hash_net.c
+++ b/net/netfilter/ipset/ip_set_hash_net.c
@@ -111,10 +111,11 @@ hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
{
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -128,13 +129,13 @@ hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data)
(const struct hash_net4_telem *)data;
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR, tdata->cidr);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout)));
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
-
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR, tdata->cidr) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(tdata->timeout))) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -339,10 +340,11 @@ hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
{
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -356,12 +358,13 @@ hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data)
(const struct hash_net6_telem *)data;
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR, e->cidr);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout)));
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR, e->cidr) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(e->timeout))) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c
index f24037ff4322..6093f3daa911 100644
--- a/net/netfilter/ipset/ip_set_hash_netiface.c
+++ b/net/netfilter/ipset/ip_set_hash_netiface.c
@@ -252,11 +252,12 @@ hash_netiface4_data_list(struct sk_buff *skb,
if (data->nomatch)
flags |= IPSET_FLAG_NOMATCH;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
- NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
+ nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -273,13 +274,14 @@ hash_netiface4_data_tlist(struct sk_buff *skb,
if (data->nomatch)
flags |= IPSET_FLAG_NOMATCH;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
- NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout)));
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
+ nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(tdata->timeout))))
+ goto nla_put_failure;
return 0;
@@ -555,11 +557,12 @@ hash_netiface6_data_list(struct sk_buff *skb,
if (data->nomatch)
flags |= IPSET_FLAG_NOMATCH;
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
- NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
+ nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -576,13 +579,14 @@ hash_netiface6_data_tlist(struct sk_buff *skb,
if (data->nomatch)
flags |= IPSET_FLAG_NOMATCH;
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
- NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout)));
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
+ nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(e->timeout))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c
index ce2e77100b64..ae3c644adc14 100644
--- a/net/netfilter/ipset/ip_set_hash_netport.c
+++ b/net/netfilter/ipset/ip_set_hash_netport.c
@@ -124,12 +124,13 @@ hash_netport4_data_list(struct sk_buff *skb,
{
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr + 1) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -144,15 +145,15 @@ hash_netport4_data_tlist(struct sk_buff *skb,
(const struct hash_netport4_telem *)data;
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
- NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout)));
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
-
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, tdata->port) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr + 1) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(tdata->timeout))) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -402,12 +403,13 @@ hash_netport6_data_list(struct sk_buff *skb,
{
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr + 1) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -422,14 +424,15 @@ hash_netport6_data_tlist(struct sk_buff *skb,
(const struct hash_netport6_telem *)data;
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
- NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
- NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1);
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout)));
- if (flags)
- NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
+ nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr + 1) ||
+ nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(e->timeout))) ||
+ (flags &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index 7e095f9005f0..6cb1225765f9 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/net/netfilter/ipset/ip_set_list_set.c
@@ -402,12 +402,13 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested)
goto nla_put_failure;
- NLA_PUT_NET32(skb, IPSET_ATTR_SIZE, htonl(map->size));
- if (with_timeout(map->timeout))
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
- NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
- NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
- htonl(sizeof(*map) + map->size * map->dsize));
+ if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
+ (with_timeout(map->timeout) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
+ nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
+ nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
+ htonl(sizeof(*map) + map->size * map->dsize)))
+ goto nla_put_failure;
ipset_nest_end(skb, nested);
return 0;
@@ -442,13 +443,15 @@ list_set_list(const struct ip_set *set,
} else
goto nla_put_failure;
}
- NLA_PUT_STRING(skb, IPSET_ATTR_NAME,
- ip_set_name_byindex(e->id));
+ if (nla_put_string(skb, IPSET_ATTR_NAME,
+ ip_set_name_byindex(e->id)))
+ goto nla_put_failure;
if (with_timeout(map->timeout)) {
const struct set_telem *te =
(const struct set_telem *) e;
- NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(te->timeout)));
+ __be32 to = htonl(ip_set_timeout_get(te->timeout));
+ if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, to))
+ goto nla_put_failure;
}
ipset_nest_end(skb, nested);
}
diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c
index 52856178c9d7..64f9e8f13207 100644
--- a/net/netfilter/ipvs/ip_vs_app.c
+++ b/net/netfilter/ipvs/ip_vs_app.c
@@ -313,7 +313,7 @@ vs_fix_ack_seq(const struct ip_vs_seq *vseq, struct tcphdr *th)
* Assumes already checked proto==IPPROTO_TCP and diff!=0.
*/
static inline void vs_seq_update(struct ip_vs_conn *cp, struct ip_vs_seq *vseq,
- unsigned flag, __u32 seq, int diff)
+ unsigned int flag, __u32 seq, int diff)
{
/* spinlock is to keep updating cp->flags atomic */
spin_lock(&cp->lock);
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index 29fa5badde75..4a09b7873003 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -86,42 +86,42 @@ struct ip_vs_aligned_lock
static struct ip_vs_aligned_lock
__ip_vs_conntbl_lock_array[CT_LOCKARRAY_SIZE] __cacheline_aligned;
-static inline void ct_read_lock(unsigned key)
+static inline void ct_read_lock(unsigned int key)
{
read_lock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
}
-static inline void ct_read_unlock(unsigned key)
+static inline void ct_read_unlock(unsigned int key)
{
read_unlock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
}
-static inline void ct_write_lock(unsigned key)
+static inline void ct_write_lock(unsigned int key)
{
write_lock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
}
-static inline void ct_write_unlock(unsigned key)
+static inline void ct_write_unlock(unsigned int key)
{
write_unlock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
}
-static inline void ct_read_lock_bh(unsigned key)
+static inline void ct_read_lock_bh(unsigned int key)
{
read_lock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
}
-static inline void ct_read_unlock_bh(unsigned key)
+static inline void ct_read_unlock_bh(unsigned int key)
{
read_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
}
-static inline void ct_write_lock_bh(unsigned key)
+static inline void ct_write_lock_bh(unsigned int key)
{
write_lock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
}
-static inline void ct_write_unlock_bh(unsigned key)
+static inline void ct_write_unlock_bh(unsigned int key)
{
write_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
}
@@ -130,7 +130,7 @@ static inline void ct_write_unlock_bh(unsigned key)
/*
* Returns hash value for IPVS connection entry
*/
-static unsigned int ip_vs_conn_hashkey(struct net *net, int af, unsigned proto,
+static unsigned int ip_vs_conn_hashkey(struct net *net, int af, unsigned int proto,
const union nf_inet_addr *addr,
__be16 port)
{
@@ -188,7 +188,7 @@ static unsigned int ip_vs_conn_hashkey_conn(const struct ip_vs_conn *cp)
*/
static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
{
- unsigned hash;
+ unsigned int hash;
int ret;
if (cp->flags & IP_VS_CONN_F_ONE_PACKET)
@@ -224,7 +224,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
*/
static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
{
- unsigned hash;
+ unsigned int hash;
int ret;
/* unhash it and decrease its reference counter */
@@ -257,7 +257,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
static inline struct ip_vs_conn *
__ip_vs_conn_in_get(const struct ip_vs_conn_param *p)
{
- unsigned hash;
+ unsigned int hash;
struct ip_vs_conn *cp;
struct hlist_node *n;
@@ -344,7 +344,7 @@ EXPORT_SYMBOL_GPL(ip_vs_conn_in_get_proto);
/* Get reference to connection template */
struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
{
- unsigned hash;
+ unsigned int hash;
struct ip_vs_conn *cp;
struct hlist_node *n;
@@ -394,7 +394,7 @@ struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
* p->vaddr, p->vport: pkt dest address (foreign host) */
struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p)
{
- unsigned hash;
+ unsigned int hash;
struct ip_vs_conn *cp, *ret=NULL;
struct hlist_node *n;
@@ -824,7 +824,7 @@ void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
*/
struct ip_vs_conn *
ip_vs_conn_new(const struct ip_vs_conn_param *p,
- const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
+ const union nf_inet_addr *daddr, __be16 dport, unsigned int flags,
struct ip_vs_dest *dest, __u32 fwmark)
{
struct ip_vs_conn *cp;
@@ -1057,7 +1057,7 @@ static const struct file_operations ip_vs_conn_fops = {
.release = seq_release_net,
};
-static const char *ip_vs_origin_name(unsigned flags)
+static const char *ip_vs_origin_name(unsigned int flags)
{
if (flags & IP_VS_CONN_F_SYNC)
return "SYNC";
@@ -1169,7 +1169,7 @@ void ip_vs_random_dropentry(struct net *net)
* Randomly scan 1/32 of the whole table every second
*/
for (idx = 0; idx < (ip_vs_conn_tab_size>>5); idx++) {
- unsigned hash = net_random() & ip_vs_conn_tab_mask;
+ unsigned int hash = net_random() & ip_vs_conn_tab_mask;
struct hlist_node *n;
/*
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 2555816e7788..b5a5c7363f83 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -80,7 +80,7 @@ static atomic_t ipvs_netns_cnt = ATOMIC_INIT(0);
#define icmp_id(icmph) (((icmph)->un).echo.id)
#define icmpv6_id(icmph) (icmph->icmp6_dataun.u_echo.identifier)
-const char *ip_vs_proto_name(unsigned proto)
+const char *ip_vs_proto_name(unsigned int proto)
{
static char buf[20];
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index b3afe189af61..e3707d2bd9c7 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -265,11 +265,11 @@ static struct list_head ip_vs_svc_fwm_table[IP_VS_SVC_TAB_SIZE];
/*
* Returns hash value for virtual service
*/
-static inline unsigned
-ip_vs_svc_hashkey(struct net *net, int af, unsigned proto,
+static inline unsigned int
+ip_vs_svc_hashkey(struct net *net, int af, unsigned int proto,
const union nf_inet_addr *addr, __be16 port)
{
- register unsigned porth = ntohs(port);
+ register unsigned int porth = ntohs(port);
__be32 addr_fold = addr->ip;
#ifdef CONFIG_IP_VS_IPV6
@@ -286,7 +286,7 @@ ip_vs_svc_hashkey(struct net *net, int af, unsigned proto,
/*
* Returns hash value of fwmark for virtual service lookup
*/
-static inline unsigned ip_vs_svc_fwm_hashkey(struct net *net, __u32 fwmark)
+static inline unsigned int ip_vs_svc_fwm_hashkey(struct net *net, __u32 fwmark)
{
return (((size_t)net>>8) ^ fwmark) & IP_VS_SVC_TAB_MASK;
}
@@ -298,7 +298,7 @@ static inline unsigned ip_vs_svc_fwm_hashkey(struct net *net, __u32 fwmark)
*/
static int ip_vs_svc_hash(struct ip_vs_service *svc)
{
- unsigned hash;
+ unsigned int hash;
if (svc->flags & IP_VS_SVC_F_HASHED) {
pr_err("%s(): request for already hashed, called from %pF\n",
@@ -361,7 +361,7 @@ static inline struct ip_vs_service *
__ip_vs_service_find(struct net *net, int af, __u16 protocol,
const union nf_inet_addr *vaddr, __be16 vport)
{
- unsigned hash;
+ unsigned int hash;
struct ip_vs_service *svc;
/* Check for "full" addressed entries */
@@ -388,7 +388,7 @@ __ip_vs_service_find(struct net *net, int af, __u16 protocol,
static inline struct ip_vs_service *
__ip_vs_svc_fwm_find(struct net *net, int af, __u32 fwmark)
{
- unsigned hash;
+ unsigned int hash;
struct ip_vs_service *svc;
/* Check for fwmark addressed entries */
@@ -489,11 +489,11 @@ __ip_vs_unbind_svc(struct ip_vs_dest *dest)
/*
* Returns hash value for real service
*/
-static inline unsigned ip_vs_rs_hashkey(int af,
+static inline unsigned int ip_vs_rs_hashkey(int af,
const union nf_inet_addr *addr,
__be16 port)
{
- register unsigned porth = ntohs(port);
+ register unsigned int porth = ntohs(port);
__be32 addr_fold = addr->ip;
#ifdef CONFIG_IP_VS_IPV6
@@ -512,7 +512,7 @@ static inline unsigned ip_vs_rs_hashkey(int af,
*/
static int ip_vs_rs_hash(struct netns_ipvs *ipvs, struct ip_vs_dest *dest)
{
- unsigned hash;
+ unsigned int hash;
if (!list_empty(&dest->d_list)) {
return 0;
@@ -555,7 +555,7 @@ ip_vs_lookup_real_service(struct net *net, int af, __u16 protocol,
__be16 dport)
{
struct netns_ipvs *ipvs = net_ipvs(net);
- unsigned hash;
+ unsigned int hash;
struct ip_vs_dest *dest;
/*
@@ -842,7 +842,7 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
struct ip_vs_dest **dest_p)
{
struct ip_vs_dest *dest;
- unsigned atype;
+ unsigned int atype;
EnterFunction(2);
@@ -1846,13 +1846,6 @@ static struct ctl_table vs_vars[] = {
{ }
};
-const struct ctl_path net_vs_ctl_path[] = {
- { .procname = "net", },
- { .procname = "ipv4", },
- { .procname = "vs", },
- { }
-};
-EXPORT_SYMBOL_GPL(net_vs_ctl_path);
#endif
#ifdef CONFIG_PROC_FS
@@ -1867,7 +1860,7 @@ struct ip_vs_iter {
* Write the contents of the VS rule table to a PROCfs file.
* (It is kept just for backward compatibility)
*/
-static inline const char *ip_vs_fwd_name(unsigned flags)
+static inline const char *ip_vs_fwd_name(unsigned int flags)
{
switch (flags & IP_VS_CONN_F_FWD_MASK) {
case IP_VS_CONN_F_LOCALNODE:
@@ -2816,17 +2809,17 @@ static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type,
ip_vs_copy_stats(&ustats, stats);
- NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, ustats.conns);
- NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, ustats.inpkts);
- NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, ustats.outpkts);
- NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, ustats.inbytes);
- NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, ustats.outbytes);
- NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, ustats.cps);
- NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, ustats.inpps);
- NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, ustats.outpps);
- NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, ustats.inbps);
- NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, ustats.outbps);
-
+ if (nla_put_u32(skb, IPVS_STATS_ATTR_CONNS, ustats.conns) ||
+ nla_put_u32(skb, IPVS_STATS_ATTR_INPKTS, ustats.inpkts) ||
+ nla_put_u32(skb, IPVS_STATS_ATTR_OUTPKTS, ustats.outpkts) ||
+ nla_put_u64(skb, IPVS_STATS_ATTR_INBYTES, ustats.inbytes) ||
+ nla_put_u64(skb, IPVS_STATS_ATTR_OUTBYTES, ustats.outbytes) ||
+ nla_put_u32(skb, IPVS_STATS_ATTR_CPS, ustats.cps) ||
+ nla_put_u32(skb, IPVS_STATS_ATTR_INPPS, ustats.inpps) ||
+ nla_put_u32(skb, IPVS_STATS_ATTR_OUTPPS, ustats.outpps) ||
+ nla_put_u32(skb, IPVS_STATS_ATTR_INBPS, ustats.inbps) ||
+ nla_put_u32(skb, IPVS_STATS_ATTR_OUTBPS, ustats.outbps))
+ goto nla_put_failure;
nla_nest_end(skb, nl_stats);
return 0;
@@ -2847,23 +2840,25 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
if (!nl_service)
return -EMSGSIZE;
- NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, svc->af);
-
+ if (nla_put_u16(skb, IPVS_SVC_ATTR_AF, svc->af))
+ goto nla_put_failure;
if (svc->fwmark) {
- NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark);
+ if (nla_put_u32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark))
+ goto nla_put_failure;
} else {
- NLA_PUT_U16(skb, IPVS_SVC_ATTR_PROTOCOL, svc->protocol);
- NLA_PUT(skb, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &svc->addr);
- NLA_PUT_U16(skb, IPVS_SVC_ATTR_PORT, svc->port);
+ if (nla_put_u16(skb, IPVS_SVC_ATTR_PROTOCOL, svc->protocol) ||
+ nla_put(skb, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &svc->addr) ||
+ nla_put_u16(skb, IPVS_SVC_ATTR_PORT, svc->port))
+ goto nla_put_failure;
}
- NLA_PUT_STRING(skb, IPVS_SVC_ATTR_SCHED_NAME, svc->scheduler->name);
- if (svc->pe)
- NLA_PUT_STRING(skb, IPVS_SVC_ATTR_PE_NAME, svc->pe->name);
- NLA_PUT(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags);
- NLA_PUT_U32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ);
- NLA_PUT_U32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask);
-
+ if (nla_put_string(skb, IPVS_SVC_ATTR_SCHED_NAME, svc->scheduler->name) ||
+ (svc->pe &&
+ nla_put_string(skb, IPVS_SVC_ATTR_PE_NAME, svc->pe->name)) ||
+ nla_put(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags) ||
+ nla_put_u32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ) ||
+ nla_put_u32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask))
+ goto nla_put_failure;
if (ip_vs_genl_fill_stats(skb, IPVS_SVC_ATTR_STATS, &svc->stats))
goto nla_put_failure;
@@ -3038,21 +3033,22 @@ static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest)
if (!nl_dest)
return -EMSGSIZE;
- NLA_PUT(skb, IPVS_DEST_ATTR_ADDR, sizeof(dest->addr), &dest->addr);
- NLA_PUT_U16(skb, IPVS_DEST_ATTR_PORT, dest->port);
-
- NLA_PUT_U32(skb, IPVS_DEST_ATTR_FWD_METHOD,
- atomic_read(&dest->conn_flags) & IP_VS_CONN_F_FWD_MASK);
- NLA_PUT_U32(skb, IPVS_DEST_ATTR_WEIGHT, atomic_read(&dest->weight));
- NLA_PUT_U32(skb, IPVS_DEST_ATTR_U_THRESH, dest->u_threshold);
- NLA_PUT_U32(skb, IPVS_DEST_ATTR_L_THRESH, dest->l_threshold);
- NLA_PUT_U32(skb, IPVS_DEST_ATTR_ACTIVE_CONNS,
- atomic_read(&dest->activeconns));
- NLA_PUT_U32(skb, IPVS_DEST_ATTR_INACT_CONNS,
- atomic_read(&dest->inactconns));
- NLA_PUT_U32(skb, IPVS_DEST_ATTR_PERSIST_CONNS,
- atomic_read(&dest->persistconns));
-
+ if (nla_put(skb, IPVS_DEST_ATTR_ADDR, sizeof(dest->addr), &dest->addr) ||
+ nla_put_u16(skb, IPVS_DEST_ATTR_PORT, dest->port) ||
+ nla_put_u32(skb, IPVS_DEST_ATTR_FWD_METHOD,
+ (atomic_read(&dest->conn_flags) &
+ IP_VS_CONN_F_FWD_MASK)) ||
+ nla_put_u32(skb, IPVS_DEST_ATTR_WEIGHT,
+ atomic_read(&dest->weight)) ||
+ nla_put_u32(skb, IPVS_DEST_ATTR_U_THRESH, dest->u_threshold) ||
+ nla_put_u32(skb, IPVS_DEST_ATTR_L_THRESH, dest->l_threshold) ||
+ nla_put_u32(skb, IPVS_DEST_ATTR_ACTIVE_CONNS,
+ atomic_read(&dest->activeconns)) ||
+ nla_put_u32(skb, IPVS_DEST_ATTR_INACT_CONNS,
+ atomic_read(&dest->inactconns)) ||
+ nla_put_u32(skb, IPVS_DEST_ATTR_PERSIST_CONNS,
+ atomic_read(&dest->persistconns)))
+ goto nla_put_failure;
if (ip_vs_genl_fill_stats(skb, IPVS_DEST_ATTR_STATS, &dest->stats))
goto nla_put_failure;
@@ -3181,10 +3177,10 @@ static int ip_vs_genl_fill_daemon(struct sk_buff *skb, __be32 state,
if (!nl_daemon)
return -EMSGSIZE;
- NLA_PUT_U32(skb, IPVS_DAEMON_ATTR_STATE, state);
- NLA_PUT_STRING(skb, IPVS_DAEMON_ATTR_MCAST_IFN, mcast_ifn);
- NLA_PUT_U32(skb, IPVS_DAEMON_ATTR_SYNC_ID, syncid);
-
+ if (nla_put_u32(skb, IPVS_DAEMON_ATTR_STATE, state) ||
+ nla_put_string(skb, IPVS_DAEMON_ATTR_MCAST_IFN, mcast_ifn) ||
+ nla_put_u32(skb, IPVS_DAEMON_ATTR_SYNC_ID, syncid))
+ goto nla_put_failure;
nla_nest_end(skb, nl_daemon);
return 0;
@@ -3473,21 +3469,26 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)
__ip_vs_get_timeouts(net, &t);
#ifdef CONFIG_IP_VS_PROTO_TCP
- NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP, t.tcp_timeout);
- NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP_FIN,
- t.tcp_fin_timeout);
+ if (nla_put_u32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP,
+ t.tcp_timeout) ||
+ nla_put_u32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP_FIN,
+ t.tcp_fin_timeout))
+ goto nla_put_failure;
#endif
#ifdef CONFIG_IP_VS_PROTO_UDP
- NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_UDP, t.udp_timeout);
+ if (nla_put_u32(msg, IPVS_CMD_ATTR_TIMEOUT_UDP, t.udp_timeout))
+ goto nla_put_failure;
#endif
break;
}
case IPVS_CMD_GET_INFO:
- NLA_PUT_U32(msg, IPVS_INFO_ATTR_VERSION, IP_VS_VERSION_CODE);
- NLA_PUT_U32(msg, IPVS_INFO_ATTR_CONN_TAB_SIZE,
- ip_vs_conn_tab_size);
+ if (nla_put_u32(msg, IPVS_INFO_ATTR_VERSION,
+ IP_VS_VERSION_CODE) ||
+ nla_put_u32(msg, IPVS_INFO_ATTR_CONN_TAB_SIZE,
+ ip_vs_conn_tab_size))
+ goto nla_put_failure;
break;
}
@@ -3664,8 +3665,7 @@ int __net_init ip_vs_control_net_init_sysctl(struct net *net)
tbl[idx++].data = &ipvs->sysctl_nat_icmp_send;
- ipvs->sysctl_hdr = register_net_sysctl_table(net, net_vs_ctl_path,
- tbl);
+ ipvs->sysctl_hdr = register_net_sysctl(net, "net/ipv4/vs", tbl);
if (ipvs->sysctl_hdr == NULL) {
if (!net_eq(net, &init_net))
kfree(tbl);
diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c
index 1c269e56200a..1a53a7a2fff0 100644
--- a/net/netfilter/ipvs/ip_vs_dh.c
+++ b/net/netfilter/ipvs/ip_vs_dh.c
@@ -68,7 +68,7 @@ struct ip_vs_dh_bucket {
/*
* Returns hash value for IPVS DH entry
*/
-static inline unsigned ip_vs_dh_hashkey(int af, const union nf_inet_addr *addr)
+static inline unsigned int ip_vs_dh_hashkey(int af, const union nf_inet_addr *addr)
{
__be32 addr_fold = addr->ip;
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c
index 538d74ee4f68..debb8c71422c 100644
--- a/net/netfilter/ipvs/ip_vs_ftp.c
+++ b/net/netfilter/ipvs/ip_vs_ftp.c
@@ -177,7 +177,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
__be16 port;
struct ip_vs_conn *n_cp;
char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */
- unsigned buf_len;
+ unsigned int buf_len;
int ret = 0;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct;
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index 0f16283fd058..1024466de124 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -142,7 +142,7 @@ static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en)
/*
* Returns hash value for IPVS LBLC entry
*/
-static inline unsigned
+static inline unsigned int
ip_vs_lblc_hashkey(int af, const union nf_inet_addr *addr)
{
__be32 addr_fold = addr->ip;
@@ -163,7 +163,7 @@ ip_vs_lblc_hashkey(int af, const union nf_inet_addr *addr)
static void
ip_vs_lblc_hash(struct ip_vs_lblc_table *tbl, struct ip_vs_lblc_entry *en)
{
- unsigned hash = ip_vs_lblc_hashkey(en->af, &en->addr);
+ unsigned int hash = ip_vs_lblc_hashkey(en->af, &en->addr);
list_add(&en->list, &tbl->bucket[hash]);
atomic_inc(&tbl->entries);
@@ -178,7 +178,7 @@ static inline struct ip_vs_lblc_entry *
ip_vs_lblc_get(int af, struct ip_vs_lblc_table *tbl,
const union nf_inet_addr *addr)
{
- unsigned hash = ip_vs_lblc_hashkey(af, addr);
+ unsigned int hash = ip_vs_lblc_hashkey(af, addr);
struct ip_vs_lblc_entry *en;
list_for_each_entry(en, &tbl->bucket[hash], list)
@@ -563,8 +563,7 @@ static int __net_init __ip_vs_lblc_init(struct net *net)
ipvs->lblc_ctl_table[0].data = &ipvs->sysctl_lblc_expiration;
ipvs->lblc_ctl_header =
- register_net_sysctl_table(net, net_vs_ctl_path,
- ipvs->lblc_ctl_table);
+ register_net_sysctl(net, "net/ipv4/vs", ipvs->lblc_ctl_table);
if (!ipvs->lblc_ctl_header) {
if (!net_eq(net, &init_net))
kfree(ipvs->lblc_ctl_table);
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index eec797f8cce7..9261825a6579 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -311,7 +311,7 @@ static inline void ip_vs_lblcr_free(struct ip_vs_lblcr_entry *en)
/*
* Returns hash value for IPVS LBLCR entry
*/
-static inline unsigned
+static inline unsigned int
ip_vs_lblcr_hashkey(int af, const union nf_inet_addr *addr)
{
__be32 addr_fold = addr->ip;
@@ -332,7 +332,7 @@ ip_vs_lblcr_hashkey(int af, const union nf_inet_addr *addr)
static void
ip_vs_lblcr_hash(struct ip_vs_lblcr_table *tbl, struct ip_vs_lblcr_entry *en)
{
- unsigned hash = ip_vs_lblcr_hashkey(en->af, &en->addr);
+ unsigned int hash = ip_vs_lblcr_hashkey(en->af, &en->addr);
list_add(&en->list, &tbl->bucket[hash]);
atomic_inc(&tbl->entries);
@@ -347,7 +347,7 @@ static inline struct ip_vs_lblcr_entry *
ip_vs_lblcr_get(int af, struct ip_vs_lblcr_table *tbl,
const union nf_inet_addr *addr)
{
- unsigned hash = ip_vs_lblcr_hashkey(af, addr);
+ unsigned int hash = ip_vs_lblcr_hashkey(af, addr);
struct ip_vs_lblcr_entry *en;
list_for_each_entry(en, &tbl->bucket[hash], list)
@@ -757,8 +757,7 @@ static int __net_init __ip_vs_lblcr_init(struct net *net)
ipvs->lblcr_ctl_table[0].data = &ipvs->sysctl_lblcr_expiration;
ipvs->lblcr_ctl_header =
- register_net_sysctl_table(net, net_vs_ctl_path,
- ipvs->lblcr_ctl_table);
+ register_net_sysctl(net, "net/ipv4/vs", ipvs->lblcr_ctl_table);
if (!ipvs->lblcr_ctl_header) {
if (!net_eq(net, &init_net))
kfree(ipvs->lblcr_ctl_table);
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
index f843a8833250..6eda11de8c05 100644
--- a/net/netfilter/ipvs/ip_vs_proto.c
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -48,7 +48,7 @@ static struct ip_vs_protocol *ip_vs_proto_table[IP_VS_PROTO_TAB_SIZE];
*/
static int __used __init register_ip_vs_protocol(struct ip_vs_protocol *pp)
{
- unsigned hash = IP_VS_PROTO_HASH(pp->protocol);
+ unsigned int hash = IP_VS_PROTO_HASH(pp->protocol);
pp->next = ip_vs_proto_table[hash];
ip_vs_proto_table[hash] = pp;
@@ -69,7 +69,7 @@ static int
register_ip_vs_proto_netns(struct net *net, struct ip_vs_protocol *pp)
{
struct netns_ipvs *ipvs = net_ipvs(net);
- unsigned hash = IP_VS_PROTO_HASH(pp->protocol);
+ unsigned int hash = IP_VS_PROTO_HASH(pp->protocol);
struct ip_vs_proto_data *pd =
kzalloc(sizeof(struct ip_vs_proto_data), GFP_ATOMIC);
@@ -94,7 +94,7 @@ register_ip_vs_proto_netns(struct net *net, struct ip_vs_protocol *pp)
static int unregister_ip_vs_protocol(struct ip_vs_protocol *pp)
{
struct ip_vs_protocol **pp_p;
- unsigned hash = IP_VS_PROTO_HASH(pp->protocol);
+ unsigned int hash = IP_VS_PROTO_HASH(pp->protocol);
pp_p = &ip_vs_proto_table[hash];
for (; *pp_p; pp_p = &(*pp_p)->next) {
@@ -117,7 +117,7 @@ unregister_ip_vs_proto_netns(struct net *net, struct ip_vs_proto_data *pd)
{
struct netns_ipvs *ipvs = net_ipvs(net);
struct ip_vs_proto_data **pd_p;
- unsigned hash = IP_VS_PROTO_HASH(pd->pp->protocol);
+ unsigned int hash = IP_VS_PROTO_HASH(pd->pp->protocol);
pd_p = &ipvs->proto_data_table[hash];
for (; *pd_p; pd_p = &(*pd_p)->next) {
@@ -139,7 +139,7 @@ unregister_ip_vs_proto_netns(struct net *net, struct ip_vs_proto_data *pd)
struct ip_vs_protocol * ip_vs_proto_get(unsigned short proto)
{
struct ip_vs_protocol *pp;
- unsigned hash = IP_VS_PROTO_HASH(proto);
+ unsigned int hash = IP_VS_PROTO_HASH(proto);
for (pp = ip_vs_proto_table[hash]; pp; pp = pp->next) {
if (pp->protocol == proto)
@@ -157,7 +157,7 @@ struct ip_vs_proto_data *
__ipvs_proto_data_get(struct netns_ipvs *ipvs, unsigned short proto)
{
struct ip_vs_proto_data *pd;
- unsigned hash = IP_VS_PROTO_HASH(proto);
+ unsigned int hash = IP_VS_PROTO_HASH(proto);
for (pd = ipvs->proto_data_table[hash]; pd; pd = pd->next) {
if (pd->pp->protocol == proto)
diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c
index 069e8d4d5c01..91e97ee049be 100644
--- a/net/netfilter/ipvs/ip_vs_sh.c
+++ b/net/netfilter/ipvs/ip_vs_sh.c
@@ -70,7 +70,7 @@ struct ip_vs_sh_bucket {
/*
* Returns hash value for IPVS SH entry
*/
-static inline unsigned ip_vs_sh_hashkey(int af, const union nf_inet_addr *addr)
+static inline unsigned int ip_vs_sh_hashkey(int af, const union nf_inet_addr *addr)
{
__be32 addr_fold = addr->ip;
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index 8a0d6d6889f0..bf5e538af67b 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -839,7 +839,7 @@ static void ip_vs_process_message_v0(struct net *net, const char *buffer,
p = (char *)buffer + sizeof(struct ip_vs_sync_mesg_v0);
for (i=0; i<m->nr_conns; i++) {
- unsigned flags, state;
+ unsigned int flags, state;
if (p + SIMPLE_CONN_SIZE > buffer+buflen) {
IP_VS_ERR_RL("BACKUP v0, bogus conn\n");
@@ -1109,7 +1109,7 @@ static void ip_vs_process_message(struct net *net, __u8 *buffer,
for (i=0; i<nr_conns; i++) {
union ip_vs_sync_conn *s;
- unsigned size;
+ unsigned int size;
int retc;
p = msg_end;
@@ -1368,7 +1368,7 @@ static struct socket *make_receive_sock(struct net *net)
*/
sk_change_net(sock->sk, net);
/* it is equivalent to the REUSEADDR option in user-space */
- sock->sk->sk_reuse = 1;
+ sock->sk->sk_reuse = SK_CAN_REUSE;
result = sock->ops->bind(sock, (struct sockaddr *) &mcast_addr,
sizeof(struct sockaddr));
diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c
index f4f8cda05986..d61e0782a797 100644
--- a/net/netfilter/nf_conntrack_acct.c
+++ b/net/netfilter/nf_conntrack_acct.c
@@ -69,8 +69,8 @@ static int nf_conntrack_acct_init_sysctl(struct net *net)
table[0].data = &net->ct.sysctl_acct;
- net->ct.acct_sysctl_header = register_net_sysctl_table(net,
- nf_net_netfilter_sysctl_path, table);
+ net->ct.acct_sysctl_header = register_net_sysctl(net, "net/netfilter",
+ table);
if (!net->ct.acct_sysctl_header) {
printk(KERN_ERR "nf_conntrack_acct: can't register to sysctl.\n");
goto out_register;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 729f157a0efa..cf0747c5741f 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1152,8 +1152,9 @@ static struct nf_ct_ext_type nf_ct_zone_extend __read_mostly = {
int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple)
{
- NLA_PUT_BE16(skb, CTA_PROTO_SRC_PORT, tuple->src.u.tcp.port);
- NLA_PUT_BE16(skb, CTA_PROTO_DST_PORT, tuple->dst.u.tcp.port);
+ if (nla_put_be16(skb, CTA_PROTO_SRC_PORT, tuple->src.u.tcp.port) ||
+ nla_put_be16(skb, CTA_PROTO_DST_PORT, tuple->dst.u.tcp.port))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c
index 5bd3047ddeec..b924f3a49a8e 100644
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -199,8 +199,7 @@ static int nf_conntrack_event_init_sysctl(struct net *net)
table[1].data = &net->ct.sysctl_events_retry_timeout;
net->ct.event_sysctl_header =
- register_net_sysctl_table(net,
- nf_net_netfilter_sysctl_path, table);
+ register_net_sysctl(net, "net/netfilter", table);
if (!net->ct.event_sysctl_header) {
printk(KERN_ERR "nf_ct_event: can't register to sysctl.\n");
goto out_register;
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 722291f8af72..471b054ad002 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -1230,7 +1230,7 @@ static struct nf_conntrack_expect *find_expect(struct nf_conn *ct,
/****************************************************************************/
static int set_expect_timeout(struct nf_conntrack_expect *exp,
- unsigned timeout)
+ unsigned int timeout)
{
if (!exp || !del_timer(&exp->timeout))
return 0;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index ca7e8354e4f8..462ec2dbe561 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -66,7 +66,8 @@ ctnetlink_dump_tuples_proto(struct sk_buff *skb,
nest_parms = nla_nest_start(skb, CTA_TUPLE_PROTO | NLA_F_NESTED);
if (!nest_parms)
goto nla_put_failure;
- NLA_PUT_U8(skb, CTA_PROTO_NUM, tuple->dst.protonum);
+ if (nla_put_u8(skb, CTA_PROTO_NUM, tuple->dst.protonum))
+ goto nla_put_failure;
if (likely(l4proto->tuple_to_nlattr))
ret = l4proto->tuple_to_nlattr(skb, tuple);
@@ -126,7 +127,8 @@ ctnetlink_dump_tuples(struct sk_buff *skb,
static inline int
ctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct)
{
- NLA_PUT_BE32(skb, CTA_STATUS, htonl(ct->status));
+ if (nla_put_be32(skb, CTA_STATUS, htonl(ct->status)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -141,7 +143,8 @@ ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct)
if (timeout < 0)
timeout = 0;
- NLA_PUT_BE32(skb, CTA_TIMEOUT, htonl(timeout));
+ if (nla_put_be32(skb, CTA_TIMEOUT, htonl(timeout)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -190,7 +193,8 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct)
nest_helper = nla_nest_start(skb, CTA_HELP | NLA_F_NESTED);
if (!nest_helper)
goto nla_put_failure;
- NLA_PUT_STRING(skb, CTA_HELP_NAME, helper->name);
+ if (nla_put_string(skb, CTA_HELP_NAME, helper->name))
+ goto nla_put_failure;
if (helper->to_nlattr)
helper->to_nlattr(skb, ct);
@@ -214,8 +218,9 @@ dump_counters(struct sk_buff *skb, u64 pkts, u64 bytes,
if (!nest_count)
goto nla_put_failure;
- NLA_PUT_BE64(skb, CTA_COUNTERS_PACKETS, cpu_to_be64(pkts));
- NLA_PUT_BE64(skb, CTA_COUNTERS_BYTES, cpu_to_be64(bytes));
+ if (nla_put_be64(skb, CTA_COUNTERS_PACKETS, cpu_to_be64(pkts)) ||
+ nla_put_be64(skb, CTA_COUNTERS_BYTES, cpu_to_be64(bytes)))
+ goto nla_put_failure;
nla_nest_end(skb, nest_count);
@@ -260,11 +265,10 @@ ctnetlink_dump_timestamp(struct sk_buff *skb, const struct nf_conn *ct)
if (!nest_count)
goto nla_put_failure;
- NLA_PUT_BE64(skb, CTA_TIMESTAMP_START, cpu_to_be64(tstamp->start));
- if (tstamp->stop != 0) {
- NLA_PUT_BE64(skb, CTA_TIMESTAMP_STOP,
- cpu_to_be64(tstamp->stop));
- }
+ if (nla_put_be64(skb, CTA_TIMESTAMP_START, cpu_to_be64(tstamp->start)) ||
+ (tstamp->stop != 0 && nla_put_be64(skb, CTA_TIMESTAMP_STOP,
+ cpu_to_be64(tstamp->stop))))
+ goto nla_put_failure;
nla_nest_end(skb, nest_count);
return 0;
@@ -277,7 +281,8 @@ nla_put_failure:
static inline int
ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct)
{
- NLA_PUT_BE32(skb, CTA_MARK, htonl(ct->mark));
+ if (nla_put_be32(skb, CTA_MARK, htonl(ct->mark)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -304,7 +309,8 @@ ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
if (!nest_secctx)
goto nla_put_failure;
- NLA_PUT_STRING(skb, CTA_SECCTX_NAME, secctx);
+ if (nla_put_string(skb, CTA_SECCTX_NAME, secctx))
+ goto nla_put_failure;
nla_nest_end(skb, nest_secctx);
ret = 0;
@@ -349,12 +355,13 @@ dump_nat_seq_adj(struct sk_buff *skb, const struct nf_nat_seq *natseq, int type)
if (!nest_parms)
goto nla_put_failure;
- NLA_PUT_BE32(skb, CTA_NAT_SEQ_CORRECTION_POS,
- htonl(natseq->correction_pos));
- NLA_PUT_BE32(skb, CTA_NAT_SEQ_OFFSET_BEFORE,
- htonl(natseq->offset_before));
- NLA_PUT_BE32(skb, CTA_NAT_SEQ_OFFSET_AFTER,
- htonl(natseq->offset_after));
+ if (nla_put_be32(skb, CTA_NAT_SEQ_CORRECTION_POS,
+ htonl(natseq->correction_pos)) ||
+ nla_put_be32(skb, CTA_NAT_SEQ_OFFSET_BEFORE,
+ htonl(natseq->offset_before)) ||
+ nla_put_be32(skb, CTA_NAT_SEQ_OFFSET_AFTER,
+ htonl(natseq->offset_after)))
+ goto nla_put_failure;
nla_nest_end(skb, nest_parms);
@@ -390,7 +397,8 @@ ctnetlink_dump_nat_seq_adj(struct sk_buff *skb, const struct nf_conn *ct)
static inline int
ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct)
{
- NLA_PUT_BE32(skb, CTA_ID, htonl((unsigned long)ct));
+ if (nla_put_be32(skb, CTA_ID, htonl((unsigned long)ct)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -400,7 +408,8 @@ nla_put_failure:
static inline int
ctnetlink_dump_use(struct sk_buff *skb, const struct nf_conn *ct)
{
- NLA_PUT_BE32(skb, CTA_USE, htonl(atomic_read(&ct->ct_general.use)));
+ if (nla_put_be32(skb, CTA_USE, htonl(atomic_read(&ct->ct_general.use))))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -440,8 +449,9 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
goto nla_put_failure;
nla_nest_end(skb, nest_parms);
- if (nf_ct_zone(ct))
- NLA_PUT_BE16(skb, CTA_ZONE, htons(nf_ct_zone(ct)));
+ if (nf_ct_zone(ct) &&
+ nla_put_be16(skb, CTA_ZONE, htons(nf_ct_zone(ct))))
+ goto nla_put_failure;
if (ctnetlink_dump_status(skb, ct) < 0 ||
ctnetlink_dump_timeout(skb, ct) < 0 ||
@@ -617,8 +627,9 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
goto nla_put_failure;
nla_nest_end(skb, nest_parms);
- if (nf_ct_zone(ct))
- NLA_PUT_BE16(skb, CTA_ZONE, htons(nf_ct_zone(ct)));
+ if (nf_ct_zone(ct) &&
+ nla_put_be16(skb, CTA_ZONE, htons(nf_ct_zone(ct))))
+ goto nla_put_failure;
if (ctnetlink_dump_id(skb, ct) < 0)
goto nla_put_failure;
@@ -1705,7 +1716,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
if (!nest_parms)
goto nla_put_failure;
- NLA_PUT_BE32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir));
+ if (nla_put_be32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir)))
+ goto nla_put_failure;
nat_tuple.src.l3num = nf_ct_l3num(master);
nat_tuple.src.u3.ip = exp->saved_ip;
@@ -1718,21 +1730,24 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
nla_nest_end(skb, nest_parms);
}
#endif
- NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout));
- NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp));
- NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags));
- NLA_PUT_BE32(skb, CTA_EXPECT_CLASS, htonl(exp->class));
+ if (nla_put_be32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)) ||
+ nla_put_be32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)) ||
+ nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
+ nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
+ goto nla_put_failure;
help = nfct_help(master);
if (help) {
struct nf_conntrack_helper *helper;
helper = rcu_dereference(help->helper);
- if (helper)
- NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name);
+ if (helper &&
+ nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
+ goto nla_put_failure;
}
expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
- if (expfn != NULL)
- NLA_PUT_STRING(skb, CTA_EXPECT_FN, expfn->name);
+ if (expfn != NULL &&
+ nla_put_string(skb, CTA_EXPECT_FN, expfn->name))
+ goto nla_put_failure;
return 0;
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index be3da2c8cdc5..8b631b07a645 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -36,11 +36,11 @@ static DEFINE_MUTEX(nf_ct_proto_mutex);
#ifdef CONFIG_SYSCTL
static int
-nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_path *path,
+nf_ct_register_sysctl(struct ctl_table_header **header, const char *path,
struct ctl_table *table, unsigned int *users)
{
if (*header == NULL) {
- *header = register_sysctl_paths(path, table);
+ *header = register_net_sysctl(&init_net, path, table);
if (*header == NULL)
return -ENOMEM;
}
@@ -56,7 +56,7 @@ nf_ct_unregister_sysctl(struct ctl_table_header **header,
if (users != NULL && --*users > 0)
return;
- unregister_sysctl_table(*header);
+ unregister_net_sysctl_table(*header);
*header = NULL;
}
#endif
@@ -250,7 +250,7 @@ static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto)
#ifdef CONFIG_SYSCTL
if (l4proto->ctl_table != NULL) {
err = nf_ct_register_sysctl(l4proto->ctl_table_header,
- nf_net_netfilter_sysctl_path,
+ "net/netfilter",
l4proto->ctl_table,
l4proto->ctl_table_users);
if (err < 0)
@@ -259,7 +259,7 @@ static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto)
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
if (l4proto->ctl_compat_table != NULL) {
err = nf_ct_register_sysctl(&l4proto->ctl_compat_table_header,
- nf_net_ipv4_netfilter_sysctl_path,
+ "net/ipv4/netfilter",
l4proto->ctl_compat_table, NULL);
if (err == 0)
goto out;
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index 24fdce256cb0..ef706a485be1 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -643,11 +643,12 @@ static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP | NLA_F_NESTED);
if (!nest_parms)
goto nla_put_failure;
- NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state);
- NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_ROLE,
- ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]);
- NLA_PUT_BE64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
- cpu_to_be64(ct->proto.dccp.handshake_seq));
+ if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state) ||
+ nla_put_u8(skb, CTA_PROTOINFO_DCCP_ROLE,
+ ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]) ||
+ nla_put_be64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
+ cpu_to_be64(ct->proto.dccp.handshake_seq)))
+ goto nla_put_failure;
nla_nest_end(skb, nest_parms);
spin_unlock_bh(&ct->lock);
return 0;
@@ -739,9 +740,10 @@ dccp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
const unsigned int *timeouts = data;
int i;
- for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++)
- NLA_PUT_BE32(skb, i, htonl(timeouts[i] / HZ));
-
+ for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) {
+ if (nla_put_be32(skb, i, htonl(timeouts[i] / HZ)))
+ goto nla_put_failure;
+ }
return 0;
nla_put_failure:
@@ -908,8 +910,8 @@ static __net_init int dccp_net_init(struct net *net)
dn->sysctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
dn->sysctl_table[7].data = &dn->dccp_loose;
- dn->sysctl_header = register_net_sysctl_table(net,
- nf_net_netfilter_sysctl_path, dn->sysctl_table);
+ dn->sysctl_header = register_net_sysctl(net, "net/netfilter",
+ dn->sysctl_table);
if (!dn->sysctl_header) {
kfree(dn->sysctl_table);
return -ENOMEM;
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index 835e24c58f0d..d8923d54b358 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -90,7 +90,8 @@ generic_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeout = data;
- NLA_PUT_BE32(skb, CTA_TIMEOUT_GENERIC_TIMEOUT, htonl(*timeout / HZ));
+ if (nla_put_be32(skb, CTA_TIMEOUT_GENERIC_TIMEOUT, htonl(*timeout / HZ)))
+ goto nla_put_failure;
return 0;
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index 659648c4b14a..4bf6b4e4b776 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -321,10 +321,11 @@ gre_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeouts = data;
- NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_UNREPLIED,
- htonl(timeouts[GRE_CT_UNREPLIED] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_REPLIED,
- htonl(timeouts[GRE_CT_REPLIED] / HZ));
+ if (nla_put_be32(skb, CTA_TIMEOUT_GRE_UNREPLIED,
+ htonl(timeouts[GRE_CT_UNREPLIED] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_GRE_REPLIED,
+ htonl(timeouts[GRE_CT_REPLIED] / HZ)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index 72b5088592dc..996db2fa21f7 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -482,15 +482,12 @@ static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
if (!nest_parms)
goto nla_put_failure;
- NLA_PUT_U8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state);
-
- NLA_PUT_BE32(skb,
- CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
- ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL]);
-
- NLA_PUT_BE32(skb,
- CTA_PROTOINFO_SCTP_VTAG_REPLY,
- ct->proto.sctp.vtag[IP_CT_DIR_REPLY]);
+ if (nla_put_u8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state) ||
+ nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
+ ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL]) ||
+ nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_REPLY,
+ ct->proto.sctp.vtag[IP_CT_DIR_REPLY]))
+ goto nla_put_failure;
spin_unlock_bh(&ct->lock);
@@ -578,9 +575,10 @@ sctp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
const unsigned int *timeouts = data;
int i;
- for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++)
- NLA_PUT_BE32(skb, i, htonl(timeouts[i] / HZ));
-
+ for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) {
+ if (nla_put_be32(skb, i, htonl(timeouts[i] / HZ)))
+ goto nla_put_failure;
+ }
return 0;
nla_put_failure:
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 0d07a1dcf605..4dfbfa840f8a 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -1147,21 +1147,22 @@ static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
if (!nest_parms)
goto nla_put_failure;
- NLA_PUT_U8(skb, CTA_PROTOINFO_TCP_STATE, ct->proto.tcp.state);
-
- NLA_PUT_U8(skb, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
- ct->proto.tcp.seen[0].td_scale);
-
- NLA_PUT_U8(skb, CTA_PROTOINFO_TCP_WSCALE_REPLY,
- ct->proto.tcp.seen[1].td_scale);
+ if (nla_put_u8(skb, CTA_PROTOINFO_TCP_STATE, ct->proto.tcp.state) ||
+ nla_put_u8(skb, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
+ ct->proto.tcp.seen[0].td_scale) ||
+ nla_put_u8(skb, CTA_PROTOINFO_TCP_WSCALE_REPLY,
+ ct->proto.tcp.seen[1].td_scale))
+ goto nla_put_failure;
tmp.flags = ct->proto.tcp.seen[0].flags;
- NLA_PUT(skb, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
- sizeof(struct nf_ct_tcp_flags), &tmp);
+ if (nla_put(skb, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
+ sizeof(struct nf_ct_tcp_flags), &tmp))
+ goto nla_put_failure;
tmp.flags = ct->proto.tcp.seen[1].flags;
- NLA_PUT(skb, CTA_PROTOINFO_TCP_FLAGS_REPLY,
- sizeof(struct nf_ct_tcp_flags), &tmp);
+ if (nla_put(skb, CTA_PROTOINFO_TCP_FLAGS_REPLY,
+ sizeof(struct nf_ct_tcp_flags), &tmp))
+ goto nla_put_failure;
spin_unlock_bh(&ct->lock);
nla_nest_end(skb, nest_parms);
@@ -1310,28 +1311,29 @@ tcp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeouts = data;
- NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_SENT,
- htonl(timeouts[TCP_CONNTRACK_SYN_SENT] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_RECV,
- htonl(timeouts[TCP_CONNTRACK_SYN_RECV] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_ESTABLISHED,
- htonl(timeouts[TCP_CONNTRACK_ESTABLISHED] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_FIN_WAIT,
- htonl(timeouts[TCP_CONNTRACK_FIN_WAIT] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_CLOSE_WAIT,
- htonl(timeouts[TCP_CONNTRACK_CLOSE_WAIT] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_LAST_ACK,
- htonl(timeouts[TCP_CONNTRACK_LAST_ACK] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_TIME_WAIT,
- htonl(timeouts[TCP_CONNTRACK_TIME_WAIT] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_CLOSE,
- htonl(timeouts[TCP_CONNTRACK_CLOSE] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_SENT2,
- htonl(timeouts[TCP_CONNTRACK_SYN_SENT2] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_RETRANS,
- htonl(timeouts[TCP_CONNTRACK_RETRANS] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_UNACK,
- htonl(timeouts[TCP_CONNTRACK_UNACK] / HZ));
+ if (nla_put_be32(skb, CTA_TIMEOUT_TCP_SYN_SENT,
+ htonl(timeouts[TCP_CONNTRACK_SYN_SENT] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_TCP_SYN_RECV,
+ htonl(timeouts[TCP_CONNTRACK_SYN_RECV] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_TCP_ESTABLISHED,
+ htonl(timeouts[TCP_CONNTRACK_ESTABLISHED] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_TCP_FIN_WAIT,
+ htonl(timeouts[TCP_CONNTRACK_FIN_WAIT] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_TCP_CLOSE_WAIT,
+ htonl(timeouts[TCP_CONNTRACK_CLOSE_WAIT] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_TCP_LAST_ACK,
+ htonl(timeouts[TCP_CONNTRACK_LAST_ACK] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_TCP_TIME_WAIT,
+ htonl(timeouts[TCP_CONNTRACK_TIME_WAIT] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_TCP_CLOSE,
+ htonl(timeouts[TCP_CONNTRACK_CLOSE] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_TCP_SYN_SENT2,
+ htonl(timeouts[TCP_CONNTRACK_SYN_SENT2] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_TCP_RETRANS,
+ htonl(timeouts[TCP_CONNTRACK_RETRANS] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_TCP_UNACK,
+ htonl(timeouts[TCP_CONNTRACK_UNACK] / HZ)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index a9073dc1548d..7259a6bdeb49 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -181,10 +181,11 @@ udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeouts = data;
- NLA_PUT_BE32(skb, CTA_TIMEOUT_UDP_UNREPLIED,
- htonl(timeouts[UDP_CT_UNREPLIED] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_UDP_REPLIED,
- htonl(timeouts[UDP_CT_REPLIED] / HZ));
+ if (nla_put_be32(skb, CTA_TIMEOUT_UDP_UNREPLIED,
+ htonl(timeouts[UDP_CT_UNREPLIED] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_UDP_REPLIED,
+ htonl(timeouts[UDP_CT_REPLIED] / HZ)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c
index e0606392cda0..4d60a5376aa6 100644
--- a/net/netfilter/nf_conntrack_proto_udplite.c
+++ b/net/netfilter/nf_conntrack_proto_udplite.c
@@ -185,10 +185,11 @@ udplite_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeouts = data;
- NLA_PUT_BE32(skb, CTA_TIMEOUT_UDPLITE_UNREPLIED,
- htonl(timeouts[UDPLITE_CT_UNREPLIED] / HZ));
- NLA_PUT_BE32(skb, CTA_TIMEOUT_UDPLITE_REPLIED,
- htonl(timeouts[UDPLITE_CT_REPLIED] / HZ));
+ if (nla_put_be32(skb, CTA_TIMEOUT_UDPLITE_UNREPLIED,
+ htonl(timeouts[UDPLITE_CT_UNREPLIED] / HZ)) ||
+ nla_put_be32(skb, CTA_TIMEOUT_UDPLITE_REPLIED,
+ htonl(timeouts[UDPLITE_CT_REPLIED] / HZ)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 885f5ab9bc28..9b3943252a5e 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -468,18 +468,13 @@ static ctl_table nf_ct_netfilter_table[] = {
{ }
};
-static struct ctl_path nf_ct_path[] = {
- { .procname = "net", },
- { }
-};
-
static int nf_conntrack_standalone_init_sysctl(struct net *net)
{
struct ctl_table *table;
if (net_eq(net, &init_net)) {
nf_ct_netfilter_header =
- register_sysctl_paths(nf_ct_path, nf_ct_netfilter_table);
+ register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
if (!nf_ct_netfilter_header)
goto out;
}
@@ -494,8 +489,7 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
table[3].data = &net->ct.sysctl_checksum;
table[4].data = &net->ct.sysctl_log_invalid;
- net->ct.sysctl_header = register_net_sysctl_table(net,
- nf_net_netfilter_sysctl_path, table);
+ net->ct.sysctl_header = register_net_sysctl(net, "net/netfilter", table);
if (!net->ct.sysctl_header)
goto out_unregister_netfilter;
@@ -505,7 +499,7 @@ out_unregister_netfilter:
kfree(table);
out_kmemdup:
if (net_eq(net, &init_net))
- unregister_sysctl_table(nf_ct_netfilter_header);
+ unregister_net_sysctl_table(nf_ct_netfilter_header);
out:
printk(KERN_ERR "nf_conntrack: can't register to sysctl.\n");
return -ENOMEM;
@@ -516,7 +510,7 @@ static void nf_conntrack_standalone_fini_sysctl(struct net *net)
struct ctl_table *table;
if (net_eq(net, &init_net))
- unregister_sysctl_table(nf_ct_netfilter_header);
+ unregister_net_sysctl_table(nf_ct_netfilter_header);
table = net->ct.sysctl_header->ctl_table_arg;
unregister_net_sysctl_table(net->ct.sysctl_header);
kfree(table);
diff --git a/net/netfilter/nf_conntrack_timestamp.c b/net/netfilter/nf_conntrack_timestamp.c
index e8d27afbbdb9..dbb364f62d6f 100644
--- a/net/netfilter/nf_conntrack_timestamp.c
+++ b/net/netfilter/nf_conntrack_timestamp.c
@@ -51,8 +51,8 @@ static int nf_conntrack_tstamp_init_sysctl(struct net *net)
table[0].data = &net->ct.sysctl_tstamp;
- net->ct.tstamp_sysctl_header = register_net_sysctl_table(net,
- nf_net_netfilter_sysctl_path, table);
+ net->ct.tstamp_sysctl_header = register_net_sysctl(net, "net/netfilter",
+ table);
if (!net->ct.tstamp_sysctl_header) {
printk(KERN_ERR "nf_ct_tstamp: can't register to sysctl.\n");
goto out_register;
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index 957374a234d4..703fb26aa48d 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -214,13 +214,6 @@ static const struct file_operations nflog_file_ops = {
#endif /* PROC_FS */
#ifdef CONFIG_SYSCTL
-static struct ctl_path nf_log_sysctl_path[] = {
- { .procname = "net", },
- { .procname = "netfilter", },
- { .procname = "nf_log", },
- { }
-};
-
static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
static struct ctl_table_header *nf_log_dir_header;
@@ -283,7 +276,7 @@ static __init int netfilter_log_sysctl_init(void)
nf_log_sysctl_table[i].extra1 = (void *)(unsigned long) i;
}
- nf_log_dir_header = register_sysctl_paths(nf_log_sysctl_path,
+ nf_log_dir_header = register_net_sysctl(&init_net, "net/netfilter/nf_log",
nf_log_sysctl_table);
if (!nf_log_dir_header)
return -ENOMEM;
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index e6ddde165612..3e797d1fcb94 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -103,7 +103,7 @@ int nfnetlink_has_listeners(struct net *net, unsigned int group)
EXPORT_SYMBOL_GPL(nfnetlink_has_listeners);
int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid,
- unsigned group, int echo, gfp_t flags)
+ unsigned int group, int echo, gfp_t flags)
{
return nlmsg_notify(net->nfnl, skb, pid, group, echo, flags);
}
diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c
index d98c868c148b..b2e7310ca0b8 100644
--- a/net/netfilter/nfnetlink_acct.c
+++ b/net/netfilter/nfnetlink_acct.c
@@ -109,7 +109,8 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
nfmsg->version = NFNETLINK_V0;
nfmsg->res_id = 0;
- NLA_PUT_STRING(skb, NFACCT_NAME, acct->name);
+ if (nla_put_string(skb, NFACCT_NAME, acct->name))
+ goto nla_put_failure;
if (type == NFNL_MSG_ACCT_GET_CTRZERO) {
pkts = atomic64_xchg(&acct->pkts, 0);
@@ -118,9 +119,10 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
pkts = atomic64_read(&acct->pkts);
bytes = atomic64_read(&acct->bytes);
}
- NLA_PUT_BE64(skb, NFACCT_PKTS, cpu_to_be64(pkts));
- NLA_PUT_BE64(skb, NFACCT_BYTES, cpu_to_be64(bytes));
- NLA_PUT_BE32(skb, NFACCT_USE, htonl(atomic_read(&acct->refcnt)));
+ if (nla_put_be64(skb, NFACCT_PKTS, cpu_to_be64(pkts)) ||
+ nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes)) ||
+ nla_put_be32(skb, NFACCT_USE, htonl(atomic_read(&acct->refcnt))))
+ goto nla_put_failure;
nlmsg_end(skb, nlh);
return skb->len;
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c
index 2b9e79f5ef05..3e655288d1d6 100644
--- a/net/netfilter/nfnetlink_cttimeout.c
+++ b/net/netfilter/nfnetlink_cttimeout.c
@@ -170,11 +170,12 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
nfmsg->version = NFNETLINK_V0;
nfmsg->res_id = 0;
- NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name);
- NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num));
- NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto);
- NLA_PUT_BE32(skb, CTA_TIMEOUT_USE,
- htonl(atomic_read(&timeout->refcnt)));
+ if (nla_put_string(skb, CTA_TIMEOUT_NAME, timeout->name) ||
+ nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)) ||
+ nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto) ||
+ nla_put_be32(skb, CTA_TIMEOUT_USE,
+ htonl(atomic_read(&timeout->refcnt))))
+ goto nla_put_failure;
if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) {
struct nlattr *nest_parms;
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 66b2c54c544f..3c3cfc0cc9b5 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -391,67 +391,78 @@ __build_packet_message(struct nfulnl_instance *inst,
pmsg.hw_protocol = skb->protocol;
pmsg.hook = hooknum;
- NLA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg);
+ if (nla_put(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg))
+ goto nla_put_failure;
- if (prefix)
- NLA_PUT(inst->skb, NFULA_PREFIX, plen, prefix);
+ if (prefix &&
+ nla_put(inst->skb, NFULA_PREFIX, plen, prefix))
+ goto nla_put_failure;
if (indev) {
#ifndef CONFIG_BRIDGE_NETFILTER
- NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV,
- htonl(indev->ifindex));
+ if (nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV,
+ htonl(indev->ifindex)))
+ goto nla_put_failure;
#else
if (pf == PF_BRIDGE) {
/* Case 1: outdev is physical input device, we need to
* look for bridge group (when called from
* netfilter_bridge) */
- NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSINDEV,
- htonl(indev->ifindex));
+ if (nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSINDEV,
+ htonl(indev->ifindex)) ||
/* this is the bridge group "brX" */
/* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
- NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV,
- htonl(br_port_get_rcu(indev)->br->dev->ifindex));
+ nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV,
+ htonl(br_port_get_rcu(indev)->br->dev->ifindex)))
+ goto nla_put_failure;
} else {
/* Case 2: indev is bridge group, we need to look for
* physical device (when called from ipv4) */
- NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV,
- htonl(indev->ifindex));
- if (skb->nf_bridge && skb->nf_bridge->physindev)
- NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSINDEV,
- htonl(skb->nf_bridge->physindev->ifindex));
+ if (nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV,
+ htonl(indev->ifindex)))
+ goto nla_put_failure;
+ if (skb->nf_bridge && skb->nf_bridge->physindev &&
+ nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSINDEV,
+ htonl(skb->nf_bridge->physindev->ifindex)))
+ goto nla_put_failure;
}
#endif
}
if (outdev) {
#ifndef CONFIG_BRIDGE_NETFILTER
- NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV,
- htonl(outdev->ifindex));
+ if (nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV,
+ htonl(outdev->ifindex)))
+ goto nla_put_failure;
#else
if (pf == PF_BRIDGE) {
/* Case 1: outdev is physical output device, we need to
* look for bridge group (when called from
* netfilter_bridge) */
- NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
- htonl(outdev->ifindex));
+ if (nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
+ htonl(outdev->ifindex)) ||
/* this is the bridge group "brX" */
/* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
- NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV,
- htonl(br_port_get_rcu(outdev)->br->dev->ifindex));
+ nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV,
+ htonl(br_port_get_rcu(outdev)->br->dev->ifindex)))
+ goto nla_put_failure;
} else {
/* Case 2: indev is a bridge group, we need to look
* for physical device (when called from ipv4) */
- NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV,
- htonl(outdev->ifindex));
- if (skb->nf_bridge && skb->nf_bridge->physoutdev)
- NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
- htonl(skb->nf_bridge->physoutdev->ifindex));
+ if (nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV,
+ htonl(outdev->ifindex)))
+ goto nla_put_failure;
+ if (skb->nf_bridge && skb->nf_bridge->physoutdev &&
+ nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
+ htonl(skb->nf_bridge->physoutdev->ifindex)))
+ goto nla_put_failure;
}
#endif
}
- if (skb->mark)
- NLA_PUT_BE32(inst->skb, NFULA_MARK, htonl(skb->mark));
+ if (skb->mark &&
+ nla_put_be32(inst->skb, NFULA_MARK, htonl(skb->mark)))
+ goto nla_put_failure;
if (indev && skb->dev &&
skb->mac_header != skb->network_header) {
@@ -459,16 +470,18 @@ __build_packet_message(struct nfulnl_instance *inst,
int len = dev_parse_header(skb, phw.hw_addr);
if (len > 0) {
phw.hw_addrlen = htons(len);
- NLA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw);
+ if (nla_put(inst->skb, NFULA_HWADDR, sizeof(phw), &phw))
+ goto nla_put_failure;
}
}
if (indev && skb_mac_header_was_set(skb)) {
- NLA_PUT_BE16(inst->skb, NFULA_HWTYPE, htons(skb->dev->type));
- NLA_PUT_BE16(inst->skb, NFULA_HWLEN,
- htons(skb->dev->hard_header_len));
- NLA_PUT(inst->skb, NFULA_HWHEADER, skb->dev->hard_header_len,
- skb_mac_header(skb));
+ if (nla_put_be32(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) ||
+ nla_put_be16(inst->skb, NFULA_HWLEN,
+ htons(skb->dev->hard_header_len)) ||
+ nla_put(inst->skb, NFULA_HWHEADER, skb->dev->hard_header_len,
+ skb_mac_header(skb)))
+ goto nla_put_failure;
}
if (skb->tstamp.tv64) {
@@ -477,7 +490,8 @@ __build_packet_message(struct nfulnl_instance *inst,
ts.sec = cpu_to_be64(tv.tv_sec);
ts.usec = cpu_to_be64(tv.tv_usec);
- NLA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts);
+ if (nla_put(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts))
+ goto nla_put_failure;
}
/* UID */
@@ -487,22 +501,24 @@ __build_packet_message(struct nfulnl_instance *inst,
struct file *file = skb->sk->sk_socket->file;
__be32 uid = htonl(file->f_cred->fsuid);
__be32 gid = htonl(file->f_cred->fsgid);
- /* need to unlock here since NLA_PUT may goto */
read_unlock_bh(&skb->sk->sk_callback_lock);
- NLA_PUT_BE32(inst->skb, NFULA_UID, uid);
- NLA_PUT_BE32(inst->skb, NFULA_GID, gid);
+ if (nla_put_be32(inst->skb, NFULA_UID, uid) ||
+ nla_put_be32(inst->skb, NFULA_GID, gid))
+ goto nla_put_failure;
} else
read_unlock_bh(&skb->sk->sk_callback_lock);
}
/* local sequence number */
- if (inst->flags & NFULNL_CFG_F_SEQ)
- NLA_PUT_BE32(inst->skb, NFULA_SEQ, htonl(inst->seq++));
+ if ((inst->flags & NFULNL_CFG_F_SEQ) &&
+ nla_put_be32(inst->skb, NFULA_SEQ, htonl(inst->seq++)))
+ goto nla_put_failure;
/* global sequence number */
- if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL)
- NLA_PUT_BE32(inst->skb, NFULA_SEQ_GLOBAL,
- htonl(atomic_inc_return(&global_seq)));
+ if ((inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) &&
+ nla_put_be32(inst->skb, NFULA_SEQ_GLOBAL,
+ htonl(atomic_inc_return(&global_seq))))
+ goto nla_put_failure;
if (data_len) {
struct nlattr *nla;
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index a80b0cb03f17..8d6bcf32c0ed 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -288,58 +288,67 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
indev = entry->indev;
if (indev) {
#ifndef CONFIG_BRIDGE_NETFILTER
- NLA_PUT_BE32(skb, NFQA_IFINDEX_INDEV, htonl(indev->ifindex));
+ if (nla_put_be32(skb, NFQA_IFINDEX_INDEV, htonl(indev->ifindex)))
+ goto nla_put_failure;
#else
if (entry->pf == PF_BRIDGE) {
/* Case 1: indev is physical input device, we need to
* look for bridge group (when called from
* netfilter_bridge) */
- NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSINDEV,
- htonl(indev->ifindex));
+ if (nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV,
+ htonl(indev->ifindex)) ||
/* this is the bridge group "brX" */
/* rcu_read_lock()ed by __nf_queue */
- NLA_PUT_BE32(skb, NFQA_IFINDEX_INDEV,
- htonl(br_port_get_rcu(indev)->br->dev->ifindex));
+ nla_put_be32(skb, NFQA_IFINDEX_INDEV,
+ htonl(br_port_get_rcu(indev)->br->dev->ifindex)))
+ goto nla_put_failure;
} else {
/* Case 2: indev is bridge group, we need to look for
* physical device (when called from ipv4) */
- NLA_PUT_BE32(skb, NFQA_IFINDEX_INDEV,
- htonl(indev->ifindex));
- if (entskb->nf_bridge && entskb->nf_bridge->physindev)
- NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSINDEV,
- htonl(entskb->nf_bridge->physindev->ifindex));
+ if (nla_put_be32(skb, NFQA_IFINDEX_INDEV,
+ htonl(indev->ifindex)))
+ goto nla_put_failure;
+ if (entskb->nf_bridge && entskb->nf_bridge->physindev &&
+ nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV,
+ htonl(entskb->nf_bridge->physindev->ifindex)))
+ goto nla_put_failure;
}
#endif
}
if (outdev) {
#ifndef CONFIG_BRIDGE_NETFILTER
- NLA_PUT_BE32(skb, NFQA_IFINDEX_OUTDEV, htonl(outdev->ifindex));
+ if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, htonl(outdev->ifindex)))
+ goto nla_put_failure;
#else
if (entry->pf == PF_BRIDGE) {
/* Case 1: outdev is physical output device, we need to
* look for bridge group (when called from
* netfilter_bridge) */
- NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSOUTDEV,
- htonl(outdev->ifindex));
+ if (nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV,
+ htonl(outdev->ifindex)) ||
/* this is the bridge group "brX" */
/* rcu_read_lock()ed by __nf_queue */
- NLA_PUT_BE32(skb, NFQA_IFINDEX_OUTDEV,
- htonl(br_port_get_rcu(outdev)->br->dev->ifindex));
+ nla_put_be32(skb, NFQA_IFINDEX_OUTDEV,
+ htonl(br_port_get_rcu(outdev)->br->dev->ifindex)))
+ goto nla_put_failure;
} else {
/* Case 2: outdev is bridge group, we need to look for
* physical output device (when called from ipv4) */
- NLA_PUT_BE32(skb, NFQA_IFINDEX_OUTDEV,
- htonl(outdev->ifindex));
- if (entskb->nf_bridge && entskb->nf_bridge->physoutdev)
- NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSOUTDEV,
- htonl(entskb->nf_bridge->physoutdev->ifindex));
+ if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV,
+ htonl(outdev->ifindex)))
+ goto nla_put_failure;
+ if (entskb->nf_bridge && entskb->nf_bridge->physoutdev &&
+ nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV,
+ htonl(entskb->nf_bridge->physoutdev->ifindex)))
+ goto nla_put_failure;
}
#endif
}
- if (entskb->mark)
- NLA_PUT_BE32(skb, NFQA_MARK, htonl(entskb->mark));
+ if (entskb->mark &&
+ nla_put_be32(skb, NFQA_MARK, htonl(entskb->mark)))
+ goto nla_put_failure;
if (indev && entskb->dev &&
entskb->mac_header != entskb->network_header) {
@@ -347,7 +356,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
int len = dev_parse_header(entskb, phw.hw_addr);
if (len) {
phw.hw_addrlen = htons(len);
- NLA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw);
+ if (nla_put(skb, NFQA_HWADDR, sizeof(phw), &phw))
+ goto nla_put_failure;
}
}
@@ -357,7 +367,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
ts.sec = cpu_to_be64(tv.tv_sec);
ts.usec = cpu_to_be64(tv.tv_usec);
- NLA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts);
+ if (nla_put(skb, NFQA_TIMESTAMP, sizeof(ts), &ts))
+ goto nla_put_failure;
}
if (data_len) {
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index d2ff15a2412b..fc0d6dbe5d17 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -314,7 +314,7 @@ static int recent_mt_check(const struct xt_mtchk_param *par)
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *pde;
#endif
- unsigned i;
+ unsigned int i;
int ret = -EINVAL;
if (unlikely(!hash_rnd_inited)) {
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index faa48f70b7c9..da8721443503 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -866,7 +866,7 @@ static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
struct sk_buff *nskb = skb_clone(skb, allocation);
if (!nskb)
return skb;
- kfree_skb(skb);
+ consume_skb(skb);
skb = nskb;
}
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 9f40441d7a7d..8340ace837f2 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -635,11 +635,12 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
if (hdr == NULL)
return -1;
- NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name);
- NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id);
- NLA_PUT_U32(skb, CTRL_ATTR_VERSION, family->version);
- NLA_PUT_U32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize);
- NLA_PUT_U32(skb, CTRL_ATTR_MAXATTR, family->maxattr);
+ if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) ||
+ nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id) ||
+ nla_put_u32(skb, CTRL_ATTR_VERSION, family->version) ||
+ nla_put_u32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize) ||
+ nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr))
+ goto nla_put_failure;
if (!list_empty(&family->ops_list)) {
struct nlattr *nla_ops;
@@ -657,8 +658,9 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT_U32(skb, CTRL_ATTR_OP_ID, ops->cmd);
- NLA_PUT_U32(skb, CTRL_ATTR_OP_FLAGS, ops->flags);
+ if (nla_put_u32(skb, CTRL_ATTR_OP_ID, ops->cmd) ||
+ nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, ops->flags))
+ goto nla_put_failure;
nla_nest_end(skb, nest);
}
@@ -682,9 +684,10 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
- NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
- grp->name);
+ 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;
nla_nest_end(skb, nest);
}
@@ -710,8 +713,9 @@ static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 pid,
if (hdr == NULL)
return -1;
- 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, grp->family->name) ||
+ nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, grp->family->id))
+ goto nla_put_failure;
nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
if (nla_grps == NULL)
@@ -721,9 +725,10 @@ static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 pid,
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
- NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
- grp->name);
+ 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;
nla_nest_end(skb, nest);
nla_nest_end(skb, nla_grps);
diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
index 1c51d7a58f0b..743262becd6e 100644
--- a/net/netrom/nr_dev.c
+++ b/net/netrom/nr_dev.c
@@ -97,7 +97,7 @@ static int nr_rebuild_header(struct sk_buff *skb)
static int nr_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
- const void *daddr, const void *saddr, unsigned len)
+ const void *daddr, const void *saddr, unsigned int len)
{
unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
diff --git a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c
index 1e0fa9e57aac..42f630b9a698 100644
--- a/net/netrom/sysctl_net_netrom.c
+++ b/net/netrom/sysctl_net_netrom.c
@@ -146,18 +146,12 @@ static ctl_table nr_table[] = {
{ }
};
-static struct ctl_path nr_path[] = {
- { .procname = "net", },
- { .procname = "netrom", },
- { }
-};
-
void __init nr_register_sysctl(void)
{
- nr_table_header = register_sysctl_paths(nr_path, nr_table);
+ nr_table_header = register_net_sysctl(&init_net, "net/netrom", nr_table);
}
void nr_unregister_sysctl(void)
{
- unregister_sysctl_table(nr_table_header);
+ unregister_net_sysctl_table(nr_table_header);
}
diff --git a/net/nfc/Kconfig b/net/nfc/Kconfig
index 44c865b86d6f..8d8d9bc4b6ff 100644
--- a/net/nfc/Kconfig
+++ b/net/nfc/Kconfig
@@ -14,6 +14,7 @@ menuconfig NFC
be called nfc.
source "net/nfc/nci/Kconfig"
+source "net/nfc/hci/Kconfig"
source "net/nfc/llcp/Kconfig"
source "drivers/nfc/Kconfig"
diff --git a/net/nfc/Makefile b/net/nfc/Makefile
index 7b4a6dcfa566..d1a117c2c401 100644
--- a/net/nfc/Makefile
+++ b/net/nfc/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_NFC) += nfc.o
obj-$(CONFIG_NFC_NCI) += nci/
+obj-$(CONFIG_NFC_HCI) += hci/
nfc-objs := core.o netlink.o af_nfc.o rawsock.o
nfc-$(CONFIG_NFC_LLCP) += llcp/llcp.o llcp/commands.o llcp/sock.o
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 295d129864d2..3192c3f589ee 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -33,6 +33,8 @@
#define VERSION "0.1"
+#define NFC_CHECK_PRES_FREQ_MS 2000
+
int nfc_devlist_generation;
DEFINE_MUTEX(nfc_devlist_mutex);
@@ -95,7 +97,7 @@ int nfc_dev_down(struct nfc_dev *dev)
goto error;
}
- if (dev->polling || dev->remote_activated) {
+ if (dev->polling || dev->activated_target_idx != NFC_TARGET_IDX_NONE) {
rc = -EBUSY;
goto error;
}
@@ -211,6 +213,8 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode)
}
rc = dev->ops->dep_link_up(dev, target_index, comm_mode, gb, gb_len);
+ if (!rc)
+ dev->activated_target_idx = target_index;
error:
device_unlock(&dev->dev);
@@ -246,6 +250,7 @@ int nfc_dep_link_down(struct nfc_dev *dev)
rc = dev->ops->dep_link_down(dev);
if (!rc) {
dev->dep_link_up = false;
+ dev->activated_target_idx = NFC_TARGET_IDX_NONE;
nfc_llcp_mac_is_down(dev);
nfc_genl_dep_link_down_event(dev);
}
@@ -289,8 +294,13 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
}
rc = dev->ops->activate_target(dev, target_idx, protocol);
- if (!rc)
- dev->remote_activated = true;
+ if (!rc) {
+ dev->activated_target_idx = target_idx;
+
+ if (dev->ops->check_presence)
+ mod_timer(&dev->check_pres_timer, jiffies +
+ msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
+ }
error:
device_unlock(&dev->dev);
@@ -317,8 +327,11 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx)
goto error;
}
+ if (dev->ops->check_presence)
+ del_timer_sync(&dev->check_pres_timer);
+
dev->ops->deactivate_target(dev, target_idx);
- dev->remote_activated = false;
+ dev->activated_target_idx = NFC_TARGET_IDX_NONE;
error:
device_unlock(&dev->dev);
@@ -352,8 +365,27 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
goto error;
}
+ if (dev->activated_target_idx == NFC_TARGET_IDX_NONE) {
+ rc = -ENOTCONN;
+ kfree_skb(skb);
+ goto error;
+ }
+
+ if (target_idx != dev->activated_target_idx) {
+ rc = -EADDRNOTAVAIL;
+ kfree_skb(skb);
+ goto error;
+ }
+
+ if (dev->ops->check_presence)
+ del_timer_sync(&dev->check_pres_timer);
+
rc = dev->ops->data_exchange(dev, target_idx, skb, cb, cb_context);
+ if (!rc && dev->ops->check_presence)
+ mod_timer(&dev->check_pres_timer, jiffies +
+ msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
+
error:
device_unlock(&dev->dev);
return rc;
@@ -428,10 +460,15 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb);
int nfc_targets_found(struct nfc_dev *dev,
struct nfc_target *targets, int n_targets)
{
+ int i;
+
pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets);
dev->polling = false;
+ for (i = 0; i < n_targets; i++)
+ targets[i].idx = dev->target_next_idx++;
+
spin_lock_bh(&dev->targets_lock);
dev->targets_generation++;
@@ -455,17 +492,92 @@ int nfc_targets_found(struct nfc_dev *dev,
}
EXPORT_SYMBOL(nfc_targets_found);
+int nfc_target_lost(struct nfc_dev *dev, u32 target_idx)
+{
+ struct nfc_target *tg;
+ int i;
+
+ pr_debug("dev_name %s n_target %d\n", dev_name(&dev->dev), target_idx);
+
+ spin_lock_bh(&dev->targets_lock);
+
+ for (i = 0; i < dev->n_targets; i++) {
+ tg = &dev->targets[i];
+ if (tg->idx == target_idx)
+ break;
+ }
+
+ if (i == dev->n_targets) {
+ spin_unlock_bh(&dev->targets_lock);
+ return -EINVAL;
+ }
+
+ dev->targets_generation++;
+ dev->n_targets--;
+ dev->activated_target_idx = NFC_TARGET_IDX_NONE;
+
+ if (dev->n_targets) {
+ memcpy(&dev->targets[i], &dev->targets[i + 1],
+ (dev->n_targets - i) * sizeof(struct nfc_target));
+ } else {
+ kfree(dev->targets);
+ dev->targets = NULL;
+ }
+
+ spin_unlock_bh(&dev->targets_lock);
+
+ nfc_genl_target_lost(dev, target_idx);
+
+ return 0;
+}
+EXPORT_SYMBOL(nfc_target_lost);
+
static void nfc_release(struct device *d)
{
struct nfc_dev *dev = to_nfc_dev(d);
pr_debug("dev_name=%s\n", dev_name(&dev->dev));
+ if (dev->ops->check_presence) {
+ del_timer_sync(&dev->check_pres_timer);
+ destroy_workqueue(dev->check_pres_wq);
+ }
+
nfc_genl_data_exit(&dev->genl_data);
kfree(dev->targets);
kfree(dev);
}
+static void nfc_check_pres_work(struct work_struct *work)
+{
+ struct nfc_dev *dev = container_of(work, struct nfc_dev,
+ check_pres_work);
+ int rc;
+
+ device_lock(&dev->dev);
+
+ if (dev->activated_target_idx != NFC_TARGET_IDX_NONE &&
+ timer_pending(&dev->check_pres_timer) == 0) {
+ rc = dev->ops->check_presence(dev, dev->activated_target_idx);
+ if (!rc) {
+ mod_timer(&dev->check_pres_timer, jiffies +
+ msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
+ } else {
+ nfc_target_lost(dev, dev->activated_target_idx);
+ dev->activated_target_idx = NFC_TARGET_IDX_NONE;
+ }
+ }
+
+ device_unlock(&dev->dev);
+}
+
+static void nfc_check_pres_timeout(unsigned long data)
+{
+ struct nfc_dev *dev = (struct nfc_dev *)data;
+
+ queue_work(dev->check_pres_wq, &dev->check_pres_work);
+}
+
struct class nfc_class = {
.name = "nfc",
.dev_release = nfc_release,
@@ -475,12 +587,12 @@ EXPORT_SYMBOL(nfc_class);
static int match_idx(struct device *d, void *data)
{
struct nfc_dev *dev = to_nfc_dev(d);
- unsigned *idx = data;
+ unsigned int *idx = data;
return dev->idx == *idx;
}
-struct nfc_dev *nfc_get_device(unsigned idx)
+struct nfc_dev *nfc_get_device(unsigned int idx)
{
struct device *d;
@@ -531,6 +643,26 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
/* first generation must not be 0 */
dev->targets_generation = 1;
+ dev->activated_target_idx = NFC_TARGET_IDX_NONE;
+
+ if (ops->check_presence) {
+ char name[32];
+ init_timer(&dev->check_pres_timer);
+ dev->check_pres_timer.data = (unsigned long)dev;
+ dev->check_pres_timer.function = nfc_check_pres_timeout;
+
+ INIT_WORK(&dev->check_pres_work, nfc_check_pres_work);
+ snprintf(name, sizeof(name), "nfc%d_check_pres_wq", dev->idx);
+ dev->check_pres_wq = alloc_workqueue(name, WQ_NON_REENTRANT |
+ WQ_UNBOUND |
+ WQ_MEM_RECLAIM, 1);
+ if (dev->check_pres_wq == NULL) {
+ kfree(dev);
+ return NULL;
+ }
+ }
+
+
return dev;
}
EXPORT_SYMBOL(nfc_allocate_device);
diff --git a/net/nfc/hci/Kconfig b/net/nfc/hci/Kconfig
new file mode 100644
index 000000000000..17213a6362b4
--- /dev/null
+++ b/net/nfc/hci/Kconfig
@@ -0,0 +1,16 @@
+config NFC_HCI
+ depends on NFC
+ tristate "NFC HCI implementation"
+ default n
+ help
+ Say Y here if you want to build support for a kernel NFC HCI
+ implementation. This is mostly needed for devices that only process
+ HCI frames, like for example the NXP pn544.
+
+config NFC_SHDLC
+ depends on NFC_HCI
+ bool "SHDLC link layer for HCI based NFC drivers"
+ default n
+ ---help---
+ Say yes if you use an NFC HCI driver that requires SHDLC link layer.
+ If unsure, say N here.
diff --git a/net/nfc/hci/Makefile b/net/nfc/hci/Makefile
new file mode 100644
index 000000000000..f9c44b2fb065
--- /dev/null
+++ b/net/nfc/hci/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Linux NFC HCI layer.
+#
+
+obj-$(CONFIG_NFC_HCI) += hci.o
+
+hci-y := core.o hcp.o command.o
+hci-$(CONFIG_NFC_SHDLC) += shdlc.o
diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c
new file mode 100644
index 000000000000..8729abf5f18b
--- /dev/null
+++ b/net/nfc/hci/command.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define pr_fmt(fmt) "hci: %s: " fmt, __func__
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+
+#include <net/nfc/hci.h>
+
+#include "hci.h"
+
+static int nfc_hci_result_to_errno(u8 result)
+{
+ switch (result) {
+ case NFC_HCI_ANY_OK:
+ return 0;
+ case NFC_HCI_ANY_E_TIMEOUT:
+ return -ETIMEDOUT;
+ default:
+ return -1;
+ }
+}
+
+static void nfc_hci_execute_cb(struct nfc_hci_dev *hdev, u8 result,
+ struct sk_buff *skb, void *cb_data)
+{
+ struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)cb_data;
+
+ pr_debug("HCI Cmd completed with HCI result=%d\n", result);
+
+ hcp_ew->exec_result = nfc_hci_result_to_errno(result);
+ if (hcp_ew->exec_result == 0)
+ hcp_ew->result_skb = skb;
+ else
+ kfree_skb(skb);
+ hcp_ew->exec_complete = true;
+
+ wake_up(hcp_ew->wq);
+}
+
+static int nfc_hci_execute_cmd(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
+ const u8 *param, size_t param_len,
+ struct sk_buff **skb)
+{
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(ew_wq);
+ struct hcp_exec_waiter hcp_ew;
+ hcp_ew.wq = &ew_wq;
+ hcp_ew.exec_complete = false;
+ hcp_ew.result_skb = NULL;
+
+ pr_debug("through pipe=%d, cmd=%d, plen=%zd\n", pipe, cmd, param_len);
+
+ /* TODO: Define hci cmd execution delay. Should it be the same
+ * for all commands?
+ */
+ hcp_ew.exec_result = nfc_hci_hcp_message_tx(hdev, pipe,
+ NFC_HCI_HCP_COMMAND, cmd,
+ param, param_len,
+ nfc_hci_execute_cb, &hcp_ew,
+ 3000);
+ if (hcp_ew.exec_result < 0)
+ return hcp_ew.exec_result;
+
+ wait_event(ew_wq, hcp_ew.exec_complete == true);
+
+ if (hcp_ew.exec_result == 0) {
+ if (skb)
+ *skb = hcp_ew.result_skb;
+ else
+ kfree_skb(hcp_ew.result_skb);
+ }
+
+ return hcp_ew.exec_result;
+}
+
+int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event,
+ const u8 *param, size_t param_len)
+{
+ u8 pipe;
+
+ pr_debug("%d to gate %d\n", event, gate);
+
+ pipe = hdev->gate2pipe[gate];
+ if (pipe == NFC_HCI_INVALID_PIPE)
+ return -EADDRNOTAVAIL;
+
+ return nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_EVENT, event,
+ param, param_len, NULL, NULL, 0);
+}
+EXPORT_SYMBOL(nfc_hci_send_event);
+
+int nfc_hci_send_response(struct nfc_hci_dev *hdev, u8 gate, u8 response,
+ const u8 *param, size_t param_len)
+{
+ u8 pipe;
+
+ pr_debug("\n");
+
+ pipe = hdev->gate2pipe[gate];
+ if (pipe == NFC_HCI_INVALID_PIPE)
+ return -EADDRNOTAVAIL;
+
+ return nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_RESPONSE,
+ response, param, param_len, NULL, NULL,
+ 0);
+}
+EXPORT_SYMBOL(nfc_hci_send_response);
+
+/*
+ * Execute an hci command sent to gate.
+ * skb will contain response data if success. skb can be NULL if you are not
+ * interested by the response.
+ */
+int nfc_hci_send_cmd(struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
+ const u8 *param, size_t param_len, struct sk_buff **skb)
+{
+ u8 pipe;
+
+ pr_debug("\n");
+
+ pipe = hdev->gate2pipe[gate];
+ if (pipe == NFC_HCI_INVALID_PIPE)
+ return -EADDRNOTAVAIL;
+
+ return nfc_hci_execute_cmd(hdev, pipe, cmd, param, param_len, skb);
+}
+EXPORT_SYMBOL(nfc_hci_send_cmd);
+
+int nfc_hci_set_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx,
+ const u8 *param, size_t param_len)
+{
+ int r;
+ u8 *tmp;
+
+ /* TODO ELa: reg idx must be inserted before param, but we don't want
+ * to ask the caller to do it to keep a simpler API.
+ * For now, just create a new temporary param buffer. This is far from
+ * optimal though, and the plan is to modify APIs to pass idx down to
+ * nfc_hci_hcp_message_tx where the frame is actually built, thereby
+ * eliminating the need for the temp allocation-copy here.
+ */
+
+ pr_debug("idx=%d to gate %d\n", idx, gate);
+
+ tmp = kmalloc(1 + param_len, GFP_KERNEL);
+ if (tmp == NULL)
+ return -ENOMEM;
+
+ *tmp = idx;
+ memcpy(tmp + 1, param, param_len);
+
+ r = nfc_hci_send_cmd(hdev, gate, NFC_HCI_ANY_SET_PARAMETER,
+ tmp, param_len + 1, NULL);
+
+ kfree(tmp);
+
+ return r;
+}
+EXPORT_SYMBOL(nfc_hci_set_param);
+
+int nfc_hci_get_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx,
+ struct sk_buff **skb)
+{
+ pr_debug("gate=%d regidx=%d\n", gate, idx);
+
+ return nfc_hci_send_cmd(hdev, gate, NFC_HCI_ANY_GET_PARAMETER,
+ &idx, 1, skb);
+}
+EXPORT_SYMBOL(nfc_hci_get_param);
+
+static int nfc_hci_open_pipe(struct nfc_hci_dev *hdev, u8 pipe)
+{
+ struct sk_buff *skb;
+ int r;
+
+ pr_debug("pipe=%d\n", pipe);
+
+ r = nfc_hci_execute_cmd(hdev, pipe, NFC_HCI_ANY_OPEN_PIPE,
+ NULL, 0, &skb);
+ if (r == 0) {
+ /* dest host other than host controller will send
+ * number of pipes already open on this gate before
+ * execution. The number can be found in skb->data[0]
+ */
+ kfree_skb(skb);
+ }
+
+ return r;
+}
+
+static int nfc_hci_close_pipe(struct nfc_hci_dev *hdev, u8 pipe)
+{
+ pr_debug("\n");
+
+ return nfc_hci_execute_cmd(hdev, pipe, NFC_HCI_ANY_CLOSE_PIPE,
+ NULL, 0, NULL);
+}
+
+static u8 nfc_hci_create_pipe(struct nfc_hci_dev *hdev, u8 dest_host,
+ u8 dest_gate, int *result)
+{
+ struct sk_buff *skb;
+ struct hci_create_pipe_params params;
+ struct hci_create_pipe_resp *resp;
+ u8 pipe;
+
+ pr_debug("gate=%d\n", dest_gate);
+
+ params.src_gate = NFC_HCI_ADMIN_GATE;
+ params.dest_host = dest_host;
+ params.dest_gate = dest_gate;
+
+ *result = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
+ NFC_HCI_ADM_CREATE_PIPE,
+ (u8 *) &params, sizeof(params), &skb);
+ if (*result == 0) {
+ resp = (struct hci_create_pipe_resp *)skb->data;
+ pipe = resp->pipe;
+ kfree_skb(skb);
+
+ pr_debug("pipe created=%d\n", pipe);
+
+ return pipe;
+ } else
+ return NFC_HCI_INVALID_PIPE;
+}
+
+static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 pipe)
+{
+ pr_debug("\n");
+
+ return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
+ NFC_HCI_ADM_DELETE_PIPE, &pipe, 1, NULL);
+}
+
+static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)
+{
+ int r;
+
+ u8 param[2];
+
+ /* TODO: Find out what the identity reference data is
+ * and fill param with it. HCI spec 6.1.3.5 */
+
+ pr_debug("\n");
+
+ r = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
+ NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL);
+
+ return 0;
+}
+
+int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate)
+{
+ int r;
+ u8 pipe = hdev->gate2pipe[gate];
+
+ pr_debug("\n");
+
+ if (pipe == NFC_HCI_INVALID_PIPE)
+ return -EADDRNOTAVAIL;
+
+ r = nfc_hci_close_pipe(hdev, pipe);
+ if (r < 0)
+ return r;
+
+ if (pipe != NFC_HCI_LINK_MGMT_PIPE && pipe != NFC_HCI_ADMIN_PIPE) {
+ r = nfc_hci_delete_pipe(hdev, pipe);
+ if (r < 0)
+ return r;
+ }
+
+ hdev->gate2pipe[gate] = NFC_HCI_INVALID_PIPE;
+
+ return 0;
+}
+EXPORT_SYMBOL(nfc_hci_disconnect_gate);
+
+int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev)
+{
+ int r;
+
+ pr_debug("\n");
+
+ r = nfc_hci_clear_all_pipes(hdev);
+ if (r < 0)
+ return r;
+
+ memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe));
+
+ return 0;
+}
+EXPORT_SYMBOL(nfc_hci_disconnect_all_gates);
+
+int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate)
+{
+ u8 pipe = NFC_HCI_INVALID_PIPE;
+ bool pipe_created = false;
+ int r;
+
+ pr_debug("\n");
+
+ if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE)
+ return -EADDRINUSE;
+
+ switch (dest_gate) {
+ case NFC_HCI_LINK_MGMT_GATE:
+ pipe = NFC_HCI_LINK_MGMT_PIPE;
+ break;
+ case NFC_HCI_ADMIN_GATE:
+ pipe = NFC_HCI_ADMIN_PIPE;
+ break;
+ default:
+ pipe = nfc_hci_create_pipe(hdev, dest_host, dest_gate, &r);
+ if (pipe == NFC_HCI_INVALID_PIPE)
+ return r;
+ pipe_created = true;
+ break;
+ }
+
+ r = nfc_hci_open_pipe(hdev, pipe);
+ if (r < 0) {
+ if (pipe_created)
+ if (nfc_hci_delete_pipe(hdev, pipe) < 0) {
+ /* TODO: Cannot clean by deleting pipe...
+ * -> inconsistent state */
+ }
+ return r;
+ }
+
+ hdev->gate2pipe[dest_gate] = pipe;
+
+ return 0;
+}
+EXPORT_SYMBOL(nfc_hci_connect_gate);
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
new file mode 100644
index 000000000000..86fd00d5a099
--- /dev/null
+++ b/net/nfc/hci/core.c
@@ -0,0 +1,830 @@
+/*
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define pr_fmt(fmt) "hci: %s: " fmt, __func__
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/nfc.h>
+
+#include <net/nfc/nfc.h>
+#include <net/nfc/hci.h>
+
+#include "hci.h"
+
+/* Largest headroom needed for outgoing HCI commands */
+#define HCI_CMDS_HEADROOM 1
+
+static void nfc_hci_msg_tx_work(struct work_struct *work)
+{
+ struct nfc_hci_dev *hdev = container_of(work, struct nfc_hci_dev,
+ msg_tx_work);
+ struct hci_msg *msg;
+ struct sk_buff *skb;
+ int r = 0;
+
+ mutex_lock(&hdev->msg_tx_mutex);
+
+ if (hdev->cmd_pending_msg) {
+ if (timer_pending(&hdev->cmd_timer) == 0) {
+ if (hdev->cmd_pending_msg->cb)
+ hdev->cmd_pending_msg->cb(hdev,
+ NFC_HCI_ANY_E_TIMEOUT,
+ NULL,
+ hdev->
+ cmd_pending_msg->
+ cb_context);
+ kfree(hdev->cmd_pending_msg);
+ hdev->cmd_pending_msg = NULL;
+ } else
+ goto exit;
+ }
+
+next_msg:
+ if (list_empty(&hdev->msg_tx_queue))
+ goto exit;
+
+ msg = list_first_entry(&hdev->msg_tx_queue, struct hci_msg, msg_l);
+ list_del(&msg->msg_l);
+
+ pr_debug("msg_tx_queue has a cmd to send\n");
+ while ((skb = skb_dequeue(&msg->msg_frags)) != NULL) {
+ r = hdev->ops->xmit(hdev, skb);
+ if (r < 0) {
+ kfree_skb(skb);
+ skb_queue_purge(&msg->msg_frags);
+ if (msg->cb)
+ msg->cb(hdev, NFC_HCI_ANY_E_NOK, NULL,
+ msg->cb_context);
+ kfree(msg);
+ break;
+ }
+ }
+
+ if (r)
+ goto next_msg;
+
+ if (msg->wait_response == false) {
+ kfree(msg);
+ goto next_msg;
+ }
+
+ hdev->cmd_pending_msg = msg;
+ mod_timer(&hdev->cmd_timer, jiffies +
+ msecs_to_jiffies(hdev->cmd_pending_msg->completion_delay));
+
+exit:
+ mutex_unlock(&hdev->msg_tx_mutex);
+}
+
+static void nfc_hci_msg_rx_work(struct work_struct *work)
+{
+ struct nfc_hci_dev *hdev = container_of(work, struct nfc_hci_dev,
+ msg_rx_work);
+ struct sk_buff *skb;
+ struct hcp_message *message;
+ u8 pipe;
+ u8 type;
+ u8 instruction;
+
+ while ((skb = skb_dequeue(&hdev->msg_rx_queue)) != NULL) {
+ pipe = skb->data[0];
+ skb_pull(skb, NFC_HCI_HCP_PACKET_HEADER_LEN);
+ message = (struct hcp_message *)skb->data;
+ type = HCP_MSG_GET_TYPE(message->header);
+ instruction = HCP_MSG_GET_CMD(message->header);
+ skb_pull(skb, NFC_HCI_HCP_MESSAGE_HEADER_LEN);
+
+ nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, skb);
+ }
+}
+
+void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result,
+ struct sk_buff *skb)
+{
+ mutex_lock(&hdev->msg_tx_mutex);
+
+ if (hdev->cmd_pending_msg == NULL) {
+ kfree_skb(skb);
+ goto exit;
+ }
+
+ del_timer_sync(&hdev->cmd_timer);
+
+ if (hdev->cmd_pending_msg->cb)
+ hdev->cmd_pending_msg->cb(hdev, result, skb,
+ hdev->cmd_pending_msg->cb_context);
+ else
+ kfree_skb(skb);
+
+ kfree(hdev->cmd_pending_msg);
+ hdev->cmd_pending_msg = NULL;
+
+ queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work);
+
+exit:
+ mutex_unlock(&hdev->msg_tx_mutex);
+}
+
+void nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
+ struct sk_buff *skb)
+{
+ kfree_skb(skb);
+}
+
+static u32 nfc_hci_sak_to_protocol(u8 sak)
+{
+ switch (NFC_HCI_TYPE_A_SEL_PROT(sak)) {
+ case NFC_HCI_TYPE_A_SEL_PROT_MIFARE:
+ return NFC_PROTO_MIFARE_MASK;
+ case NFC_HCI_TYPE_A_SEL_PROT_ISO14443:
+ return NFC_PROTO_ISO14443_MASK;
+ case NFC_HCI_TYPE_A_SEL_PROT_DEP:
+ return NFC_PROTO_NFC_DEP_MASK;
+ case NFC_HCI_TYPE_A_SEL_PROT_ISO14443_DEP:
+ return NFC_PROTO_ISO14443_MASK | NFC_PROTO_NFC_DEP_MASK;
+ default:
+ return 0xffffffff;
+ }
+}
+
+static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
+{
+ struct nfc_target *targets;
+ struct sk_buff *atqa_skb = NULL;
+ struct sk_buff *sak_skb = NULL;
+ int r;
+
+ pr_debug("from gate %d\n", gate);
+
+ targets = kzalloc(sizeof(struct nfc_target), GFP_KERNEL);
+ if (targets == NULL)
+ return -ENOMEM;
+
+ switch (gate) {
+ case NFC_HCI_RF_READER_A_GATE:
+ r = nfc_hci_get_param(hdev, NFC_HCI_RF_READER_A_GATE,
+ NFC_HCI_RF_READER_A_ATQA, &atqa_skb);
+ if (r < 0)
+ goto exit;
+
+ r = nfc_hci_get_param(hdev, NFC_HCI_RF_READER_A_GATE,
+ NFC_HCI_RF_READER_A_SAK, &sak_skb);
+ if (r < 0)
+ goto exit;
+
+ if (atqa_skb->len != 2 || sak_skb->len != 1) {
+ r = -EPROTO;
+ goto exit;
+ }
+
+ targets->supported_protocols =
+ nfc_hci_sak_to_protocol(sak_skb->data[0]);
+ if (targets->supported_protocols == 0xffffffff) {
+ r = -EPROTO;
+ goto exit;
+ }
+
+ targets->sens_res = be16_to_cpu(*(u16 *)atqa_skb->data);
+ targets->sel_res = sak_skb->data[0];
+
+ if (hdev->ops->complete_target_discovered) {
+ r = hdev->ops->complete_target_discovered(hdev, gate,
+ targets);
+ if (r < 0)
+ goto exit;
+ }
+ break;
+ case NFC_HCI_RF_READER_B_GATE:
+ targets->supported_protocols = NFC_PROTO_ISO14443_MASK;
+ break;
+ default:
+ if (hdev->ops->target_from_gate)
+ r = hdev->ops->target_from_gate(hdev, gate, targets);
+ else
+ r = -EPROTO;
+ if (r < 0)
+ goto exit;
+
+ if (hdev->ops->complete_target_discovered) {
+ r = hdev->ops->complete_target_discovered(hdev, gate,
+ targets);
+ if (r < 0)
+ goto exit;
+ }
+ break;
+ }
+
+ targets->hci_reader_gate = gate;
+
+ r = nfc_targets_found(hdev->ndev, targets, 1);
+ if (r < 0)
+ goto exit;
+
+ kfree(hdev->targets);
+ hdev->targets = targets;
+ targets = NULL;
+ hdev->target_count = 1;
+
+exit:
+ kfree(targets);
+ kfree_skb(atqa_skb);
+ kfree_skb(sak_skb);
+
+ return r;
+}
+
+void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
+ struct sk_buff *skb)
+{
+ int r = 0;
+
+ switch (event) {
+ case NFC_HCI_EVT_TARGET_DISCOVERED:
+ if (hdev->poll_started == false) {
+ r = -EPROTO;
+ goto exit;
+ }
+
+ if (skb->len < 1) { /* no status data? */
+ r = -EPROTO;
+ goto exit;
+ }
+
+ if (skb->data[0] == 3) {
+ /* TODO: Multiple targets in field, none activated
+ * poll is supposedly stopped, but there is no
+ * single target to activate, so nothing to report
+ * up.
+ * if we need to restart poll, we must save the
+ * protocols from the initial poll and reuse here.
+ */
+ }
+
+ if (skb->data[0] != 0) {
+ r = -EPROTO;
+ goto exit;
+ }
+
+ r = nfc_hci_target_discovered(hdev,
+ nfc_hci_pipe2gate(hdev, pipe));
+ break;
+ default:
+ /* TODO: Unknown events are hardware specific
+ * pass them to the driver (needs a new hci_ops) */
+ break;
+ }
+
+exit:
+ kfree_skb(skb);
+
+ if (r) {
+ /* TODO: There was an error dispatching the event,
+ * how to propagate up to nfc core?
+ */
+ }
+}
+
+static void nfc_hci_cmd_timeout(unsigned long data)
+{
+ struct nfc_hci_dev *hdev = (struct nfc_hci_dev *)data;
+
+ queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work);
+}
+
+static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count,
+ u8 gates[])
+{
+ int r;
+ u8 *p = gates;
+ while (gate_count--) {
+ r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, *p);
+ if (r < 0)
+ return r;
+ p++;
+ }
+
+ return 0;
+}
+
+static int hci_dev_session_init(struct nfc_hci_dev *hdev)
+{
+ struct sk_buff *skb = NULL;
+ int r;
+ u8 hci_gates[] = { /* NFC_HCI_ADMIN_GATE MUST be first */
+ NFC_HCI_ADMIN_GATE, NFC_HCI_LOOPBACK_GATE,
+ NFC_HCI_ID_MGMT_GATE, NFC_HCI_LINK_MGMT_GATE,
+ NFC_HCI_RF_READER_B_GATE, NFC_HCI_RF_READER_A_GATE
+ };
+
+ r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID,
+ NFC_HCI_ADMIN_GATE);
+ if (r < 0)
+ goto exit;
+
+ r = nfc_hci_get_param(hdev, NFC_HCI_ADMIN_GATE,
+ NFC_HCI_ADMIN_SESSION_IDENTITY, &skb);
+ if (r < 0)
+ goto disconnect_all;
+
+ if (skb->len && skb->len == strlen(hdev->init_data.session_id))
+ if (memcmp(hdev->init_data.session_id, skb->data,
+ skb->len) == 0) {
+ /* TODO ELa: restore gate<->pipe table from
+ * some TBD location.
+ * note: it doesn't seem possible to get the chip
+ * currently open gate/pipe table.
+ * It is only possible to obtain the supported
+ * gate list.
+ */
+
+ /* goto exit
+ * For now, always do a full initialization */
+ }
+
+ r = nfc_hci_disconnect_all_gates(hdev);
+ if (r < 0)
+ goto exit;
+
+ r = hci_dev_connect_gates(hdev, sizeof(hci_gates), hci_gates);
+ if (r < 0)
+ goto disconnect_all;
+
+ r = hci_dev_connect_gates(hdev, hdev->init_data.gate_count,
+ hdev->init_data.gates);
+ if (r < 0)
+ goto disconnect_all;
+
+ r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE,
+ NFC_HCI_ADMIN_SESSION_IDENTITY,
+ hdev->init_data.session_id,
+ strlen(hdev->init_data.session_id));
+ if (r == 0)
+ goto exit;
+
+disconnect_all:
+ nfc_hci_disconnect_all_gates(hdev);
+
+exit:
+ if (skb)
+ kfree_skb(skb);
+
+ return r;
+}
+
+static int hci_dev_version(struct nfc_hci_dev *hdev)
+{
+ int r;
+ struct sk_buff *skb;
+
+ r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE,
+ NFC_HCI_ID_MGMT_VERSION_SW, &skb);
+ if (r < 0)
+ return r;
+
+ if (skb->len != 3) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ hdev->sw_romlib = (skb->data[0] & 0xf0) >> 4;
+ hdev->sw_patch = skb->data[0] & 0x0f;
+ hdev->sw_flashlib_major = skb->data[1];
+ hdev->sw_flashlib_minor = skb->data[2];
+
+ kfree_skb(skb);
+
+ r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE,
+ NFC_HCI_ID_MGMT_VERSION_HW, &skb);
+ if (r < 0)
+ return r;
+
+ if (skb->len != 3) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ hdev->hw_derivative = (skb->data[0] & 0xe0) >> 5;
+ hdev->hw_version = skb->data[0] & 0x1f;
+ hdev->hw_mpw = (skb->data[1] & 0xc0) >> 6;
+ hdev->hw_software = skb->data[1] & 0x3f;
+ hdev->hw_bsid = skb->data[2];
+
+ kfree_skb(skb);
+
+ pr_info("SOFTWARE INFO:\n");
+ pr_info("RomLib : %d\n", hdev->sw_romlib);
+ pr_info("Patch : %d\n", hdev->sw_patch);
+ pr_info("FlashLib Major : %d\n", hdev->sw_flashlib_major);
+ pr_info("FlashLib Minor : %d\n", hdev->sw_flashlib_minor);
+ pr_info("HARDWARE INFO:\n");
+ pr_info("Derivative : %d\n", hdev->hw_derivative);
+ pr_info("HW Version : %d\n", hdev->hw_version);
+ pr_info("#MPW : %d\n", hdev->hw_mpw);
+ pr_info("Software : %d\n", hdev->hw_software);
+ pr_info("BSID Version : %d\n", hdev->hw_bsid);
+
+ return 0;
+}
+
+static int hci_dev_up(struct nfc_dev *nfc_dev)
+{
+ struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
+ int r = 0;
+
+ if (hdev->ops->open) {
+ r = hdev->ops->open(hdev);
+ if (r < 0)
+ return r;
+ }
+
+ r = hci_dev_session_init(hdev);
+ if (r < 0)
+ goto exit;
+
+ r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
+ NFC_HCI_EVT_END_OPERATION, NULL, 0);
+ if (r < 0)
+ goto exit;
+
+ if (hdev->ops->hci_ready) {
+ r = hdev->ops->hci_ready(hdev);
+ if (r < 0)
+ goto exit;
+ }
+
+ r = hci_dev_version(hdev);
+ if (r < 0)
+ goto exit;
+
+exit:
+ if (r < 0)
+ if (hdev->ops->close)
+ hdev->ops->close(hdev);
+ return r;
+}
+
+static int hci_dev_down(struct nfc_dev *nfc_dev)
+{
+ struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
+
+ if (hdev->ops->close)
+ hdev->ops->close(hdev);
+
+ memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe));
+
+ return 0;
+}
+
+static int hci_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
+{
+ struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
+ int r;
+
+ if (hdev->ops->start_poll)
+ r = hdev->ops->start_poll(hdev, protocols);
+ else
+ r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
+ NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
+ if (r == 0)
+ hdev->poll_started = true;
+
+ return r;
+}
+
+static void hci_stop_poll(struct nfc_dev *nfc_dev)
+{
+ struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
+
+ if (hdev->poll_started) {
+ nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
+ NFC_HCI_EVT_END_OPERATION, NULL, 0);
+ hdev->poll_started = false;
+ }
+}
+
+static struct nfc_target *hci_find_target(struct nfc_hci_dev *hdev,
+ u32 target_idx)
+{
+ int i;
+ if (hdev->poll_started == false || hdev->targets == NULL)
+ return NULL;
+
+ for (i = 0; i < hdev->target_count; i++) {
+ if (hdev->targets[i].idx == target_idx)
+ return &hdev->targets[i];
+ }
+
+ return NULL;
+}
+
+static int hci_activate_target(struct nfc_dev *nfc_dev, u32 target_idx,
+ u32 protocol)
+{
+ struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
+
+ if (hci_find_target(hdev, target_idx) == NULL)
+ return -ENOMEDIUM;
+
+ return 0;
+}
+
+static void hci_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx)
+{
+}
+
+static int hci_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx,
+ struct sk_buff *skb, data_exchange_cb_t cb,
+ void *cb_context)
+{
+ struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
+ int r;
+ struct nfc_target *target;
+ struct sk_buff *res_skb = NULL;
+
+ pr_debug("target_idx=%d\n", target_idx);
+
+ target = hci_find_target(hdev, target_idx);
+ if (target == NULL)
+ return -ENOMEDIUM;
+
+ switch (target->hci_reader_gate) {
+ case NFC_HCI_RF_READER_A_GATE:
+ case NFC_HCI_RF_READER_B_GATE:
+ if (hdev->ops->data_exchange) {
+ r = hdev->ops->data_exchange(hdev, target, skb,
+ &res_skb);
+ if (r <= 0) /* handled */
+ break;
+ }
+
+ *skb_push(skb, 1) = 0; /* CTR, see spec:10.2.2.1 */
+ r = nfc_hci_send_cmd(hdev, target->hci_reader_gate,
+ NFC_HCI_WR_XCHG_DATA,
+ skb->data, skb->len, &res_skb);
+ /*
+ * TODO: Check RF Error indicator to make sure data is valid.
+ * It seems that HCI cmd can complete without error, but data
+ * can be invalid if an RF error occured? Ignore for now.
+ */
+ if (r == 0)
+ skb_trim(res_skb, res_skb->len - 1); /* RF Err ind */
+ break;
+ default:
+ if (hdev->ops->data_exchange) {
+ r = hdev->ops->data_exchange(hdev, target, skb,
+ &res_skb);
+ if (r == 1)
+ r = -ENOTSUPP;
+ }
+ else
+ r = -ENOTSUPP;
+ }
+
+ kfree_skb(skb);
+
+ cb(cb_context, res_skb, r);
+
+ return 0;
+}
+
+struct nfc_ops hci_nfc_ops = {
+ .dev_up = hci_dev_up,
+ .dev_down = hci_dev_down,
+ .start_poll = hci_start_poll,
+ .stop_poll = hci_stop_poll,
+ .activate_target = hci_activate_target,
+ .deactivate_target = hci_deactivate_target,
+ .data_exchange = hci_data_exchange,
+};
+
+struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
+ struct nfc_hci_init_data *init_data,
+ u32 protocols,
+ int tx_headroom,
+ int tx_tailroom,
+ int max_link_payload)
+{
+ struct nfc_hci_dev *hdev;
+
+ if (ops->xmit == NULL)
+ return NULL;
+
+ if (protocols == 0)
+ return NULL;
+
+ hdev = kzalloc(sizeof(struct nfc_hci_dev), GFP_KERNEL);
+ if (hdev == NULL)
+ return NULL;
+
+ hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols,
+ tx_headroom + HCI_CMDS_HEADROOM,
+ tx_tailroom);
+ if (!hdev->ndev) {
+ kfree(hdev);
+ return NULL;
+ }
+
+ hdev->ops = ops;
+ hdev->max_data_link_payload = max_link_payload;
+ hdev->init_data = *init_data;
+
+ nfc_set_drvdata(hdev->ndev, hdev);
+
+ memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe));
+
+ return hdev;
+}
+EXPORT_SYMBOL(nfc_hci_allocate_device);
+
+void nfc_hci_free_device(struct nfc_hci_dev *hdev)
+{
+ nfc_free_device(hdev->ndev);
+ kfree(hdev);
+}
+EXPORT_SYMBOL(nfc_hci_free_device);
+
+int nfc_hci_register_device(struct nfc_hci_dev *hdev)
+{
+ struct device *dev = &hdev->ndev->dev;
+ const char *devname = dev_name(dev);
+ char name[32];
+ int r = 0;
+
+ mutex_init(&hdev->msg_tx_mutex);
+
+ INIT_LIST_HEAD(&hdev->msg_tx_queue);
+
+ INIT_WORK(&hdev->msg_tx_work, nfc_hci_msg_tx_work);
+ snprintf(name, sizeof(name), "%s_hci_msg_tx_wq", devname);
+ hdev->msg_tx_wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND |
+ WQ_MEM_RECLAIM, 1);
+ if (hdev->msg_tx_wq == NULL) {
+ r = -ENOMEM;
+ goto exit;
+ }
+
+ init_timer(&hdev->cmd_timer);
+ hdev->cmd_timer.data = (unsigned long)hdev;
+ hdev->cmd_timer.function = nfc_hci_cmd_timeout;
+
+ skb_queue_head_init(&hdev->rx_hcp_frags);
+
+ INIT_WORK(&hdev->msg_rx_work, nfc_hci_msg_rx_work);
+ snprintf(name, sizeof(name), "%s_hci_msg_rx_wq", devname);
+ hdev->msg_rx_wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND |
+ WQ_MEM_RECLAIM, 1);
+ if (hdev->msg_rx_wq == NULL) {
+ r = -ENOMEM;
+ goto exit;
+ }
+
+ skb_queue_head_init(&hdev->msg_rx_queue);
+
+ r = nfc_register_device(hdev->ndev);
+
+exit:
+ if (r < 0) {
+ if (hdev->msg_tx_wq)
+ destroy_workqueue(hdev->msg_tx_wq);
+ if (hdev->msg_rx_wq)
+ destroy_workqueue(hdev->msg_rx_wq);
+ }
+
+ return r;
+}
+EXPORT_SYMBOL(nfc_hci_register_device);
+
+void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)
+{
+ struct hci_msg *msg;
+
+ skb_queue_purge(&hdev->rx_hcp_frags);
+ skb_queue_purge(&hdev->msg_rx_queue);
+
+ while ((msg = list_first_entry(&hdev->msg_tx_queue, struct hci_msg,
+ msg_l)) != NULL) {
+ list_del(&msg->msg_l);
+ skb_queue_purge(&msg->msg_frags);
+ kfree(msg);
+ }
+
+ del_timer_sync(&hdev->cmd_timer);
+
+ nfc_unregister_device(hdev->ndev);
+
+ destroy_workqueue(hdev->msg_tx_wq);
+
+ destroy_workqueue(hdev->msg_rx_wq);
+}
+EXPORT_SYMBOL(nfc_hci_unregister_device);
+
+void nfc_hci_set_clientdata(struct nfc_hci_dev *hdev, void *clientdata)
+{
+ hdev->clientdata = clientdata;
+}
+EXPORT_SYMBOL(nfc_hci_set_clientdata);
+
+void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev)
+{
+ return hdev->clientdata;
+}
+EXPORT_SYMBOL(nfc_hci_get_clientdata);
+
+void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hcp_packet *packet;
+ u8 type;
+ u8 instruction;
+ struct sk_buff *hcp_skb;
+ u8 pipe;
+ struct sk_buff *frag_skb;
+ int msg_len;
+
+ if (skb == NULL) {
+ /* TODO ELa: lower layer had permanent failure, need to
+ * propagate that up
+ */
+
+ skb_queue_purge(&hdev->rx_hcp_frags);
+
+ return;
+ }
+
+ packet = (struct hcp_packet *)skb->data;
+ if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) {
+ skb_queue_tail(&hdev->rx_hcp_frags, skb);
+ return;
+ }
+
+ /* it's the last fragment. Does it need re-aggregation? */
+ if (skb_queue_len(&hdev->rx_hcp_frags)) {
+ pipe = packet->header & NFC_HCI_FRAGMENT;
+ skb_queue_tail(&hdev->rx_hcp_frags, skb);
+
+ msg_len = 0;
+ skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) {
+ msg_len += (frag_skb->len -
+ NFC_HCI_HCP_PACKET_HEADER_LEN);
+ }
+
+ hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN +
+ msg_len, GFP_KERNEL);
+ if (hcp_skb == NULL) {
+ /* TODO ELa: cannot deliver HCP message. How to
+ * propagate error up?
+ */
+ }
+
+ *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe;
+
+ skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) {
+ msg_len = frag_skb->len - NFC_HCI_HCP_PACKET_HEADER_LEN;
+ memcpy(skb_put(hcp_skb, msg_len),
+ frag_skb->data + NFC_HCI_HCP_PACKET_HEADER_LEN,
+ msg_len);
+ }
+
+ skb_queue_purge(&hdev->rx_hcp_frags);
+ } else {
+ packet->header &= NFC_HCI_FRAGMENT;
+ hcp_skb = skb;
+ }
+
+ /* if this is a response, dispatch immediately to
+ * unblock waiting cmd context. Otherwise, enqueue to dispatch
+ * in separate context where handler can also execute command.
+ */
+ packet = (struct hcp_packet *)hcp_skb->data;
+ type = HCP_MSG_GET_TYPE(packet->message.header);
+ if (type == NFC_HCI_HCP_RESPONSE) {
+ pipe = packet->header;
+ instruction = HCP_MSG_GET_CMD(packet->message.header);
+ skb_pull(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN +
+ NFC_HCI_HCP_MESSAGE_HEADER_LEN);
+ nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, hcp_skb);
+ } else {
+ skb_queue_tail(&hdev->msg_rx_queue, hcp_skb);
+ queue_work(hdev->msg_rx_wq, &hdev->msg_rx_work);
+ }
+}
+EXPORT_SYMBOL(nfc_hci_recv_frame);
+
+MODULE_LICENSE("GPL");
diff --git a/net/nfc/hci/hci.h b/net/nfc/hci/hci.h
new file mode 100644
index 000000000000..45f2fe4fd486
--- /dev/null
+++ b/net/nfc/hci/hci.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LOCAL_HCI_H
+#define __LOCAL_HCI_H
+
+struct gate_pipe_map {
+ u8 gate;
+ u8 pipe;
+};
+
+struct hcp_message {
+ u8 header; /* type -cmd,evt,rsp- + instruction */
+ u8 data[];
+} __packed;
+
+struct hcp_packet {
+ u8 header; /* cbit+pipe */
+ struct hcp_message message;
+} __packed;
+
+/*
+ * HCI command execution completion callback.
+ * result will be one of the HCI response codes.
+ * skb contains the response data and must be disposed.
+ */
+typedef void (*hci_cmd_cb_t) (struct nfc_hci_dev *hdev, u8 result,
+ struct sk_buff *skb, void *cb_data);
+
+struct hcp_exec_waiter {
+ wait_queue_head_t *wq;
+ bool exec_complete;
+ int exec_result;
+ struct sk_buff *result_skb;
+};
+
+struct hci_msg {
+ struct list_head msg_l;
+ struct sk_buff_head msg_frags;
+ bool wait_response;
+ hci_cmd_cb_t cb;
+ void *cb_context;
+ unsigned long completion_delay;
+};
+
+struct hci_create_pipe_params {
+ u8 src_gate;
+ u8 dest_host;
+ u8 dest_gate;
+} __packed;
+
+struct hci_create_pipe_resp {
+ u8 src_host;
+ u8 src_gate;
+ u8 dest_host;
+ u8 dest_gate;
+ u8 pipe;
+} __packed;
+
+#define NFC_HCI_FRAGMENT 0x7f
+
+#define HCP_HEADER(type, instr) ((((type) & 0x03) << 6) | ((instr) & 0x3f))
+#define HCP_MSG_GET_TYPE(header) ((header & 0xc0) >> 6)
+#define HCP_MSG_GET_CMD(header) (header & 0x3f)
+
+int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
+ u8 type, u8 instruction,
+ const u8 *payload, size_t payload_len,
+ hci_cmd_cb_t cb, void *cb_data,
+ unsigned long completion_delay);
+
+u8 nfc_hci_pipe2gate(struct nfc_hci_dev *hdev, u8 pipe);
+
+void nfc_hci_hcp_message_rx(struct nfc_hci_dev *hdev, u8 pipe, u8 type,
+ u8 instruction, struct sk_buff *skb);
+
+/* HCP headers */
+#define NFC_HCI_HCP_PACKET_HEADER_LEN 1
+#define NFC_HCI_HCP_MESSAGE_HEADER_LEN 1
+#define NFC_HCI_HCP_HEADER_LEN 2
+
+/* HCP types */
+#define NFC_HCI_HCP_COMMAND 0x00
+#define NFC_HCI_HCP_EVENT 0x01
+#define NFC_HCI_HCP_RESPONSE 0x02
+
+/* Generic commands */
+#define NFC_HCI_ANY_SET_PARAMETER 0x01
+#define NFC_HCI_ANY_GET_PARAMETER 0x02
+#define NFC_HCI_ANY_OPEN_PIPE 0x03
+#define NFC_HCI_ANY_CLOSE_PIPE 0x04
+
+/* Reader RF commands */
+#define NFC_HCI_WR_XCHG_DATA 0x10
+
+/* Admin commands */
+#define NFC_HCI_ADM_CREATE_PIPE 0x10
+#define NFC_HCI_ADM_DELETE_PIPE 0x11
+#define NFC_HCI_ADM_NOTIFY_PIPE_CREATED 0x12
+#define NFC_HCI_ADM_NOTIFY_PIPE_DELETED 0x13
+#define NFC_HCI_ADM_CLEAR_ALL_PIPE 0x14
+#define NFC_HCI_ADM_NOTIFY_ALL_PIPE_CLEARED 0x15
+
+/* Generic responses */
+#define NFC_HCI_ANY_OK 0x00
+#define NFC_HCI_ANY_E_NOT_CONNECTED 0x01
+#define NFC_HCI_ANY_E_CMD_PAR_UNKNOWN 0x02
+#define NFC_HCI_ANY_E_NOK 0x03
+#define NFC_HCI_ANY_E_PIPES_FULL 0x04
+#define NFC_HCI_ANY_E_REG_PAR_UNKNOWN 0x05
+#define NFC_HCI_ANY_E_PIPE_NOT_OPENED 0x06
+#define NFC_HCI_ANY_E_CMD_NOT_SUPPORTED 0x07
+#define NFC_HCI_ANY_E_INHIBITED 0x08
+#define NFC_HCI_ANY_E_TIMEOUT 0x09
+#define NFC_HCI_ANY_E_REG_ACCESS_DENIED 0x0a
+#define NFC_HCI_ANY_E_PIPE_ACCESS_DENIED 0x0b
+
+/* Pipes */
+#define NFC_HCI_INVALID_PIPE 0x80
+#define NFC_HCI_LINK_MGMT_PIPE 0x00
+#define NFC_HCI_ADMIN_PIPE 0x01
+
+#endif /* __LOCAL_HCI_H */
diff --git a/net/nfc/hci/hcp.c b/net/nfc/hci/hcp.c
new file mode 100644
index 000000000000..7212cf2c5785
--- /dev/null
+++ b/net/nfc/hci/hcp.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define pr_fmt(fmt) "hci: %s: " fmt, __func__
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <net/nfc/hci.h>
+
+#include "hci.h"
+
+/*
+ * Payload is the HCP message data only. Instruction will be prepended.
+ * Guarantees that cb will be called upon completion or timeout delay
+ * counted from the moment the cmd is sent to the transport.
+ */
+int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
+ u8 type, u8 instruction,
+ const u8 *payload, size_t payload_len,
+ hci_cmd_cb_t cb, void *cb_data,
+ unsigned long completion_delay)
+{
+ struct nfc_dev *ndev = hdev->ndev;
+ struct hci_msg *cmd;
+ const u8 *ptr = payload;
+ int hci_len, err;
+ bool firstfrag = true;
+
+ cmd = kzalloc(sizeof(struct hci_msg), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&cmd->msg_l);
+ skb_queue_head_init(&cmd->msg_frags);
+ cmd->wait_response = (type == NFC_HCI_HCP_COMMAND) ? true : false;
+ cmd->cb = cb;
+ cmd->cb_context = cb_data;
+ cmd->completion_delay = completion_delay;
+
+ hci_len = payload_len + 1;
+ while (hci_len > 0) {
+ struct sk_buff *skb;
+ int skb_len, data_link_len;
+ struct hcp_packet *packet;
+
+ if (NFC_HCI_HCP_PACKET_HEADER_LEN + hci_len <=
+ hdev->max_data_link_payload)
+ data_link_len = hci_len;
+ else
+ data_link_len = hdev->max_data_link_payload -
+ NFC_HCI_HCP_PACKET_HEADER_LEN;
+
+ skb_len = ndev->tx_headroom + NFC_HCI_HCP_PACKET_HEADER_LEN +
+ data_link_len + ndev->tx_tailroom;
+ hci_len -= data_link_len;
+
+ skb = alloc_skb(skb_len, GFP_KERNEL);
+ if (skb == NULL) {
+ err = -ENOMEM;
+ goto out_skb_err;
+ }
+ skb_reserve(skb, ndev->tx_headroom);
+
+ skb_put(skb, NFC_HCI_HCP_PACKET_HEADER_LEN + data_link_len);
+
+ /* Only the last fragment will have the cb bit set to 1 */
+ packet = (struct hcp_packet *)skb->data;
+ packet->header = pipe;
+ if (firstfrag) {
+ firstfrag = false;
+ packet->message.header = HCP_HEADER(type, instruction);
+ if (ptr) {
+ memcpy(packet->message.data, ptr,
+ data_link_len - 1);
+ ptr += data_link_len - 1;
+ }
+ } else {
+ memcpy(&packet->message, ptr, data_link_len);
+ ptr += data_link_len;
+ }
+
+ /* This is the last fragment, set the cb bit */
+ if (hci_len == 0)
+ packet->header |= ~NFC_HCI_FRAGMENT;
+
+ skb_queue_tail(&cmd->msg_frags, skb);
+ }
+
+ mutex_lock(&hdev->msg_tx_mutex);
+ list_add_tail(&hdev->msg_tx_queue, &cmd->msg_l);
+ mutex_unlock(&hdev->msg_tx_mutex);
+
+ queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work);
+
+ return 0;
+
+out_skb_err:
+ skb_queue_purge(&cmd->msg_frags);
+ kfree(cmd);
+
+ return err;
+}
+
+u8 nfc_hci_pipe2gate(struct nfc_hci_dev *hdev, u8 pipe)
+{
+ int gate;
+
+ for (gate = 0; gate < NFC_HCI_MAX_GATES; gate++)
+ if (hdev->gate2pipe[gate] == pipe)
+ return gate;
+
+ return 0xff;
+}
+
+/*
+ * Receive hcp message for pipe, with type and cmd.
+ * skb contains optional message data only.
+ */
+void nfc_hci_hcp_message_rx(struct nfc_hci_dev *hdev, u8 pipe, u8 type,
+ u8 instruction, struct sk_buff *skb)
+{
+ switch (type) {
+ case NFC_HCI_HCP_RESPONSE:
+ nfc_hci_resp_received(hdev, instruction, skb);
+ break;
+ case NFC_HCI_HCP_COMMAND:
+ nfc_hci_cmd_received(hdev, pipe, instruction, skb);
+ break;
+ case NFC_HCI_HCP_EVENT:
+ nfc_hci_event_received(hdev, pipe, instruction, skb);
+ break;
+ default:
+ pr_err("UNKNOWN MSG Type %d, instruction=%d\n",
+ type, instruction);
+ kfree_skb(skb);
+ break;
+ }
+}
diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c
new file mode 100644
index 000000000000..923bdf7c26d6
--- /dev/null
+++ b/net/nfc/hci/shdlc.c
@@ -0,0 +1,945 @@
+/*
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define pr_fmt(fmt) "shdlc: %s: " fmt, __func__
+
+#include <linux/sched.h>
+#include <linux/export.h>
+#include <linux/wait.h>
+#include <linux/crc-ccitt.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+
+#include <net/nfc/hci.h>
+#include <net/nfc/shdlc.h>
+
+#define SHDLC_LLC_HEAD_ROOM 2
+#define SHDLC_LLC_TAIL_ROOM 2
+
+#define SHDLC_MAX_WINDOW 4
+#define SHDLC_SREJ_SUPPORT false
+
+#define SHDLC_CONTROL_HEAD_MASK 0xe0
+#define SHDLC_CONTROL_HEAD_I 0x80
+#define SHDLC_CONTROL_HEAD_I2 0xa0
+#define SHDLC_CONTROL_HEAD_S 0xc0
+#define SHDLC_CONTROL_HEAD_U 0xe0
+
+#define SHDLC_CONTROL_NS_MASK 0x38
+#define SHDLC_CONTROL_NR_MASK 0x07
+#define SHDLC_CONTROL_TYPE_MASK 0x18
+
+#define SHDLC_CONTROL_M_MASK 0x1f
+
+enum sframe_type {
+ S_FRAME_RR = 0x00,
+ S_FRAME_REJ = 0x01,
+ S_FRAME_RNR = 0x02,
+ S_FRAME_SREJ = 0x03
+};
+
+enum uframe_modifier {
+ U_FRAME_UA = 0x06,
+ U_FRAME_RSET = 0x19
+};
+
+#define SHDLC_CONNECT_VALUE_MS 5
+#define SHDLC_T1_VALUE_MS(w) ((5 * w) / 4)
+#define SHDLC_T2_VALUE_MS 300
+
+#define SHDLC_DUMP_SKB(info, skb) \
+do { \
+ pr_debug("%s:\n", info); \
+ print_hex_dump(KERN_DEBUG, "shdlc: ", DUMP_PREFIX_OFFSET, \
+ 16, 1, skb->data, skb->len, 0); \
+} while (0)
+
+/* checks x < y <= z modulo 8 */
+static bool nfc_shdlc_x_lt_y_lteq_z(int x, int y, int z)
+{
+ if (x < z)
+ return ((x < y) && (y <= z)) ? true : false;
+ else
+ return ((y > x) || (y <= z)) ? true : false;
+}
+
+/* checks x <= y < z modulo 8 */
+static bool nfc_shdlc_x_lteq_y_lt_z(int x, int y, int z)
+{
+ if (x <= z)
+ return ((x <= y) && (y < z)) ? true : false;
+ else /* x > z -> z+8 > x */
+ return ((y >= x) || (y < z)) ? true : false;
+}
+
+static struct sk_buff *nfc_shdlc_alloc_skb(struct nfc_shdlc *shdlc,
+ int payload_len)
+{
+ struct sk_buff *skb;
+
+ skb = alloc_skb(shdlc->client_headroom + SHDLC_LLC_HEAD_ROOM +
+ shdlc->client_tailroom + SHDLC_LLC_TAIL_ROOM +
+ payload_len, GFP_KERNEL);
+ if (skb)
+ skb_reserve(skb, shdlc->client_headroom + SHDLC_LLC_HEAD_ROOM);
+
+ return skb;
+}
+
+static void nfc_shdlc_add_len_crc(struct sk_buff *skb)
+{
+ u16 crc;
+ int len;
+
+ len = skb->len + 2;
+ *skb_push(skb, 1) = len;
+
+ crc = crc_ccitt(0xffff, skb->data, skb->len);
+ crc = ~crc;
+ *skb_put(skb, 1) = crc & 0xff;
+ *skb_put(skb, 1) = crc >> 8;
+}
+
+/* immediately sends an S frame. */
+static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc,
+ enum sframe_type sframe_type, int nr)
+{
+ int r;
+ struct sk_buff *skb;
+
+ pr_debug("sframe_type=%d nr=%d\n", sframe_type, nr);
+
+ skb = nfc_shdlc_alloc_skb(shdlc, 0);
+ if (skb == NULL)
+ return -ENOMEM;
+
+ *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_S | (sframe_type << 3) | nr;
+
+ nfc_shdlc_add_len_crc(skb);
+
+ r = shdlc->ops->xmit(shdlc, skb);
+
+ kfree_skb(skb);
+
+ return r;
+}
+
+/* immediately sends an U frame. skb may contain optional payload */
+static int nfc_shdlc_send_u_frame(struct nfc_shdlc *shdlc,
+ struct sk_buff *skb,
+ enum uframe_modifier uframe_modifier)
+{
+ int r;
+
+ pr_debug("uframe_modifier=%d\n", uframe_modifier);
+
+ *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_U | uframe_modifier;
+
+ nfc_shdlc_add_len_crc(skb);
+
+ r = shdlc->ops->xmit(shdlc, skb);
+
+ kfree_skb(skb);
+
+ return r;
+}
+
+/*
+ * Free ack_pending frames until y_nr - 1, and reset t2 according to
+ * the remaining oldest ack_pending frame sent time
+ */
+static void nfc_shdlc_reset_t2(struct nfc_shdlc *shdlc, int y_nr)
+{
+ struct sk_buff *skb;
+ int dnr = shdlc->dnr; /* MUST initially be < y_nr */
+
+ pr_debug("release ack pending up to frame %d excluded\n", y_nr);
+
+ while (dnr != y_nr) {
+ pr_debug("release ack pending frame %d\n", dnr);
+
+ skb = skb_dequeue(&shdlc->ack_pending_q);
+ kfree_skb(skb);
+
+ dnr = (dnr + 1) % 8;
+ }
+
+ if (skb_queue_empty(&shdlc->ack_pending_q)) {
+ if (shdlc->t2_active) {
+ del_timer_sync(&shdlc->t2_timer);
+ shdlc->t2_active = false;
+
+ pr_debug
+ ("All sent frames acked. Stopped T2(retransmit)\n");
+ }
+ } else {
+ skb = skb_peek(&shdlc->ack_pending_q);
+
+ mod_timer(&shdlc->t2_timer, *(unsigned long *)skb->cb +
+ msecs_to_jiffies(SHDLC_T2_VALUE_MS));
+ shdlc->t2_active = true;
+
+ pr_debug
+ ("Start T2(retransmit) for remaining unacked sent frames\n");
+ }
+}
+
+/*
+ * Receive validated frames from lower layer. skb contains HCI payload only.
+ * Handle according to algorithm at spec:10.8.2
+ */
+static void nfc_shdlc_rcv_i_frame(struct nfc_shdlc *shdlc,
+ struct sk_buff *skb, int ns, int nr)
+{
+ int x_ns = ns;
+ int y_nr = nr;
+
+ pr_debug("recvd I-frame %d, remote waiting frame %d\n", ns, nr);
+
+ if (shdlc->state != SHDLC_CONNECTED)
+ goto exit;
+
+ if (x_ns != shdlc->nr) {
+ nfc_shdlc_send_s_frame(shdlc, S_FRAME_REJ, shdlc->nr);
+ goto exit;
+ }
+
+ if (shdlc->t1_active == false) {
+ shdlc->t1_active = true;
+ mod_timer(&shdlc->t1_timer,
+ msecs_to_jiffies(SHDLC_T1_VALUE_MS(shdlc->w)));
+ pr_debug("(re)Start T1(send ack)\n");
+ }
+
+ if (skb->len) {
+ nfc_hci_recv_frame(shdlc->hdev, skb);
+ skb = NULL;
+ }
+
+ shdlc->nr = (shdlc->nr + 1) % 8;
+
+ if (nfc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) {
+ nfc_shdlc_reset_t2(shdlc, y_nr);
+
+ shdlc->dnr = y_nr;
+ }
+
+exit:
+ if (skb)
+ kfree_skb(skb);
+}
+
+static void nfc_shdlc_rcv_ack(struct nfc_shdlc *shdlc, int y_nr)
+{
+ pr_debug("remote acked up to frame %d excluded\n", y_nr);
+
+ if (nfc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) {
+ nfc_shdlc_reset_t2(shdlc, y_nr);
+ shdlc->dnr = y_nr;
+ }
+}
+
+static void nfc_shdlc_requeue_ack_pending(struct nfc_shdlc *shdlc)
+{
+ struct sk_buff *skb;
+
+ pr_debug("ns reset to %d\n", shdlc->dnr);
+
+ while ((skb = skb_dequeue_tail(&shdlc->ack_pending_q))) {
+ skb_pull(skb, 2); /* remove len+control */
+ skb_trim(skb, skb->len - 2); /* remove crc */
+ skb_queue_head(&shdlc->send_q, skb);
+ }
+ shdlc->ns = shdlc->dnr;
+}
+
+static void nfc_shdlc_rcv_rej(struct nfc_shdlc *shdlc, int y_nr)
+{
+ struct sk_buff *skb;
+
+ pr_debug("remote asks retransmition from frame %d\n", y_nr);
+
+ if (nfc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) {
+ if (shdlc->t2_active) {
+ del_timer_sync(&shdlc->t2_timer);
+ shdlc->t2_active = false;
+ pr_debug("Stopped T2(retransmit)\n");
+ }
+
+ if (shdlc->dnr != y_nr) {
+ while ((shdlc->dnr = ((shdlc->dnr + 1) % 8)) != y_nr) {
+ skb = skb_dequeue(&shdlc->ack_pending_q);
+ kfree_skb(skb);
+ }
+ }
+
+ nfc_shdlc_requeue_ack_pending(shdlc);
+ }
+}
+
+/* See spec RR:10.8.3 REJ:10.8.4 */
+static void nfc_shdlc_rcv_s_frame(struct nfc_shdlc *shdlc,
+ enum sframe_type s_frame_type, int nr)
+{
+ struct sk_buff *skb;
+
+ if (shdlc->state != SHDLC_CONNECTED)
+ return;
+
+ switch (s_frame_type) {
+ case S_FRAME_RR:
+ nfc_shdlc_rcv_ack(shdlc, nr);
+ if (shdlc->rnr == true) { /* see SHDLC 10.7.7 */
+ shdlc->rnr = false;
+ if (shdlc->send_q.qlen == 0) {
+ skb = nfc_shdlc_alloc_skb(shdlc, 0);
+ if (skb)
+ skb_queue_tail(&shdlc->send_q, skb);
+ }
+ }
+ break;
+ case S_FRAME_REJ:
+ nfc_shdlc_rcv_rej(shdlc, nr);
+ break;
+ case S_FRAME_RNR:
+ nfc_shdlc_rcv_ack(shdlc, nr);
+ shdlc->rnr = true;
+ break;
+ default:
+ break;
+ }
+}
+
+static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r)
+{
+ pr_debug("result=%d\n", r);
+
+ del_timer_sync(&shdlc->connect_timer);
+
+ if (r == 0) {
+ shdlc->ns = 0;
+ shdlc->nr = 0;
+ shdlc->dnr = 0;
+
+ shdlc->state = SHDLC_CONNECTED;
+ } else {
+ shdlc->state = SHDLC_DISCONNECTED;
+
+ /*
+ * TODO: Could it be possible that there are pending
+ * executing commands that are waiting for connect to complete
+ * before they can be carried? As connect is a blocking
+ * operation, it would require that the userspace process can
+ * send commands on the same device from a second thread before
+ * the device is up. I don't think that is possible, is it?
+ */
+ }
+
+ shdlc->connect_result = r;
+
+ wake_up(shdlc->connect_wq);
+}
+
+static int nfc_shdlc_connect_initiate(struct nfc_shdlc *shdlc)
+{
+ struct sk_buff *skb;
+
+ pr_debug("\n");
+
+ skb = nfc_shdlc_alloc_skb(shdlc, 2);
+ if (skb == NULL)
+ return -ENOMEM;
+
+ *skb_put(skb, 1) = SHDLC_MAX_WINDOW;
+ *skb_put(skb, 1) = SHDLC_SREJ_SUPPORT ? 1 : 0;
+
+ return nfc_shdlc_send_u_frame(shdlc, skb, U_FRAME_RSET);
+}
+
+static int nfc_shdlc_connect_send_ua(struct nfc_shdlc *shdlc)
+{
+ struct sk_buff *skb;
+
+ pr_debug("\n");
+
+ skb = nfc_shdlc_alloc_skb(shdlc, 0);
+ if (skb == NULL)
+ return -ENOMEM;
+
+ return nfc_shdlc_send_u_frame(shdlc, skb, U_FRAME_UA);
+}
+
+static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc,
+ struct sk_buff *skb,
+ enum uframe_modifier u_frame_modifier)
+{
+ u8 w = SHDLC_MAX_WINDOW;
+ bool srej_support = SHDLC_SREJ_SUPPORT;
+ int r;
+
+ pr_debug("u_frame_modifier=%d\n", u_frame_modifier);
+
+ switch (u_frame_modifier) {
+ case U_FRAME_RSET:
+ if (shdlc->state == SHDLC_NEGOCIATING) {
+ /* we sent RSET, but chip wants to negociate */
+ if (skb->len > 0)
+ w = skb->data[0];
+
+ if (skb->len > 1)
+ srej_support = skb->data[1] & 0x01 ? true :
+ false;
+
+ if ((w <= SHDLC_MAX_WINDOW) &&
+ (SHDLC_SREJ_SUPPORT || (srej_support == false))) {
+ shdlc->w = w;
+ shdlc->srej_support = srej_support;
+ r = nfc_shdlc_connect_send_ua(shdlc);
+ nfc_shdlc_connect_complete(shdlc, r);
+ }
+ } else if (shdlc->state > SHDLC_NEGOCIATING) {
+ /*
+ * TODO: Chip wants to reset link
+ * send ua, empty skb lists, reset counters
+ * propagate info to HCI layer
+ */
+ }
+ break;
+ case U_FRAME_UA:
+ if ((shdlc->state == SHDLC_CONNECTING &&
+ shdlc->connect_tries > 0) ||
+ (shdlc->state == SHDLC_NEGOCIATING))
+ nfc_shdlc_connect_complete(shdlc, 0);
+ break;
+ default:
+ break;
+ }
+
+ kfree_skb(skb);
+}
+
+static void nfc_shdlc_handle_rcv_queue(struct nfc_shdlc *shdlc)
+{
+ struct sk_buff *skb;
+ u8 control;
+ int nr;
+ int ns;
+ enum sframe_type s_frame_type;
+ enum uframe_modifier u_frame_modifier;
+
+ if (shdlc->rcv_q.qlen)
+ pr_debug("rcvQlen=%d\n", shdlc->rcv_q.qlen);
+
+ while ((skb = skb_dequeue(&shdlc->rcv_q)) != NULL) {
+ control = skb->data[0];
+ skb_pull(skb, 1);
+ switch (control & SHDLC_CONTROL_HEAD_MASK) {
+ case SHDLC_CONTROL_HEAD_I:
+ case SHDLC_CONTROL_HEAD_I2:
+ ns = (control & SHDLC_CONTROL_NS_MASK) >> 3;
+ nr = control & SHDLC_CONTROL_NR_MASK;
+ nfc_shdlc_rcv_i_frame(shdlc, skb, ns, nr);
+ break;
+ case SHDLC_CONTROL_HEAD_S:
+ s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3;
+ nr = control & SHDLC_CONTROL_NR_MASK;
+ nfc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr);
+ kfree_skb(skb);
+ break;
+ case SHDLC_CONTROL_HEAD_U:
+ u_frame_modifier = control & SHDLC_CONTROL_M_MASK;
+ nfc_shdlc_rcv_u_frame(shdlc, skb, u_frame_modifier);
+ break;
+ default:
+ pr_err("UNKNOWN Control=%d\n", control);
+ kfree_skb(skb);
+ break;
+ }
+ }
+}
+
+static int nfc_shdlc_w_used(int ns, int dnr)
+{
+ int unack_count;
+
+ if (dnr <= ns)
+ unack_count = ns - dnr;
+ else
+ unack_count = 8 - dnr + ns;
+
+ return unack_count;
+}
+
+/* Send frames according to algorithm at spec:10.8.1 */
+static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc)
+{
+ struct sk_buff *skb;
+ int r;
+ unsigned long time_sent;
+
+ if (shdlc->send_q.qlen)
+ pr_debug
+ ("sendQlen=%d ns=%d dnr=%d rnr=%s w_room=%d unackQlen=%d\n",
+ shdlc->send_q.qlen, shdlc->ns, shdlc->dnr,
+ shdlc->rnr == false ? "false" : "true",
+ shdlc->w - nfc_shdlc_w_used(shdlc->ns, shdlc->dnr),
+ shdlc->ack_pending_q.qlen);
+
+ while (shdlc->send_q.qlen && shdlc->ack_pending_q.qlen < shdlc->w &&
+ (shdlc->rnr == false)) {
+
+ if (shdlc->t1_active) {
+ del_timer_sync(&shdlc->t1_timer);
+ shdlc->t1_active = false;
+ pr_debug("Stopped T1(send ack)\n");
+ }
+
+ skb = skb_dequeue(&shdlc->send_q);
+
+ *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_I | (shdlc->ns << 3) |
+ shdlc->nr;
+
+ pr_debug("Sending I-Frame %d, waiting to rcv %d\n", shdlc->ns,
+ shdlc->nr);
+ /* SHDLC_DUMP_SKB("shdlc frame written", skb); */
+
+ nfc_shdlc_add_len_crc(skb);
+
+ r = shdlc->ops->xmit(shdlc, skb);
+ if (r < 0) {
+ /*
+ * TODO: Cannot send, shdlc machine is dead, we
+ * must propagate the information up to HCI.
+ */
+ shdlc->hard_fault = r;
+ break;
+ }
+
+ shdlc->ns = (shdlc->ns + 1) % 8;
+
+ time_sent = jiffies;
+ *(unsigned long *)skb->cb = time_sent;
+
+ skb_queue_tail(&shdlc->ack_pending_q, skb);
+
+ if (shdlc->t2_active == false) {
+ shdlc->t2_active = true;
+ mod_timer(&shdlc->t2_timer, time_sent +
+ msecs_to_jiffies(SHDLC_T2_VALUE_MS));
+ pr_debug("Started T2 (retransmit)\n");
+ }
+ }
+}
+
+static void nfc_shdlc_connect_timeout(unsigned long data)
+{
+ struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data;
+
+ pr_debug("\n");
+
+ queue_work(shdlc->sm_wq, &shdlc->sm_work);
+}
+
+static void nfc_shdlc_t1_timeout(unsigned long data)
+{
+ struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data;
+
+ pr_debug("SoftIRQ: need to send ack\n");
+
+ queue_work(shdlc->sm_wq, &shdlc->sm_work);
+}
+
+static void nfc_shdlc_t2_timeout(unsigned long data)
+{
+ struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data;
+
+ pr_debug("SoftIRQ: need to retransmit\n");
+
+ queue_work(shdlc->sm_wq, &shdlc->sm_work);
+}
+
+static void nfc_shdlc_sm_work(struct work_struct *work)
+{
+ struct nfc_shdlc *shdlc = container_of(work, struct nfc_shdlc, sm_work);
+ int r;
+
+ pr_debug("\n");
+
+ mutex_lock(&shdlc->state_mutex);
+
+ switch (shdlc->state) {
+ case SHDLC_DISCONNECTED:
+ skb_queue_purge(&shdlc->rcv_q);
+ skb_queue_purge(&shdlc->send_q);
+ skb_queue_purge(&shdlc->ack_pending_q);
+ break;
+ case SHDLC_CONNECTING:
+ if (shdlc->connect_tries++ < 5)
+ r = nfc_shdlc_connect_initiate(shdlc);
+ else
+ r = -ETIME;
+ if (r < 0)
+ nfc_shdlc_connect_complete(shdlc, r);
+ else {
+ mod_timer(&shdlc->connect_timer, jiffies +
+ msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS));
+
+ shdlc->state = SHDLC_NEGOCIATING;
+ }
+ break;
+ case SHDLC_NEGOCIATING:
+ if (timer_pending(&shdlc->connect_timer) == 0) {
+ shdlc->state = SHDLC_CONNECTING;
+ queue_work(shdlc->sm_wq, &shdlc->sm_work);
+ }
+
+ nfc_shdlc_handle_rcv_queue(shdlc);
+ break;
+ case SHDLC_CONNECTED:
+ nfc_shdlc_handle_rcv_queue(shdlc);
+ nfc_shdlc_handle_send_queue(shdlc);
+
+ if (shdlc->t1_active && timer_pending(&shdlc->t1_timer) == 0) {
+ pr_debug
+ ("Handle T1(send ack) elapsed (T1 now inactive)\n");
+
+ shdlc->t1_active = false;
+ r = nfc_shdlc_send_s_frame(shdlc, S_FRAME_RR,
+ shdlc->nr);
+ if (r < 0)
+ shdlc->hard_fault = r;
+ }
+
+ if (shdlc->t2_active && timer_pending(&shdlc->t2_timer) == 0) {
+ pr_debug
+ ("Handle T2(retransmit) elapsed (T2 inactive)\n");
+
+ shdlc->t2_active = false;
+
+ nfc_shdlc_requeue_ack_pending(shdlc);
+ nfc_shdlc_handle_send_queue(shdlc);
+ }
+
+ if (shdlc->hard_fault) {
+ /*
+ * TODO: Handle hard_fault that occured during
+ * this invocation of the shdlc worker
+ */
+ }
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&shdlc->state_mutex);
+}
+
+/*
+ * Called from syscall context to establish shdlc link. Sleeps until
+ * link is ready or failure.
+ */
+static int nfc_shdlc_connect(struct nfc_shdlc *shdlc)
+{
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(connect_wq);
+
+ pr_debug("\n");
+
+ mutex_lock(&shdlc->state_mutex);
+
+ shdlc->state = SHDLC_CONNECTING;
+ shdlc->connect_wq = &connect_wq;
+ shdlc->connect_tries = 0;
+ shdlc->connect_result = 1;
+
+ mutex_unlock(&shdlc->state_mutex);
+
+ queue_work(shdlc->sm_wq, &shdlc->sm_work);
+
+ wait_event(connect_wq, shdlc->connect_result != 1);
+
+ return shdlc->connect_result;
+}
+
+static void nfc_shdlc_disconnect(struct nfc_shdlc *shdlc)
+{
+ pr_debug("\n");
+
+ mutex_lock(&shdlc->state_mutex);
+
+ shdlc->state = SHDLC_DISCONNECTED;
+
+ mutex_unlock(&shdlc->state_mutex);
+
+ queue_work(shdlc->sm_wq, &shdlc->sm_work);
+}
+
+/*
+ * Receive an incoming shdlc frame. Frame has already been crc-validated.
+ * skb contains only LLC header and payload.
+ * If skb == NULL, it is a notification that the link below is dead.
+ */
+void nfc_shdlc_recv_frame(struct nfc_shdlc *shdlc, struct sk_buff *skb)
+{
+ if (skb == NULL) {
+ pr_err("NULL Frame -> link is dead\n");
+ shdlc->hard_fault = -EREMOTEIO;
+ } else {
+ SHDLC_DUMP_SKB("incoming frame", skb);
+ skb_queue_tail(&shdlc->rcv_q, skb);
+ }
+
+ queue_work(shdlc->sm_wq, &shdlc->sm_work);
+}
+EXPORT_SYMBOL(nfc_shdlc_recv_frame);
+
+static int nfc_shdlc_open(struct nfc_hci_dev *hdev)
+{
+ struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
+ int r;
+
+ pr_debug("\n");
+
+ if (shdlc->ops->open) {
+ r = shdlc->ops->open(shdlc);
+ if (r < 0)
+ return r;
+ }
+
+ r = nfc_shdlc_connect(shdlc);
+ if (r < 0 && shdlc->ops->close)
+ shdlc->ops->close(shdlc);
+
+ return r;
+}
+
+static void nfc_shdlc_close(struct nfc_hci_dev *hdev)
+{
+ struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
+
+ pr_debug("\n");
+
+ nfc_shdlc_disconnect(shdlc);
+
+ if (shdlc->ops->close)
+ shdlc->ops->close(shdlc);
+}
+
+static int nfc_shdlc_hci_ready(struct nfc_hci_dev *hdev)
+{
+ struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
+ int r = 0;
+
+ pr_debug("\n");
+
+ if (shdlc->ops->hci_ready)
+ r = shdlc->ops->hci_ready(shdlc);
+
+ return r;
+}
+
+static int nfc_shdlc_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+{
+ struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
+
+ SHDLC_DUMP_SKB("queuing HCP packet to shdlc", skb);
+
+ skb_queue_tail(&shdlc->send_q, skb);
+
+ queue_work(shdlc->sm_wq, &shdlc->sm_work);
+
+ return 0;
+}
+
+static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev, u32 protocols)
+{
+ struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
+
+ pr_debug("\n");
+
+ if (shdlc->ops->start_poll)
+ return shdlc->ops->start_poll(shdlc, protocols);
+
+ return 0;
+}
+
+static int nfc_shdlc_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
+ struct nfc_target *target)
+{
+ struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
+
+ if (shdlc->ops->target_from_gate)
+ return shdlc->ops->target_from_gate(shdlc, gate, target);
+
+ return -EPERM;
+}
+
+static int nfc_shdlc_complete_target_discovered(struct nfc_hci_dev *hdev,
+ u8 gate,
+ struct nfc_target *target)
+{
+ struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
+
+ pr_debug("\n");
+
+ if (shdlc->ops->complete_target_discovered)
+ return shdlc->ops->complete_target_discovered(shdlc, gate,
+ target);
+
+ return 0;
+}
+
+static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev,
+ struct nfc_target *target,
+ struct sk_buff *skb,
+ struct sk_buff **res_skb)
+{
+ struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
+
+ if (shdlc->ops->data_exchange)
+ return shdlc->ops->data_exchange(shdlc, target, skb, res_skb);
+
+ return -EPERM;
+}
+
+static struct nfc_hci_ops shdlc_ops = {
+ .open = nfc_shdlc_open,
+ .close = nfc_shdlc_close,
+ .hci_ready = nfc_shdlc_hci_ready,
+ .xmit = nfc_shdlc_xmit,
+ .start_poll = nfc_shdlc_start_poll,
+ .target_from_gate = nfc_shdlc_target_from_gate,
+ .complete_target_discovered = nfc_shdlc_complete_target_discovered,
+ .data_exchange = nfc_shdlc_data_exchange,
+};
+
+struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops,
+ struct nfc_hci_init_data *init_data,
+ u32 protocols,
+ int tx_headroom, int tx_tailroom,
+ int max_link_payload, const char *devname)
+{
+ struct nfc_shdlc *shdlc;
+ int r;
+ char name[32];
+
+ if (ops->xmit == NULL)
+ return NULL;
+
+ shdlc = kzalloc(sizeof(struct nfc_shdlc), GFP_KERNEL);
+ if (shdlc == NULL)
+ return NULL;
+
+ mutex_init(&shdlc->state_mutex);
+ shdlc->ops = ops;
+ shdlc->state = SHDLC_DISCONNECTED;
+
+ init_timer(&shdlc->connect_timer);
+ shdlc->connect_timer.data = (unsigned long)shdlc;
+ shdlc->connect_timer.function = nfc_shdlc_connect_timeout;
+
+ init_timer(&shdlc->t1_timer);
+ shdlc->t1_timer.data = (unsigned long)shdlc;
+ shdlc->t1_timer.function = nfc_shdlc_t1_timeout;
+
+ init_timer(&shdlc->t2_timer);
+ shdlc->t2_timer.data = (unsigned long)shdlc;
+ shdlc->t2_timer.function = nfc_shdlc_t2_timeout;
+
+ shdlc->w = SHDLC_MAX_WINDOW;
+ shdlc->srej_support = SHDLC_SREJ_SUPPORT;
+
+ skb_queue_head_init(&shdlc->rcv_q);
+ skb_queue_head_init(&shdlc->send_q);
+ skb_queue_head_init(&shdlc->ack_pending_q);
+
+ INIT_WORK(&shdlc->sm_work, nfc_shdlc_sm_work);
+ snprintf(name, sizeof(name), "%s_shdlc_sm_wq", devname);
+ shdlc->sm_wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND |
+ WQ_MEM_RECLAIM, 1);
+ if (shdlc->sm_wq == NULL)
+ goto err_allocwq;
+
+ shdlc->client_headroom = tx_headroom;
+ shdlc->client_tailroom = tx_tailroom;
+
+ shdlc->hdev = nfc_hci_allocate_device(&shdlc_ops, init_data, protocols,
+ tx_headroom + SHDLC_LLC_HEAD_ROOM,
+ tx_tailroom + SHDLC_LLC_TAIL_ROOM,
+ max_link_payload);
+ if (shdlc->hdev == NULL)
+ goto err_allocdev;
+
+ nfc_hci_set_clientdata(shdlc->hdev, shdlc);
+
+ r = nfc_hci_register_device(shdlc->hdev);
+ if (r < 0)
+ goto err_regdev;
+
+ return shdlc;
+
+err_regdev:
+ nfc_hci_free_device(shdlc->hdev);
+
+err_allocdev:
+ destroy_workqueue(shdlc->sm_wq);
+
+err_allocwq:
+ kfree(shdlc);
+
+ return NULL;
+}
+EXPORT_SYMBOL(nfc_shdlc_allocate);
+
+void nfc_shdlc_free(struct nfc_shdlc *shdlc)
+{
+ pr_debug("\n");
+
+ /* TODO: Check that this cannot be called while still in use */
+
+ nfc_hci_unregister_device(shdlc->hdev);
+ nfc_hci_free_device(shdlc->hdev);
+
+ destroy_workqueue(shdlc->sm_wq);
+
+ skb_queue_purge(&shdlc->rcv_q);
+ skb_queue_purge(&shdlc->send_q);
+ skb_queue_purge(&shdlc->ack_pending_q);
+
+ kfree(shdlc);
+}
+EXPORT_SYMBOL(nfc_shdlc_free);
+
+void nfc_shdlc_set_clientdata(struct nfc_shdlc *shdlc, void *clientdata)
+{
+ pr_debug("\n");
+
+ shdlc->clientdata = clientdata;
+}
+EXPORT_SYMBOL(nfc_shdlc_set_clientdata);
+
+void *nfc_shdlc_get_clientdata(struct nfc_shdlc *shdlc)
+{
+ return shdlc->clientdata;
+}
+EXPORT_SYMBOL(nfc_shdlc_get_clientdata);
+
+struct nfc_hci_dev *nfc_shdlc_get_hci_dev(struct nfc_shdlc *shdlc)
+{
+ return shdlc->hdev;
+}
+EXPORT_SYMBOL(nfc_shdlc_get_hci_dev);
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c
index ef10ffcb4b6f..11a3b7d98dc5 100644
--- a/net/nfc/llcp/commands.c
+++ b/net/nfc/llcp/commands.c
@@ -102,7 +102,7 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length)
length = llcp_tlv_length[type];
if (length == 0 && value_length == 0)
return NULL;
- else
+ else if (length == 0)
length = value_length;
*tlv_length = 2 + length;
@@ -248,7 +248,7 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock)
skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
- skb = llcp_add_header(skb, sock->ssap, sock->dsap, LLCP_PDU_DISC);
+ skb = llcp_add_header(skb, sock->dsap, sock->ssap, LLCP_PDU_DISC);
skb_queue_tail(&local->tx_queue, skb);
@@ -416,7 +416,7 @@ int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason)
skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
- skb = llcp_add_header(skb, ssap, dsap, LLCP_PDU_DM);
+ skb = llcp_add_header(skb, dsap, ssap, LLCP_PDU_DM);
memcpy(skb_put(skb, 1), &reason, 1);
@@ -522,7 +522,7 @@ int nfc_llcp_send_rr(struct nfc_llcp_sock *sock)
skb_put(skb, LLCP_SEQUENCE_SIZE);
- skb->data[2] = sock->recv_n % 16;
+ skb->data[2] = sock->recv_n;
skb_queue_head(&local->tx_queue, skb);
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 17a578f641f1..92988aa620dc 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -307,6 +307,8 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
u8 *gb_cur, *version_tlv, version, version_length;
u8 *lto_tlv, lto, lto_length;
u8 *wks_tlv, wks_length;
+ u8 *miux_tlv, miux_length;
+ __be16 miux;
u8 gb_len = 0;
version = LLCP_VERSION_11;
@@ -316,7 +318,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
/* 1500 ms */
lto = 150;
- lto_tlv = nfc_llcp_build_tlv(LLCP_TLV_VERSION, &lto, 1, &lto_length);
+ lto_tlv = nfc_llcp_build_tlv(LLCP_TLV_LTO, &lto, 1, &lto_length);
gb_len += lto_length;
pr_debug("Local wks 0x%lx\n", local->local_wks);
@@ -324,6 +326,11 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
&wks_length);
gb_len += wks_length;
+ miux = cpu_to_be16(LLCP_MAX_MIUX);
+ miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
+ &miux_length);
+ gb_len += miux_length;
+
gb_len += ARRAY_SIZE(llcp_magic);
if (gb_len > NFC_MAX_GT_LEN) {
@@ -345,6 +352,9 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
memcpy(gb_cur, wks_tlv, wks_length);
gb_cur += wks_length;
+ memcpy(gb_cur, miux_tlv, miux_length);
+ gb_cur += miux_length;
+
kfree(version_tlv);
kfree(lto_tlv);
@@ -388,6 +398,9 @@ static void nfc_llcp_tx_work(struct work_struct *work)
skb = skb_dequeue(&local->tx_queue);
if (skb != NULL) {
pr_debug("Sending pending skb\n");
+ print_hex_dump(KERN_DEBUG, "LLCP Tx: ", DUMP_PREFIX_OFFSET,
+ 16, 1, skb->data, skb->len, true);
+
nfc_data_exchange(local->dev, local->target_idx,
skb, nfc_llcp_recv, local);
} else {
@@ -425,7 +438,7 @@ static u8 nfc_llcp_nr(struct sk_buff *pdu)
static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu)
{
- pdu->data[2] = (sock->send_n << 4) | (sock->recv_n % 16);
+ pdu->data[2] = (sock->send_n << 4) | (sock->recv_n);
sock->send_n = (sock->send_n + 1) % 16;
sock->recv_ack_n = (sock->recv_n - 1) % 16;
}
@@ -814,6 +827,10 @@ static void nfc_llcp_rx_work(struct work_struct *work)
pr_debug("ptype 0x%x dsap 0x%x ssap 0x%x\n", ptype, dsap, ssap);
+ if (ptype != LLCP_PDU_SYMM)
+ print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET,
+ 16, 1, skb->data, skb->len, true);
+
switch (ptype) {
case LLCP_PDU_SYMM:
pr_debug("SYMM\n");
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 9ec065bb9ee1..8737c2089fdd 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -477,7 +477,7 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
}
if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) {
- param.rf_discovery_id = target->idx;
+ param.rf_discovery_id = target->logical_idx;
if (protocol == NFC_PROTO_JEWEL)
param.rf_protocol = NCI_RF_PROTOCOL_T1T;
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
index 2e3dee42196d..99e1632e6aac 100644
--- a/net/nfc/nci/ntf.c
+++ b/net/nfc/nci/ntf.c
@@ -227,7 +227,7 @@ static void nci_add_new_target(struct nci_dev *ndev,
for (i = 0; i < ndev->n_targets; i++) {
target = &ndev->targets[i];
- if (target->idx == ntf->rf_discovery_id) {
+ if (target->logical_idx == ntf->rf_discovery_id) {
/* This target already exists, add the new protocol */
nci_add_new_protocol(ndev, target, ntf->rf_protocol,
ntf->rf_tech_and_mode,
@@ -248,10 +248,10 @@ static void nci_add_new_target(struct nci_dev *ndev,
ntf->rf_tech_and_mode,
&ntf->rf_tech_specific_params);
if (!rc) {
- target->idx = ntf->rf_discovery_id;
+ target->logical_idx = ntf->rf_discovery_id;
ndev->n_targets++;
- pr_debug("target_idx %d, n_targets %d\n", target->idx,
+ pr_debug("logical idx %d, n_targets %d\n", target->logical_idx,
ndev->n_targets);
}
}
@@ -372,10 +372,11 @@ static void nci_target_auto_activated(struct nci_dev *ndev,
if (rc)
return;
- target->idx = ntf->rf_discovery_id;
+ target->logical_idx = ntf->rf_discovery_id;
ndev->n_targets++;
- pr_debug("target_idx %d, n_targets %d\n", target->idx, ndev->n_targets);
+ pr_debug("logical idx %d, n_targets %d\n",
+ target->logical_idx, ndev->n_targets);
nfc_targets_found(ndev->nfc_dev, ndev->targets, ndev->n_targets);
}
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index 6404052d6c07..f1829f6ae9c5 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -63,19 +63,23 @@ static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
- NLA_PUT_U32(msg, NFC_ATTR_TARGET_INDEX, target->idx);
- NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, target->supported_protocols);
- NLA_PUT_U16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res);
- NLA_PUT_U8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res);
- if (target->nfcid1_len > 0)
- NLA_PUT(msg, NFC_ATTR_TARGET_NFCID1, target->nfcid1_len,
- target->nfcid1);
- if (target->sensb_res_len > 0)
- NLA_PUT(msg, NFC_ATTR_TARGET_SENSB_RES, target->sensb_res_len,
- target->sensb_res);
- if (target->sensf_res_len > 0)
- NLA_PUT(msg, NFC_ATTR_TARGET_SENSF_RES, target->sensf_res_len,
- target->sensf_res);
+ if (nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target->idx) ||
+ nla_put_u32(msg, NFC_ATTR_PROTOCOLS, target->supported_protocols) ||
+ nla_put_u16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res) ||
+ nla_put_u8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res))
+ goto nla_put_failure;
+ if (target->nfcid1_len > 0 &&
+ nla_put(msg, NFC_ATTR_TARGET_NFCID1, target->nfcid1_len,
+ target->nfcid1))
+ goto nla_put_failure;
+ if (target->sensb_res_len > 0 &&
+ nla_put(msg, NFC_ATTR_TARGET_SENSB_RES, target->sensb_res_len,
+ target->sensb_res))
+ goto nla_put_failure;
+ if (target->sensf_res_len > 0 &&
+ nla_put(msg, NFC_ATTR_TARGET_SENSF_RES, target->sensf_res_len,
+ target->sensf_res))
+ goto nla_put_failure;
return genlmsg_end(msg, hdr);
@@ -170,7 +174,8 @@ int nfc_genl_targets_found(struct nfc_dev *dev)
if (!hdr)
goto free_msg;
- NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
+ if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -183,6 +188,37 @@ free_msg:
return -EMSGSIZE;
}
+int nfc_genl_target_lost(struct nfc_dev *dev, u32 target_idx)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+ NFC_EVENT_TARGET_LOST);
+ if (!hdr)
+ goto free_msg;
+
+ if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
+ nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target_idx))
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+
+ genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+
+ return 0;
+
+nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+free_msg:
+ nlmsg_free(msg);
+ return -EMSGSIZE;
+}
+
int nfc_genl_device_added(struct nfc_dev *dev)
{
struct sk_buff *msg;
@@ -197,10 +233,11 @@ int nfc_genl_device_added(struct nfc_dev *dev)
if (!hdr)
goto free_msg;
- NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev));
- NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
- NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols);
- NLA_PUT_U8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up);
+ if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
+ nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
+ nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
+ nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -229,7 +266,8 @@ int nfc_genl_device_removed(struct nfc_dev *dev)
if (!hdr)
goto free_msg;
- NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
+ if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -259,10 +297,11 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
if (cb)
genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
- NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev));
- NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
- NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols);
- NLA_PUT_U8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up);
+ if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
+ nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
+ nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
+ nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up))
+ goto nla_put_failure;
return genlmsg_end(msg, hdr);
@@ -339,11 +378,14 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
if (!hdr)
goto free_msg;
- NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
- if (rf_mode == NFC_RF_INITIATOR)
- NLA_PUT_U32(msg, NFC_ATTR_TARGET_INDEX, target_idx);
- NLA_PUT_U8(msg, NFC_ATTR_COMM_MODE, comm_mode);
- NLA_PUT_U8(msg, NFC_ATTR_RF_MODE, rf_mode);
+ if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
+ goto nla_put_failure;
+ if (rf_mode == NFC_RF_INITIATOR &&
+ nla_put_u32(msg, NFC_ATTR_TARGET_INDEX, target_idx))
+ goto nla_put_failure;
+ if (nla_put_u8(msg, NFC_ATTR_COMM_MODE, comm_mode) ||
+ nla_put_u8(msg, NFC_ATTR_RF_MODE, rf_mode))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -376,7 +418,8 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev)
if (!hdr)
goto free_msg;
- NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
+ if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index ec8794c1099c..7d589a81942e 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -119,6 +119,7 @@ void nfc_genl_data_init(struct nfc_genl_data *genl_data);
void nfc_genl_data_exit(struct nfc_genl_data *genl_data);
int nfc_genl_targets_found(struct nfc_dev *dev);
+int nfc_genl_target_lost(struct nfc_dev *dev, u32 target_idx);
int nfc_genl_device_added(struct nfc_dev *dev);
int nfc_genl_device_removed(struct nfc_dev *dev);
@@ -127,7 +128,7 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
u8 comm_mode, u8 rf_mode);
int nfc_genl_dep_link_down_event(struct nfc_dev *dev);
-struct nfc_dev *nfc_get_device(unsigned idx);
+struct nfc_dev *nfc_get_device(unsigned int idx);
static inline void nfc_put_device(struct nfc_dev *dev)
{
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
index 5a839ceb2e82..ec1134c9e07f 100644
--- a/net/nfc/rawsock.c
+++ b/net/nfc/rawsock.c
@@ -92,6 +92,12 @@ static int rawsock_connect(struct socket *sock, struct sockaddr *_addr,
goto error;
}
+ if (addr->target_idx > dev->target_next_idx - 1 ||
+ addr->target_idx < dev->target_next_idx - dev->n_targets) {
+ rc = -EINVAL;
+ goto error;
+ }
+
rc = nfc_activate_target(dev, addr->target_idx, addr->nfc_protocol);
if (rc)
goto put_dev;
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index e44e631ea952..f86de29979ef 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -778,15 +778,18 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
tcp_flags = flow->tcp_flags;
spin_unlock_bh(&flow->lock);
- if (used)
- NLA_PUT_U64(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used));
+ if (used &&
+ nla_put_u64(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used)))
+ goto nla_put_failure;
- if (stats.n_packets)
- NLA_PUT(skb, OVS_FLOW_ATTR_STATS,
- sizeof(struct ovs_flow_stats), &stats);
+ if (stats.n_packets &&
+ nla_put(skb, OVS_FLOW_ATTR_STATS,
+ sizeof(struct ovs_flow_stats), &stats))
+ goto nla_put_failure;
- if (tcp_flags)
- NLA_PUT_U8(skb, OVS_FLOW_ATTR_TCP_FLAGS, tcp_flags);
+ if (tcp_flags &&
+ nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS, tcp_flags))
+ goto nla_put_failure;
/* If OVS_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if
* this is the first flow to be dumped into 'skb'. This is unusual for
@@ -1168,7 +1171,8 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb,
goto nla_put_failure;
get_dp_stats(dp, &dp_stats);
- NLA_PUT(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats), &dp_stats);
+ if (nla_put(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats), &dp_stats))
+ goto nla_put_failure;
return genlmsg_end(skb, ovs_header);
@@ -1468,14 +1472,16 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
ovs_header->dp_ifindex = get_dpifindex(vport->dp);
- NLA_PUT_U32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no);
- NLA_PUT_U32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type);
- NLA_PUT_STRING(skb, OVS_VPORT_ATTR_NAME, vport->ops->get_name(vport));
- NLA_PUT_U32(skb, OVS_VPORT_ATTR_UPCALL_PID, vport->upcall_pid);
+ if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) ||
+ nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) ||
+ nla_put_string(skb, OVS_VPORT_ATTR_NAME, vport->ops->get_name(vport)) ||
+ nla_put_u32(skb, OVS_VPORT_ATTR_UPCALL_PID, vport->upcall_pid))
+ goto nla_put_failure;
ovs_vport_get_stats(vport, &vport_stats);
- NLA_PUT(skb, OVS_VPORT_ATTR_STATS, sizeof(struct ovs_vport_stats),
- &vport_stats);
+ if (nla_put(skb, OVS_VPORT_ATTR_STATS, sizeof(struct ovs_vport_stats),
+ &vport_stats))
+ goto nla_put_failure;
err = ovs_vport_get_options(vport, skb);
if (err == -EMSGSIZE)
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index 1252c3081ef1..7cb416381e87 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -1174,11 +1174,13 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
struct ovs_key_ethernet *eth_key;
struct nlattr *nla, *encap;
- if (swkey->phy.priority)
- NLA_PUT_U32(skb, OVS_KEY_ATTR_PRIORITY, swkey->phy.priority);
+ if (swkey->phy.priority &&
+ nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, swkey->phy.priority))
+ goto nla_put_failure;
- if (swkey->phy.in_port != USHRT_MAX)
- NLA_PUT_U32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port);
+ if (swkey->phy.in_port != USHRT_MAX &&
+ nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port))
+ goto nla_put_failure;
nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
if (!nla)
@@ -1188,8 +1190,9 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
memcpy(eth_key->eth_dst, swkey->eth.dst, ETH_ALEN);
if (swkey->eth.tci || swkey->eth.type == htons(ETH_P_8021Q)) {
- NLA_PUT_BE16(skb, OVS_KEY_ATTR_ETHERTYPE, htons(ETH_P_8021Q));
- NLA_PUT_BE16(skb, OVS_KEY_ATTR_VLAN, swkey->eth.tci);
+ if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, htons(ETH_P_8021Q)) ||
+ nla_put_be16(skb, OVS_KEY_ATTR_VLAN, swkey->eth.tci))
+ goto nla_put_failure;
encap = nla_nest_start(skb, OVS_KEY_ATTR_ENCAP);
if (!swkey->eth.tci)
goto unencap;
@@ -1200,7 +1203,8 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
if (swkey->eth.type == htons(ETH_P_802_2))
goto unencap;
- NLA_PUT_BE16(skb, OVS_KEY_ATTR_ETHERTYPE, swkey->eth.type);
+ if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, swkey->eth.type))
+ goto nla_put_failure;
if (swkey->eth.type == htons(ETH_P_IP)) {
struct ovs_key_ipv4 *ipv4_key;
diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c
index c1068aed03d1..5920bda4ab6b 100644
--- a/net/openvswitch/vport-netdev.c
+++ b/net/openvswitch/vport-netdev.c
@@ -140,9 +140,9 @@ int ovs_netdev_get_ifindex(const struct vport *vport)
return netdev_vport->dev->ifindex;
}
-static unsigned packet_length(const struct sk_buff *skb)
+static unsigned int packet_length(const struct sk_buff *skb)
{
- unsigned length = skb->len - ETH_HLEN;
+ unsigned int length = skb->len - ETH_HLEN;
if (skb->protocol == htons(ETH_P_8021Q))
length -= VLAN_HLEN;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 4f2c0df79563..0f661745df0f 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1654,7 +1654,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
skb->data = skb_head;
skb->len = skb_len;
}
- kfree_skb(skb);
+ consume_skb(skb);
skb = nskb;
}
@@ -1764,7 +1764,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
macoff = netoff = TPACKET_ALIGN(po->tp_hdrlen) + 16 +
po->tp_reserve;
} else {
- unsigned maclen = skb_network_offset(skb);
+ unsigned int maclen = skb_network_offset(skb);
netoff = TPACKET_ALIGN(po->tp_hdrlen +
(maclen < 16 ? 16 : maclen)) +
po->tp_reserve;
@@ -3224,10 +3224,10 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
{
int len;
- int val;
+ int val, lv = sizeof(val);
struct sock *sk = sock->sk;
struct packet_sock *po = pkt_sk(sk);
- void *data;
+ void *data = &val;
struct tpacket_stats st;
union tpacket_stats_u st_u;
@@ -3242,21 +3242,17 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
switch (optname) {
case PACKET_STATISTICS:
- if (po->tp_version == TPACKET_V3) {
- len = sizeof(struct tpacket_stats_v3);
- } else {
- if (len > sizeof(struct tpacket_stats))
- len = sizeof(struct tpacket_stats);
- }
spin_lock_bh(&sk->sk_receive_queue.lock);
if (po->tp_version == TPACKET_V3) {
+ lv = sizeof(struct tpacket_stats_v3);
memcpy(&st_u.stats3, &po->stats,
- sizeof(struct tpacket_stats));
+ sizeof(struct tpacket_stats));
st_u.stats3.tp_freeze_q_cnt =
- po->stats_u.stats3.tp_freeze_q_cnt;
+ po->stats_u.stats3.tp_freeze_q_cnt;
st_u.stats3.tp_packets += po->stats.tp_drops;
data = &st_u.stats3;
} else {
+ lv = sizeof(struct tpacket_stats);
st = po->stats;
st.tp_packets += st.tp_drops;
data = &st;
@@ -3265,31 +3261,16 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
spin_unlock_bh(&sk->sk_receive_queue.lock);
break;
case PACKET_AUXDATA:
- if (len > sizeof(int))
- len = sizeof(int);
val = po->auxdata;
-
- data = &val;
break;
case PACKET_ORIGDEV:
- if (len > sizeof(int))
- len = sizeof(int);
val = po->origdev;
-
- data = &val;
break;
case PACKET_VNET_HDR:
- if (len > sizeof(int))
- len = sizeof(int);
val = po->has_vnet_hdr;
-
- data = &val;
break;
case PACKET_VERSION:
- if (len > sizeof(int))
- len = sizeof(int);
val = po->tp_version;
- data = &val;
break;
case PACKET_HDRLEN:
if (len > sizeof(int))
@@ -3309,39 +3290,28 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
default:
return -EINVAL;
}
- data = &val;
break;
case PACKET_RESERVE:
- if (len > sizeof(unsigned int))
- len = sizeof(unsigned int);
val = po->tp_reserve;
- data = &val;
break;
case PACKET_LOSS:
- if (len > sizeof(unsigned int))
- len = sizeof(unsigned int);
val = po->tp_loss;
- data = &val;
break;
case PACKET_TIMESTAMP:
- if (len > sizeof(int))
- len = sizeof(int);
val = po->tp_tstamp;
- data = &val;
break;
case PACKET_FANOUT:
- if (len > sizeof(int))
- len = sizeof(int);
val = (po->fanout ?
((u32)po->fanout->id |
((u32)po->fanout->type << 16)) :
0);
- data = &val;
break;
default:
return -ENOPROTOOPT;
}
+ if (len > lv)
+ len = lv;
if (put_user(len, optlen))
return -EFAULT;
if (copy_to_user(optval, data, len))
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
index d65f699fbf34..779ce4ff92ec 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -129,7 +129,7 @@ static const struct net_proto_family phonet_proto_family = {
/* Phonet device header operations */
static int pn_header_create(struct sk_buff *skb, struct net_device *dev,
unsigned short type, const void *daddr,
- const void *saddr, unsigned len)
+ const void *saddr, unsigned int len)
{
u8 *media = skb_push(skb, 1);
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 9726fe684ab8..9dd4f926f7d1 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -273,7 +273,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
hdr = pnp_hdr(skb);
if (hdr->data[0] != PN_PEP_TYPE_COMMON) {
LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP type: %u\n",
- (unsigned)hdr->data[0]);
+ (unsigned int)hdr->data[0]);
return -EOPNOTSUPP;
}
@@ -305,7 +305,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
default:
LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP indication: %u\n",
- (unsigned)hdr->data[1]);
+ (unsigned int)hdr->data[1]);
return -EOPNOTSUPP;
}
if (wake)
@@ -478,9 +478,9 @@ static void pipe_destruct(struct sock *sk)
skb_queue_purge(&pn->ctrlreq_queue);
}
-static u8 pipe_negotiate_fc(const u8 *fcs, unsigned n)
+static u8 pipe_negotiate_fc(const u8 *fcs, unsigned int n)
{
- unsigned i;
+ unsigned int i;
u8 final_fc = PN_NO_FLOW_CONTROL;
for (i = 0; i < n; i++) {
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index bf5cf69c820a..36f75a9e2c3d 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -44,7 +44,7 @@ struct phonet_net {
struct phonet_routes routes;
};
-int phonet_net_id __read_mostly;
+static int phonet_net_id __read_mostly;
static struct phonet_net *phonet_pernet(struct net *net)
{
@@ -268,7 +268,7 @@ static int phonet_device_autoconf(struct net_device *dev)
static void phonet_route_autodel(struct net_device *dev)
{
struct phonet_net *pnn = phonet_pernet(dev_net(dev));
- unsigned i;
+ unsigned int i;
DECLARE_BITMAP(deleted, 64);
/* Remove left-over Phonet routes */
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
index d61f6761777d..cfdf135fcd69 100644
--- a/net/phonet/pn_netlink.c
+++ b/net/phonet/pn_netlink.c
@@ -116,7 +116,8 @@ static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr,
ifm->ifa_flags = IFA_F_PERMANENT;
ifm->ifa_scope = RT_SCOPE_LINK;
ifm->ifa_index = dev->ifindex;
- NLA_PUT_U8(skb, IFA_LOCAL, addr);
+ if (nla_put_u8(skb, IFA_LOCAL, addr))
+ goto nla_put_failure;
return nlmsg_end(skb, nlh);
nla_put_failure:
@@ -183,8 +184,9 @@ static int fill_route(struct sk_buff *skb, struct net_device *dev, u8 dst,
rtm->rtm_scope = RT_SCOPE_UNIVERSE;
rtm->rtm_type = RTN_UNICAST;
rtm->rtm_flags = 0;
- NLA_PUT_U8(skb, RTA_DST, dst);
- NLA_PUT_U32(skb, RTA_OIF, dev->ifindex);
+ if (nla_put_u8(skb, RTA_DST, dst) ||
+ nla_put_u32(skb, RTA_OIF, dev->ifindex))
+ goto nla_put_failure;
return nlmsg_end(skb, nlh);
nla_put_failure:
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 4c7eff30dfa9..89cfa9ce4939 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -58,7 +58,7 @@ static struct {
void __init pn_sock_init(void)
{
- unsigned i;
+ unsigned int i;
for (i = 0; i < PN_HASHSIZE; i++)
INIT_HLIST_HEAD(pnsocks.hlist + i);
@@ -116,7 +116,7 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
{
struct hlist_head *hlist = pnsocks.hlist;
- unsigned h;
+ unsigned int h;
rcu_read_lock();
for (h = 0; h < PN_HASHSIZE; h++) {
@@ -545,7 +545,7 @@ static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
struct hlist_head *hlist = pnsocks.hlist;
struct hlist_node *node;
struct sock *sknode;
- unsigned h;
+ unsigned int h;
for (h = 0; h < PN_HASHSIZE; h++) {
sk_for_each_rcu(sknode, node, hlist) {
@@ -710,7 +710,7 @@ int pn_sock_unbind_res(struct sock *sk, u8 res)
void pn_sock_unbind_all_res(struct sock *sk)
{
- unsigned res, match = 0;
+ unsigned int res, match = 0;
mutex_lock(&resource_mutex);
for (res = 0; res < 256; res++) {
@@ -732,7 +732,7 @@ void pn_sock_unbind_all_res(struct sock *sk)
static struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos)
{
struct net *net = seq_file_net(seq);
- unsigned i;
+ unsigned int i;
if (!net_eq(net, &init_net))
return NULL;
@@ -750,7 +750,7 @@ static struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos)
static struct sock **pn_res_get_next(struct seq_file *seq, struct sock **sk)
{
struct net *net = seq_file_net(seq);
- unsigned i;
+ unsigned int i;
BUG_ON(!net_eq(net, &init_net));
diff --git a/net/phonet/sysctl.c b/net/phonet/sysctl.c
index cea1c7dbdae2..696348fd31a1 100644
--- a/net/phonet/sysctl.c
+++ b/net/phonet/sysctl.c
@@ -27,6 +27,10 @@
#include <linux/errno.h>
#include <linux/init.h>
+#include <net/sock.h>
+#include <linux/phonet.h>
+#include <net/phonet/phonet.h>
+
#define DYNAMIC_PORT_MIN 0x40
#define DYNAMIC_PORT_MAX 0x7f
@@ -46,7 +50,8 @@ static void set_local_port_range(int range[2])
void phonet_get_local_port_range(int *min, int *max)
{
- unsigned seq;
+ unsigned int seq;
+
do {
seq = read_seqbegin(&local_port_range_lock);
if (min)
@@ -93,19 +98,13 @@ static struct ctl_table phonet_table[] = {
{ }
};
-static struct ctl_path phonet_ctl_path[] = {
- { .procname = "net", },
- { .procname = "phonet", },
- { },
-};
-
int __init phonet_sysctl_init(void)
{
- phonet_table_hrd = register_sysctl_paths(phonet_ctl_path, phonet_table);
+ phonet_table_hrd = register_net_sysctl(&init_net, "net/phonet", phonet_table);
return phonet_table_hrd == NULL ? -ENOMEM : 0;
}
void phonet_sysctl_exit(void)
{
- unregister_sysctl_table(phonet_table_hrd);
+ unregister_net_sysctl_table(phonet_table_hrd);
}
diff --git a/net/rds/ib_sysctl.c b/net/rds/ib_sysctl.c
index 1253b006efdb..7e643bafb4af 100644
--- a/net/rds/ib_sysctl.c
+++ b/net/rds/ib_sysctl.c
@@ -106,22 +106,15 @@ static ctl_table rds_ib_sysctl_table[] = {
{ }
};
-static struct ctl_path rds_ib_sysctl_path[] = {
- { .procname = "net", },
- { .procname = "rds", },
- { .procname = "ib", },
- { }
-};
-
void rds_ib_sysctl_exit(void)
{
if (rds_ib_sysctl_hdr)
- unregister_sysctl_table(rds_ib_sysctl_hdr);
+ unregister_net_sysctl_table(rds_ib_sysctl_hdr);
}
int rds_ib_sysctl_init(void)
{
- rds_ib_sysctl_hdr = register_sysctl_paths(rds_ib_sysctl_path, rds_ib_sysctl_table);
+ rds_ib_sysctl_hdr = register_net_sysctl(&init_net, "net/rds/ib", rds_ib_sysctl_table);
if (!rds_ib_sysctl_hdr)
return -ENOMEM;
return 0;
diff --git a/net/rds/iw_sysctl.c b/net/rds/iw_sysctl.c
index e2e47176e729..5d5ebd576f3f 100644
--- a/net/rds/iw_sysctl.c
+++ b/net/rds/iw_sysctl.c
@@ -109,22 +109,15 @@ static ctl_table rds_iw_sysctl_table[] = {
{ }
};
-static struct ctl_path rds_iw_sysctl_path[] = {
- { .procname = "net", },
- { .procname = "rds", },
- { .procname = "iw", },
- { }
-};
-
void rds_iw_sysctl_exit(void)
{
if (rds_iw_sysctl_hdr)
- unregister_sysctl_table(rds_iw_sysctl_hdr);
+ unregister_net_sysctl_table(rds_iw_sysctl_hdr);
}
int rds_iw_sysctl_init(void)
{
- rds_iw_sysctl_hdr = register_sysctl_paths(rds_iw_sysctl_path, rds_iw_sysctl_table);
+ rds_iw_sysctl_hdr = register_net_sysctl(&init_net, "net/rds/iw", rds_iw_sysctl_table);
if (!rds_iw_sysctl_hdr)
return -ENOMEM;
return 0;
diff --git a/net/rds/sysctl.c b/net/rds/sysctl.c
index 25ad0c77a26c..907214b4c4d0 100644
--- a/net/rds/sysctl.c
+++ b/net/rds/sysctl.c
@@ -92,17 +92,10 @@ static ctl_table rds_sysctl_rds_table[] = {
{ }
};
-static struct ctl_path rds_sysctl_path[] = {
- { .procname = "net", },
- { .procname = "rds", },
- { }
-};
-
-
void rds_sysctl_exit(void)
{
if (rds_sysctl_reg_table)
- unregister_sysctl_table(rds_sysctl_reg_table);
+ unregister_net_sysctl_table(rds_sysctl_reg_table);
}
int rds_sysctl_init(void)
@@ -110,7 +103,7 @@ int rds_sysctl_init(void)
rds_sysctl_reconnect_min = msecs_to_jiffies(1);
rds_sysctl_reconnect_min_jiffies = rds_sysctl_reconnect_min;
- rds_sysctl_reg_table = register_sysctl_paths(rds_sysctl_path, rds_sysctl_rds_table);
+ rds_sysctl_reg_table = register_net_sysctl(&init_net,"net/rds", rds_sysctl_rds_table);
if (!rds_sysctl_reg_table)
return -ENOMEM;
return 0;
diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c
index 8b5cc4aa8868..72981375f47c 100644
--- a/net/rds/tcp_listen.c
+++ b/net/rds/tcp_listen.c
@@ -145,7 +145,7 @@ int rds_tcp_listen_init(void)
if (ret < 0)
goto out;
- sock->sk->sk_reuse = 1;
+ sock->sk->sk_reuse = SK_CAN_REUSE;
rds_tcp_nonagle(sock);
write_lock_bh(&sock->sk->sk_callback_lock);
diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c
index 906cc05bba63..28dbdb911b85 100644
--- a/net/rose/rose_dev.c
+++ b/net/rose/rose_dev.c
@@ -37,7 +37,7 @@
static int rose_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
- const void *daddr, const void *saddr, unsigned len)
+ const void *daddr, const void *saddr, unsigned int len)
{
unsigned char *buff = skb_push(skb, ROSE_MIN_LEN + 2);
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c
index 47f1fdb346b0..7ca57741b2fb 100644
--- a/net/rose/rose_subr.c
+++ b/net/rose/rose_subr.c
@@ -399,7 +399,7 @@ int rose_parse_facilities(unsigned char *p, unsigned packet_len,
facilities_len = *p++;
- if (facilities_len == 0 || (unsigned)facilities_len > packet_len)
+ if (facilities_len == 0 || (unsigned int)facilities_len > packet_len)
return 0;
while (facilities_len >= 3 && *p == 0x00) {
diff --git a/net/rose/sysctl_net_rose.c b/net/rose/sysctl_net_rose.c
index df6d9dac2186..94ca9c2ccd69 100644
--- a/net/rose/sysctl_net_rose.c
+++ b/net/rose/sysctl_net_rose.c
@@ -118,18 +118,12 @@ static ctl_table rose_table[] = {
{ }
};
-static struct ctl_path rose_path[] = {
- { .procname = "net", },
- { .procname = "rose", },
- { }
-};
-
void __init rose_register_sysctl(void)
{
- rose_table_header = register_sysctl_paths(rose_path, rose_table);
+ rose_table_header = register_net_sysctl(&init_net, "net/rose", rose_table);
}
void rose_unregister_sysctl(void)
{
- unregister_sysctl_table(rose_table_header);
+ unregister_net_sysctl_table(rose_table_header);
}
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 74c064c0dfdd..05996d0dd828 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -26,7 +26,7 @@ MODULE_AUTHOR("Red Hat, Inc.");
MODULE_LICENSE("GPL");
MODULE_ALIAS_NETPROTO(PF_RXRPC);
-unsigned rxrpc_debug; // = RXRPC_DEBUG_KPROTO;
+unsigned int rxrpc_debug; // = RXRPC_DEBUG_KPROTO;
module_param_named(debug, rxrpc_debug, uint, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(debug, "RxRPC debugging mask");
@@ -513,7 +513,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen)
{
struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
- unsigned min_sec_level;
+ unsigned int min_sec_level;
int ret;
_enter(",%d,%d,,%d", level, optname, optlen);
@@ -555,13 +555,13 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
case RXRPC_MIN_SECURITY_LEVEL:
ret = -EINVAL;
- if (optlen != sizeof(unsigned))
+ if (optlen != sizeof(unsigned int))
goto error;
ret = -EISCONN;
if (rx->sk.sk_state != RXRPC_UNCONNECTED)
goto error;
ret = get_user(min_sec_level,
- (unsigned __user *) optval);
+ (unsigned int __user *) optval);
if (ret < 0)
goto error;
ret = -EINVAL;
diff --git a/net/rxrpc/ar-ack.c b/net/rxrpc/ar-ack.c
index c3126e864f3c..e4d9cbcff402 100644
--- a/net/rxrpc/ar-ack.c
+++ b/net/rxrpc/ar-ack.c
@@ -19,7 +19,7 @@
#include <net/af_rxrpc.h>
#include "ar-internal.h"
-static unsigned rxrpc_ack_defer = 1;
+static unsigned int rxrpc_ack_defer = 1;
static const char *const rxrpc_acks[] = {
"---", "REQ", "DUP", "OOS", "WIN", "MEM", "PNG", "PNR", "DLY", "IDL",
@@ -548,11 +548,11 @@ static void rxrpc_zap_tx_window(struct rxrpc_call *call)
* process the extra information that may be appended to an ACK packet
*/
static void rxrpc_extract_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,
- unsigned latest, int nAcks)
+ unsigned int latest, int nAcks)
{
struct rxrpc_ackinfo ackinfo;
struct rxrpc_peer *peer;
- unsigned mtu;
+ unsigned int mtu;
if (skb_copy_bits(skb, nAcks + 3, &ackinfo, sizeof(ackinfo)) < 0) {
_leave(" [no ackinfo]");
diff --git a/net/rxrpc/ar-call.c b/net/rxrpc/ar-call.c
index bf656c230ba9..a3bbb360a3f9 100644
--- a/net/rxrpc/ar-call.c
+++ b/net/rxrpc/ar-call.c
@@ -38,8 +38,8 @@ const char *const rxrpc_call_states[] = {
struct kmem_cache *rxrpc_call_jar;
LIST_HEAD(rxrpc_calls);
DEFINE_RWLOCK(rxrpc_call_lock);
-static unsigned rxrpc_call_max_lifetime = 60;
-static unsigned rxrpc_dead_call_timeout = 2;
+static unsigned int rxrpc_call_max_lifetime = 60;
+static unsigned int rxrpc_dead_call_timeout = 2;
static void rxrpc_destroy_call(struct work_struct *work);
static void rxrpc_call_life_expired(unsigned long _call);
diff --git a/net/rxrpc/ar-input.c b/net/rxrpc/ar-input.c
index 1a2b0633fece..529572f18d1f 100644
--- a/net/rxrpc/ar-input.c
+++ b/net/rxrpc/ar-input.c
@@ -76,7 +76,7 @@ int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb,
* --ANK */
// ret = -ENOBUFS;
// if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
-// (unsigned) sk->sk_rcvbuf)
+// (unsigned int) sk->sk_rcvbuf)
// goto out;
ret = sk_filter(sk, skb);
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 8e22bd345e71..a693aca2ae2e 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -83,7 +83,7 @@ struct rxrpc_skb_priv {
struct rxrpc_call *call; /* call with which associated */
unsigned long resend_at; /* time in jiffies at which to resend */
union {
- unsigned offset; /* offset into buffer of next read */
+ unsigned int offset; /* offset into buffer of next read */
int remain; /* amount of space remaining for next write */
u32 error; /* network error code */
bool need_resend; /* T if needs resending */
@@ -176,9 +176,9 @@ struct rxrpc_peer {
struct list_head error_targets; /* targets for net error distribution */
spinlock_t lock; /* access lock */
atomic_t usage;
- unsigned if_mtu; /* interface MTU for this peer */
- unsigned mtu; /* network MTU for this peer */
- unsigned maxdata; /* data size (MTU - hdrsize) */
+ unsigned int if_mtu; /* interface MTU for this peer */
+ unsigned int mtu; /* network MTU for this peer */
+ unsigned int maxdata; /* data size (MTU - hdrsize) */
unsigned short hdrsize; /* header size (IP + UDP + RxRPC) */
int debug_id; /* debug ID for printks */
int net_error; /* network error distributed */
@@ -187,8 +187,8 @@ struct rxrpc_peer {
/* calculated RTT cache */
#define RXRPC_RTT_CACHE_SIZE 32
suseconds_t rtt; /* current RTT estimate (in uS) */
- unsigned rtt_point; /* next entry at which to insert */
- unsigned rtt_usage; /* amount of cache actually used */
+ unsigned int rtt_point; /* next entry at which to insert */
+ unsigned int rtt_usage; /* amount of cache actually used */
suseconds_t rtt_cache[RXRPC_RTT_CACHE_SIZE]; /* calculated RTT cache */
};
@@ -271,7 +271,7 @@ struct rxrpc_connection {
} state;
int error; /* error code for local abort */
int debug_id; /* debug ID for printks */
- unsigned call_counter; /* call ID counter */
+ unsigned int call_counter; /* call ID counter */
atomic_t serial; /* packet serial number counter */
atomic_t hi_serial; /* highest serial number received */
u8 avail_calls; /* number of calls available */
@@ -592,7 +592,7 @@ extern struct rxrpc_transport *rxrpc_find_transport(struct rxrpc_local *,
/*
* debug tracing
*/
-extern unsigned rxrpc_debug;
+extern unsigned int rxrpc_debug;
#define dbgprintk(FMT,...) \
printk("[%-6.6s] "FMT"\n", current->comm ,##__VA_ARGS__)
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
index ae3a035f5390..8b1f9f49960f 100644
--- a/net/rxrpc/ar-key.c
+++ b/net/rxrpc/ar-key.c
@@ -82,7 +82,7 @@ static int rxrpc_vet_description_s(const char *desc)
* - the caller guarantees we have at least 4 words
*/
static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,
- unsigned toklen)
+ unsigned int toklen)
{
struct rxrpc_key_token *token, **pptoken;
size_t plen;
@@ -210,10 +210,10 @@ static void rxrpc_rxk5_free(struct rxk5_key *rxk5)
*/
static int rxrpc_krb5_decode_principal(struct krb5_principal *princ,
const __be32 **_xdr,
- unsigned *_toklen)
+ unsigned int *_toklen)
{
const __be32 *xdr = *_xdr;
- unsigned toklen = *_toklen, n_parts, loop, tmp;
+ unsigned int toklen = *_toklen, n_parts, loop, tmp;
/* there must be at least one name, and at least #names+1 length
* words */
@@ -286,10 +286,10 @@ static int rxrpc_krb5_decode_principal(struct krb5_principal *princ,
static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td,
size_t max_data_size,
const __be32 **_xdr,
- unsigned *_toklen)
+ unsigned int *_toklen)
{
const __be32 *xdr = *_xdr;
- unsigned toklen = *_toklen, len;
+ unsigned int toklen = *_toklen, len;
/* there must be at least one tag and one length word */
if (toklen <= 8)
@@ -330,11 +330,11 @@ static int rxrpc_krb5_decode_tagged_array(struct krb5_tagged_data **_td,
u8 max_n_elem,
size_t max_elem_size,
const __be32 **_xdr,
- unsigned *_toklen)
+ unsigned int *_toklen)
{
struct krb5_tagged_data *td;
const __be32 *xdr = *_xdr;
- unsigned toklen = *_toklen, n_elem, loop;
+ unsigned int toklen = *_toklen, n_elem, loop;
int ret;
/* there must be at least one count */
@@ -380,10 +380,10 @@ static int rxrpc_krb5_decode_tagged_array(struct krb5_tagged_data **_td,
* extract a krb5 ticket
*/
static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen,
- const __be32 **_xdr, unsigned *_toklen)
+ const __be32 **_xdr, unsigned int *_toklen)
{
const __be32 *xdr = *_xdr;
- unsigned toklen = *_toklen, len;
+ unsigned int toklen = *_toklen, len;
/* there must be at least one length word */
if (toklen <= 4)
@@ -419,7 +419,7 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen,
* - the caller guarantees we have at least 4 words
*/
static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr,
- unsigned toklen)
+ unsigned int toklen)
{
struct rxrpc_key_token *token, **pptoken;
struct rxk5_key *rxk5;
@@ -549,7 +549,7 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal
{
const __be32 *xdr = data, *token;
const char *cp;
- unsigned len, tmp, loop, ntoken, toklen, sec_ix;
+ unsigned int len, tmp, loop, ntoken, toklen, sec_ix;
int ret;
_enter(",{%x,%x,%x,%x},%zu",
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index 7635107726ce..f226709ebd8f 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -31,7 +31,7 @@
#define REALM_SZ 40 /* size of principal's auth domain */
#define SNAME_SZ 40 /* size of service name */
-unsigned rxrpc_debug;
+unsigned int rxrpc_debug;
module_param_named(debug, rxrpc_debug, uint, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(debug, "rxkad debugging mask");
@@ -207,7 +207,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
struct rxrpc_crypt iv;
struct scatterlist sg[16];
struct sk_buff *trailer;
- unsigned len;
+ unsigned int len;
u16 check;
int nsg;
@@ -826,7 +826,7 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
struct rxrpc_crypt iv, key;
struct scatterlist sg[1];
struct in_addr addr;
- unsigned life;
+ unsigned int life;
time_t issue, now;
bool little_endian;
int ret;
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 93fdf131bd75..5cfb160df063 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -127,7 +127,8 @@ static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a,
nest = nla_nest_start(skb, a->order);
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT_STRING(skb, TCA_KIND, a->ops->kind);
+ if (nla_put_string(skb, TCA_KIND, a->ops->kind))
+ goto nla_put_failure;
for (i = 0; i < (hinfo->hmask + 1); i++) {
p = hinfo->htab[tcf_hash(i, hinfo->hmask)];
@@ -139,7 +140,8 @@ static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a,
p = s_p;
}
}
- NLA_PUT_U32(skb, TCA_FCNT, n_i);
+ if (nla_put_u32(skb, TCA_FCNT, n_i))
+ goto nla_put_failure;
nla_nest_end(skb, nest);
return n_i;
@@ -437,7 +439,8 @@ tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
if (a->ops == NULL || a->ops->dump == NULL)
return err;
- NLA_PUT_STRING(skb, TCA_KIND, a->ops->kind);
+ if (nla_put_string(skb, TCA_KIND, a->ops->kind))
+ goto nla_put_failure;
if (tcf_action_copy_stats(skb, a, 0))
goto nla_put_failure;
nest = nla_nest_start(skb, TCA_OPTIONS);
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index 453a73431ac4..882124ceb70c 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -550,11 +550,13 @@ static int tcf_csum_dump(struct sk_buff *skb,
};
struct tcf_t t;
- NLA_PUT(skb, TCA_CSUM_PARMS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_CSUM_PARMS, sizeof(opt), &opt))
+ goto nla_put_failure;
t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
- NLA_PUT(skb, TCA_CSUM_TM, sizeof(t), &t);
+ if (nla_put(skb, TCA_CSUM_TM, sizeof(t), &t))
+ goto nla_put_failure;
return skb->len;
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index b77f5a06a658..f10fb8256442 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -162,7 +162,8 @@ static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int
};
struct tcf_t t;
- NLA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_GACT_PARMS, sizeof(opt), &opt))
+ goto nla_put_failure;
#ifdef CONFIG_GACT_PROB
if (gact->tcfg_ptype) {
struct tc_gact_p p_opt = {
@@ -171,13 +172,15 @@ static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int
.ptype = gact->tcfg_ptype,
};
- NLA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt);
+ if (nla_put(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt))
+ goto nla_put_failure;
}
#endif
t.install = jiffies_to_clock_t(jiffies - gact->tcf_tm.install);
t.lastuse = jiffies_to_clock_t(jiffies - gact->tcf_tm.lastuse);
t.expires = jiffies_to_clock_t(gact->tcf_tm.expires);
- NLA_PUT(skb, TCA_GACT_TM, sizeof(t), &t);
+ if (nla_put(skb, TCA_GACT_TM, sizeof(t), &t))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 60f8f616e8fa..0beba0e5312e 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -267,15 +267,17 @@ static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int
c.refcnt = ipt->tcf_refcnt - ref;
strcpy(t->u.user.name, ipt->tcfi_t->u.kernel.target->name);
- NLA_PUT(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t);
- NLA_PUT_U32(skb, TCA_IPT_INDEX, ipt->tcf_index);
- NLA_PUT_U32(skb, TCA_IPT_HOOK, ipt->tcfi_hook);
- NLA_PUT(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c);
- NLA_PUT_STRING(skb, TCA_IPT_TABLE, ipt->tcfi_tname);
+ if (nla_put(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t) ||
+ nla_put_u32(skb, TCA_IPT_INDEX, ipt->tcf_index) ||
+ nla_put_u32(skb, TCA_IPT_HOOK, ipt->tcfi_hook) ||
+ nla_put(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c) ||
+ nla_put_string(skb, TCA_IPT_TABLE, ipt->tcfi_tname))
+ goto nla_put_failure;
tm.install = jiffies_to_clock_t(jiffies - ipt->tcf_tm.install);
tm.lastuse = jiffies_to_clock_t(jiffies - ipt->tcf_tm.lastuse);
tm.expires = jiffies_to_clock_t(ipt->tcf_tm.expires);
- NLA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm);
+ if (nla_put(skb, TCA_IPT_TM, sizeof (tm), &tm))
+ goto nla_put_failure;
kfree(t);
return skb->len;
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index e051398fdf6b..d583aea3b3df 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -227,11 +227,13 @@ static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, i
};
struct tcf_t t;
- NLA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt))
+ goto nla_put_failure;
t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install);
t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse);
t.expires = jiffies_to_clock_t(m->tcf_tm.expires);
- NLA_PUT(skb, TCA_MIRRED_TM, sizeof(t), &t);
+ if (nla_put(skb, TCA_MIRRED_TM, sizeof(t), &t))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index 001d1b354869..b5d029eb44f2 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -284,11 +284,13 @@ static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a,
};
struct tcf_t t;
- NLA_PUT(skb, TCA_NAT_PARMS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_NAT_PARMS, sizeof(opt), &opt))
+ goto nla_put_failure;
t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
- NLA_PUT(skb, TCA_NAT_TM, sizeof(t), &t);
+ if (nla_put(skb, TCA_NAT_TM, sizeof(t), &t))
+ goto nla_put_failure;
return skb->len;
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index 10d3aed86560..26aa2f6ce257 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -215,11 +215,13 @@ static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,
opt->refcnt = p->tcf_refcnt - ref;
opt->bindcnt = p->tcf_bindcnt - bind;
- NLA_PUT(skb, TCA_PEDIT_PARMS, s, opt);
+ if (nla_put(skb, TCA_PEDIT_PARMS, s, opt))
+ goto nla_put_failure;
t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
- NLA_PUT(skb, TCA_PEDIT_TM, sizeof(t), &t);
+ if (nla_put(skb, TCA_PEDIT_TM, sizeof(t), &t))
+ goto nla_put_failure;
kfree(opt);
return skb->len;
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 6fb3f5af0f85..a9de23297d47 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -356,11 +356,14 @@ tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
opt.rate = police->tcfp_R_tab->rate;
if (police->tcfp_P_tab)
opt.peakrate = police->tcfp_P_tab->rate;
- NLA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt);
- if (police->tcfp_result)
- NLA_PUT_U32(skb, TCA_POLICE_RESULT, police->tcfp_result);
- if (police->tcfp_ewma_rate)
- NLA_PUT_U32(skb, TCA_POLICE_AVRATE, police->tcfp_ewma_rate);
+ if (nla_put(skb, TCA_POLICE_TBF, sizeof(opt), &opt))
+ goto nla_put_failure;
+ if (police->tcfp_result &&
+ nla_put_u32(skb, TCA_POLICE_RESULT, police->tcfp_result))
+ goto nla_put_failure;
+ if (police->tcfp_ewma_rate &&
+ nla_put_u32(skb, TCA_POLICE_AVRATE, police->tcfp_ewma_rate))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index 73e0a3ab4d55..3922f2a2821b 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -172,12 +172,14 @@ static int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a,
};
struct tcf_t t;
- NLA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt);
- NLA_PUT_STRING(skb, TCA_DEF_DATA, d->tcfd_defdata);
+ if (nla_put(skb, TCA_DEF_PARMS, sizeof(opt), &opt) ||
+ nla_put_string(skb, TCA_DEF_DATA, d->tcfd_defdata))
+ goto nla_put_failure;
t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install);
t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse);
t.expires = jiffies_to_clock_t(d->tcf_tm.expires);
- NLA_PUT(skb, TCA_DEF_TM, sizeof(t), &t);
+ if (nla_put(skb, TCA_DEF_TM, sizeof(t), &t))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 35dbbe91027e..476e0fac6712 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -166,20 +166,25 @@ static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
};
struct tcf_t t;
- NLA_PUT(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt);
- if (d->flags & SKBEDIT_F_PRIORITY)
- NLA_PUT(skb, TCA_SKBEDIT_PRIORITY, sizeof(d->priority),
- &d->priority);
- if (d->flags & SKBEDIT_F_QUEUE_MAPPING)
- NLA_PUT(skb, TCA_SKBEDIT_QUEUE_MAPPING,
- sizeof(d->queue_mapping), &d->queue_mapping);
- if (d->flags & SKBEDIT_F_MARK)
- NLA_PUT(skb, TCA_SKBEDIT_MARK, sizeof(d->mark),
- &d->mark);
+ if (nla_put(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt))
+ goto nla_put_failure;
+ if ((d->flags & SKBEDIT_F_PRIORITY) &&
+ nla_put(skb, TCA_SKBEDIT_PRIORITY, sizeof(d->priority),
+ &d->priority))
+ goto nla_put_failure;
+ if ((d->flags & SKBEDIT_F_QUEUE_MAPPING) &&
+ nla_put(skb, TCA_SKBEDIT_QUEUE_MAPPING,
+ sizeof(d->queue_mapping), &d->queue_mapping))
+ goto nla_put_failure;
+ if ((d->flags & SKBEDIT_F_MARK) &&
+ nla_put(skb, TCA_SKBEDIT_MARK, sizeof(d->mark),
+ &d->mark))
+ goto nla_put_failure;
t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install);
t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse);
t.expires = jiffies_to_clock_t(d->tcf_tm.expires);
- NLA_PUT(skb, TCA_SKBEDIT_TM, sizeof(t), &t);
+ if (nla_put(skb, TCA_SKBEDIT_TM, sizeof(t), &t))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index a69d44f1dac5..f452f696b4b3 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -357,7 +357,8 @@ static int tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp,
tcm->tcm_ifindex = qdisc_dev(tp->q)->ifindex;
tcm->tcm_parent = tp->classid;
tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol);
- NLA_PUT_STRING(skb, TCA_KIND, tp->ops->kind);
+ if (nla_put_string(skb, TCA_KIND, tp->ops->kind))
+ goto nla_put_failure;
tcm->tcm_handle = fh;
if (RTM_DELTFILTER != event) {
tcm->tcm_handle = 0;
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index ea1f70b5a5f4..590960a22a77 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -257,8 +257,9 @@ static int basic_dump(struct tcf_proto *tp, unsigned long fh,
if (nest == NULL)
goto nla_put_failure;
- if (f->res.classid)
- NLA_PUT_U32(skb, TCA_BASIC_CLASSID, f->res.classid);
+ if (f->res.classid &&
+ nla_put_u32(skb, TCA_BASIC_CLASSID, f->res.classid))
+ goto nla_put_failure;
if (tcf_exts_dump(skb, &f->exts, &basic_ext_map) < 0 ||
tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0)
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 1d8bd0dbcd1f..ccd08c8dc6a7 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -572,25 +572,32 @@ static int flow_dump(struct tcf_proto *tp, unsigned long fh,
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT_U32(skb, TCA_FLOW_KEYS, f->keymask);
- NLA_PUT_U32(skb, TCA_FLOW_MODE, f->mode);
+ if (nla_put_u32(skb, TCA_FLOW_KEYS, f->keymask) ||
+ nla_put_u32(skb, TCA_FLOW_MODE, f->mode))
+ goto nla_put_failure;
if (f->mask != ~0 || f->xor != 0) {
- NLA_PUT_U32(skb, TCA_FLOW_MASK, f->mask);
- NLA_PUT_U32(skb, TCA_FLOW_XOR, f->xor);
+ if (nla_put_u32(skb, TCA_FLOW_MASK, f->mask) ||
+ nla_put_u32(skb, TCA_FLOW_XOR, f->xor))
+ goto nla_put_failure;
}
- if (f->rshift)
- NLA_PUT_U32(skb, TCA_FLOW_RSHIFT, f->rshift);
- if (f->addend)
- NLA_PUT_U32(skb, TCA_FLOW_ADDEND, f->addend);
+ if (f->rshift &&
+ nla_put_u32(skb, TCA_FLOW_RSHIFT, f->rshift))
+ goto nla_put_failure;
+ if (f->addend &&
+ nla_put_u32(skb, TCA_FLOW_ADDEND, f->addend))
+ goto nla_put_failure;
- if (f->divisor)
- NLA_PUT_U32(skb, TCA_FLOW_DIVISOR, f->divisor);
- if (f->baseclass)
- NLA_PUT_U32(skb, TCA_FLOW_BASECLASS, f->baseclass);
+ if (f->divisor &&
+ nla_put_u32(skb, TCA_FLOW_DIVISOR, f->divisor))
+ goto nla_put_failure;
+ if (f->baseclass &&
+ nla_put_u32(skb, TCA_FLOW_BASECLASS, f->baseclass))
+ goto nla_put_failure;
- if (f->perturb_period)
- NLA_PUT_U32(skb, TCA_FLOW_PERTURB, f->perturb_period / HZ);
+ if (f->perturb_period &&
+ nla_put_u32(skb, TCA_FLOW_PERTURB, f->perturb_period / HZ))
+ goto nla_put_failure;
if (tcf_exts_dump(skb, &f->exts, &flow_ext_map) < 0)
goto nla_put_failure;
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index 389af152ec45..8384a4797240 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -346,14 +346,17 @@ static int fw_dump(struct tcf_proto *tp, unsigned long fh,
if (nest == NULL)
goto nla_put_failure;
- if (f->res.classid)
- NLA_PUT_U32(skb, TCA_FW_CLASSID, f->res.classid);
+ if (f->res.classid &&
+ nla_put_u32(skb, TCA_FW_CLASSID, f->res.classid))
+ goto nla_put_failure;
#ifdef CONFIG_NET_CLS_IND
- if (strlen(f->indev))
- NLA_PUT_STRING(skb, TCA_FW_INDEV, f->indev);
+ if (strlen(f->indev) &&
+ nla_put_string(skb, TCA_FW_INDEV, f->indev))
+ goto nla_put_failure;
#endif /* CONFIG_NET_CLS_IND */
- if (head->mask != 0xFFFFFFFF)
- NLA_PUT_U32(skb, TCA_FW_MASK, head->mask);
+ if (head->mask != 0xFFFFFFFF &&
+ nla_put_u32(skb, TCA_FW_MASK, head->mask))
+ goto nla_put_failure;
if (tcf_exts_dump(skb, &f->exts, &fw_ext_map) < 0)
goto nla_put_failure;
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index 13ab66e9df58..36fec4227401 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -571,17 +571,21 @@ static int route4_dump(struct tcf_proto *tp, unsigned long fh,
if (!(f->handle & 0x8000)) {
id = f->id & 0xFF;
- NLA_PUT_U32(skb, TCA_ROUTE4_TO, id);
+ if (nla_put_u32(skb, TCA_ROUTE4_TO, id))
+ goto nla_put_failure;
}
if (f->handle & 0x80000000) {
- if ((f->handle >> 16) != 0xFFFF)
- NLA_PUT_U32(skb, TCA_ROUTE4_IIF, f->iif);
+ if ((f->handle >> 16) != 0xFFFF &&
+ nla_put_u32(skb, TCA_ROUTE4_IIF, f->iif))
+ goto nla_put_failure;
} else {
id = f->id >> 16;
- NLA_PUT_U32(skb, TCA_ROUTE4_FROM, id);
+ if (nla_put_u32(skb, TCA_ROUTE4_FROM, id))
+ goto nla_put_failure;
}
- if (f->res.classid)
- NLA_PUT_U32(skb, TCA_ROUTE4_CLASSID, f->res.classid);
+ if (f->res.classid &&
+ nla_put_u32(skb, TCA_ROUTE4_CLASSID, f->res.classid))
+ goto nla_put_failure;
if (tcf_exts_dump(skb, &f->exts, &route_ext_map) < 0)
goto nla_put_failure;
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h
index b01427924f81..18ab93ec8d7e 100644
--- a/net/sched/cls_rsvp.h
+++ b/net/sched/cls_rsvp.h
@@ -615,18 +615,22 @@ static int rsvp_dump(struct tcf_proto *tp, unsigned long fh,
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT(skb, TCA_RSVP_DST, sizeof(s->dst), &s->dst);
+ if (nla_put(skb, TCA_RSVP_DST, sizeof(s->dst), &s->dst))
+ goto nla_put_failure;
pinfo.dpi = s->dpi;
pinfo.spi = f->spi;
pinfo.protocol = s->protocol;
pinfo.tunnelid = s->tunnelid;
pinfo.tunnelhdr = f->tunnelhdr;
pinfo.pad = 0;
- NLA_PUT(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo);
- if (f->res.classid)
- NLA_PUT_U32(skb, TCA_RSVP_CLASSID, f->res.classid);
- if (((f->handle >> 8) & 0xFF) != 16)
- NLA_PUT(skb, TCA_RSVP_SRC, sizeof(f->src), f->src);
+ if (nla_put(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo))
+ goto nla_put_failure;
+ if (f->res.classid &&
+ nla_put_u32(skb, TCA_RSVP_CLASSID, f->res.classid))
+ goto nla_put_failure;
+ if (((f->handle >> 8) & 0xFF) != 16 &&
+ nla_put(skb, TCA_RSVP_SRC, sizeof(f->src), f->src))
+ goto nla_put_failure;
if (tcf_exts_dump(skb, &f->exts, &rsvp_ext_map) < 0)
goto nla_put_failure;
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
index dbe199234c63..fe29420d0b0e 100644
--- a/net/sched/cls_tcindex.c
+++ b/net/sched/cls_tcindex.c
@@ -438,10 +438,11 @@ static int tcindex_dump(struct tcf_proto *tp, unsigned long fh,
if (!fh) {
t->tcm_handle = ~0; /* whatever ... */
- NLA_PUT_U32(skb, TCA_TCINDEX_HASH, p->hash);
- NLA_PUT_U16(skb, TCA_TCINDEX_MASK, p->mask);
- NLA_PUT_U32(skb, TCA_TCINDEX_SHIFT, p->shift);
- NLA_PUT_U32(skb, TCA_TCINDEX_FALL_THROUGH, p->fall_through);
+ if (nla_put_u32(skb, TCA_TCINDEX_HASH, p->hash) ||
+ nla_put_u16(skb, TCA_TCINDEX_MASK, p->mask) ||
+ nla_put_u32(skb, TCA_TCINDEX_SHIFT, p->shift) ||
+ nla_put_u32(skb, TCA_TCINDEX_FALL_THROUGH, p->fall_through))
+ goto nla_put_failure;
nla_nest_end(skb, nest);
} else {
if (p->perfect) {
@@ -460,8 +461,9 @@ static int tcindex_dump(struct tcf_proto *tp, unsigned long fh,
}
}
pr_debug("handle = %d\n", t->tcm_handle);
- if (r->res.class)
- NLA_PUT_U32(skb, TCA_TCINDEX_CLASSID, r->res.classid);
+ if (r->res.class &&
+ nla_put_u32(skb, TCA_TCINDEX_CLASSID, r->res.classid))
+ goto nla_put_failure;
if (tcf_exts_dump(skb, &r->exts, &tcindex_ext_map) < 0)
goto nla_put_failure;
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 939b627b4795..591b006a8c5a 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -733,36 +733,44 @@ static int u32_dump(struct tcf_proto *tp, unsigned long fh,
struct tc_u_hnode *ht = (struct tc_u_hnode *)fh;
u32 divisor = ht->divisor + 1;
- NLA_PUT_U32(skb, TCA_U32_DIVISOR, divisor);
+ if (nla_put_u32(skb, TCA_U32_DIVISOR, divisor))
+ goto nla_put_failure;
} else {
- NLA_PUT(skb, TCA_U32_SEL,
- sizeof(n->sel) + n->sel.nkeys*sizeof(struct tc_u32_key),
- &n->sel);
+ if (nla_put(skb, TCA_U32_SEL,
+ sizeof(n->sel) + n->sel.nkeys*sizeof(struct tc_u32_key),
+ &n->sel))
+ goto nla_put_failure;
if (n->ht_up) {
u32 htid = n->handle & 0xFFFFF000;
- NLA_PUT_U32(skb, TCA_U32_HASH, htid);
+ if (nla_put_u32(skb, TCA_U32_HASH, htid))
+ goto nla_put_failure;
}
- if (n->res.classid)
- NLA_PUT_U32(skb, TCA_U32_CLASSID, n->res.classid);
- if (n->ht_down)
- NLA_PUT_U32(skb, TCA_U32_LINK, n->ht_down->handle);
+ if (n->res.classid &&
+ nla_put_u32(skb, TCA_U32_CLASSID, n->res.classid))
+ goto nla_put_failure;
+ if (n->ht_down &&
+ nla_put_u32(skb, TCA_U32_LINK, n->ht_down->handle))
+ goto nla_put_failure;
#ifdef CONFIG_CLS_U32_MARK
- if (n->mark.val || n->mark.mask)
- NLA_PUT(skb, TCA_U32_MARK, sizeof(n->mark), &n->mark);
+ if ((n->mark.val || n->mark.mask) &&
+ nla_put(skb, TCA_U32_MARK, sizeof(n->mark), &n->mark))
+ goto nla_put_failure;
#endif
if (tcf_exts_dump(skb, &n->exts, &u32_ext_map) < 0)
goto nla_put_failure;
#ifdef CONFIG_NET_CLS_IND
- if (strlen(n->indev))
- NLA_PUT_STRING(skb, TCA_U32_INDEV, n->indev);
+ if (strlen(n->indev) &&
+ nla_put_string(skb, TCA_U32_INDEV, n->indev))
+ goto nla_put_failure;
#endif
#ifdef CONFIG_CLS_U32_PERF
- NLA_PUT(skb, TCA_U32_PCNT,
- sizeof(struct tc_u32_pcnt) + n->sel.nkeys*sizeof(u64),
- n->pf);
+ if (nla_put(skb, TCA_U32_PCNT,
+ sizeof(struct tc_u32_pcnt) + n->sel.nkeys*sizeof(u64),
+ n->pf))
+ goto nla_put_failure;
#endif
}
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
index 1363bf14e61b..4790c696cbce 100644
--- a/net/sched/em_meta.c
+++ b/net/sched/em_meta.c
@@ -585,8 +585,9 @@ static void meta_var_apply_extras(struct meta_value *v,
static int meta_var_dump(struct sk_buff *skb, struct meta_value *v, int tlv)
{
- if (v->val && v->len)
- NLA_PUT(skb, tlv, v->len, (void *) v->val);
+ if (v->val && v->len &&
+ nla_put(skb, tlv, v->len, (void *) v->val))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -636,10 +637,13 @@ static void meta_int_apply_extras(struct meta_value *v,
static int meta_int_dump(struct sk_buff *skb, struct meta_value *v, int tlv)
{
- if (v->len == sizeof(unsigned long))
- NLA_PUT(skb, tlv, sizeof(unsigned long), &v->val);
- else if (v->len == sizeof(u32))
- NLA_PUT_U32(skb, tlv, v->val);
+ if (v->len == sizeof(unsigned long)) {
+ if (nla_put(skb, tlv, sizeof(unsigned long), &v->val))
+ goto nla_put_failure;
+ } else if (v->len == sizeof(u32)) {
+ if (nla_put_u32(skb, tlv, v->val))
+ goto nla_put_failure;
+ }
return 0;
@@ -831,7 +835,8 @@ static int em_meta_dump(struct sk_buff *skb, struct tcf_ematch *em)
memcpy(&hdr.left, &meta->lvalue.hdr, sizeof(hdr.left));
memcpy(&hdr.right, &meta->rvalue.hdr, sizeof(hdr.right));
- NLA_PUT(skb, TCA_EM_META_HDR, sizeof(hdr), &hdr);
+ if (nla_put(skb, TCA_EM_META_HDR, sizeof(hdr), &hdr))
+ goto nla_put_failure;
ops = meta_type_ops(&meta->lvalue);
if (ops->dump(skb, &meta->lvalue, TCA_EM_META_LVALUE) < 0 ||
diff --git a/net/sched/ematch.c b/net/sched/ematch.c
index 88d93eb92507..aca233c2b848 100644
--- a/net/sched/ematch.c
+++ b/net/sched/ematch.c
@@ -441,7 +441,8 @@ int tcf_em_tree_dump(struct sk_buff *skb, struct tcf_ematch_tree *tree, int tlv)
if (top_start == NULL)
goto nla_put_failure;
- NLA_PUT(skb, TCA_EMATCH_TREE_HDR, sizeof(tree->hdr), &tree->hdr);
+ if (nla_put(skb, TCA_EMATCH_TREE_HDR, sizeof(tree->hdr), &tree->hdr))
+ goto nla_put_failure;
list_start = nla_nest_start(skb, TCA_EMATCH_TREE_LIST);
if (list_start == NULL)
@@ -457,7 +458,8 @@ int tcf_em_tree_dump(struct sk_buff *skb, struct tcf_ematch_tree *tree, int tlv)
.flags = em->flags
};
- NLA_PUT(skb, i + 1, sizeof(em_hdr), &em_hdr);
+ if (nla_put(skb, i + 1, sizeof(em_hdr), &em_hdr))
+ goto nla_put_failure;
if (em->ops && em->ops->dump) {
if (em->ops->dump(skb, em) < 0)
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 3d8981fde301..d2daefcc205f 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -426,7 +426,8 @@ static int qdisc_dump_stab(struct sk_buff *skb, struct qdisc_size_table *stab)
nest = nla_nest_start(skb, TCA_STAB);
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts);
+ if (nla_put(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts))
+ goto nla_put_failure;
nla_nest_end(skb, nest);
return skb->len;
@@ -1201,7 +1202,8 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
tcm->tcm_parent = clid;
tcm->tcm_handle = q->handle;
tcm->tcm_info = atomic_read(&q->refcnt);
- NLA_PUT_STRING(skb, TCA_KIND, q->ops->id);
+ if (nla_put_string(skb, TCA_KIND, q->ops->id))
+ goto nla_put_failure;
if (q->ops->dump && q->ops->dump(q, skb) < 0)
goto nla_put_failure;
q->qstats.qlen = q->q.qlen;
@@ -1505,7 +1507,8 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
tcm->tcm_parent = q->handle;
tcm->tcm_handle = q->handle;
tcm->tcm_info = 0;
- NLA_PUT_STRING(skb, TCA_KIND, q->ops->id);
+ if (nla_put_string(skb, TCA_KIND, q->ops->id))
+ goto nla_put_failure;
if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0)
goto nla_put_failure;
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index e25e49061a0d..a77a4fbc069a 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -601,7 +601,8 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT(skb, TCA_ATM_HDR, flow->hdr_len, flow->hdr);
+ if (nla_put(skb, TCA_ATM_HDR, flow->hdr_len, flow->hdr))
+ goto nla_put_failure;
if (flow->vcc) {
struct sockaddr_atmpvc pvc;
int state;
@@ -610,15 +611,19 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1;
pvc.sap_addr.vpi = flow->vcc->vpi;
pvc.sap_addr.vci = flow->vcc->vci;
- NLA_PUT(skb, TCA_ATM_ADDR, sizeof(pvc), &pvc);
+ if (nla_put(skb, TCA_ATM_ADDR, sizeof(pvc), &pvc))
+ goto nla_put_failure;
state = ATM_VF2VS(flow->vcc->flags);
- NLA_PUT_U32(skb, TCA_ATM_STATE, state);
+ if (nla_put_u32(skb, TCA_ATM_STATE, state))
+ goto nla_put_failure;
+ }
+ if (flow->excess) {
+ if (nla_put_u32(skb, TCA_ATM_EXCESS, flow->classid))
+ goto nla_put_failure;
+ } else {
+ if (nla_put_u32(skb, TCA_ATM_EXCESS, 0))
+ goto nla_put_failure;
}
- if (flow->excess)
- NLA_PUT_U32(skb, TCA_ATM_EXCESS, flow->classid);
- else
- NLA_PUT_U32(skb, TCA_ATM_EXCESS, 0);
-
nla_nest_end(skb, nest);
return skb->len;
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 24d94c097b35..6aabd77d1cfd 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1425,7 +1425,8 @@ static int cbq_dump_rate(struct sk_buff *skb, struct cbq_class *cl)
{
unsigned char *b = skb_tail_pointer(skb);
- NLA_PUT(skb, TCA_CBQ_RATE, sizeof(cl->R_tab->rate), &cl->R_tab->rate);
+ if (nla_put(skb, TCA_CBQ_RATE, sizeof(cl->R_tab->rate), &cl->R_tab->rate))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
@@ -1450,7 +1451,8 @@ static int cbq_dump_lss(struct sk_buff *skb, struct cbq_class *cl)
opt.minidle = (u32)(-cl->minidle);
opt.offtime = cl->offtime;
opt.change = ~0;
- NLA_PUT(skb, TCA_CBQ_LSSOPT, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_CBQ_LSSOPT, sizeof(opt), &opt))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
@@ -1468,7 +1470,8 @@ static int cbq_dump_wrr(struct sk_buff *skb, struct cbq_class *cl)
opt.priority = cl->priority + 1;
opt.cpriority = cl->cpriority + 1;
opt.weight = cl->weight;
- NLA_PUT(skb, TCA_CBQ_WRROPT, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_CBQ_WRROPT, sizeof(opt), &opt))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
@@ -1485,7 +1488,8 @@ static int cbq_dump_ovl(struct sk_buff *skb, struct cbq_class *cl)
opt.priority2 = cl->priority2 + 1;
opt.pad = 0;
opt.penalty = cl->penalty;
- NLA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
@@ -1502,7 +1506,8 @@ static int cbq_dump_fopt(struct sk_buff *skb, struct cbq_class *cl)
opt.split = cl->split ? cl->split->common.classid : 0;
opt.defmap = cl->defmap;
opt.defchange = ~0;
- NLA_PUT(skb, TCA_CBQ_FOPT, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_CBQ_FOPT, sizeof(opt), &opt))
+ goto nla_put_failure;
}
return skb->len;
@@ -1521,7 +1526,8 @@ static int cbq_dump_police(struct sk_buff *skb, struct cbq_class *cl)
opt.police = cl->police;
opt.__res1 = 0;
opt.__res2 = 0;
- NLA_PUT(skb, TCA_CBQ_POLICE, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_CBQ_POLICE, sizeof(opt), &opt))
+ goto nla_put_failure;
}
return skb->len;
diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c
index 7e267d7b9c75..81445cc8196f 100644
--- a/net/sched/sch_choke.c
+++ b/net/sched/sch_choke.c
@@ -515,8 +515,9 @@ static int choke_dump(struct Qdisc *sch, struct sk_buff *skb)
if (opts == NULL)
goto nla_put_failure;
- NLA_PUT(skb, TCA_CHOKE_PARMS, sizeof(opt), &opt);
- NLA_PUT_U32(skb, TCA_CHOKE_MAX_P, q->parms.max_P);
+ if (nla_put(skb, TCA_CHOKE_PARMS, sizeof(opt), &opt) ||
+ nla_put_u32(skb, TCA_CHOKE_MAX_P, q->parms.max_P))
+ goto nla_put_failure;
return nla_nest_end(skb, opts);
nla_put_failure:
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index 6b7fe4a84f13..c2189879359b 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -260,7 +260,8 @@ static int drr_dump_class(struct Qdisc *sch, unsigned long arg,
nest = nla_nest_start(skb, TCA_OPTIONS);
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT_U32(skb, TCA_DRR_QUANTUM, cl->quantum);
+ if (nla_put_u32(skb, TCA_DRR_QUANTUM, cl->quantum))
+ goto nla_put_failure;
return nla_nest_end(skb, nest);
nla_put_failure:
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 2c790204d042..389b856c6653 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -429,8 +429,9 @@ static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl,
opts = nla_nest_start(skb, TCA_OPTIONS);
if (opts == NULL)
goto nla_put_failure;
- NLA_PUT_U8(skb, TCA_DSMARK_MASK, p->mask[cl - 1]);
- NLA_PUT_U8(skb, TCA_DSMARK_VALUE, p->value[cl - 1]);
+ if (nla_put_u8(skb, TCA_DSMARK_MASK, p->mask[cl - 1]) ||
+ nla_put_u8(skb, TCA_DSMARK_VALUE, p->value[cl - 1]))
+ goto nla_put_failure;
return nla_nest_end(skb, opts);
@@ -447,13 +448,16 @@ static int dsmark_dump(struct Qdisc *sch, struct sk_buff *skb)
opts = nla_nest_start(skb, TCA_OPTIONS);
if (opts == NULL)
goto nla_put_failure;
- NLA_PUT_U16(skb, TCA_DSMARK_INDICES, p->indices);
+ if (nla_put_u16(skb, TCA_DSMARK_INDICES, p->indices))
+ goto nla_put_failure;
- if (p->default_index != NO_DEFAULT_INDEX)
- NLA_PUT_U16(skb, TCA_DSMARK_DEFAULT_INDEX, p->default_index);
+ if (p->default_index != NO_DEFAULT_INDEX &&
+ nla_put_u16(skb, TCA_DSMARK_DEFAULT_INDEX, p->default_index))
+ goto nla_put_failure;
- if (p->set_tc_index)
- NLA_PUT_FLAG(skb, TCA_DSMARK_SET_TC_INDEX);
+ if (p->set_tc_index &&
+ nla_put_flag(skb, TCA_DSMARK_SET_TC_INDEX))
+ goto nla_put_failure;
return nla_nest_end(skb, opts);
diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c
index 66effe2da8e0..e15a9eb29087 100644
--- a/net/sched/sch_fifo.c
+++ b/net/sched/sch_fifo.c
@@ -85,7 +85,8 @@ static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
{
struct tc_fifo_qopt opt = { .limit = sch->limit };
- NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 67fc573e013a..0eb1202c22a6 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -512,7 +512,8 @@ static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb)
struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS };
memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1);
- NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index 8179494c269a..ab620bf90785 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -521,14 +521,16 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)
opts = nla_nest_start(skb, TCA_OPTIONS);
if (opts == NULL)
goto nla_put_failure;
- NLA_PUT(skb, TCA_GRED_DPS, sizeof(sopt), &sopt);
+ if (nla_put(skb, TCA_GRED_DPS, sizeof(sopt), &sopt))
+ goto nla_put_failure;
for (i = 0; i < MAX_DPs; i++) {
struct gred_sched_data *q = table->tab[i];
max_p[i] = q ? q->parms.max_P : 0;
}
- NLA_PUT(skb, TCA_GRED_MAX_P, sizeof(max_p), max_p);
+ if (nla_put(skb, TCA_GRED_MAX_P, sizeof(max_p), max_p))
+ goto nla_put_failure;
parms = nla_nest_start(skb, TCA_GRED_PARMS);
if (parms == NULL)
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 9bdca2e011e9..8db3e2c72827 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1305,7 +1305,8 @@ hfsc_dump_sc(struct sk_buff *skb, int attr, struct internal_sc *sc)
tsc.m1 = sm2m(sc->sm1);
tsc.d = dx2d(sc->dx);
tsc.m2 = sm2m(sc->sm2);
- NLA_PUT(skb, attr, sizeof(tsc), &tsc);
+ if (nla_put(skb, attr, sizeof(tsc), &tsc))
+ goto nla_put_failure;
return skb->len;
@@ -1573,7 +1574,8 @@ hfsc_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb)
}
qopt.defcls = q->defcls;
- NLA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt);
+ if (nla_put(skb, TCA_OPTIONS, sizeof(qopt), &qopt))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 29b942ce9e82..2ea6f196e3c8 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1051,7 +1051,8 @@ static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
nest = nla_nest_start(skb, TCA_OPTIONS);
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt);
+ if (nla_put(skb, TCA_HTB_INIT, sizeof(gopt), &gopt))
+ goto nla_put_failure;
nla_nest_end(skb, nest);
spin_unlock_bh(root_lock);
@@ -1090,7 +1091,8 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
opt.quantum = cl->quantum;
opt.prio = cl->prio;
opt.level = cl->level;
- NLA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_HTB_PARMS, sizeof(opt), &opt))
+ goto nla_put_failure;
nla_nest_end(skb, nest);
spin_unlock_bh(root_lock);
diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c
index 28de43092330..d1831ca966d4 100644
--- a/net/sched/sch_mqprio.c
+++ b/net/sched/sch_mqprio.c
@@ -247,7 +247,8 @@ static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb)
opt.offset[i] = dev->tc_to_txq[i].offset;
}
- NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
+ goto nla_put_failure;
return skb->len;
nla_put_failure:
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
index 49131d7a7446..2a2b096d9a66 100644
--- a/net/sched/sch_multiq.c
+++ b/net/sched/sch_multiq.c
@@ -284,7 +284,8 @@ static int multiq_dump(struct Qdisc *sch, struct sk_buff *skb)
opt.bands = q->bands;
opt.max_bands = q->max_bands;
- NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
+ goto nla_put_failure;
return skb->len;
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 5da548fa7ae9..110973145a4b 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -834,7 +834,8 @@ static int dump_loss_model(const struct netem_sched_data *q,
.p23 = q->clg.a5,
};
- NLA_PUT(skb, NETEM_LOSS_GI, sizeof(gi), &gi);
+ if (nla_put(skb, NETEM_LOSS_GI, sizeof(gi), &gi))
+ goto nla_put_failure;
break;
}
case CLG_GILB_ELL: {
@@ -845,7 +846,8 @@ static int dump_loss_model(const struct netem_sched_data *q,
.k1 = q->clg.a4,
};
- NLA_PUT(skb, NETEM_LOSS_GE, sizeof(ge), &ge);
+ if (nla_put(skb, NETEM_LOSS_GE, sizeof(ge), &ge))
+ goto nla_put_failure;
break;
}
}
@@ -874,26 +876,31 @@ static int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
qopt.loss = q->loss;
qopt.gap = q->gap;
qopt.duplicate = q->duplicate;
- NLA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt);
+ if (nla_put(skb, TCA_OPTIONS, sizeof(qopt), &qopt))
+ goto nla_put_failure;
cor.delay_corr = q->delay_cor.rho;
cor.loss_corr = q->loss_cor.rho;
cor.dup_corr = q->dup_cor.rho;
- NLA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor);
+ if (nla_put(skb, TCA_NETEM_CORR, sizeof(cor), &cor))
+ goto nla_put_failure;
reorder.probability = q->reorder;
reorder.correlation = q->reorder_cor.rho;
- NLA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder);
+ if (nla_put(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder))
+ goto nla_put_failure;
corrupt.probability = q->corrupt;
corrupt.correlation = q->corrupt_cor.rho;
- NLA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
+ if (nla_put(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt))
+ goto nla_put_failure;
rate.rate = q->rate;
rate.packet_overhead = q->packet_overhead;
rate.cell_size = q->cell_size;
rate.cell_overhead = q->cell_overhead;
- NLA_PUT(skb, TCA_NETEM_RATE, sizeof(rate), &rate);
+ if (nla_put(skb, TCA_NETEM_RATE, sizeof(rate), &rate))
+ goto nla_put_failure;
if (dump_loss_model(q, skb) != 0)
goto nla_put_failure;
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index b5d56a22b1d2..79359b69ad8d 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -247,7 +247,8 @@ static int prio_dump(struct Qdisc *sch, struct sk_buff *skb)
opt.bands = q->bands;
memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX + 1);
- NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
+ goto nla_put_failure;
return skb->len;
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
index e68cb440756a..9af01f3df18c 100644
--- a/net/sched/sch_qfq.c
+++ b/net/sched/sch_qfq.c
@@ -429,8 +429,9 @@ static int qfq_dump_class(struct Qdisc *sch, unsigned long arg,
nest = nla_nest_start(skb, TCA_OPTIONS);
if (nest == NULL)
goto nla_put_failure;
- NLA_PUT_U32(skb, TCA_QFQ_WEIGHT, ONE_FP/cl->inv_w);
- NLA_PUT_U32(skb, TCA_QFQ_LMAX, cl->lmax);
+ if (nla_put_u32(skb, TCA_QFQ_WEIGHT, ONE_FP/cl->inv_w) ||
+ nla_put_u32(skb, TCA_QFQ_LMAX, cl->lmax))
+ goto nla_put_failure;
return nla_nest_end(skb, nest);
nla_put_failure:
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index a5cc3012cf42..633e32defdcc 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -272,8 +272,9 @@ static int red_dump(struct Qdisc *sch, struct sk_buff *skb)
opts = nla_nest_start(skb, TCA_OPTIONS);
if (opts == NULL)
goto nla_put_failure;
- NLA_PUT(skb, TCA_RED_PARMS, sizeof(opt), &opt);
- NLA_PUT_U32(skb, TCA_RED_MAX_P, q->parms.max_P);
+ if (nla_put(skb, TCA_RED_PARMS, sizeof(opt), &opt) ||
+ nla_put_u32(skb, TCA_RED_MAX_P, q->parms.max_P))
+ goto nla_put_failure;
return nla_nest_end(skb, opts);
nla_put_failure:
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
index d7eea99333e9..74305c883bd3 100644
--- a/net/sched/sch_sfb.c
+++ b/net/sched/sch_sfb.c
@@ -570,7 +570,8 @@ static int sfb_dump(struct Qdisc *sch, struct sk_buff *skb)
sch->qstats.backlog = q->qdisc->qstats.backlog;
opts = nla_nest_start(skb, TCA_OPTIONS);
- NLA_PUT(skb, TCA_SFB_PARMS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_SFB_PARMS, sizeof(opt), &opt))
+ goto nla_put_failure;
return nla_nest_end(skb, opts);
nla_put_failure:
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 02a21abea65e..d3a1bc26dbfc 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -812,7 +812,8 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
memcpy(&opt.stats, &q->stats, sizeof(opt.stats));
opt.flags = q->flags;
- NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
+ goto nla_put_failure;
return skb->len;
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index b8e156319d7b..4b056c15e90c 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -359,7 +359,8 @@ static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb)
memset(&opt.peakrate, 0, sizeof(opt.peakrate));
opt.mtu = q->mtu;
opt.buffer = q->buffer;
- NLA_PUT(skb, TCA_TBF_PARMS, sizeof(opt), &opt);
+ if (nla_put(skb, TCA_TBF_PARMS, sizeof(opt), &opt))
+ goto nla_put_failure;
nla_nest_end(skb, nest);
return skb->len;
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index acd2edbc073e..5bc9ab161b37 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -1408,7 +1408,7 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc)
}
/* Increase asoc's rwnd by len and send any window update SACK if needed. */
-void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len)
+void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len)
{
struct sctp_chunk *sack;
struct timer_list *timer;
@@ -1465,7 +1465,7 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len)
}
/* Decrease asoc's rwnd by len. */
-void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len)
+void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned int len)
{
int rx_count;
int over = 0;
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 80f71af71384..80564fe03024 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -342,7 +342,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
sctp_bh_lock_sock(sk);
if (sock_owned_by_user(sk)) {
- if (sk_add_backlog(sk, skb))
+ if (sk_add_backlog(sk, skb, sk->sk_rcvbuf))
sctp_chunk_free(chunk);
else
backloged = 1;
@@ -376,7 +376,7 @@ static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb)
struct sctp_ep_common *rcvr = chunk->rcvr;
int ret;
- ret = sk_add_backlog(sk, skb);
+ ret = sk_add_backlog(sk, skb, sk->sk_rcvbuf);
if (!ret) {
/* Hold the assoc/ep while hanging on the backlog queue.
* This way, we know structures we need will not disappear
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 817174eb5f41..69534c5f8afa 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -663,8 +663,8 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
*/
if (!sctp_sk(asoc->base.sk)->nodelay && sctp_packet_empty(packet) &&
inflight && sctp_state(asoc, ESTABLISHED)) {
- unsigned max = transport->pathmtu - packet->overhead;
- unsigned len = chunk->skb->len + q->out_qlen;
+ unsigned int max = transport->pathmtu - packet->overhead;
+ unsigned int len = chunk->skb->len + q->out_qlen;
/* Check whether this chunk and all the rest of pending
* data will fit or delay in hopes of bundling a full
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index cfeb1d4a1ee6..a0fa19f5650c 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -1147,7 +1147,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
__u32 sack_ctsn, ctsn, tsn;
__u32 highest_tsn, highest_new_tsn;
__u32 sack_a_rwnd;
- unsigned outstanding;
+ unsigned int outstanding;
struct sctp_transport *primary = asoc->peer.primary_path;
int count_of_newacks = 0;
int gap_ack_blocks;
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 1ff51c9d18d5..fbb374c65945 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -524,7 +524,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
/* Worker routine to handle INIT command failure. */
static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
struct sctp_association *asoc,
- unsigned error)
+ unsigned int error)
{
struct sctp_ulpevent *event;
@@ -550,7 +550,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
sctp_event_t event_type,
sctp_subtype_t subtype,
struct sctp_chunk *chunk,
- unsigned error)
+ unsigned int error)
{
struct sctp_ulpevent *event;
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 891f5db8cc31..a147b4d307d2 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -2410,7 +2410,7 @@ static sctp_disposition_t __sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
sctp_cmd_seq_t *commands)
{
struct sctp_chunk *chunk = arg;
- unsigned len;
+ unsigned int len;
__be16 error = SCTP_ERROR_NO_ERROR;
/* See if we have an error cause code in the chunk. */
@@ -2446,7 +2446,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
sctp_cmd_seq_t *commands)
{
struct sctp_chunk *chunk = arg;
- unsigned len;
+ unsigned int len;
__be16 error = SCTP_ERROR_NO_ERROR;
if (!sctp_vtag_verify_either(chunk, asoc))
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 60ffbd067ff7..e5fe639c89e7 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -275,22 +275,16 @@ static ctl_table sctp_table[] = {
{ /* sentinel */ }
};
-static struct ctl_path sctp_path[] = {
- { .procname = "net", },
- { .procname = "sctp", },
- { }
-};
-
static struct ctl_table_header * sctp_sysctl_header;
/* Sysctl registration. */
void sctp_sysctl_register(void)
{
- sctp_sysctl_header = register_sysctl_paths(sctp_path, sctp_table);
+ sctp_sysctl_header = register_net_sysctl(&init_net, "net/sctp", sctp_table);
}
/* Sysctl deregistration. */
void sctp_sysctl_unregister(void)
{
- unregister_sysctl_table(sctp_sysctl_header);
+ unregister_net_sysctl_table(sctp_sysctl_header);
}
diff --git a/net/socket.c b/net/socket.c
index 851edcd6b098..d3aaa4f67a3b 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1479,7 +1479,7 @@ SYSCALL_DEFINE2(listen, int, fd, int, backlog)
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (sock) {
somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn;
- if ((unsigned)backlog > somaxconn)
+ if ((unsigned int)backlog > somaxconn)
backlog = somaxconn;
err = security_socket_listen(sock, backlog);
@@ -1691,7 +1691,7 @@ SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
*/
SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
- unsigned, flags, struct sockaddr __user *, addr,
+ unsigned int, flags, struct sockaddr __user *, addr,
int, addr_len)
{
struct socket *sock;
@@ -1738,7 +1738,7 @@ out:
*/
SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len,
- unsigned, flags)
+ unsigned int, flags)
{
return sys_sendto(fd, buff, len, flags, NULL, 0);
}
@@ -1750,7 +1750,7 @@ SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len,
*/
SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
- unsigned, flags, struct sockaddr __user *, addr,
+ unsigned int, flags, struct sockaddr __user *, addr,
int __user *, addr_len)
{
struct socket *sock;
@@ -1795,7 +1795,7 @@ out:
*/
asmlinkage long sys_recv(int fd, void __user *ubuf, size_t size,
- unsigned flags)
+ unsigned int flags)
{
return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL);
}
@@ -1897,7 +1897,7 @@ struct used_address {
};
static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
- struct msghdr *msg_sys, unsigned flags,
+ struct msghdr *msg_sys, unsigned int flags,
struct used_address *used_address)
{
struct compat_msghdr __user *msg_compat =
@@ -1908,7 +1908,7 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
__attribute__ ((aligned(sizeof(__kernel_size_t))));
/* 20 is size of ipv6_pktinfo */
unsigned char *ctl_buf = ctl;
- int err, ctl_len, iov_size, total_len;
+ int err, ctl_len, total_len;
err = -EFAULT;
if (MSG_CMSG_COMPAT & flags) {
@@ -1917,16 +1917,13 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
} else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT;
- /* do not move before msg_sys is valid */
- err = -EMSGSIZE;
- if (msg_sys->msg_iovlen > UIO_MAXIOV)
- goto out;
-
- /* Check whether to allocate the iovec area */
- err = -ENOMEM;
- iov_size = msg_sys->msg_iovlen * sizeof(struct iovec);
if (msg_sys->msg_iovlen > UIO_FASTIOV) {
- iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
+ err = -EMSGSIZE;
+ if (msg_sys->msg_iovlen > UIO_MAXIOV)
+ goto out;
+ err = -ENOMEM;
+ iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec),
+ GFP_KERNEL);
if (!iov)
goto out;
}
@@ -2005,7 +2002,7 @@ out_freectl:
sock_kfree_s(sock->sk, ctl_buf, ctl_len);
out_freeiov:
if (iov != iovstack)
- sock_kfree_s(sock->sk, iov, iov_size);
+ kfree(iov);
out:
return err;
}
@@ -2014,7 +2011,7 @@ out:
* BSD sendmsg interface
*/
-SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
+SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
{
int fput_needed, err;
struct msghdr msg_sys;
@@ -2096,14 +2093,14 @@ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
}
static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
- struct msghdr *msg_sys, unsigned flags, int nosec)
+ struct msghdr *msg_sys, unsigned int flags, int nosec)
{
struct compat_msghdr __user *msg_compat =
(struct compat_msghdr __user *)msg;
struct iovec iovstack[UIO_FASTIOV];
struct iovec *iov = iovstack;
unsigned long cmsg_ptr;
- int err, iov_size, total_len, len;
+ int err, total_len, len;
/* kernel mode address */
struct sockaddr_storage addr;
@@ -2118,15 +2115,13 @@ static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
} else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT;
- err = -EMSGSIZE;
- if (msg_sys->msg_iovlen > UIO_MAXIOV)
- goto out;
-
- /* Check whether to allocate the iovec area */
- err = -ENOMEM;
- iov_size = msg_sys->msg_iovlen * sizeof(struct iovec);
if (msg_sys->msg_iovlen > UIO_FASTIOV) {
- iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
+ err = -EMSGSIZE;
+ if (msg_sys->msg_iovlen > UIO_MAXIOV)
+ goto out;
+ err = -ENOMEM;
+ iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec),
+ GFP_KERNEL);
if (!iov)
goto out;
}
@@ -2180,7 +2175,7 @@ static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
out_freeiov:
if (iov != iovstack)
- sock_kfree_s(sock->sk, iov, iov_size);
+ kfree(iov);
out:
return err;
}
@@ -2524,6 +2519,12 @@ EXPORT_SYMBOL(sock_unregister);
static int __init sock_init(void)
{
int err;
+ /*
+ * Initialize the network sysctl infrastructure.
+ */
+ err = net_sysctl_init();
+ if (err)
+ goto out;
/*
* Initialize sock SLAB cache.
@@ -3223,7 +3224,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
return -ENOIOCTLCMD;
}
-static long compat_sock_ioctl(struct file *file, unsigned cmd,
+static long compat_sock_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct socket *sock = file->private_data;
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 8eff8c32d1b9..d3611f11a8df 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -624,7 +624,7 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx,
ctx->seq_send = ctx->seq_send64;
if (ctx->seq_send64 != ctx->seq_send) {
dprintk("%s: seq_send64 %lx, seq_send %x overflow?\n", __func__,
- (long unsigned)ctx->seq_send64, ctx->seq_send);
+ (unsigned long)ctx->seq_send64, ctx->seq_send);
p = ERR_PTR(-EINVAL);
goto out_err;
}
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index de0b0f39d9d8..47ad2666fdf6 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -1273,7 +1273,7 @@ static void *c_start(struct seq_file *m, loff_t *pos)
__acquires(cd->hash_lock)
{
loff_t n = *pos;
- unsigned hash, entry;
+ unsigned int hash, entry;
struct cache_head *ch;
struct cache_detail *cd = ((struct handle*)m->private)->cd;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 824d32fb3121..f0132b2e875e 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1556,7 +1556,7 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
(char *)&val, sizeof(val));
if (type == SOCK_STREAM)
- sock->sk->sk_reuse = 1; /* allow address reuse */
+ sock->sk->sk_reuse = SK_CAN_REUSE; /* allow address reuse */
error = kernel_bind(sock, sin, len);
if (error < 0)
goto bummer;
diff --git a/net/sunrpc/timer.c b/net/sunrpc/timer.c
index dd824341c349..08881d0c9672 100644
--- a/net/sunrpc/timer.c
+++ b/net/sunrpc/timer.c
@@ -34,7 +34,7 @@
void rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
{
unsigned long init = 0;
- unsigned i;
+ unsigned int i;
rt->timeo = timeo;
@@ -57,7 +57,7 @@ EXPORT_SYMBOL_GPL(rpc_init_rtt);
* NB: When computing the smoothed RTT and standard deviation,
* be careful not to produce negative intermediate results.
*/
-void rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m)
+void rpc_update_rtt(struct rpc_rtt *rt, unsigned int timer, long m)
{
long *srtt, *sdrtt;
@@ -106,7 +106,7 @@ EXPORT_SYMBOL_GPL(rpc_update_rtt);
* read, write, commit - A+4D
* other - timeo
*/
-unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned timer)
+unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned int timer)
{
unsigned long res;
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index b97a3dd9a60a..fddcccfcdf76 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -1204,7 +1204,7 @@ xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len,
int (*actor)(struct scatterlist *, void *), void *data)
{
int i, ret = 0;
- unsigned page_len, thislen, page_offset;
+ unsigned int page_len, thislen, page_offset;
struct scatterlist sg[1];
sg_init_table(sg, 1);
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 0cbcd1ab49ab..6fe2dcead150 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -783,7 +783,7 @@ static void xprt_update_rtt(struct rpc_task *task)
{
struct rpc_rqst *req = task->tk_rqstp;
struct rpc_rtt *rtt = task->tk_client->cl_rtt;
- unsigned timer = task->tk_msg.rpc_proc->p_timer;
+ unsigned int timer = task->tk_msg.rpc_proc->p_timer;
long m = usecs_to_jiffies(ktime_to_us(req->rq_rtt));
if (timer) {
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index c3e65aebecc0..f3e813a8d107 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -59,19 +59,6 @@ static struct ctl_table_root net_sysctl_root = {
.permissions = net_ctl_permissions,
};
-static int net_ctl_ro_header_perms(struct ctl_table_root *root,
- struct nsproxy *namespaces, struct ctl_table *table)
-{
- if (net_eq(namespaces->net_ns, &init_net))
- return table->mode;
- else
- return table->mode & ~0222;
-}
-
-static struct ctl_table_root net_sysctl_ro_root = {
- .permissions = net_ctl_ro_header_perms,
-};
-
static int __net_init sysctl_net_init(struct net *net)
{
setup_sysctl_set(&net->sysctls, &net_sysctl_root, is_seen);
@@ -88,34 +75,32 @@ static struct pernet_operations sysctl_pernet_ops = {
.exit = sysctl_net_exit,
};
-static __init int net_sysctl_init(void)
+static struct ctl_table_header *net_header;
+__init int net_sysctl_init(void)
{
- int ret;
+ static struct ctl_table empty[1];
+ int ret = -ENOMEM;
+ /* Avoid limitations in the sysctl implementation by
+ * registering "/proc/sys/net" as an empty directory not in a
+ * network namespace.
+ */
+ net_header = register_sysctl("net", empty);
+ if (!net_header)
+ goto out;
ret = register_pernet_subsys(&sysctl_pernet_ops);
if (ret)
goto out;
- setup_sysctl_set(&net_sysctl_ro_root.default_set, &net_sysctl_ro_root, NULL);
- register_sysctl_root(&net_sysctl_ro_root);
register_sysctl_root(&net_sysctl_root);
out:
return ret;
}
-subsys_initcall(net_sysctl_init);
-
-struct ctl_table_header *register_net_sysctl_table(struct net *net,
- const struct ctl_path *path, struct ctl_table *table)
-{
- return __register_sysctl_paths(&net->sysctls, path, table);
-}
-EXPORT_SYMBOL_GPL(register_net_sysctl_table);
-struct ctl_table_header *register_net_sysctl_rotable(const
- struct ctl_path *path, struct ctl_table *table)
+struct ctl_table_header *register_net_sysctl(struct net *net,
+ const char *path, struct ctl_table *table)
{
- return __register_sysctl_paths(&net_sysctl_ro_root.default_set,
- path, table);
+ return __register_sysctl_table(&net->sysctls, path, table);
}
-EXPORT_SYMBOL_GPL(register_net_sysctl_rotable);
+EXPORT_SYMBOL_GPL(register_net_sysctl);
void unregister_net_sysctl_table(struct ctl_table_header *header)
{
diff --git a/net/tipc/addr.h b/net/tipc/addr.h
index e4f35afe3207..d706a1d92be8 100644
--- a/net/tipc/addr.h
+++ b/net/tipc/addr.h
@@ -50,12 +50,30 @@ static inline u32 tipc_cluster_mask(u32 addr)
return addr & TIPC_CLUSTER_MASK;
}
-static inline int in_own_cluster(u32 addr)
+static inline int in_own_cluster_exact(u32 addr)
{
return !((addr ^ tipc_own_addr) >> 12);
}
/**
+ * in_own_node - test for node inclusion; <0.0.0> always matches
+ */
+
+static inline int in_own_node(u32 addr)
+{
+ return (addr == tipc_own_addr) || !addr;
+}
+
+/**
+ * in_own_cluster - test for cluster inclusion; <0.0.0> always matches
+ */
+
+static inline int in_own_cluster(u32 addr)
+{
+ return in_own_cluster_exact(addr) || !addr;
+}
+
+/**
* addr_domain - convert 2-bit scope value to equivalent message lookup domain
*
* Needed when address of a named message must be looked up a second time
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 5dfd89c40429..0bfdeba91d51 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -449,7 +449,7 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
if (tipc_in_scope(disc_domain, tipc_own_addr)) {
disc_domain = tipc_own_addr & TIPC_CLUSTER_MASK;
res = 0; /* accept any node in own cluster */
- } else if (in_own_cluster(disc_domain))
+ } else if (in_own_cluster_exact(disc_domain))
res = 0; /* accept specified node in own cluster */
}
if (res) {
diff --git a/net/tipc/config.c b/net/tipc/config.c
index f76d3b15e4e2..f5458eddd7bc 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -290,7 +290,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
/* Check command authorization */
- if (likely(orig_node == tipc_own_addr)) {
+ if (likely(in_own_node(orig_node))) {
/* command is permitted */
} else if (cmd >= 0x8000) {
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
diff --git a/net/tipc/link.c b/net/tipc/link.c
index b4b9b30167a3..33cecd6fc37d 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -612,7 +612,7 @@ static void link_activate(struct tipc_link *l_ptr)
* @event: state machine event to process
*/
-static void link_state_event(struct tipc_link *l_ptr, unsigned event)
+static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
{
struct tipc_link *other;
u32 cont_intv = l_ptr->continuity_interval;
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index d57da6159616..211c1723a190 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -68,12 +68,37 @@ struct distr_item {
};
/**
- * List of externally visible publications by this node --
- * that is, all publications having scope > TIPC_NODE_SCOPE.
+ * struct publ_list - list of publications made by this node
+ * @list: circular list of publications
+ * @list_size: number of entries in list
*/
+struct publ_list {
+ struct list_head list;
+ u32 size;
+};
+
+static struct publ_list publ_zone = {
+ .list = LIST_HEAD_INIT(publ_zone.list),
+ .size = 0,
+};
+
+static struct publ_list publ_cluster = {
+ .list = LIST_HEAD_INIT(publ_cluster.list),
+ .size = 0,
+};
+
+static struct publ_list publ_node = {
+ .list = LIST_HEAD_INIT(publ_node.list),
+ .size = 0,
+};
+
+static struct publ_list *publ_lists[] = {
+ NULL,
+ &publ_zone, /* publ_lists[TIPC_ZONE_SCOPE] */
+ &publ_cluster, /* publ_lists[TIPC_CLUSTER_SCOPE] */
+ &publ_node /* publ_lists[TIPC_NODE_SCOPE] */
+};
-static LIST_HEAD(publ_root);
-static u32 publ_cnt;
/**
* publ_to_item - add publication info to a publication message
@@ -132,8 +157,11 @@ void tipc_named_publish(struct publication *publ)
struct sk_buff *buf;
struct distr_item *item;
- list_add_tail(&publ->local_list, &publ_root);
- publ_cnt++;
+ list_add_tail(&publ->local_list, &publ_lists[publ->scope]->list);
+ publ_lists[publ->scope]->size++;
+
+ if (publ->scope == TIPC_NODE_SCOPE)
+ return;
buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
if (!buf) {
@@ -156,7 +184,10 @@ void tipc_named_withdraw(struct publication *publ)
struct distr_item *item;
list_del(&publ->local_list);
- publ_cnt--;
+ publ_lists[publ->scope]->size--;
+
+ if (publ->scope == TIPC_NODE_SCOPE)
+ return;
buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0);
if (!buf) {
@@ -169,6 +200,39 @@ void tipc_named_withdraw(struct publication *publ)
named_cluster_distribute(buf);
}
+/*
+ * named_distribute - prepare name info for bulk distribution to another node
+ */
+static void named_distribute(struct list_head *message_list, u32 node,
+ struct publ_list *pls, u32 max_item_buf)
+{
+ struct publication *publ;
+ struct sk_buff *buf = NULL;
+ struct distr_item *item = NULL;
+ u32 left = 0;
+ u32 rest = pls->size * ITEM_SIZE;
+
+ list_for_each_entry(publ, &pls->list, local_list) {
+ if (!buf) {
+ left = (rest <= max_item_buf) ? rest : max_item_buf;
+ rest -= left;
+ buf = named_prepare_buf(PUBLICATION, left, node);
+ if (!buf) {
+ warn("Bulk publication failure\n");
+ return;
+ }
+ item = (struct distr_item *)msg_data(buf_msg(buf));
+ }
+ publ_to_item(item, publ);
+ item++;
+ left -= ITEM_SIZE;
+ if (!left) {
+ list_add_tail((struct list_head *)buf, message_list);
+ buf = NULL;
+ }
+ }
+}
+
/**
* tipc_named_node_up - tell specified node about all publications by this node
*/
@@ -177,13 +241,8 @@ void tipc_named_node_up(unsigned long nodearg)
{
struct tipc_node *n_ptr;
struct tipc_link *l_ptr;
- struct publication *publ;
- struct distr_item *item = NULL;
- struct sk_buff *buf = NULL;
struct list_head message_list;
u32 node = (u32)nodearg;
- u32 left = 0;
- u32 rest;
u32 max_item_buf = 0;
/* compute maximum amount of publication data to send per message */
@@ -207,28 +266,8 @@ void tipc_named_node_up(unsigned long nodearg)
INIT_LIST_HEAD(&message_list);
read_lock_bh(&tipc_nametbl_lock);
- rest = publ_cnt * ITEM_SIZE;
-
- list_for_each_entry(publ, &publ_root, local_list) {
- if (!buf) {
- left = (rest <= max_item_buf) ? rest : max_item_buf;
- rest -= left;
- buf = named_prepare_buf(PUBLICATION, left, node);
- if (!buf) {
- warn("Bulk publication distribution failure\n");
- goto exit;
- }
- item = (struct distr_item *)msg_data(buf_msg(buf));
- }
- publ_to_item(item, publ);
- item++;
- left -= ITEM_SIZE;
- if (!left) {
- list_add_tail((struct list_head *)buf, &message_list);
- buf = NULL;
- }
- }
-exit:
+ named_distribute(&message_list, node, &publ_cluster, max_item_buf);
+ named_distribute(&message_list, node, &publ_zone, max_item_buf);
read_unlock_bh(&tipc_nametbl_lock);
tipc_link_send_names(&message_list, (u32)node);
@@ -316,21 +355,23 @@ void tipc_named_recv(struct sk_buff *buf)
}
/**
- * tipc_named_reinit - re-initialize local publication list
+ * tipc_named_reinit - re-initialize local publications
*
* This routine is called whenever TIPC networking is enabled.
- * All existing publications by this node that have "cluster" or "zone" scope
- * are updated to reflect the node's new network address.
+ * All name table entries published by this node are updated to reflect
+ * the node's new network address.
*/
void tipc_named_reinit(void)
{
struct publication *publ;
+ int scope;
write_lock_bh(&tipc_nametbl_lock);
- list_for_each_entry(publ, &publ_root, local_list)
- publ->node = tipc_own_addr;
+ for (scope = TIPC_ZONE_SCOPE; scope <= TIPC_NODE_SCOPE; scope++)
+ list_for_each_entry(publ, &publ_lists[scope]->list, local_list)
+ publ->node = tipc_own_addr;
write_unlock_bh(&tipc_nametbl_lock);
}
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index c6a1ae36952e..25c2975d86ee 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -347,7 +347,7 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
info->cluster_list_size++;
}
- if (node == tipc_own_addr) {
+ if (in_own_node(node)) {
list_add(&publ->node_list, &info->node_list);
info->node_list_size++;
}
@@ -418,7 +418,7 @@ found:
/* Remove publication from node scope list, if present */
- if (node == tipc_own_addr) {
+ if (in_own_node(node)) {
list_del(&publ->node_list);
info->node_list_size--;
}
@@ -604,7 +604,7 @@ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
publ = list_first_entry(&info->node_list, struct publication,
node_list);
list_move_tail(&publ->node_list, &info->node_list);
- } else if (in_own_cluster(*destnode)) {
+ } else if (in_own_cluster_exact(*destnode)) {
if (list_empty(&info->cluster_list))
goto no_match;
publ = list_first_entry(&info->cluster_list, struct publication,
@@ -695,11 +695,12 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
}
write_lock_bh(&tipc_nametbl_lock);
- table.local_publ_count++;
publ = tipc_nametbl_insert_publ(type, lower, upper, scope,
tipc_own_addr, port_ref, key);
- if (publ && (scope != TIPC_NODE_SCOPE))
+ if (likely(publ)) {
+ table.local_publ_count++;
tipc_named_publish(publ);
+ }
write_unlock_bh(&tipc_nametbl_lock);
return publ;
}
@@ -716,8 +717,7 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
if (likely(publ)) {
table.local_publ_count--;
- if (publ->scope != TIPC_NODE_SCOPE)
- tipc_named_withdraw(publ);
+ tipc_named_withdraw(publ);
write_unlock_bh(&tipc_nametbl_lock);
list_del_init(&publ->pport_list);
kfree(publ);
diff --git a/net/tipc/net.c b/net/tipc/net.c
index d4531b07076c..5fab4ff24a94 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -178,11 +178,12 @@ int tipc_net_start(u32 addr)
tipc_subscr_stop();
tipc_cfg_stop();
+ write_lock_bh(&tipc_net_lock);
tipc_own_addr = addr;
tipc_named_reinit();
tipc_port_reinit();
-
tipc_bclink_init();
+ write_unlock_bh(&tipc_net_lock);
tipc_k_signal((Handler)tipc_subscr_start, 0);
tipc_k_signal((Handler)tipc_cfg_init, 0);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index a34cabc2c43a..6a71bea91db0 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -72,7 +72,7 @@ struct tipc_node *tipc_node_find(u32 addr)
struct tipc_node *node;
struct hlist_node *pos;
- if (unlikely(!in_own_cluster(addr)))
+ if (unlikely(!in_own_cluster_exact(addr)))
return NULL;
hlist_for_each_entry(node, pos, &node_htable[tipc_hashfn(addr)], hash) {
diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c
index c3c2815ae630..327ffbbfee00 100644
--- a/net/tipc/node_subscr.c
+++ b/net/tipc/node_subscr.c
@@ -45,7 +45,7 @@
void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr,
void *usr_handle, net_ev_handler handle_down)
{
- if (addr == tipc_own_addr) {
+ if (in_own_node(addr)) {
node_sub->node = NULL;
return;
}
diff --git a/net/tipc/port.c b/net/tipc/port.c
index 94d2904cce66..0f40b1055306 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -59,16 +59,38 @@ static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *, u32 err);
static void port_timeout(unsigned long ref);
-static u32 port_peernode(struct tipc_port *p_ptr)
+static inline u32 port_peernode(struct tipc_port *p_ptr)
{
return msg_destnode(&p_ptr->phdr);
}
-static u32 port_peerport(struct tipc_port *p_ptr)
+static inline u32 port_peerport(struct tipc_port *p_ptr)
{
return msg_destport(&p_ptr->phdr);
}
+/*
+ * tipc_port_peer_msg - verify message was sent by connected port's peer
+ *
+ * Handles cases where the node's network address has changed from
+ * the default of <0.0.0> to its configured setting.
+ */
+
+int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg)
+{
+ u32 peernode;
+ u32 orignode;
+
+ if (msg_origport(msg) != port_peerport(p_ptr))
+ return 0;
+
+ orignode = msg_orignode(msg);
+ peernode = port_peernode(p_ptr);
+ return (orignode == peernode) ||
+ (!orignode && (peernode == tipc_own_addr)) ||
+ (!peernode && (orignode == tipc_own_addr));
+}
+
/**
* tipc_multicast - send a multicast message to local and remote destinations
*/
@@ -221,18 +243,25 @@ struct tipc_port *tipc_createport_raw(void *usr_handle,
p_ptr->usr_handle = usr_handle;
p_ptr->max_pkt = MAX_PKT_DEFAULT;
p_ptr->ref = ref;
- msg = &p_ptr->phdr;
- tipc_msg_init(msg, importance, TIPC_NAMED_MSG, NAMED_H_SIZE, 0);
- msg_set_origport(msg, ref);
INIT_LIST_HEAD(&p_ptr->wait_list);
INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
p_ptr->dispatcher = dispatcher;
p_ptr->wakeup = wakeup;
p_ptr->user_port = NULL;
k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
- spin_lock_bh(&tipc_port_list_lock);
INIT_LIST_HEAD(&p_ptr->publications);
INIT_LIST_HEAD(&p_ptr->port_list);
+
+ /*
+ * Must hold port list lock while initializing message header template
+ * to ensure a change to node's own network address doesn't result
+ * in template containing out-dated network address information
+ */
+
+ spin_lock_bh(&tipc_port_list_lock);
+ msg = &p_ptr->phdr;
+ tipc_msg_init(msg, importance, TIPC_NAMED_MSG, NAMED_H_SIZE, 0);
+ msg_set_origport(msg, ref);
list_add_tail(&p_ptr->port_list, &ports);
spin_unlock_bh(&tipc_port_list_lock);
return p_ptr;
@@ -415,7 +444,7 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err)
/* send returned message & dispose of rejected message */
src_node = msg_prevnode(msg);
- if (src_node == tipc_own_addr)
+ if (in_own_node(src_node))
tipc_port_recv_msg(rbuf);
else
tipc_link_send(rbuf, src_node, msg_link_selector(rmsg));
@@ -519,25 +548,21 @@ void tipc_port_recv_proto_msg(struct sk_buff *buf)
struct tipc_msg *msg = buf_msg(buf);
struct tipc_port *p_ptr;
struct sk_buff *r_buf = NULL;
- u32 orignode = msg_orignode(msg);
- u32 origport = msg_origport(msg);
u32 destport = msg_destport(msg);
int wakeable;
/* Validate connection */
p_ptr = tipc_port_lock(destport);
- if (!p_ptr || !p_ptr->connected ||
- (port_peernode(p_ptr) != orignode) ||
- (port_peerport(p_ptr) != origport)) {
+ if (!p_ptr || !p_ptr->connected || !tipc_port_peer_msg(p_ptr, msg)) {
r_buf = tipc_buf_acquire(BASIC_H_SIZE);
if (r_buf) {
msg = buf_msg(r_buf);
tipc_msg_init(msg, TIPC_HIGH_IMPORTANCE, TIPC_CONN_MSG,
- BASIC_H_SIZE, orignode);
+ BASIC_H_SIZE, msg_orignode(msg));
msg_set_errcode(msg, TIPC_ERR_NO_PORT);
msg_set_origport(msg, destport);
- msg_set_destport(msg, origport);
+ msg_set_destport(msg, msg_origport(msg));
}
if (p_ptr)
tipc_port_unlock(p_ptr);
@@ -646,8 +671,6 @@ void tipc_port_reinit(void)
spin_lock_bh(&tipc_port_list_lock);
list_for_each_entry(p_ptr, &ports, port_list) {
msg = &p_ptr->phdr;
- if (msg_orignode(msg) == tipc_own_addr)
- break;
msg_set_prevnode(msg, tipc_own_addr);
msg_set_orignode(msg, tipc_own_addr);
}
@@ -676,6 +699,7 @@ static void port_dispatcher_sigh(void *dummy)
struct tipc_name_seq dseq;
void *usr_handle;
int connected;
+ int peer_invalid;
int published;
u32 message_type;
@@ -696,6 +720,7 @@ static void port_dispatcher_sigh(void *dummy)
up_ptr = p_ptr->user_port;
usr_handle = up_ptr->usr_handle;
connected = p_ptr->connected;
+ peer_invalid = connected && !tipc_port_peer_msg(p_ptr, msg);
published = p_ptr->published;
if (unlikely(msg_errcode(msg)))
@@ -705,8 +730,6 @@ static void port_dispatcher_sigh(void *dummy)
case TIPC_CONN_MSG:{
tipc_conn_msg_event cb = up_ptr->conn_msg_cb;
- u32 peer_port = port_peerport(p_ptr);
- u32 peer_node = port_peernode(p_ptr);
u32 dsz;
tipc_port_unlock(p_ptr);
@@ -715,8 +738,7 @@ static void port_dispatcher_sigh(void *dummy)
if (unlikely(!connected)) {
if (tipc_connect2port(dref, &orig))
goto reject;
- } else if ((msg_origport(msg) != peer_port) ||
- (msg_orignode(msg) != peer_node))
+ } else if (peer_invalid)
goto reject;
dsz = msg_data_sz(msg);
if (unlikely(dsz &&
@@ -768,14 +790,9 @@ err:
case TIPC_CONN_MSG:{
tipc_conn_shutdown_event cb =
up_ptr->conn_err_cb;
- u32 peer_port = port_peerport(p_ptr);
- u32 peer_node = port_peernode(p_ptr);
tipc_port_unlock(p_ptr);
- if (!cb || !connected)
- break;
- if ((msg_origport(msg) != peer_port) ||
- (msg_orignode(msg) != peer_node))
+ if (!cb || !connected || peer_invalid)
break;
tipc_disconnect(dref);
skb_pull(buf, msg_hdr_sz(msg));
@@ -1152,17 +1169,6 @@ int tipc_port_recv_msg(struct sk_buff *buf)
/* validate destination & pass to port, otherwise reject message */
p_ptr = tipc_port_lock(destport);
if (likely(p_ptr)) {
- if (likely(p_ptr->connected)) {
- if ((unlikely(msg_origport(msg) !=
- tipc_peer_port(p_ptr))) ||
- (unlikely(msg_orignode(msg) !=
- tipc_peer_node(p_ptr))) ||
- (unlikely(!msg_connected(msg)))) {
- err = TIPC_ERR_NO_PORT;
- tipc_port_unlock(p_ptr);
- goto reject;
- }
- }
err = p_ptr->dispatcher(p_ptr, buf);
tipc_port_unlock(p_ptr);
if (likely(!err))
@@ -1170,7 +1176,7 @@ int tipc_port_recv_msg(struct sk_buff *buf)
} else {
err = TIPC_ERR_NO_PORT;
}
-reject:
+
return tipc_reject_msg(buf, err);
}
@@ -1211,7 +1217,7 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect,
p_ptr->congested = 1;
if (!tipc_port_congested(p_ptr)) {
destnode = port_peernode(p_ptr);
- if (likely(destnode != tipc_own_addr))
+ if (likely(!in_own_node(destnode)))
res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect,
total_len, destnode);
else
@@ -1261,13 +1267,17 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,
msg_set_destport(msg, destport);
if (likely(destport || destnode)) {
- if (likely(destnode == tipc_own_addr))
+ if (likely(in_own_node(destnode)))
res = tipc_port_recv_sections(p_ptr, num_sect,
msg_sect, total_len);
- else
+ else if (tipc_own_addr)
res = tipc_link_send_sections_fast(p_ptr, msg_sect,
num_sect, total_len,
destnode);
+ else
+ res = tipc_port_reject_sections(p_ptr, msg, msg_sect,
+ num_sect, total_len,
+ TIPC_ERR_NO_NODE);
if (likely(res != -ELINKCONG)) {
if (res > 0)
p_ptr->sent++;
@@ -1305,12 +1315,15 @@ int tipc_send2port(u32 ref, struct tipc_portid const *dest,
msg_set_destport(msg, dest->ref);
msg_set_hdr_sz(msg, BASIC_H_SIZE);
- if (dest->node == tipc_own_addr)
+ if (in_own_node(dest->node))
res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect,
total_len);
- else
+ else if (tipc_own_addr)
res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect,
total_len, dest->node);
+ else
+ res = tipc_port_reject_sections(p_ptr, msg, msg_sect, num_sect,
+ total_len, TIPC_ERR_NO_NODE);
if (likely(res != -ELINKCONG)) {
if (res > 0)
p_ptr->sent++;
@@ -1349,7 +1362,7 @@ int tipc_send_buf2port(u32 ref, struct tipc_portid const *dest,
skb_push(buf, BASIC_H_SIZE);
skb_copy_to_linear_data(buf, msg, BASIC_H_SIZE);
- if (dest->node == tipc_own_addr)
+ if (in_own_node(dest->node))
res = tipc_port_recv_msg(buf);
else
res = tipc_send_buf_fast(buf, dest->node);
diff --git a/net/tipc/port.h b/net/tipc/port.h
index 9b88531e5a61..301e1bd840d1 100644
--- a/net/tipc/port.h
+++ b/net/tipc/port.h
@@ -201,6 +201,7 @@ int tipc_shutdown(u32 ref);
* The following routines require that the port be locked on entry
*/
int tipc_disconnect_port(struct tipc_port *tp_ptr);
+int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg);
/*
* TIPC messaging routines
@@ -257,16 +258,6 @@ static inline struct tipc_port *tipc_port_deref(u32 ref)
return (struct tipc_port *)tipc_ref_deref(ref);
}
-static inline u32 tipc_peer_port(struct tipc_port *p_ptr)
-{
- return msg_destport(&p_ptr->phdr);
-}
-
-static inline u32 tipc_peer_node(struct tipc_port *p_ptr)
-{
- return msg_destnode(&p_ptr->phdr);
-}
-
static inline int tipc_port_congested(struct tipc_port *p_ptr)
{
return (p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2);
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 29e957f64458..6d4991e8f670 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -535,7 +535,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
(dest->family != AF_TIPC)))
return -EINVAL;
if ((total_len > TIPC_MAX_USER_MSG_SIZE) ||
- (m->msg_iovlen > (unsigned)INT_MAX))
+ (m->msg_iovlen > (unsigned int)INT_MAX))
return -EMSGSIZE;
if (iocb)
@@ -647,7 +647,7 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,
return send_msg(iocb, sock, m, total_len);
if ((total_len > TIPC_MAX_USER_MSG_SIZE) ||
- (m->msg_iovlen > (unsigned)INT_MAX))
+ (m->msg_iovlen > (unsigned int)INT_MAX))
return -EMSGSIZE;
if (iocb)
@@ -734,8 +734,8 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
goto exit;
}
- if ((total_len > (unsigned)INT_MAX) ||
- (m->msg_iovlen > (unsigned)INT_MAX)) {
+ if ((total_len > (unsigned int)INT_MAX) ||
+ (m->msg_iovlen > (unsigned int)INT_MAX)) {
res = -EMSGSIZE;
goto exit;
}
@@ -1236,7 +1236,8 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)
if (msg_mcast(msg))
return TIPC_ERR_NO_PORT;
if (sock->state == SS_CONNECTED) {
- if (!msg_connected(msg))
+ if (!msg_connected(msg) ||
+ !tipc_port_peer_msg(tipc_sk_port(sk), msg))
return TIPC_ERR_NO_PORT;
} else if (sock->state == SS_CONNECTING) {
if (!msg_connected(msg) && (msg_errcode(msg) == 0))
@@ -1329,7 +1330,7 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
if (!sock_owned_by_user(sk)) {
res = filter_rcv(sk, buf);
} else {
- if (sk_add_backlog(sk, buf))
+ if (sk_add_backlog(sk, buf, sk->sk_rcvbuf))
res = TIPC_ERR_OVERLOAD;
else
res = TIPC_OK;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index d510353ef431..641f2e47f165 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -149,9 +149,10 @@ static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
* each socket state is protected by separate spin lock.
*/
-static inline unsigned unix_hash_fold(__wsum n)
+static inline unsigned int unix_hash_fold(__wsum n)
{
- unsigned hash = (__force unsigned)n;
+ unsigned int hash = (__force unsigned int)n;
+
hash ^= hash>>16;
hash ^= hash>>8;
return hash&(UNIX_HASH_SIZE-1);
@@ -200,7 +201,7 @@ static inline void unix_release_addr(struct unix_address *addr)
* - if started by zero, it is abstract name.
*/
-static int unix_mkname(struct sockaddr_un *sunaddr, int len, unsigned *hashp)
+static int unix_mkname(struct sockaddr_un *sunaddr, int len, unsigned int *hashp)
{
if (len <= sizeof(short) || len > sizeof(*sunaddr))
return -EINVAL;
@@ -250,7 +251,7 @@ static inline void unix_insert_socket(struct hlist_head *list, struct sock *sk)
static struct sock *__unix_find_socket_byname(struct net *net,
struct sockaddr_un *sunname,
- int len, int type, unsigned hash)
+ int len, int type, unsigned int hash)
{
struct sock *s;
struct hlist_node *node;
@@ -273,7 +274,7 @@ found:
static inline struct sock *unix_find_socket_byname(struct net *net,
struct sockaddr_un *sunname,
int len, int type,
- unsigned hash)
+ unsigned int hash)
{
struct sock *s;
@@ -760,7 +761,7 @@ out: mutex_unlock(&u->readlock);
static struct sock *unix_find_other(struct net *net,
struct sockaddr_un *sunname, int len,
- int type, unsigned hash, int *error)
+ int type, unsigned int hash, int *error)
{
struct sock *u;
struct path path;
@@ -824,7 +825,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct dentry *dentry = NULL;
struct path path;
int err;
- unsigned hash;
+ unsigned int hash;
struct unix_address *addr;
struct hlist_head *list;
@@ -964,7 +965,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
struct net *net = sock_net(sk);
struct sockaddr_un *sunaddr = (struct sockaddr_un *)addr;
struct sock *other;
- unsigned hash;
+ unsigned int hash;
int err;
if (addr->sa_family != AF_UNSPEC) {
@@ -1062,7 +1063,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
struct sock *newsk = NULL;
struct sock *other = NULL;
struct sk_buff *skb = NULL;
- unsigned hash;
+ unsigned int hash;
int st;
int err;
long timeo;
@@ -1437,11 +1438,12 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
struct sock *other = NULL;
int namelen = 0; /* fake GCC */
int err;
- unsigned hash;
+ unsigned int hash;
struct sk_buff *skb;
long timeo;
struct scm_cookie tmp_scm;
int max_level;
+ int data_len = 0;
if (NULL == siocb->scm)
siocb->scm = &tmp_scm;
@@ -1475,7 +1477,13 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
if (len > sk->sk_sndbuf - 32)
goto out;
- skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err);
+ if (len > SKB_MAX_ALLOC)
+ data_len = min_t(size_t,
+ len - SKB_MAX_ALLOC,
+ MAX_SKB_FRAGS * PAGE_SIZE);
+
+ skb = sock_alloc_send_pskb(sk, len - data_len, data_len,
+ msg->msg_flags & MSG_DONTWAIT, &err);
if (skb == NULL)
goto out;
@@ -1485,8 +1493,10 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
max_level = err + 1;
unix_get_secdata(siocb->scm, skb);
- skb_reset_transport_header(skb);
- err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+ skb_put(skb, len - data_len);
+ skb->data_len = data_len;
+ skb->len = len;
+ err = skb_copy_datagram_from_iovec(skb, 0, msg->msg_iov, 0, len);
if (err)
goto out_free;
diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c
index 397cffebb3b6..b34b5b9792f0 100644
--- a/net/unix/sysctl_net_unix.c
+++ b/net/unix/sysctl_net_unix.c
@@ -26,12 +26,6 @@ static ctl_table unix_table[] = {
{ }
};
-static struct ctl_path unix_path[] = {
- { .procname = "net", },
- { .procname = "unix", },
- { },
-};
-
int __net_init unix_sysctl_register(struct net *net)
{
struct ctl_table *table;
@@ -41,7 +35,7 @@ int __net_init unix_sysctl_register(struct net *net)
goto err_alloc;
table[0].data = &net->unx.sysctl_max_dgram_qlen;
- net->unx.ctl = register_net_sysctl_table(net, unix_path, table);
+ net->unx.ctl = register_net_sysctl(net, "net/unix", table);
if (net->unx.ctl == NULL)
goto err_reg;
@@ -58,6 +52,6 @@ void unix_sysctl_unregister(struct net *net)
struct ctl_table *table;
table = net->unx.ctl->ctl_table_arg;
- unregister_sysctl_table(net->unx.ctl);
+ unregister_net_sysctl_table(net->unx.ctl);
kfree(table);
}
diff --git a/net/wimax/stack.c b/net/wimax/stack.c
index 3c65eae701c4..a6470ac39498 100644
--- a/net/wimax/stack.c
+++ b/net/wimax/stack.c
@@ -187,7 +187,7 @@ out:
static
void __check_new_state(enum wimax_st old_state, enum wimax_st new_state,
- unsigned allowed_states_bm)
+ unsigned int allowed_states_bm)
{
if (WARN_ON(((1 << new_state) & allowed_states_bm) == 0)) {
printk(KERN_ERR "SW BUG! Forbidden state change %u -> %u\n",
@@ -425,7 +425,8 @@ static
size_t wimax_addr_scnprint(char *addr_str, size_t addr_str_size,
unsigned char *addr, size_t addr_len)
{
- unsigned cnt, total;
+ unsigned int cnt, total;
+
for (total = cnt = 0; cnt < addr_len; cnt++)
total += scnprintf(addr_str + total, addr_str_size - total,
"%02x%c", addr[cnt],
diff --git a/net/wireless/core.c b/net/wireless/core.c
index ccdfed897651..39f2538a46fc 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -422,10 +422,6 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
const struct ieee80211_iface_combination *c;
int i, j;
- /* If we have combinations enforce them */
- if (wiphy->n_iface_combinations)
- wiphy->flags |= WIPHY_FLAG_ENFORCE_COMBINATIONS;
-
for (i = 0; i < wiphy->n_iface_combinations; i++) {
u32 cnt = 0;
u16 all_iftypes = 0;
@@ -708,6 +704,10 @@ void wiphy_unregister(struct wiphy *wiphy)
flush_work(&rdev->scan_done_wk);
cancel_work_sync(&rdev->conn_work);
flush_work(&rdev->event_work);
+
+ if (rdev->wowlan && rdev->ops->set_wakeup)
+ rdev->ops->set_wakeup(&rdev->wiphy, false);
+ cfg80211_rdev_free_wowlan(rdev);
}
EXPORT_SYMBOL(wiphy_unregister);
@@ -720,7 +720,6 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
mutex_destroy(&rdev->sched_scan_mtx);
list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
cfg80211_put_bss(&scan->pub);
- cfg80211_rdev_free_wowlan(rdev);
kfree(rdev);
}
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index ba21ab22187b..8c747fa9319b 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -38,6 +38,7 @@
#define MESH_MAX_PREQ_RETRIES 4
+#define MESH_SYNC_NEIGHBOR_OFFSET_MAX 50
const struct mesh_config default_mesh_config = {
.dot11MeshRetryTimeout = MESH_RET_T,
@@ -48,6 +49,7 @@ const struct mesh_config default_mesh_config = {
.element_ttl = MESH_DEFAULT_ELEMENT_TTL,
.auto_open_plinks = true,
.dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS,
+ .dot11MeshNbrOffsetMaxNeighbor = MESH_SYNC_NEIGHBOR_OFFSET_MAX,
.dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT,
.dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT,
.dot11MeshHWMPperrMinInterval = MESH_PERR_MIN_INT,
@@ -62,6 +64,7 @@ const struct mesh_config default_mesh_config = {
};
const struct mesh_setup default_mesh_setup = {
+ .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
.path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
.path_metric = IEEE80211_PATH_METRIC_AIRTIME,
.ie = NULL,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index f5a7ac3a0939..6801d96bc224 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -6,6 +6,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/nl80211.h>
#include <linux/slab.h>
@@ -100,7 +101,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
ASSERT_WDEV_LOCK(wdev);
if (wdev->current_bss &&
- memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
+ compare_ether_addr(wdev->current_bss->pub.bssid, bssid) == 0) {
cfg80211_unhold_bss(wdev->current_bss);
cfg80211_put_bss(&wdev->current_bss->pub);
wdev->current_bss = NULL;
@@ -115,7 +116,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
- from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
+ from_ap = compare_ether_addr(mgmt->sa, dev->dev_addr) != 0;
__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
} else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
@@ -154,7 +155,7 @@ void __cfg80211_send_disassoc(struct net_device *dev,
return;
if (wdev->current_bss &&
- memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
+ compare_ether_addr(wdev->current_bss->pub.bssid, bssid) == 0) {
cfg80211_sme_disassoc(dev, wdev->current_bss);
cfg80211_unhold_bss(wdev->current_bss);
cfg80211_put_bss(&wdev->current_bss->pub);
@@ -165,7 +166,7 @@ void __cfg80211_send_disassoc(struct net_device *dev,
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
- from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
+ from_ap = compare_ether_addr(mgmt->sa, dev->dev_addr) != 0;
__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
}
EXPORT_SYMBOL(__cfg80211_send_disassoc);
@@ -285,7 +286,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
return -EINVAL;
if (wdev->current_bss &&
- memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
+ compare_ether_addr(bssid, wdev->current_bss->pub.bssid) == 0)
return -EALREADY;
memset(&req, 0, sizeof(req));
@@ -362,7 +363,7 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
memset(&req, 0, sizeof(req));
if (wdev->current_bss && prev_bssid &&
- memcmp(wdev->current_bss->pub.bssid, prev_bssid, ETH_ALEN) == 0) {
+ compare_ether_addr(wdev->current_bss->pub.bssid, prev_bssid) == 0) {
/*
* Trying to reassociate: Allow this to proceed and let the old
* association to be dropped when the new one is completed.
@@ -446,7 +447,8 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
if (local_state_change) {
if (wdev->current_bss &&
- memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
+ compare_ether_addr(wdev->current_bss->pub.bssid, bssid)
+ == 0) {
cfg80211_unhold_bss(wdev->current_bss);
cfg80211_put_bss(&wdev->current_bss->pub);
wdev->current_bss = NULL;
@@ -495,7 +497,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
req.local_state_change = local_state_change;
req.ie = ie;
req.ie_len = ie_len;
- if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
+ if (compare_ether_addr(wdev->current_bss->pub.bssid, bssid) == 0)
req.bss = &wdev->current_bss->pub;
else
return -ENOTCONN;
@@ -758,8 +760,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
break;
}
- if (memcmp(wdev->current_bss->pub.bssid,
- mgmt->bssid, ETH_ALEN)) {
+ if (compare_ether_addr(wdev->current_bss->pub.bssid,
+ mgmt->bssid)) {
err = -ENOTCONN;
break;
}
@@ -772,8 +774,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
break;
/* for station, check that DA is the AP */
- if (memcmp(wdev->current_bss->pub.bssid,
- mgmt->da, ETH_ALEN)) {
+ if (compare_ether_addr(wdev->current_bss->pub.bssid,
+ mgmt->da)) {
err = -ENOTCONN;
break;
}
@@ -781,11 +783,11 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_AP_VLAN:
- if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN))
+ if (compare_ether_addr(mgmt->bssid, dev->dev_addr))
err = -EINVAL;
break;
case NL80211_IFTYPE_MESH_POINT:
- if (memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN)) {
+ if (compare_ether_addr(mgmt->sa, mgmt->bssid)) {
err = -EINVAL;
break;
}
@@ -804,7 +806,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
return err;
}
- if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
+ if (compare_ether_addr(mgmt->sa, dev->dev_addr) != 0)
return -EINVAL;
/* Transmit the Action frame as requested by user space */
@@ -928,6 +930,33 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
}
EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
+void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
+ enum nl80211_channel_type type)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ struct ieee80211_channel *chan;
+
+ wdev_lock(wdev);
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+ wdev->iftype != NL80211_IFTYPE_P2P_GO))
+ goto out;
+
+ chan = rdev_freq_to_chan(rdev, freq, type);
+ if (WARN_ON(!chan))
+ goto out;
+
+ wdev->channel = chan;
+
+ nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
+out:
+ wdev_unlock(wdev);
+ return;
+}
+EXPORT_SYMBOL(cfg80211_ch_switch_notify);
+
bool cfg80211_rx_spurious_frame(struct net_device *dev,
const u8 *addr, gfp_t gfp)
{
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f432c57af05d..83d71d6b63a4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -356,20 +356,26 @@ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
static int nl80211_msg_put_channel(struct sk_buff *msg,
struct ieee80211_channel *chan)
{
- NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ,
- chan->center_freq);
+ if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
+ chan->center_freq))
+ goto nla_put_failure;
- if (chan->flags & IEEE80211_CHAN_DISABLED)
- NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED);
- if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
- NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN);
- if (chan->flags & IEEE80211_CHAN_NO_IBSS)
- NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS);
- if (chan->flags & IEEE80211_CHAN_RADAR)
- NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
+ if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
+ goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN))
+ goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
+ goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_RADAR) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
+ goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
- DBM_TO_MBM(chan->max_power));
+ if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+ DBM_TO_MBM(chan->max_power)))
+ goto nla_put_failure;
return 0;
@@ -621,8 +627,8 @@ static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
i = 0;
while (ifmodes) {
- if (ifmodes & 1)
- NLA_PUT_FLAG(msg, i);
+ if ((ifmodes & 1) && nla_put_flag(msg, i))
+ goto nla_put_failure;
ifmodes >>= 1;
i++;
}
@@ -665,8 +671,9 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
nl_limit = nla_nest_start(msg, j + 1);
if (!nl_limit)
goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_IFACE_LIMIT_MAX,
- c->limits[j].max);
+ if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX,
+ c->limits[j].max))
+ goto nla_put_failure;
if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
c->limits[j].types))
goto nla_put_failure;
@@ -675,13 +682,14 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
nla_nest_end(msg, nl_limits);
- if (c->beacon_int_infra_match)
- NLA_PUT_FLAG(msg,
- NL80211_IFACE_COMB_STA_AP_BI_MATCH);
- NLA_PUT_U32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
- c->num_different_channels);
- NLA_PUT_U32(msg, NL80211_IFACE_COMB_MAXNUM,
- c->max_interfaces);
+ if (c->beacon_int_infra_match &&
+ nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
+ goto nla_put_failure;
+ if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
+ c->num_different_channels) ||
+ nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
+ c->max_interfaces))
+ goto nla_put_failure;
nla_nest_end(msg, nl_combi);
}
@@ -712,64 +720,74 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
if (!hdr)
return -1;
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx);
- NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
-
- NLA_PUT_U32(msg, NL80211_ATTR_GENERATION,
- cfg80211_rdev_list_generation);
-
- NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
- dev->wiphy.retry_short);
- NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
- dev->wiphy.retry_long);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
- dev->wiphy.frag_threshold);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
- dev->wiphy.rts_threshold);
- NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
- dev->wiphy.coverage_class);
- NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
- dev->wiphy.max_scan_ssids);
- NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
- dev->wiphy.max_sched_scan_ssids);
- NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
- dev->wiphy.max_scan_ie_len);
- NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
- dev->wiphy.max_sched_scan_ie_len);
- NLA_PUT_U8(msg, NL80211_ATTR_MAX_MATCH_SETS,
- dev->wiphy.max_match_sets);
-
- if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)
- NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN);
- if (dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH)
- NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH);
- if (dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD)
- NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_AP_UAPSD);
- if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)
- NLA_PUT_FLAG(msg, NL80211_ATTR_ROAM_SUPPORT);
- if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS)
- NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_SUPPORT);
- if (dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)
- NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP);
-
- NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES,
- sizeof(u32) * dev->wiphy.n_cipher_suites,
- dev->wiphy.cipher_suites);
-
- NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
- dev->wiphy.max_num_pmkids);
-
- if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL)
- NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE);
-
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
- dev->wiphy.available_antennas_tx);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
- dev->wiphy.available_antennas_rx);
-
- if (dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD)
- NLA_PUT_U32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
- dev->wiphy.probe_resp_offload);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) ||
+ nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)) ||
+ nla_put_u32(msg, NL80211_ATTR_GENERATION,
+ cfg80211_rdev_list_generation) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
+ dev->wiphy.retry_short) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
+ dev->wiphy.retry_long) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ dev->wiphy.frag_threshold) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
+ dev->wiphy.rts_threshold) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
+ dev->wiphy.coverage_class) ||
+ nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+ dev->wiphy.max_scan_ssids) ||
+ nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+ dev->wiphy.max_sched_scan_ssids) ||
+ nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
+ dev->wiphy.max_scan_ie_len) ||
+ nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
+ dev->wiphy.max_sched_scan_ie_len) ||
+ nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
+ dev->wiphy.max_match_sets))
+ goto nla_put_failure;
+
+ if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
+ nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
+ goto nla_put_failure;
+ if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
+ nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
+ goto nla_put_failure;
+ if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
+ nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
+ goto nla_put_failure;
+ if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
+ nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
+ goto nla_put_failure;
+ if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
+ nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
+ goto nla_put_failure;
+ if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
+ nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
+ goto nla_put_failure;
+
+ if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
+ sizeof(u32) * dev->wiphy.n_cipher_suites,
+ dev->wiphy.cipher_suites))
+ goto nla_put_failure;
+
+ if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
+ dev->wiphy.max_num_pmkids))
+ goto nla_put_failure;
+
+ if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
+ goto nla_put_failure;
+
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
+ dev->wiphy.available_antennas_tx) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
+ dev->wiphy.available_antennas_rx))
+ goto nla_put_failure;
+
+ if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
+ nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
+ dev->wiphy.probe_resp_offload))
+ goto nla_put_failure;
if ((dev->wiphy.available_antennas_tx ||
dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
@@ -777,8 +795,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
int res;
res = dev->ops->get_antenna(&dev->wiphy, &tx_ant, &rx_ant);
if (!res) {
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX,
+ tx_ant) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX,
+ rx_ant))
+ goto nla_put_failure;
}
}
@@ -799,17 +820,17 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
goto nla_put_failure;
/* add HT info */
- if (dev->wiphy.bands[band]->ht_cap.ht_supported) {
- NLA_PUT(msg, NL80211_BAND_ATTR_HT_MCS_SET,
- sizeof(dev->wiphy.bands[band]->ht_cap.mcs),
- &dev->wiphy.bands[band]->ht_cap.mcs);
- NLA_PUT_U16(msg, NL80211_BAND_ATTR_HT_CAPA,
- dev->wiphy.bands[band]->ht_cap.cap);
- NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
- dev->wiphy.bands[band]->ht_cap.ampdu_factor);
- NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
- dev->wiphy.bands[band]->ht_cap.ampdu_density);
- }
+ if (dev->wiphy.bands[band]->ht_cap.ht_supported &&
+ (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
+ sizeof(dev->wiphy.bands[band]->ht_cap.mcs),
+ &dev->wiphy.bands[band]->ht_cap.mcs) ||
+ nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
+ dev->wiphy.bands[band]->ht_cap.cap) ||
+ nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
+ dev->wiphy.bands[band]->ht_cap.ampdu_factor) ||
+ nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+ dev->wiphy.bands[band]->ht_cap.ampdu_density)))
+ goto nla_put_failure;
/* add frequencies */
nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
@@ -842,11 +863,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
goto nla_put_failure;
rate = &dev->wiphy.bands[band]->bitrates[i];
- NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE,
- rate->bitrate);
- if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
- NLA_PUT_FLAG(msg,
- NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE);
+ if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
+ rate->bitrate))
+ goto nla_put_failure;
+ if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
+ nla_put_flag(msg,
+ NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
+ goto nla_put_failure;
nla_nest_end(msg, nl_rate);
}
@@ -866,7 +889,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
do { \
if (dev->ops->op) { \
i++; \
- NLA_PUT_U32(msg, i, NL80211_CMD_ ## n); \
+ if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
+ goto nla_put_failure; \
} \
} while (0)
@@ -894,7 +918,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
i++;
- NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
+ if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
+ goto nla_put_failure;
}
CMD(set_channel, SET_CHANNEL);
CMD(set_wds_peer, SET_WDS_PEER);
@@ -908,7 +933,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
CMD(set_noack_map, SET_NOACK_MAP);
if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
i++;
- NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
+ if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
+ goto nla_put_failure;
}
#ifdef CONFIG_NL80211_TESTMODE
@@ -919,23 +945,27 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
if (dev->ops->connect || dev->ops->auth) {
i++;
- NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT);
+ if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
+ goto nla_put_failure;
}
if (dev->ops->disconnect || dev->ops->deauth) {
i++;
- NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT);
+ if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
+ goto nla_put_failure;
}
nla_nest_end(msg, nl_cmds);
if (dev->ops->remain_on_channel &&
- dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
- NLA_PUT_U32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
- dev->wiphy.max_remain_on_channel_duration);
+ (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
+ nla_put_u32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
+ dev->wiphy.max_remain_on_channel_duration))
+ goto nla_put_failure;
- if (dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)
- NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
+ if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
+ nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
+ goto nla_put_failure;
if (mgmt_stypes) {
u16 stypes;
@@ -953,9 +983,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
i = 0;
stypes = mgmt_stypes[ift].tx;
while (stypes) {
- if (stypes & 1)
- NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE,
- (i << 4) | IEEE80211_FTYPE_MGMT);
+ if ((stypes & 1) &&
+ nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
+ (i << 4) | IEEE80211_FTYPE_MGMT))
+ goto nla_put_failure;
stypes >>= 1;
i++;
}
@@ -975,9 +1006,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
i = 0;
stypes = mgmt_stypes[ift].rx;
while (stypes) {
- if (stypes & 1)
- NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE,
- (i << 4) | IEEE80211_FTYPE_MGMT);
+ if ((stypes & 1) &&
+ nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
+ (i << 4) | IEEE80211_FTYPE_MGMT))
+ goto nla_put_failure;
stypes >>= 1;
i++;
}
@@ -994,22 +1026,23 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
if (!nl_wowlan)
goto nla_put_failure;
- if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY);
- if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT);
- if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT);
- if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED);
- if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE);
- if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST);
- if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE);
- if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE);
+ if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
+ goto nla_put_failure;
if (dev->wiphy.wowlan.n_patterns) {
struct nl80211_wowlan_pattern_support pat = {
.max_patterns = dev->wiphy.wowlan.n_patterns,
@@ -1018,8 +1051,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
.max_pattern_len =
dev->wiphy.wowlan.pattern_max_len,
};
- NLA_PUT(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
- sizeof(pat), &pat);
+ if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
+ sizeof(pat), &pat))
+ goto nla_put_failure;
}
nla_nest_end(msg, nl_wowlan);
@@ -1032,16 +1066,20 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
if (nl80211_put_iface_combinations(&dev->wiphy, msg))
goto nla_put_failure;
- if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME)
- NLA_PUT_U32(msg, NL80211_ATTR_DEVICE_AP_SME,
- dev->wiphy.ap_sme_capa);
+ if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
+ nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
+ dev->wiphy.ap_sme_capa))
+ goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features);
+ if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS,
+ dev->wiphy.features))
+ goto nla_put_failure;
- if (dev->wiphy.ht_capa_mod_mask)
- NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
- sizeof(*dev->wiphy.ht_capa_mod_mask),
- dev->wiphy.ht_capa_mod_mask);
+ if (dev->wiphy.ht_capa_mod_mask &&
+ nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
+ sizeof(*dev->wiphy.ht_capa_mod_mask),
+ dev->wiphy.ht_capa_mod_mask))
+ goto nla_put_failure;
return genlmsg_end(msg, hdr);
@@ -1104,17 +1142,20 @@ static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
static int parse_txq_params(struct nlattr *tb[],
struct ieee80211_txq_params *txq_params)
{
- if (!tb[NL80211_TXQ_ATTR_QUEUE] || !tb[NL80211_TXQ_ATTR_TXOP] ||
+ if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
!tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
!tb[NL80211_TXQ_ATTR_AIFS])
return -EINVAL;
- txq_params->queue = nla_get_u8(tb[NL80211_TXQ_ATTR_QUEUE]);
+ txq_params->ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
+ if (txq_params->ac >= NL80211_NUM_ACS)
+ return -EINVAL;
+
return 0;
}
@@ -1489,14 +1530,28 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
if (!hdr)
return -1;
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
- NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype);
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) ||
+ nla_put_u32(msg, NL80211_ATTR_IFTYPE,
+ dev->ieee80211_ptr->iftype) ||
+ nla_put_u32(msg, NL80211_ATTR_GENERATION,
+ rdev->devlist_generation ^
+ (cfg80211_rdev_list_generation << 2)))
+ goto nla_put_failure;
+
+ if (rdev->ops->get_channel) {
+ struct ieee80211_channel *chan;
+ enum nl80211_channel_type channel_type;
- NLA_PUT_U32(msg, NL80211_ATTR_GENERATION,
- rdev->devlist_generation ^
- (cfg80211_rdev_list_generation << 2));
+ chan = rdev->ops->get_channel(&rdev->wiphy, &channel_type);
+ if (chan &&
+ (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+ chan->center_freq) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ channel_type)))
+ goto nla_put_failure;
+ }
return genlmsg_end(msg, hdr);
@@ -1794,35 +1849,34 @@ static void get_key_callback(void *c, struct key_params *params)
struct nlattr *key;
struct get_key_cookie *cookie = c;
- if (params->key)
- NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
- params->key_len, params->key);
-
- if (params->seq)
- NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
- params->seq_len, params->seq);
-
- if (params->cipher)
- NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
- params->cipher);
+ if ((params->key &&
+ nla_put(cookie->msg, NL80211_ATTR_KEY_DATA,
+ params->key_len, params->key)) ||
+ (params->seq &&
+ nla_put(cookie->msg, NL80211_ATTR_KEY_SEQ,
+ params->seq_len, params->seq)) ||
+ (params->cipher &&
+ nla_put_u32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
+ params->cipher)))
+ goto nla_put_failure;
key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY);
if (!key)
goto nla_put_failure;
- if (params->key)
- NLA_PUT(cookie->msg, NL80211_KEY_DATA,
- params->key_len, params->key);
-
- if (params->seq)
- NLA_PUT(cookie->msg, NL80211_KEY_SEQ,
- params->seq_len, params->seq);
-
- if (params->cipher)
- NLA_PUT_U32(cookie->msg, NL80211_KEY_CIPHER,
- params->cipher);
+ if ((params->key &&
+ nla_put(cookie->msg, NL80211_KEY_DATA,
+ params->key_len, params->key)) ||
+ (params->seq &&
+ nla_put(cookie->msg, NL80211_KEY_SEQ,
+ params->seq_len, params->seq)) ||
+ (params->cipher &&
+ nla_put_u32(cookie->msg, NL80211_KEY_CIPHER,
+ params->cipher)))
+ goto nla_put_failure;
- NLA_PUT_U8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx);
+ if (nla_put_u8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx))
+ goto nla_put_failure;
nla_nest_end(cookie->msg, key);
@@ -1880,10 +1934,12 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
cookie.msg = msg;
cookie.idx = key_idx;
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
- NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
- if (mac_addr)
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+ nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
+ goto nla_put_failure;
+ if (mac_addr &&
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
+ goto nla_put_failure;
if (pairwise && mac_addr &&
!(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
@@ -2373,15 +2429,15 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
/* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
bitrate = cfg80211_calculate_bitrate(info);
- if (bitrate > 0)
- NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
-
- if (info->flags & RATE_INFO_FLAGS_MCS)
- NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, info->mcs);
- if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
- NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
- if (info->flags & RATE_INFO_FLAGS_SHORT_GI)
- NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
+ if ((bitrate > 0 &&
+ nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate)) ||
+ ((info->flags & RATE_INFO_FLAGS_MCS) &&
+ nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) ||
+ ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) &&
+ nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) ||
+ ((info->flags & RATE_INFO_FLAGS_SHORT_GI) &&
+ nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)))
+ goto nla_put_failure;
nla_nest_end(msg, rate);
return true;
@@ -2403,43 +2459,50 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
if (!hdr)
return -1;
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
-
- NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, sinfo->generation);
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
+ nla_put_u32(msg, NL80211_ATTR_GENERATION, sinfo->generation))
+ goto nla_put_failure;
sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
if (!sinfoattr)
goto nla_put_failure;
- if (sinfo->filled & STATION_INFO_CONNECTED_TIME)
- NLA_PUT_U32(msg, NL80211_STA_INFO_CONNECTED_TIME,
- sinfo->connected_time);
- if (sinfo->filled & STATION_INFO_INACTIVE_TIME)
- NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME,
- sinfo->inactive_time);
- if (sinfo->filled & STATION_INFO_RX_BYTES)
- NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES,
- sinfo->rx_bytes);
- if (sinfo->filled & STATION_INFO_TX_BYTES)
- NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES,
- sinfo->tx_bytes);
- if (sinfo->filled & STATION_INFO_LLID)
- NLA_PUT_U16(msg, NL80211_STA_INFO_LLID,
- sinfo->llid);
- if (sinfo->filled & STATION_INFO_PLID)
- NLA_PUT_U16(msg, NL80211_STA_INFO_PLID,
- sinfo->plid);
- if (sinfo->filled & STATION_INFO_PLINK_STATE)
- NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE,
- sinfo->plink_state);
+ if ((sinfo->filled & STATION_INFO_CONNECTED_TIME) &&
+ nla_put_u32(msg, NL80211_STA_INFO_CONNECTED_TIME,
+ sinfo->connected_time))
+ goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_INACTIVE_TIME) &&
+ nla_put_u32(msg, NL80211_STA_INFO_INACTIVE_TIME,
+ sinfo->inactive_time))
+ goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_RX_BYTES) &&
+ nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
+ sinfo->rx_bytes))
+ goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_TX_BYTES) &&
+ nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
+ sinfo->tx_bytes))
+ goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_LLID) &&
+ nla_put_u16(msg, NL80211_STA_INFO_LLID, sinfo->llid))
+ goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_PLID) &&
+ nla_put_u16(msg, NL80211_STA_INFO_PLID, sinfo->plid))
+ goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_PLINK_STATE) &&
+ nla_put_u8(msg, NL80211_STA_INFO_PLINK_STATE,
+ sinfo->plink_state))
+ goto nla_put_failure;
switch (rdev->wiphy.signal_type) {
case CFG80211_SIGNAL_TYPE_MBM:
- if (sinfo->filled & STATION_INFO_SIGNAL)
- NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL,
- sinfo->signal);
- if (sinfo->filled & STATION_INFO_SIGNAL_AVG)
- NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL_AVG,
- sinfo->signal_avg);
+ if ((sinfo->filled & STATION_INFO_SIGNAL) &&
+ nla_put_u8(msg, NL80211_STA_INFO_SIGNAL,
+ sinfo->signal))
+ goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_SIGNAL_AVG) &&
+ nla_put_u8(msg, NL80211_STA_INFO_SIGNAL_AVG,
+ sinfo->signal_avg))
+ goto nla_put_failure;
break;
default:
break;
@@ -2454,49 +2517,60 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
NL80211_STA_INFO_RX_BITRATE))
goto nla_put_failure;
}
- if (sinfo->filled & STATION_INFO_RX_PACKETS)
- NLA_PUT_U32(msg, NL80211_STA_INFO_RX_PACKETS,
- sinfo->rx_packets);
- if (sinfo->filled & STATION_INFO_TX_PACKETS)
- NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS,
- sinfo->tx_packets);
- if (sinfo->filled & STATION_INFO_TX_RETRIES)
- NLA_PUT_U32(msg, NL80211_STA_INFO_TX_RETRIES,
- sinfo->tx_retries);
- if (sinfo->filled & STATION_INFO_TX_FAILED)
- NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED,
- sinfo->tx_failed);
- if (sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT)
- NLA_PUT_U32(msg, NL80211_STA_INFO_BEACON_LOSS,
- sinfo->beacon_loss_count);
+ if ((sinfo->filled & STATION_INFO_RX_PACKETS) &&
+ nla_put_u32(msg, NL80211_STA_INFO_RX_PACKETS,
+ sinfo->rx_packets))
+ goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_TX_PACKETS) &&
+ nla_put_u32(msg, NL80211_STA_INFO_TX_PACKETS,
+ sinfo->tx_packets))
+ goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_TX_RETRIES) &&
+ nla_put_u32(msg, NL80211_STA_INFO_TX_RETRIES,
+ sinfo->tx_retries))
+ goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_TX_FAILED) &&
+ nla_put_u32(msg, NL80211_STA_INFO_TX_FAILED,
+ sinfo->tx_failed))
+ goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) &&
+ nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS,
+ sinfo->beacon_loss_count))
+ goto nla_put_failure;
if (sinfo->filled & STATION_INFO_BSS_PARAM) {
bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
if (!bss_param)
goto nla_put_failure;
- if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT)
- NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_CTS_PROT);
- if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE)
- NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE);
- if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME)
- NLA_PUT_FLAG(msg,
- NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME);
- NLA_PUT_U8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
- sinfo->bss_param.dtim_period);
- NLA_PUT_U16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
- sinfo->bss_param.beacon_interval);
+ if (((sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) &&
+ nla_put_flag(msg, NL80211_STA_BSS_PARAM_CTS_PROT)) ||
+ ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) &&
+ nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE)) ||
+ ((sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) &&
+ nla_put_flag(msg, NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME)) ||
+ nla_put_u8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
+ sinfo->bss_param.dtim_period) ||
+ nla_put_u16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
+ sinfo->bss_param.beacon_interval))
+ goto nla_put_failure;
nla_nest_end(msg, bss_param);
}
- if (sinfo->filled & STATION_INFO_STA_FLAGS)
- NLA_PUT(msg, NL80211_STA_INFO_STA_FLAGS,
- sizeof(struct nl80211_sta_flag_update),
- &sinfo->sta_flags);
+ if ((sinfo->filled & STATION_INFO_STA_FLAGS) &&
+ nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
+ sizeof(struct nl80211_sta_flag_update),
+ &sinfo->sta_flags))
+ goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_T_OFFSET) &&
+ nla_put_u64(msg, NL80211_STA_INFO_T_OFFSET,
+ sinfo->t_offset))
+ goto nla_put_failure;
nla_nest_end(msg, sinfoattr);
- if (sinfo->filled & STATION_INFO_ASSOC_REQ_IES)
- NLA_PUT(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
- sinfo->assoc_req_ies);
+ if ((sinfo->filled & STATION_INFO_ASSOC_REQ_IES) &&
+ nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
+ sinfo->assoc_req_ies))
+ goto nla_put_failure;
return genlmsg_end(msg, hdr);
@@ -2918,36 +2992,37 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
if (!hdr)
return -1;
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
- NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop);
-
- NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, pinfo->generation);
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
+ nla_put(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop) ||
+ nla_put_u32(msg, NL80211_ATTR_GENERATION, pinfo->generation))
+ goto nla_put_failure;
pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO);
if (!pinfoattr)
goto nla_put_failure;
- if (pinfo->filled & MPATH_INFO_FRAME_QLEN)
- NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
- pinfo->frame_qlen);
- if (pinfo->filled & MPATH_INFO_SN)
- NLA_PUT_U32(msg, NL80211_MPATH_INFO_SN,
- pinfo->sn);
- if (pinfo->filled & MPATH_INFO_METRIC)
- NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC,
- pinfo->metric);
- if (pinfo->filled & MPATH_INFO_EXPTIME)
- NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME,
- pinfo->exptime);
- if (pinfo->filled & MPATH_INFO_FLAGS)
- NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS,
- pinfo->flags);
- if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT)
- NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
- pinfo->discovery_timeout);
- if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES)
- NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
- pinfo->discovery_retries);
+ if ((pinfo->filled & MPATH_INFO_FRAME_QLEN) &&
+ nla_put_u32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
+ pinfo->frame_qlen))
+ goto nla_put_failure;
+ if (((pinfo->filled & MPATH_INFO_SN) &&
+ nla_put_u32(msg, NL80211_MPATH_INFO_SN, pinfo->sn)) ||
+ ((pinfo->filled & MPATH_INFO_METRIC) &&
+ nla_put_u32(msg, NL80211_MPATH_INFO_METRIC,
+ pinfo->metric)) ||
+ ((pinfo->filled & MPATH_INFO_EXPTIME) &&
+ nla_put_u32(msg, NL80211_MPATH_INFO_EXPTIME,
+ pinfo->exptime)) ||
+ ((pinfo->filled & MPATH_INFO_FLAGS) &&
+ nla_put_u8(msg, NL80211_MPATH_INFO_FLAGS,
+ pinfo->flags)) ||
+ ((pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) &&
+ nla_put_u32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+ pinfo->discovery_timeout)) ||
+ ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) &&
+ nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+ pinfo->discovery_retries)))
+ goto nla_put_failure;
nla_nest_end(msg, pinfoattr);
@@ -3273,47 +3348,50 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
if (!pinfoattr)
goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
- NLA_PUT_U16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
- cur_params.dot11MeshRetryTimeout);
- NLA_PUT_U16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
- cur_params.dot11MeshConfirmTimeout);
- NLA_PUT_U16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
- cur_params.dot11MeshHoldingTimeout);
- NLA_PUT_U16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
- cur_params.dot11MeshMaxPeerLinks);
- NLA_PUT_U8(msg, NL80211_MESHCONF_MAX_RETRIES,
- cur_params.dot11MeshMaxRetries);
- NLA_PUT_U8(msg, NL80211_MESHCONF_TTL,
- cur_params.dot11MeshTTL);
- NLA_PUT_U8(msg, NL80211_MESHCONF_ELEMENT_TTL,
- cur_params.element_ttl);
- NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
- cur_params.auto_open_plinks);
- NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
- cur_params.dot11MeshHWMPmaxPREQretries);
- NLA_PUT_U32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
- cur_params.path_refresh_time);
- NLA_PUT_U16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
- cur_params.min_discovery_timeout);
- NLA_PUT_U32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
- cur_params.dot11MeshHWMPactivePathTimeout);
- NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
- cur_params.dot11MeshHWMPpreqMinInterval);
- NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
- cur_params.dot11MeshHWMPperrMinInterval);
- NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
- cur_params.dot11MeshHWMPnetDiameterTraversalTime);
- NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
- cur_params.dot11MeshHWMPRootMode);
- NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
- cur_params.dot11MeshHWMPRannInterval);
- NLA_PUT_U8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
- cur_params.dot11MeshGateAnnouncementProtocol);
- NLA_PUT_U8(msg, NL80211_MESHCONF_FORWARDING,
- cur_params.dot11MeshForwarding);
- NLA_PUT_U32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
- cur_params.rssi_threshold);
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+ nla_put_u16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
+ cur_params.dot11MeshRetryTimeout) ||
+ nla_put_u16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
+ cur_params.dot11MeshConfirmTimeout) ||
+ nla_put_u16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
+ cur_params.dot11MeshHoldingTimeout) ||
+ nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+ cur_params.dot11MeshMaxPeerLinks) ||
+ nla_put_u8(msg, NL80211_MESHCONF_MAX_RETRIES,
+ cur_params.dot11MeshMaxRetries) ||
+ nla_put_u8(msg, NL80211_MESHCONF_TTL,
+ cur_params.dot11MeshTTL) ||
+ nla_put_u8(msg, NL80211_MESHCONF_ELEMENT_TTL,
+ cur_params.element_ttl) ||
+ nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+ cur_params.auto_open_plinks) ||
+ nla_put_u32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
+ cur_params.dot11MeshNbrOffsetMaxNeighbor) ||
+ nla_put_u8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+ cur_params.dot11MeshHWMPmaxPREQretries) ||
+ nla_put_u32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
+ cur_params.path_refresh_time) ||
+ nla_put_u16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+ cur_params.min_discovery_timeout) ||
+ nla_put_u32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+ cur_params.dot11MeshHWMPactivePathTimeout) ||
+ nla_put_u16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+ cur_params.dot11MeshHWMPpreqMinInterval) ||
+ nla_put_u16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
+ cur_params.dot11MeshHWMPperrMinInterval) ||
+ nla_put_u16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+ cur_params.dot11MeshHWMPnetDiameterTraversalTime) ||
+ nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
+ cur_params.dot11MeshHWMPRootMode) ||
+ nla_put_u16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ cur_params.dot11MeshHWMPRannInterval) ||
+ nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+ cur_params.dot11MeshGateAnnouncementProtocol) ||
+ nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
+ cur_params.dot11MeshForwarding) ||
+ nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
+ cur_params.rssi_threshold))
+ goto nla_put_failure;
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
@@ -3334,6 +3412,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
[NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
[NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
[NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
[NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
@@ -3351,6 +3430,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
static const struct nla_policy
nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
+ [NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC] = { .type = NLA_U8 },
[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
[NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
@@ -3403,6 +3483,9 @@ do {\
mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks,
mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8);
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
+ mask, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
+ nla_get_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries,
mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
nla_get_u8);
@@ -3460,6 +3543,12 @@ static int nl80211_parse_mesh_setup(struct genl_info *info,
nl80211_mesh_setup_params_policy))
return -EINVAL;
+ if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])
+ setup->sync_method =
+ (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC])) ?
+ IEEE80211_SYNC_METHOD_VENDOR :
+ IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET;
+
if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
setup->path_sel_proto =
(nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
@@ -3544,11 +3633,12 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
if (!hdr)
goto put_failure;
- NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2,
- cfg80211_regdomain->alpha2);
- if (cfg80211_regdomain->dfs_region)
- NLA_PUT_U8(msg, NL80211_ATTR_DFS_REGION,
- cfg80211_regdomain->dfs_region);
+ if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
+ cfg80211_regdomain->alpha2) ||
+ (cfg80211_regdomain->dfs_region &&
+ nla_put_u8(msg, NL80211_ATTR_DFS_REGION,
+ cfg80211_regdomain->dfs_region)))
+ goto nla_put_failure;
nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
if (!nl_reg_rules)
@@ -3568,18 +3658,19 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
if (!nl_reg_rule)
goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_ATTR_REG_RULE_FLAGS,
- reg_rule->flags);
- NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_START,
- freq_range->start_freq_khz);
- NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_END,
- freq_range->end_freq_khz);
- NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
- freq_range->max_bandwidth_khz);
- NLA_PUT_U32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
- power_rule->max_antenna_gain);
- NLA_PUT_U32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
- power_rule->max_eirp);
+ if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
+ reg_rule->flags) ||
+ nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START,
+ freq_range->start_freq_khz) ||
+ nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END,
+ freq_range->end_freq_khz) ||
+ nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
+ freq_range->max_bandwidth_khz) ||
+ nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
+ power_rule->max_antenna_gain) ||
+ nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
+ power_rule->max_eirp))
+ goto nla_put_failure;
nla_nest_end(msg, nl_reg_rule);
}
@@ -4150,37 +4241,44 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
genl_dump_check_consistent(cb, hdr, &nl80211_fam);
- NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex);
+ if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
+ goto nla_put_failure;
bss = nla_nest_start(msg, NL80211_ATTR_BSS);
if (!bss)
goto nla_put_failure;
- if (!is_zero_ether_addr(res->bssid))
- NLA_PUT(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid);
- if (res->information_elements && res->len_information_elements)
- NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS,
- res->len_information_elements,
- res->information_elements);
- if (res->beacon_ies && res->len_beacon_ies &&
- res->beacon_ies != res->information_elements)
- NLA_PUT(msg, NL80211_BSS_BEACON_IES,
- res->len_beacon_ies, res->beacon_ies);
- if (res->tsf)
- NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf);
- if (res->beacon_interval)
- NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval);
- NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability);
- NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq);
- NLA_PUT_U32(msg, NL80211_BSS_SEEN_MS_AGO,
- jiffies_to_msecs(jiffies - intbss->ts));
+ if ((!is_zero_ether_addr(res->bssid) &&
+ nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)) ||
+ (res->information_elements && res->len_information_elements &&
+ nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
+ res->len_information_elements,
+ res->information_elements)) ||
+ (res->beacon_ies && res->len_beacon_ies &&
+ res->beacon_ies != res->information_elements &&
+ nla_put(msg, NL80211_BSS_BEACON_IES,
+ res->len_beacon_ies, res->beacon_ies)))
+ goto nla_put_failure;
+ if (res->tsf &&
+ nla_put_u64(msg, NL80211_BSS_TSF, res->tsf))
+ goto nla_put_failure;
+ if (res->beacon_interval &&
+ nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
+ goto nla_put_failure;
+ if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
+ nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
+ nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
+ jiffies_to_msecs(jiffies - intbss->ts)))
+ goto nla_put_failure;
switch (rdev->wiphy.signal_type) {
case CFG80211_SIGNAL_TYPE_MBM:
- NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal);
+ if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
+ goto nla_put_failure;
break;
case CFG80211_SIGNAL_TYPE_UNSPEC:
- NLA_PUT_U8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal);
+ if (nla_put_u8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal))
+ goto nla_put_failure;
break;
default:
break;
@@ -4189,14 +4287,16 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
switch (wdev->iftype) {
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
- if (intbss == wdev->current_bss)
- NLA_PUT_U32(msg, NL80211_BSS_STATUS,
- NL80211_BSS_STATUS_ASSOCIATED);
+ if (intbss == wdev->current_bss &&
+ nla_put_u32(msg, NL80211_BSS_STATUS,
+ NL80211_BSS_STATUS_ASSOCIATED))
+ goto nla_put_failure;
break;
case NL80211_IFTYPE_ADHOC:
- if (intbss == wdev->current_bss)
- NLA_PUT_U32(msg, NL80211_BSS_STATUS,
- NL80211_BSS_STATUS_IBSS_JOINED);
+ if (intbss == wdev->current_bss &&
+ nla_put_u32(msg, NL80211_BSS_STATUS,
+ NL80211_BSS_STATUS_IBSS_JOINED))
+ goto nla_put_failure;
break;
default:
break;
@@ -4265,34 +4365,43 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
if (!hdr)
return -ENOMEM;
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
+ goto nla_put_failure;
infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
if (!infoattr)
goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY,
- survey->channel->center_freq);
- if (survey->filled & SURVEY_INFO_NOISE_DBM)
- NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE,
- survey->noise);
- if (survey->filled & SURVEY_INFO_IN_USE)
- NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE);
- if (survey->filled & SURVEY_INFO_CHANNEL_TIME)
- NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME,
- survey->channel_time);
- if (survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY)
- NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
- survey->channel_time_busy);
- if (survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY)
- NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
- survey->channel_time_ext_busy);
- if (survey->filled & SURVEY_INFO_CHANNEL_TIME_RX)
- NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
- survey->channel_time_rx);
- if (survey->filled & SURVEY_INFO_CHANNEL_TIME_TX)
- NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
- survey->channel_time_tx);
+ if (nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
+ survey->channel->center_freq))
+ goto nla_put_failure;
+
+ if ((survey->filled & SURVEY_INFO_NOISE_DBM) &&
+ nla_put_u8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise))
+ goto nla_put_failure;
+ if ((survey->filled & SURVEY_INFO_IN_USE) &&
+ nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
+ goto nla_put_failure;
+ if ((survey->filled & SURVEY_INFO_CHANNEL_TIME) &&
+ nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME,
+ survey->channel_time))
+ goto nla_put_failure;
+ if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY) &&
+ nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
+ survey->channel_time_busy))
+ goto nla_put_failure;
+ if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) &&
+ nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
+ survey->channel_time_ext_busy))
+ goto nla_put_failure;
+ if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_RX) &&
+ nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
+ survey->channel_time_rx))
+ goto nla_put_failure;
+ if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_TX) &&
+ nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
+ survey->channel_time_tx))
+ goto nla_put_failure;
nla_nest_end(msg, infoattr);
@@ -4973,7 +5082,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
NL80211_CMD_TESTMODE);
struct nlattr *tmdata;
- if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx) < 0) {
+ if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
genlmsg_cancel(skb, hdr);
break;
}
@@ -5024,7 +5133,8 @@ __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev,
return NULL;
}
- NLA_PUT_U32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
+ goto nla_put_failure;
data = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
((void **)skb->cb)[0] = rdev;
@@ -5403,7 +5513,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
if (err)
goto free_msg;
- NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+ if (nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -5690,7 +5801,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
goto free_msg;
if (msg) {
- NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+ if (nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
@@ -5795,7 +5907,8 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
else
ps_state = NL80211_PS_DISABLED;
- NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
+ if (nla_put_u32(msg, NL80211_ATTR_PS_STATE, ps_state))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
@@ -5942,20 +6055,21 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
if (!nl_wowlan)
goto nla_put_failure;
- if (rdev->wowlan->any)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY);
- if (rdev->wowlan->disconnect)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT);
- if (rdev->wowlan->magic_pkt)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT);
- if (rdev->wowlan->gtk_rekey_failure)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE);
- if (rdev->wowlan->eap_identity_req)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST);
- if (rdev->wowlan->four_way_handshake)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE);
- if (rdev->wowlan->rfkill_release)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE);
+ if ((rdev->wowlan->any &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
+ (rdev->wowlan->disconnect &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
+ (rdev->wowlan->magic_pkt &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
+ (rdev->wowlan->gtk_rekey_failure &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
+ (rdev->wowlan->eap_identity_req &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
+ (rdev->wowlan->four_way_handshake &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
+ (rdev->wowlan->rfkill_release &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
+ goto nla_put_failure;
if (rdev->wowlan->n_patterns) {
struct nlattr *nl_pats, *nl_pat;
int i, pat_len;
@@ -5970,12 +6084,13 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
if (!nl_pat)
goto nla_put_failure;
pat_len = rdev->wowlan->patterns[i].pattern_len;
- NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_MASK,
- DIV_ROUND_UP(pat_len, 8),
- rdev->wowlan->patterns[i].mask);
- NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_PATTERN,
- pat_len,
- rdev->wowlan->patterns[i].pattern);
+ if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK,
+ DIV_ROUND_UP(pat_len, 8),
+ rdev->wowlan->patterns[i].mask) ||
+ nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN,
+ pat_len,
+ rdev->wowlan->patterns[i].pattern))
+ goto nla_put_failure;
nla_nest_end(msg, nl_pat);
}
nla_nest_end(msg, nl_pats);
@@ -6000,6 +6115,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_wowlan new_triggers = {};
struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan;
int err, i;
+ bool prev_enabled = rdev->wowlan;
if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns)
return -EOPNOTSUPP;
@@ -6132,6 +6248,9 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
rdev->wowlan = NULL;
}
+ if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan)
+ rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan);
+
return 0;
error:
for (i = 0; i < new_triggers.n_patterns; i++)
@@ -6248,7 +6367,8 @@ static int nl80211_probe_client(struct sk_buff *skb,
if (err)
goto free_msg;
- NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+ if (nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -6916,19 +7036,24 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
if (!nest)
goto nla_put_failure;
- for (i = 0; i < req->n_ssids; i++)
- NLA_PUT(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid);
+ for (i = 0; i < req->n_ssids; i++) {
+ if (nla_put(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
+ goto nla_put_failure;
+ }
nla_nest_end(msg, nest);
nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
if (!nest)
goto nla_put_failure;
- for (i = 0; i < req->n_channels; i++)
- NLA_PUT_U32(msg, i, req->channels[i]->center_freq);
+ for (i = 0; i < req->n_channels; i++) {
+ if (nla_put_u32(msg, i, req->channels[i]->center_freq))
+ goto nla_put_failure;
+ }
nla_nest_end(msg, nest);
- if (req->ie)
- NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie);
+ if (req->ie &&
+ nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
+ goto nla_put_failure;
return 0;
nla_put_failure:
@@ -6947,8 +7072,9 @@ static int nl80211_send_scan_msg(struct sk_buff *msg,
if (!hdr)
return -1;
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
+ goto nla_put_failure;
/* ignore errors and send incomplete event anyway */
nl80211_add_scan_req(msg, rdev);
@@ -6972,8 +7098,9 @@ nl80211_send_sched_scan_msg(struct sk_buff *msg,
if (!hdr)
return -1;
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
+ goto nla_put_failure;
return genlmsg_end(msg, hdr);
@@ -7096,26 +7223,33 @@ void nl80211_send_reg_change_event(struct regulatory_request *request)
}
/* Userspace can always count this one always being set */
- NLA_PUT_U8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator);
-
- if (request->alpha2[0] == '0' && request->alpha2[1] == '0')
- NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
- NL80211_REGDOM_TYPE_WORLD);
- else if (request->alpha2[0] == '9' && request->alpha2[1] == '9')
- NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
- NL80211_REGDOM_TYPE_CUSTOM_WORLD);
- else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
- request->intersect)
- NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
- NL80211_REGDOM_TYPE_INTERSECTION);
- else {
- NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
- NL80211_REGDOM_TYPE_COUNTRY);
- NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, request->alpha2);
- }
-
- if (wiphy_idx_valid(request->wiphy_idx))
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx);
+ if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
+ goto nla_put_failure;
+
+ if (request->alpha2[0] == '0' && request->alpha2[1] == '0') {
+ if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
+ NL80211_REGDOM_TYPE_WORLD))
+ goto nla_put_failure;
+ } else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') {
+ if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
+ NL80211_REGDOM_TYPE_CUSTOM_WORLD))
+ goto nla_put_failure;
+ } else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
+ request->intersect) {
+ if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
+ NL80211_REGDOM_TYPE_INTERSECTION))
+ goto nla_put_failure;
+ } else {
+ if (nla_put_u8(msg, NL80211_ATTR_REG_TYPE,
+ NL80211_REGDOM_TYPE_COUNTRY) ||
+ nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
+ request->alpha2))
+ goto nla_put_failure;
+ }
+
+ if (wiphy_idx_valid(request->wiphy_idx) &&
+ nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7149,9 +7283,10 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_FRAME, len, buf))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7229,10 +7364,11 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7280,15 +7416,15 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- if (bssid)
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
- NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status);
- if (req_ie)
- NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie);
- if (resp_ie)
- NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) ||
+ nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status) ||
+ (req_ie &&
+ nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
+ (resp_ie &&
+ nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7320,13 +7456,14 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
- if (req_ie)
- NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie);
- if (resp_ie)
- NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
+ (req_ie &&
+ nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
+ (resp_ie &&
+ nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7357,14 +7494,14 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- if (from_ap && reason)
- NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason);
- if (from_ap)
- NLA_PUT_FLAG(msg, NL80211_ATTR_DISCONNECTED_BY_AP);
- if (ie)
- NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ (from_ap && reason &&
+ nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason)) ||
+ (from_ap &&
+ nla_put_flag(msg, NL80211_ATTR_DISCONNECTED_BY_AP)) ||
+ (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie)))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7395,9 +7532,10 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7428,11 +7566,12 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr);
- if (ie_len && ie)
- NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr) ||
+ (ie_len && ie &&
+ nla_put(msg, NL80211_ATTR_IE, ie_len , ie)))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7463,15 +7602,14 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- if (addr)
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type);
- if (key_id != -1)
- NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id);
- if (tsc)
- NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
+ nla_put_u32(msg, NL80211_ATTR_KEY_TYPE, key_type) ||
+ (key_id != -1 &&
+ nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_id)) ||
+ (tsc && nla_put(msg, NL80211_ATTR_KEY_SEQ, 6, tsc)))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7506,7 +7644,8 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
* Since we are applying the beacon hint to a wiphy we know its
* wiphy_idx is valid
*/
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy));
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
+ goto nla_put_failure;
/* Before */
nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE);
@@ -7558,14 +7697,16 @@ static void nl80211_send_remain_on_chan_event(
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type);
- NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) ||
+ nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
+ goto nla_put_failure;
- if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL)
- NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
+ if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL &&
+ nla_put_u32(msg, NL80211_ATTR_DURATION, duration))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7636,8 +7777,9 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7673,9 +7815,10 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
return true;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+ goto nla_put_failure;
err = genlmsg_end(msg, hdr);
if (err < 0) {
@@ -7724,12 +7867,13 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
return -ENOMEM;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
- if (sig_dbm)
- NLA_PUT_U32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm);
- NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
+ (sig_dbm &&
+ nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
+ nla_put(msg, NL80211_ATTR_FRAME, len, buf))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7759,12 +7903,12 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
- NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
- if (ack)
- NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
+ nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) ||
+ (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -7796,15 +7940,17 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
+ goto nla_put_failure;
pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
if (!pinfoattr)
goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
- rssi_event);
+ if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
+ rssi_event))
+ goto nla_put_failure;
nla_nest_end(msg, pinfoattr);
@@ -7837,16 +7983,18 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
+ goto nla_put_failure;
rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
if (!rekey_attr)
goto nla_put_failure;
- NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR,
- NL80211_REPLAY_CTR_LEN, replay_ctr);
+ if (nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR,
+ NL80211_REPLAY_CTR_LEN, replay_ctr))
+ goto nla_put_failure;
nla_nest_end(msg, rekey_attr);
@@ -7879,17 +8027,19 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
+ goto nla_put_failure;
attr = nla_nest_start(msg, NL80211_ATTR_PMKSA_CANDIDATE);
if (!attr)
goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index);
- NLA_PUT(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid);
- if (preauth)
- NLA_PUT_FLAG(msg, NL80211_PMKSA_CANDIDATE_PREAUTH);
+ if (nla_put_u32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index) ||
+ nla_put(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid) ||
+ (preauth &&
+ nla_put_flag(msg, NL80211_PMKSA_CANDIDATE_PREAUTH)))
+ goto nla_put_failure;
nla_nest_end(msg, attr);
@@ -7904,6 +8054,39 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}
+void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, int freq,
+ enum nl80211_channel_type type, gfp_t gfp)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CH_SWITCH_NOTIFY);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, type))
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, gfp);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+
void
nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *peer,
@@ -7923,15 +8106,17 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
+ goto nla_put_failure;
pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
if (!pinfoattr)
goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets);
+ if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
+ goto nla_put_failure;
nla_nest_end(msg, pinfoattr);
@@ -7965,12 +8150,12 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
- NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
- if (acked)
- NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) ||
+ (acked && nla_put_flag(msg, NL80211_ATTR_ACK)))
+ goto nla_put_failure;
err = genlmsg_end(msg, hdr);
if (err < 0) {
@@ -8010,12 +8195,13 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
return;
}
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- if (freq)
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
- if (sig_dbm)
- NLA_PUT_U32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm);
- NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ (freq &&
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
+ (sig_dbm &&
+ nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
+ nla_put(msg, NL80211_ATTR_FRAME, len, frame))
+ goto nla_put_failure;
genlmsg_end(msg, hdr);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 4ffe50df9f31..01a1122c3b33 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -118,6 +118,10 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev, int index,
const u8 *bssid, bool preauth, gfp_t gfp);
+void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, int freq,
+ enum nl80211_channel_type type, gfp_t gfp);
+
bool nl80211_unexpected_frame(struct net_device *dev,
const u8 *addr, gfp_t gfp);
bool nl80211_unexpected_4addr_frame(struct net_device *dev,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index e9a0ac83b84c..15f347477a99 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -388,7 +388,15 @@ static void reg_regdb_query(const char *alpha2)
schedule_work(&reg_regdb_work);
}
+
+/* Feel free to add any other sanity checks here */
+static void reg_regdb_size_check(void)
+{
+ /* We should ideally BUILD_BUG_ON() but then random builds would fail */
+ WARN_ONCE(!reg_regdb_size, "db.txt is empty, you should update it...");
+}
#else
+static inline void reg_regdb_size_check(void) {}
static inline void reg_regdb_query(const char *alpha2) {}
#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
@@ -2322,6 +2330,8 @@ int __init regulatory_init(void)
spin_lock_init(&reg_requests_lock);
spin_lock_init(&reg_pending_beacons_lock);
+ reg_regdb_size_check();
+
cfg80211_regdomain = cfg80211_world_regdom;
user_alpha2[0] = '9';
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 70faadf16a32..1442bb68a3f3 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -18,7 +18,7 @@
#include "nl80211.h"
#include "wext-compat.h"
-#define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ)
+#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
{
@@ -378,7 +378,7 @@ static int cmp_bss_core(struct cfg80211_bss *a,
b->len_information_elements);
}
- return memcmp(a->bssid, b->bssid, ETH_ALEN);
+ return compare_ether_addr(a->bssid, b->bssid);
}
static int cmp_bss(struct cfg80211_bss *a,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 957f25621617..6cba00173a2f 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -946,13 +946,6 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
if (rdev->wiphy.software_iftypes & BIT(iftype))
return 0;
- /*
- * Drivers will gradually all set this flag, until all
- * have it we only enforce for those that set it.
- */
- if (!(rdev->wiphy.flags & WIPHY_FLAG_ENFORCE_COMBINATIONS))
- return 0;
-
memset(num, 0, sizeof(num));
num[iftype] = 1;
@@ -972,6 +965,9 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
}
mutex_unlock(&rdev->devlist_mtx);
+ if (total == 1)
+ return 0;
+
for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
const struct ieee80211_iface_combination *c;
struct ieee80211_iface_limit *limits;
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 3c24eb97e9d7..6a6181a673ca 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -821,6 +821,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct ieee80211_channel *chan;
+ enum nl80211_channel_type channel_type;
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
@@ -831,7 +832,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
if (!rdev->ops->get_channel)
return -EINVAL;
- chan = rdev->ops->get_channel(wdev->wiphy);
+ chan = rdev->ops->get_channel(wdev->wiphy, &channel_type);
if (!chan)
return -EINVAL;
freq->m = chan->center_freq;
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c
index af648e08e61b..b0eb7aa49b60 100644
--- a/net/wireless/wext-core.c
+++ b/net/wireless/wext-core.c
@@ -256,7 +256,7 @@ static const struct iw_ioctl_description standard_ioctl[] = {
.max_tokens = sizeof(struct iw_pmksa),
},
};
-static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl);
+static const unsigned int standard_ioctl_num = ARRAY_SIZE(standard_ioctl);
/*
* Meta-data about all the additional standard Wireless Extension events
@@ -306,7 +306,7 @@ static const struct iw_ioctl_description standard_event[] = {
.max_tokens = sizeof(struct iw_pmkid_cand),
},
};
-static const unsigned standard_event_num = ARRAY_SIZE(standard_event);
+static const unsigned int standard_event_num = ARRAY_SIZE(standard_event);
/* Size (in bytes) of various events */
static const int event_type_size[] = {
@@ -402,7 +402,8 @@ static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev,
r->ifi_flags = dev_get_flags(dev);
r->ifi_change = 0; /* Wireless changes don't affect those flags */
- NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
+ if (nla_put_string(skb, IFLA_IFNAME, dev->name))
+ goto nla_put_failure;
return nlh;
nla_put_failure:
@@ -428,7 +429,7 @@ void wireless_send_event(struct net_device * dev,
int hdr_len; /* Size of the event header */
int wrqu_off = 0; /* Offset in wrqu */
/* Don't "optimise" the following variable, it will crash */
- unsigned cmd_index; /* *MUST* be unsigned */
+ unsigned int cmd_index; /* *MUST* be unsigned */
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct nlattr *nla;
diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c
index d2efd29f434e..43239527a205 100644
--- a/net/x25/sysctl_net_x25.c
+++ b/net/x25/sysctl_net_x25.c
@@ -73,18 +73,12 @@ static struct ctl_table x25_table[] = {
{ 0, },
};
-static struct ctl_path x25_path[] = {
- { .procname = "net", },
- { .procname = "x25", },
- { }
-};
-
void __init x25_register_sysctl(void)
{
- x25_table_header = register_sysctl_paths(x25_path, x25_table);
+ x25_table_header = register_net_sysctl(&init_net, "net/x25", x25_table);
}
void x25_unregister_sysctl(void)
{
- unregister_sysctl_table(x25_table_header);
+ unregister_net_sysctl_table(x25_table_header);
}
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index f0ce862d1f46..a8a236338e61 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -58,7 +58,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
if (!sock_owned_by_user(sk)) {
queued = x25_process_rx_frame(sk, skb);
} else {
- queued = !sk_add_backlog(sk, skb);
+ queued = !sk_add_backlog(sk, skb, sk->sk_rcvbuf);
}
bh_unlock_sock(sk);
sock_put(sk);
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
index 36384a1fa9f2..66c638730c7a 100644
--- a/net/x25/x25_facilities.c
+++ b/net/x25/x25_facilities.c
@@ -231,7 +231,7 @@ int x25_create_facilities(unsigned char *buffer,
}
if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) {
- unsigned bytecount = (dte_facs->calling_len + 1) >> 1;
+ unsigned int bytecount = (dte_facs->calling_len + 1) >> 1;
*p++ = X25_FAC_CALLING_AE;
*p++ = 1 + bytecount;
*p++ = dte_facs->calling_len;
@@ -240,7 +240,7 @@ int x25_create_facilities(unsigned char *buffer,
}
if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) {
- unsigned bytecount = (dte_facs->called_len % 2) ?
+ unsigned int bytecount = (dte_facs->called_len % 2) ?
dte_facs->called_len / 2 + 1 :
dte_facs->called_len / 2;
*p++ = X25_FAC_CALLED_AE;
diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h
index 7199d78b2aa1..716502ada53b 100644
--- a/net/xfrm/xfrm_hash.h
+++ b/net/xfrm/xfrm_hash.h
@@ -45,10 +45,10 @@ static inline unsigned int __xfrm_dst_hash(const xfrm_address_t *daddr,
return (h ^ (h >> 16)) & hmask;
}
-static inline unsigned __xfrm_src_hash(const xfrm_address_t *daddr,
- const xfrm_address_t *saddr,
- unsigned short family,
- unsigned int hmask)
+static inline unsigned int __xfrm_src_hash(const xfrm_address_t *daddr,
+ const xfrm_address_t *saddr,
+ unsigned short family,
+ unsigned int hmask)
{
unsigned int h = family;
switch (family) {
diff --git a/net/xfrm/xfrm_sysctl.c b/net/xfrm/xfrm_sysctl.c
index 05640bc9594b..380976f74c4c 100644
--- a/net/xfrm/xfrm_sysctl.c
+++ b/net/xfrm/xfrm_sysctl.c
@@ -54,7 +54,7 @@ int __net_init xfrm_sysctl_init(struct net *net)
table[2].data = &net->xfrm.sysctl_larval_drop;
table[3].data = &net->xfrm.sysctl_acq_expires;
- net->xfrm.sysctl_hdr = register_net_sysctl_table(net, net_core_path, table);
+ net->xfrm.sysctl_hdr = register_net_sysctl(net, "net/core", table);
if (!net->xfrm.sysctl_hdr)
goto out_register;
return 0;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 7128dde0fe1a..44293b3fd6a1 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -756,40 +756,50 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
{
copy_to_user_state(x, p);
- if (x->coaddr)
- NLA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);
+ if (x->coaddr &&
+ nla_put(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr))
+ goto nla_put_failure;
- if (x->lastused)
- NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused);
+ if (x->lastused &&
+ nla_put_u64(skb, XFRMA_LASTUSED, x->lastused))
+ goto nla_put_failure;
- if (x->aead)
- NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead);
- if (x->aalg) {
- if (copy_to_user_auth(x->aalg, skb))
- goto nla_put_failure;
+ if (x->aead &&
+ nla_put(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead))
+ goto nla_put_failure;
- NLA_PUT(skb, XFRMA_ALG_AUTH_TRUNC,
- xfrm_alg_auth_len(x->aalg), x->aalg);
- }
- if (x->ealg)
- NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg);
- if (x->calg)
- NLA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
+ if (x->aalg &&
+ (copy_to_user_auth(x->aalg, skb) ||
+ nla_put(skb, XFRMA_ALG_AUTH_TRUNC,
+ xfrm_alg_auth_len(x->aalg), x->aalg)))
+ goto nla_put_failure;
- if (x->encap)
- NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
+ if (x->ealg &&
+ nla_put(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg))
+ goto nla_put_failure;
- if (x->tfcpad)
- NLA_PUT_U32(skb, XFRMA_TFCPAD, x->tfcpad);
+ if (x->calg &&
+ nla_put(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg))
+ goto nla_put_failure;
+
+ if (x->encap &&
+ nla_put(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap))
+ goto nla_put_failure;
+
+ if (x->tfcpad &&
+ nla_put_u32(skb, XFRMA_TFCPAD, x->tfcpad))
+ goto nla_put_failure;
if (xfrm_mark_put(skb, &x->mark))
goto nla_put_failure;
- if (x->replay_esn)
- NLA_PUT(skb, XFRMA_REPLAY_ESN_VAL,
- xfrm_replay_state_esn_len(x->replay_esn), x->replay_esn);
+ if (x->replay_esn &&
+ nla_put(skb, XFRMA_REPLAY_ESN_VAL,
+ xfrm_replay_state_esn_len(x->replay_esn),
+ x->replay_esn))
+ goto nla_put_failure;
- if (x->security && copy_sec_ctx(x->security, skb) < 0)
+ if (x->security && copy_sec_ctx(x->security, skb))
goto nla_put_failure;
return 0;
@@ -912,8 +922,9 @@ static int build_spdinfo(struct sk_buff *skb, struct net *net,
sph.spdhcnt = si.spdhcnt;
sph.spdhmcnt = si.spdhmcnt;
- NLA_PUT(skb, XFRMA_SPD_INFO, sizeof(spc), &spc);
- NLA_PUT(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph);
+ if (nla_put(skb, XFRMA_SPD_INFO, sizeof(spc), &spc) ||
+ nla_put(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph))
+ goto nla_put_failure;
return nlmsg_end(skb, nlh);
@@ -967,8 +978,9 @@ static int build_sadinfo(struct sk_buff *skb, struct net *net,
sh.sadhmcnt = si.sadhmcnt;
sh.sadhcnt = si.sadhcnt;
- NLA_PUT_U32(skb, XFRMA_SAD_CNT, si.sadcnt);
- NLA_PUT(skb, XFRMA_SAD_HINFO, sizeof(sh), &sh);
+ if (nla_put_u32(skb, XFRMA_SAD_CNT, si.sadcnt) ||
+ nla_put(skb, XFRMA_SAD_HINFO, sizeof(sh), &sh))
+ goto nla_put_failure;
return nlmsg_end(skb, nlh);
@@ -1690,21 +1702,27 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct
id->reqid = x->props.reqid;
id->flags = c->data.aevent;
- if (x->replay_esn)
- NLA_PUT(skb, XFRMA_REPLAY_ESN_VAL,
- xfrm_replay_state_esn_len(x->replay_esn),
- x->replay_esn);
- else
- NLA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay);
-
- NLA_PUT(skb, XFRMA_LTIME_VAL, sizeof(x->curlft), &x->curlft);
+ if (x->replay_esn) {
+ if (nla_put(skb, XFRMA_REPLAY_ESN_VAL,
+ xfrm_replay_state_esn_len(x->replay_esn),
+ x->replay_esn))
+ goto nla_put_failure;
+ } else {
+ if (nla_put(skb, XFRMA_REPLAY_VAL, sizeof(x->replay),
+ &x->replay))
+ goto nla_put_failure;
+ }
+ if (nla_put(skb, XFRMA_LTIME_VAL, sizeof(x->curlft), &x->curlft))
+ goto nla_put_failure;
- if (id->flags & XFRM_AE_RTHR)
- NLA_PUT_U32(skb, XFRMA_REPLAY_THRESH, x->replay_maxdiff);
+ if ((id->flags & XFRM_AE_RTHR) &&
+ nla_put_u32(skb, XFRMA_REPLAY_THRESH, x->replay_maxdiff))
+ goto nla_put_failure;
- if (id->flags & XFRM_AE_ETHR)
- NLA_PUT_U32(skb, XFRMA_ETIMER_THRESH,
- x->replay_maxage * 10 / HZ);
+ if ((id->flags & XFRM_AE_ETHR) &&
+ nla_put_u32(skb, XFRMA_ETIMER_THRESH,
+ x->replay_maxage * 10 / HZ))
+ goto nla_put_failure;
if (xfrm_mark_put(skb, &x->mark))
goto nla_put_failure;
@@ -2835,8 +2853,9 @@ static int build_report(struct sk_buff *skb, u8 proto,
ur->proto = proto;
memcpy(&ur->sel, sel, sizeof(ur->sel));
- if (addr)
- NLA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr);
+ if (addr &&
+ nla_put(skb, XFRMA_COADDR, sizeof(*addr), addr))
+ goto nla_put_failure;
return nlmsg_end(skb, nlh);