aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-21 10:03:46 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-21 10:03:46 -0700
commitcb62ab71fe2b16e8203a0f0a2ef4eda23d761338 (patch)
tree536ba39658e47d511a489c52f7aac60cd78967e5 /net
parent31ed8e6f93a27304c9e157dab0267772cd94eaad (diff)
parent74863948f925d9f3bb4e3d3a783e49e9c662d839 (diff)
downloadlinux-cb62ab71fe2b16e8203a0f0a2ef4eda23d761338.tar.gz
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking changes from David Miller: 1) Get rid of the error prone NLA_PUT*() macros that used an embedded goto. 2) Kill off the token-ring and MCA networking drivers, from Paul Gortmaker. 3) Reduce high-order allocations made by datagram AF_UNIX sockets, from Eric Dumazet. 4) Add PTP hardware clock support to IGB and IXGBE, from Richard Cochran and Jacob Keller. 5) Allow users to query timestamping capabilities of a card via ethtool, from Richard Cochran. 6) Add loadbalance mode to the teaming driver, from Jiri Pirko. Part of this is that we can now have BPF filters not attached to sockets, and the loadbalancing function is calculated using one. 7) Francois Romieu went through the network drivers removing gratuitous uses of netdev->base_addr, perhaps some day we can remove it completely but it's used for ISA probing still. 8) Add a BPF JIT for sparc. I know, who cares, right? :-) 9) Move networking sysctl registry away from using the compatability mode interfaces in the sysctl code. From Eric W Biederman. 10) Pavel Emelyanov added a way to save and restore TCP socket state via TCP_REPAIR, TCP_REPAIR_QUEUE, and TCP_QUEUE_SEQ socket options as well as a way to forcefully bind a socket to a port via the sk->sk_reuse value SK_FORCE_REUSE. There is also a TCP_REPAIR_OPTIONS which allows to reinstante the TCP options enabled on the connection. 11) Several enhancements from Eric Dumazet that, in particular, can enhance splice performance on TCP sockets significantly. a) Reset the offset of the per-socket sendmsg page when we know we're the only use of the page in linear_to_page(). b) Add facilities such that skb->data can be backed a page rather than SLAB kmalloc'd memory. In particular devices which were receiving into linear RX buffers can now end up providing paged data. The big result is that code like splice and GRO do not have to copy any more. 12) Allow a pure sender to more gracefully handle ACK backlogs in TCP. What can happen at high rates is that the sender hasn't grown his receive buffer limits at all (he's not receiving data so really doesn't need to), but the non-data ACKs consume receive buffer space. sk_add_backlog() is too aggressive in dropping frames in this case, so relax it's requirements by using the receive buffer plus the send buffer limit as the backlog limit instead of just the former. Also from Eric Dumazet. 13) Add ipv6 support to L2TP, from Benjamin LaHaise, James Chapman, and Chris Elston. 14) Implement TCP early retransmit (RFC 5827), from Yuchung Cheng. Basically, we can start fast retransmit before hiting the dupack threshold under certain conditions. 15) New CODEL active queue management packet scheduler, from Eric Dumazet based upon initial work by Dave Taht. Basically, the big feature is that packets are dropped (or ECN bits are set) based upon how long packets live in the queue, rather than the queue length (which is what RED uses). * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1341 commits) drivers/net/stmmac: seq_file fix memory leak ipv6/exthdrs: strict Pad1 and PadN check USB: qmi_wwan: Add ZTE (Vodafone) K3520-Z USB: qmi_wwan: Add ZTE (Vodafone) K3765-Z USB: qmi_wwan: Make forced int 4 whitelist generic net/ipv4: replace simple_strtoul with kstrtoul net/ipv4/ipconfig: neaten __setup placement net: qmi_wwan: Add Vodafone/Huawei K5005 support net: cdc_ether: Add ZTE WWAN matches before generic Ethernet ipv6: use skb coalescing in reassembly ipv4: use skb coalescing in defragmentation net: introduce skb_try_coalesce() net:ipv6:fixed space issues relating to operators. net:ipv6:fixed a trailing white space issue. ipv6: disable GSO on sockets hitting dst_allfrag tg3: use netdev_alloc_frag() API net: napi_frags_skb() is static ppp: avoid false drop_monitor false positives ipv6: bool/const conversions phase2 ipx: Remove spurious NULL checking in ipx_ioctl(). ...
Diffstat (limited to 'net')
-rw-r--r--net/802/Makefile1
-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/p8022.c3
-rw-r--r--net/802/stp.c2
-rw-r--r--net/802/tr.c676
-rw-r--r--net/8021q/vlan.c10
-rw-r--r--net/8021q/vlan_core.c3
-rw-r--r--net/8021q/vlan_dev.c10
-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/Kconfig4
-rw-r--r--net/Makefile2
-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/ioctl.c8
-rw-r--r--net/atm/lec.c144
-rw-r--r--net/atm/lec.h1
-rw-r--r--net/atm/mpc.c3
-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.c23
-rw-r--r--net/batman-adv/bat_iv_ogm.c257
-rw-r--r--net/batman-adv/bat_sysfs.c110
-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/gateway_client.c6
-rw-r--r--net/batman-adv/hard-interface.c170
-rw-r--r--net/batman-adv/icmp_socket.c4
-rw-r--r--net/batman-adv/main.c138
-rw-r--r--net/batman-adv/main.h19
-rw-r--r--net/batman-adv/originator.c55
-rw-r--r--net/batman-adv/originator.h7
-rw-r--r--net/batman-adv/packet.h50
-rw-r--r--net/batman-adv/routing.c86
-rw-r--r--net/batman-adv/routing.h5
-rw-r--r--net/batman-adv/send.c20
-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.c460
-rw-r--r--net/batman-adv/translation-table.h12
-rw-r--r--net/batman-adv/types.h108
-rw-r--r--net/batman-adv/unicast.c8
-rw-r--r--net/batman-adv/vis.c8
-rw-r--r--net/bluetooth/bnep/core.c6
-rw-r--r--net/bridge/br_device.c5
-rw-r--r--net/bridge/br_fdb.c150
-rw-r--r--net/bridge/br_forward.c2
-rw-r--r--net/bridge/br_input.c2
-rw-r--r--net/bridge/br_multicast.c77
-rw-r--r--net/bridge/br_netfilter.c38
-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_bpdu.c2
-rw-r--r--net/bridge/br_stp_if.c11
-rw-r--r--net/bridge/br_stp_timer.c6
-rw-r--r--net/bridge/br_sysfs_br.c20
-rw-r--r--net/bridge/netfilter/ebt_stp.c4
-rw-r--r--net/caif/caif_socket.c28
-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.c9
-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.c62
-rw-r--r--net/core/dev_addr_lists.c97
-rw-r--r--net/core/drop_monitor.c56
-rw-r--r--net/core/ethtool.c130
-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.c128
-rw-r--r--net/core/net-sysfs.c13
-rw-r--r--net/core/net_namespace.c6
-rw-r--r--net/core/netprio_cgroup.c6
-rw-r--r--net/core/pktgen.c68
-rw-r--r--net/core/rtnetlink.c359
-rw-r--r--net/core/skbuff.c446
-rw-r--r--net/core/sock.c95
-rw-r--r--net/core/sock_diag.c12
-rw-r--r--net/core/sysctl_net_core.c15
-rw-r--r--net/core/utils.c9
-rw-r--r--net/dcb/dcbnl.c94
-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/proto.c4
-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.c10
-rw-r--r--net/decnet/dn_neigh.c22
-rw-r--r--net/decnet/dn_nsp_in.c13
-rw-r--r--net/decnet/dn_nsp_out.c9
-rw-r--r--net/decnet/dn_route.c33
-rw-r--r--net/decnet/dn_rules.c14
-rw-r--r--net/decnet/dn_table.c4
-rw-r--r--net/decnet/netfilter/dn_rtmsg.c3
-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/dsa/slave.c10
-rw-r--r--net/econet/Kconfig36
-rw-r--r--net/econet/Makefile7
-rw-r--r--net/econet/af_econet.c1172
-rw-r--r--net/ethernet/eth.c7
-rw-r--r--net/ieee802154/6lowpan.c87
-rw-r--r--net/ieee802154/6lowpan.h3
-rw-r--r--net/ieee802154/dgram.c6
-rw-r--r--net/ieee802154/nl-mac.c146
-rw-r--r--net/ieee802154/nl-phy.c38
-rw-r--r--net/ieee802154/raw.c2
-rw-r--r--net/ipv4/Kconfig8
-rw-r--r--net/ipv4/af_inet.c4
-rw-r--r--net/ipv4/ah4.c6
-rw-r--r--net/ipv4/arp.c26
-rw-r--r--net/ipv4/devinet.c66
-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/icmp.c20
-rw-r--r--net/ipv4/igmp.c18
-rw-r--r--net/ipv4/inet_connection_sock.c29
-rw-r--r--net/ipv4/inet_diag.c4
-rw-r--r--net/ipv4/inet_hashtables.c2
-rw-r--r--net/ipv4/inet_timewait_sock.c6
-rw-r--r--net/ipv4/ip_forward.c4
-rw-r--r--net/ipv4/ip_fragment.c45
-rw-r--r--net/ipv4/ip_gre.c102
-rw-r--r--net/ipv4/ip_input.c13
-rw-r--r--net/ipv4/ip_options.c32
-rw-r--r--net/ipv4/ip_output.c4
-rw-r--r--net/ipv4/ip_sockglue.c19
-rw-r--r--net/ipv4/ipconfig.c20
-rw-r--r--net/ipv4/ipip.c57
-rw-r--r--net/ipv4/ipmr.c12
-rw-r--r--net/ipv4/netfilter.c12
-rw-r--r--net/ipv4/netfilter/Makefile3
-rw-r--r--net/ipv4/netfilter/arp_tables.c7
-rw-r--r--net/ipv4/netfilter/ip_queue.c639
-rw-r--r--net/ipv4/netfilter/ip_tables.c5
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c3
-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_h323.c26
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c2
-rw-r--r--net/ipv4/netfilter/nf_nat_snmp_basic.c8
-rw-r--r--net/ipv4/ping.c10
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/route.c160
-rw-r--r--net/ipv4/sysctl_net_ipv4.c26
-rw-r--r--net/ipv4/tcp.c311
-rw-r--r--net/ipv4/tcp_cong.c6
-rw-r--r--net/ipv4/tcp_hybla.c10
-rw-r--r--net/ipv4/tcp_input.c612
-rw-r--r--net/ipv4/tcp_ipv4.c116
-rw-r--r--net/ipv4/tcp_minisocks.c25
-rw-r--r--net/ipv4/tcp_output.c151
-rw-r--r--net/ipv4/tcp_probe.c4
-rw-r--r--net/ipv4/tcp_timer.c5
-rw-r--r--net/ipv4/udp.c28
-rw-r--r--net/ipv4/udp_impl.h2
-rw-r--r--net/ipv4/xfrm4_policy.c6
-rw-r--r--net/ipv6/Kconfig4
-rw-r--r--net/ipv6/addrconf.c202
-rw-r--r--net/ipv6/addrconf_core.c4
-rw-r--r--net/ipv6/addrlabel.c26
-rw-r--r--net/ipv6/af_inet6.c70
-rw-r--r--net/ipv6/ah6.c30
-rw-r--r--net/ipv6/anycast.c12
-rw-r--r--net/ipv6/datagram.c20
-rw-r--r--net/ipv6/esp6.c14
-rw-r--r--net/ipv6/exthdrs.c101
-rw-r--r--net/ipv6/exthdrs_core.c5
-rw-r--r--net/ipv6/fib6_rules.c18
-rw-r--r--net/ipv6/icmp.c27
-rw-r--r--net/ipv6/inet6_connection_sock.c2
-rw-r--r--net/ipv6/ip6_fib.c25
-rw-r--r--net/ipv6/ip6_flowlabel.c29
-rw-r--r--net/ipv6/ip6_input.c9
-rw-r--r--net/ipv6/ip6_output.c23
-rw-r--r--net/ipv6/ip6_tunnel.c62
-rw-r--r--net/ipv6/ip6mr.c14
-rw-r--r--net/ipv6/ipcomp6.c15
-rw-r--r--net/ipv6/ipv6_sockglue.c3
-rw-r--r--net/ipv6/mcast.c71
-rw-r--r--net/ipv6/mip6.c32
-rw-r--r--net/ipv6/ndisc.c252
-rw-r--r--net/ipv6/netfilter/Kconfig22
-rw-r--r--net/ipv6/netfilter/Makefile1
-rw-r--r--net/ipv6/netfilter/ip6_queue.c641
-rw-r--r--net/ipv6/netfilter/ip6_tables.c41
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c6
-rw-r--r--net/ipv6/netfilter/ip6t_ah.c4
-rw-r--r--net/ipv6/netfilter/ip6t_frag.c4
-rw-r--r--net/ipv6/netfilter/ip6t_hbh.c4
-rw-r--r--net/ipv6/netfilter/ip6t_rt.c4
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c3
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c12
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c12
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c13
-rw-r--r--net/ipv6/raw.c10
-rw-r--r--net/ipv6/reassembly.c47
-rw-r--r--net/ipv6/route.c74
-rw-r--r--net/ipv6/sit.c70
-rw-r--r--net/ipv6/sysctl_net_ipv6.c83
-rw-r--r--net/ipv6/tcp_ipv6.c75
-rw-r--r--net/ipv6/tunnel6.c10
-rw-r--r--net/ipv6/udp.c180
-rw-r--r--net/ipv6/xfrm6_policy.c4
-rw-r--r--net/ipv6/xfrm6_tunnel.c6
-rw-r--r--net/ipx/af_ipx.c14
-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/Makefile3
-rw-r--r--net/l2tp/l2tp_core.c525
-rw-r--r--net/l2tp/l2tp_core.h57
-rw-r--r--net/l2tp/l2tp_debugfs.c14
-rw-r--r--net/l2tp/l2tp_eth.c15
-rw-r--r--net/l2tp/l2tp_ip.c101
-rw-r--r--net/l2tp/l2tp_ip6.c787
-rw-r--r--net/l2tp/l2tp_netlink.c194
-rw-r--r--net/l2tp/l2tp_ppp.c206
-rw-r--r--net/lapb/lapb_iface.c22
-rw-r--r--net/lapb/lapb_in.c320
-rw-r--r--net/lapb/lapb_out.c38
-rw-r--r--net/lapb/lapb_subr.c28
-rw-r--r--net/lapb/lapb_timer.c32
-rw-r--r--net/llc/af_llc.c16
-rw-r--r--net/llc/llc_conn.c2
-rw-r--r--net/llc/llc_output.c3
-rw-r--r--net/llc/llc_sap.c4
-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.c31
-rw-r--r--net/mac80211/agg-tx.c57
-rw-r--r--net/mac80211/cfg.c267
-rw-r--r--net/mac80211/chan.c26
-rw-r--r--net/mac80211/debugfs_netdev.c87
-rw-r--r--net/mac80211/debugfs_sta.c5
-rw-r--r--net/mac80211/driver-ops.h78
-rw-r--r--net/mac80211/driver-trace.h70
-rw-r--r--net/mac80211/ht.c17
-rw-r--r--net/mac80211/ibss.c44
-rw-r--r--net/mac80211/ieee80211_i.h80
-rw-r--r--net/mac80211/iface.c172
-rw-r--r--net/mac80211/main.c16
-rw-r--r--net/mac80211/mesh.c74
-rw-r--r--net/mac80211/mesh.h37
-rw-r--r--net/mac80211/mesh_hwmp.c47
-rw-r--r--net/mac80211/mesh_pathtbl.c14
-rw-r--r--net/mac80211/mesh_plink.c237
-rw-r--r--net/mac80211/mesh_sync.c316
-rw-r--r--net/mac80211/mlme.c379
-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.c62
-rw-r--r--net/mac80211/scan.c140
-rw-r--r--net/mac80211/sta_info.c34
-rw-r--r--net/mac80211/sta_info.h14
-rw-r--r--net/mac80211/status.c10
-rw-r--r--net/mac80211/tx.c113
-rw-r--r--net/mac80211/util.c251
-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/mac802154/Kconfig16
-rw-r--r--net/mac802154/Makefile2
-rw-r--r--net/mac802154/ieee802154_dev.c294
-rw-r--r--net/mac802154/mac802154.h109
-rw-r--r--net/mac802154/mac_cmd.c45
-rw-r--r--net/mac802154/mib.c93
-rw-r--r--net/mac802154/monitor.c116
-rw-r--r--net/mac802154/rx.c114
-rw-r--r--net/mac802154/tx.c116
-rw-r--r--net/netfilter/Kconfig15
-rw-r--r--net/netfilter/Makefile1
-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.c47
-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.c104
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c32
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c214
-rw-r--r--net/netfilter/ipvs/ip_vs_dh.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_ftp.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_lblc.c11
-rw-r--r--net/netfilter/ipvs/ip_vs_lblcr.c11
-rw-r--r--net/netfilter/ipvs/ip_vs_proto.c18
-rw-r--r--net/netfilter/ipvs/ip_vs_sh.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c668
-rw-r--r--net/netfilter/ipvs/ip_vs_wrr.c2
-rw-r--r--net/netfilter/nf_conntrack_acct.c4
-rw-r--r--net/netfilter/nf_conntrack_amanda.c3
-rw-r--r--net/netfilter/nf_conntrack_core.c25
-rw-r--r--net/netfilter/nf_conntrack_ecache.c13
-rw-r--r--net/netfilter/nf_conntrack_expect.c4
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c15
-rw-r--r--net/netfilter/nf_conntrack_helper.c122
-rw-r--r--net/netfilter/nf_conntrack_irc.c8
-rw-r--r--net/netfilter/nf_conntrack_netlink.c93
-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.c71
-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.c68
-rw-r--r--net/netfilter/xt_CT.c1
-rw-r--r--net/netfilter/xt_HMARK.c362
-rw-r--r--net/netfilter/xt_TCPMSS.c10
-rw-r--r--net/netfilter/xt_TPROXY.c4
-rw-r--r--net/netfilter/xt_hashlimit.c132
-rw-r--r--net/netfilter/xt_limit.c5
-rw-r--r--net/netfilter/xt_mac.c2
-rw-r--r--net/netfilter/xt_recent.c2
-rw-r--r--net/netfilter/xt_set.c15
-rw-r--r--net/netfilter/xt_socket.c4
-rw-r--r--net/netlink/af_netlink.c75
-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.c10
-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/Kconfig22
-rw-r--r--net/sched/Makefile2
-rw-r--r--net/sched/act_api.c9
-rw-r--r--net/sched/act_csum.c8
-rw-r--r--net/sched/act_gact.c9
-rw-r--r--net/sched/act_ipt.c21
-rw-r--r--net/sched/act_mirred.c11
-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.c43
-rw-r--r--net/sched/em_meta.c19
-rw-r--r--net/sched/ematch.c10
-rw-r--r--net/sched/sch_api.c19
-rw-r--r--net/sched/sch_atm.c25
-rw-r--r--net/sched/sch_cbq.c18
-rw-r--r--net/sched/sch_choke.c13
-rw-r--r--net/sched/sch_codel.c276
-rw-r--r--net/sched/sch_drr.c7
-rw-r--r--net/sched/sch_dsmark.c21
-rw-r--r--net/sched/sch_fifo.c3
-rw-r--r--net/sched/sch_fq_codel.c626
-rw-r--r--net/sched/sch_generic.c14
-rw-r--r--net/sched/sch_gred.c18
-rw-r--r--net/sched/sch_hfsc.c8
-rw-r--r--net/sched/sch_htb.c12
-rw-r--r--net/sched/sch_mqprio.c3
-rw-r--r--net/sched/sch_multiq.c3
-rw-r--r--net/sched/sch_netem.c39
-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/sched/sch_teql.c4
-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.c9
-rw-r--r--net/sctp/sm_statefuns.c22
-rw-r--r--net/sctp/socket.c6
-rw-r--r--net/sctp/sysctl.c10
-rw-r--r--net/socket.c64
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c2
-rw-r--r--net/sunrpc/cache.c2
-rw-r--r--net/sunrpc/svc.c18
-rw-r--r--net/sunrpc/svc_xprt.c13
-rw-r--r--net/sunrpc/svcsock.c30
-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.c49
-rw-r--r--net/tipc/Makefile2
-rw-r--r--net/tipc/addr.c3
-rw-r--r--net/tipc/addr.h19
-rw-r--r--net/tipc/bcast.c22
-rw-r--r--net/tipc/bcast.h3
-rw-r--r--net/tipc/bearer.c24
-rw-r--r--net/tipc/bearer.h4
-rw-r--r--net/tipc/config.c30
-rw-r--r--net/tipc/config.h1
-rw-r--r--net/tipc/core.c11
-rw-r--r--net/tipc/core.h14
-rw-r--r--net/tipc/discover.c14
-rw-r--r--net/tipc/eth_media.c19
-rw-r--r--net/tipc/handler.c1
-rw-r--r--net/tipc/link.c122
-rw-r--r--net/tipc/link.h6
-rw-r--r--net/tipc/log.c14
-rw-r--r--net/tipc/log.h1
-rw-r--r--net/tipc/msg.c3
-rw-r--r--net/tipc/msg.h21
-rw-r--r--net/tipc/name_distr.c130
-rw-r--r--net/tipc/name_table.c98
-rw-r--r--net/tipc/name_table.h3
-rw-r--r--net/tipc/net.c9
-rw-r--r--net/tipc/node.c17
-rw-r--r--net/tipc/node.h2
-rw-r--r--net/tipc/node_subscr.c5
-rw-r--r--net/tipc/node_subscr.h1
-rw-r--r--net/tipc/port.c130
-rw-r--r--net/tipc/port.h14
-rw-r--r--net/tipc/ref.c13
-rw-r--r--net/tipc/socket.c103
-rw-r--r--net/tipc/subscr.c45
-rw-r--r--net/tipc/subscr.h2
-rw-r--r--net/unix/af_unix.c36
-rw-r--r--net/unix/diag.c2
-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/ethtool.c29
-rw-r--r--net/wireless/ibss.c2
-rw-r--r--net/wireless/lib80211_crypt_ccmp.c33
-rw-r--r--net/wireless/lib80211_crypt_tkip.c50
-rw-r--r--net/wireless/mesh.c4
-rw-r--r--net/wireless/mlme.c58
-rw-r--r--net/wireless/nl80211.c1284
-rw-r--r--net/wireless/nl80211.h4
-rw-r--r--net/wireless/reg.c10
-rw-r--r--net/wireless/scan.c10
-rw-r--r--net/wireless/util.c21
-rw-r--r--net/wireless/wext-compat.c3
-rw-r--r--net/wireless/wext-core.c9
-rw-r--r--net/wireless/wext-sme.c2
-rw-r--r--net/wireless/wext-spy.c2
-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/Kconfig13
-rw-r--r--net/xfrm/Makefile3
-rw-r--r--net/xfrm/xfrm_algo.c5
-rw-r--r--net/xfrm/xfrm_hash.h8
-rw-r--r--net/xfrm/xfrm_policy.c27
-rw-r--r--net/xfrm/xfrm_sysctl.c2
-rw-r--r--net/xfrm/xfrm_user.c105
543 files changed, 18656 insertions, 11997 deletions
diff --git a/net/802/Makefile b/net/802/Makefile
index 7893d679910..a30d6e385ae 100644
--- a/net/802/Makefile
+++ b/net/802/Makefile
@@ -4,7 +4,6 @@
# Check the p8022 selections against net/core/Makefile.
obj-$(CONFIG_LLC) += p8022.o psnap.o
-obj-$(CONFIG_TR) += p8022.o psnap.o tr.o
obj-$(CONFIG_NET_FC) += fc.o
obj-$(CONFIG_FDDI) += fddi.o
obj-$(CONFIG_HIPPI) += hippi.o
diff --git a/net/802/fc.c b/net/802/fc.c
index b324e31401a..05eea6b98bb 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 5ab25cd4314..9cda40661e0 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 a5c22483043..8456f5d98b8 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 056794e6637..51a1f530417 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/p8022.c b/net/802/p8022.c
index 7f353c4f437..0bda8de7df5 100644
--- a/net/802/p8022.c
+++ b/net/802/p8022.c
@@ -1,6 +1,5 @@
/*
- * NET3: Support for 802.2 demultiplexing off Ethernet (Token ring
- * is kept separate see p8022tr.c)
+ * NET3: Support for 802.2 demultiplexing off Ethernet
* 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
diff --git a/net/802/stp.c b/net/802/stp.c
index 15540b7323c..2c40ba0ec11 100644
--- a/net/802/stp.c
+++ b/net/802/stp.c
@@ -46,7 +46,7 @@ static int stp_pdu_rcv(struct sk_buff *skb, struct net_device *dev,
proto = rcu_dereference(garp_protos[eh->h_dest[5] -
GARP_ADDR_MIN]);
if (proto &&
- compare_ether_addr(eh->h_dest, proto->group_address))
+ !ether_addr_equal(eh->h_dest, proto->group_address))
goto err;
} else
proto = rcu_dereference(stp_proto);
diff --git a/net/802/tr.c b/net/802/tr.c
deleted file mode 100644
index b9a3a145e34..00000000000
--- a/net/802/tr.c
+++ /dev/null
@@ -1,676 +0,0 @@
-/*
- * NET3: Token ring device handling subroutines
- *
- * 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.
- *
- * Fixes: 3 Feb 97 Paul Norton <pnorton@cts.com> Minor routing fixes.
- * Added rif table to /proc/net/tr_rif and rif timeout to
- * /proc/sys/net/token-ring/rif_timeout.
- * 22 Jun 98 Paul Norton <p.norton@computer.org> Rearranged
- * tr_header and tr_type_trans to handle passing IPX SNAP and
- * 802.2 through the correct layers. Eliminated tr_reformat.
- *
- */
-
-#include <asm/uaccess.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/trdevice.h>
-#include <linux/skbuff.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/net.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/init.h>
-#include <linux/sysctl.h>
-#include <linux/slab.h>
-#include <net/arp.h>
-#include <net/net_namespace.h>
-
-static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev);
-static void rif_check_expire(unsigned long dummy);
-
-#define TR_SR_DEBUG 0
-
-/*
- * Each RIF entry we learn is kept this way
- */
-
-struct rif_cache {
- unsigned char addr[TR_ALEN];
- int iface;
- __be16 rcf;
- __be16 rseg[8];
- struct rif_cache *next;
- unsigned long last_used;
- unsigned char local_ring;
-};
-
-#define RIF_TABLE_SIZE 32
-
-/*
- * We hash the RIF cache 32 ways. We do after all have to look it
- * up a lot.
- */
-
-static struct rif_cache *rif_table[RIF_TABLE_SIZE];
-
-static DEFINE_SPINLOCK(rif_lock);
-
-
-/*
- * Garbage disposal timer.
- */
-
-static struct timer_list rif_timer;
-
-static int sysctl_tr_rif_timeout = 60*10*HZ;
-
-static inline unsigned long rif_hash(const unsigned char *addr)
-{
- unsigned long x;
-
- x = addr[0];
- x = (x << 2) ^ addr[1];
- x = (x << 2) ^ addr[2];
- x = (x << 2) ^ addr[3];
- x = (x << 2) ^ addr[4];
- x = (x << 2) ^ addr[5];
-
- x ^= x >> 8;
-
- return x & (RIF_TABLE_SIZE - 1);
-}
-
-/*
- * Put the headers on a token ring packet. Token ring source routing
- * makes this a little more exciting than on ethernet.
- */
-
-static int tr_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type,
- const void *daddr, const void *saddr, unsigned len)
-{
- struct trh_hdr *trh;
- int hdr_len;
-
- /*
- * Add the 802.2 SNAP header if IP as the IPv4/IPv6 code calls
- * dev->hard_header directly.
- */
- if (type == ETH_P_IP || type == ETH_P_IPV6 || type == ETH_P_ARP)
- {
- struct trllc *trllc;
-
- hdr_len = sizeof(struct trh_hdr) + sizeof(struct trllc);
- trh = (struct trh_hdr *)skb_push(skb, hdr_len);
- trllc = (struct trllc *)(trh+1);
- trllc->dsap = trllc->ssap = EXTENDED_SAP;
- trllc->llc = UI_CMD;
- trllc->protid[0] = trllc->protid[1] = trllc->protid[2] = 0x00;
- trllc->ethertype = htons(type);
- }
- else
- {
- hdr_len = sizeof(struct trh_hdr);
- trh = (struct trh_hdr *)skb_push(skb, hdr_len);
- }
-
- trh->ac=AC;
- trh->fc=LLC_FRAME;
-
- if(saddr)
- memcpy(trh->saddr,saddr,dev->addr_len);
- else
- memcpy(trh->saddr,dev->dev_addr,dev->addr_len);
-
- /*
- * Build the destination and then source route the frame
- */
-
- if(daddr)
- {
- memcpy(trh->daddr,daddr,dev->addr_len);
- tr_source_route(skb, trh, dev);
- return hdr_len;
- }
-
- return -hdr_len;
-}
-
-/*
- * A neighbour discovery of some species (eg arp) has completed. We
- * can now send the packet.
- */
-
-static int tr_rebuild_header(struct sk_buff *skb)
-{
- struct trh_hdr *trh=(struct trh_hdr *)skb->data;
- struct trllc *trllc=(struct trllc *)(skb->data+sizeof(struct trh_hdr));
- struct net_device *dev = skb->dev;
-
- /*
- * FIXME: We don't yet support IPv6 over token rings
- */
-
- if(trllc->ethertype != htons(ETH_P_IP)) {
- printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n", ntohs(trllc->ethertype));
- return 0;
- }
-
-#ifdef CONFIG_INET
- if(arp_find(trh->daddr, skb)) {
- return 1;
- }
- else
-#endif
- {
- tr_source_route(skb,trh,dev);
- return 0;
- }
-}
-
-/*
- * Some of this is a bit hackish. We intercept RIF information
- * used for source routing. We also grab IP directly and don't feed
- * it via SNAP.
- */
-
-__be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
-
- struct trh_hdr *trh;
- struct trllc *trllc;
- unsigned riflen=0;
-
- skb->dev = dev;
- skb_reset_mac_header(skb);
- trh = tr_hdr(skb);
-
- if(trh->saddr[0] & TR_RII)
- riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
-
- trllc = (struct trllc *)(skb->data+sizeof(struct trh_hdr)-TR_MAXRIFLEN+riflen);
-
- skb_pull(skb,sizeof(struct trh_hdr)-TR_MAXRIFLEN+riflen);
-
- if(*trh->daddr & 0x80)
- {
- if(!memcmp(trh->daddr,dev->broadcast,TR_ALEN))
- skb->pkt_type=PACKET_BROADCAST;
- else
- skb->pkt_type=PACKET_MULTICAST;
- }
- else if ( (trh->daddr[0] & 0x01) && (trh->daddr[1] & 0x00) && (trh->daddr[2] & 0x5E))
- {
- skb->pkt_type=PACKET_MULTICAST;
- }
- else if(dev->flags & IFF_PROMISC)
- {
- if(memcmp(trh->daddr, dev->dev_addr, TR_ALEN))
- skb->pkt_type=PACKET_OTHERHOST;
- }
-
- if ((skb->pkt_type != PACKET_BROADCAST) &&
- (skb->pkt_type != PACKET_MULTICAST))
- tr_add_rif_info(trh,dev) ;
-
- /*
- * Strip the SNAP header from ARP packets since we don't
- * pass them through to the 802.2/SNAP layers.
- */
-
- if (trllc->dsap == EXTENDED_SAP &&
- (trllc->ethertype == htons(ETH_P_IP) ||
- trllc->ethertype == htons(ETH_P_IPV6) ||
- trllc->ethertype == htons(ETH_P_ARP)))
- {
- skb_pull(skb, sizeof(struct trllc));
- return trllc->ethertype;
- }
-
- return htons(ETH_P_TR_802_2);
-}
-
-/*
- * We try to do source routing...
- */
-
-void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,
- struct net_device *dev)
-{
- int slack;
- unsigned int hash;
- struct rif_cache *entry;
- unsigned char *olddata;
- unsigned long flags;
- static const unsigned char mcast_func_addr[]
- = {0xC0,0x00,0x00,0x04,0x00,0x00};
-
- spin_lock_irqsave(&rif_lock, flags);
-
- /*
- * Broadcasts are single route as stated in RFC 1042
- */
- if( (!memcmp(&(trh->daddr[0]),&(dev->broadcast[0]),TR_ALEN)) ||
- (!memcmp(&(trh->daddr[0]),&(mcast_func_addr[0]), TR_ALEN)) )
- {
- trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK)
- | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
- trh->saddr[0]|=TR_RII;
- }
- else
- {
- hash = rif_hash(trh->daddr);
- /*
- * Walk the hash table and look for an entry
- */
- for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->daddr[0]),TR_ALEN);entry=entry->next);
-
- /*
- * If we found an entry we can route the frame.
- */
- if(entry)
- {
-#if TR_SR_DEBUG
-printk("source routing for %pM\n", trh->daddr);
-#endif
- if(!entry->local_ring && (ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8)
- {
- trh->rcf=entry->rcf;
- memcpy(&trh->rseg[0],&entry->rseg[0],8*sizeof(unsigned short));
- trh->rcf^=htons(TR_RCF_DIR_BIT);
- trh->rcf&=htons(0x1fff); /* Issam Chehab <ichehab@madge1.demon.co.uk> */
-
- trh->saddr[0]|=TR_RII;
-#if TR_SR_DEBUG
- printk("entry found with rcf %04x\n", entry->rcf);
- }
- else
- {
- printk("entry found but without rcf length, local=%02x\n", entry->local_ring);
-#endif
- }
- entry->last_used=jiffies;
- }
- else
- {
- /*
- * Without the information we simply have to shout
- * on the wire. The replies should rapidly clean this
- * situation up.
- */
- trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK)
- | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
- trh->saddr[0]|=TR_RII;
-#if TR_SR_DEBUG
- printk("no entry in rif table found - broadcasting frame\n");
-#endif
- }
- }
-
- /* Compress the RIF here so we don't have to do it in the driver(s) */
- if (!(trh->saddr[0] & 0x80))
- slack = 18;
- else
- slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8);
- olddata = skb->data;
- spin_unlock_irqrestore(&rif_lock, flags);
-
- skb_pull(skb, slack);
- memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack);
-}
-
-/*
- * We have learned some new RIF information for our source
- * routing.
- */
-
-static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev)
-{
- unsigned int hash, rii_p = 0;
- unsigned long flags;
- struct rif_cache *entry;
- unsigned char saddr0;
-
- spin_lock_irqsave(&rif_lock, flags);
- saddr0 = trh->saddr[0];
-
- /*
- * Firstly see if the entry exists
- */
-
- if(trh->saddr[0] & TR_RII)
- {
- trh->saddr[0]&=0x7f;
- if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2)
- {
- rii_p = 1;
- }
- }
-
- hash = rif_hash(trh->saddr);
- for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);entry=entry->next);
-
- if(entry==NULL)
- {
-#if TR_SR_DEBUG
- printk("adding rif_entry: addr:%pM rcf:%04X\n",
- trh->saddr, ntohs(trh->rcf));
-#endif
- /*
- * Allocate our new entry. A failure to allocate loses
- * use the information. This is harmless.
- *
- * FIXME: We ought to keep some kind of cache size
- * limiting and adjust the timers to suit.
- */
- entry=kmalloc(sizeof(struct rif_cache),GFP_ATOMIC);
-
- if(!entry)
- {
- printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n");
- spin_unlock_irqrestore(&rif_lock, flags);
- return;
- }
-
- memcpy(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);
- entry->iface = dev->ifindex;
- entry->next=rif_table[hash];
- entry->last_used=jiffies;
- rif_table[hash]=entry;
-
- if (rii_p)
- {
- entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK);
- memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
- entry->local_ring = 0;
- }
- else
- {
- entry->local_ring = 1;
- }
- }
- else /* Y. Tahara added */
- {
- /*
- * Update existing entries
- */
- if (!entry->local_ring)
- if (entry->rcf != (trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK)) &&
- !(trh->rcf & htons(TR_RCF_BROADCAST_MASK)))
- {
-#if TR_SR_DEBUG
-printk("updating rif_entry: addr:%pM rcf:%04X\n",
- trh->saddr, ntohs(trh->rcf));
-#endif
- entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK);
- memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
- }
- entry->last_used=jiffies;
- }
- trh->saddr[0]=saddr0; /* put the routing indicator back for tcpdump */
- spin_unlock_irqrestore(&rif_lock, flags);
-}
-
-/*
- * Scan the cache with a timer and see what we need to throw out.
- */
-
-static void rif_check_expire(unsigned long dummy)
-{
- int i;
- unsigned long flags, next_interval = jiffies + sysctl_tr_rif_timeout/2;
-
- spin_lock_irqsave(&rif_lock, flags);
-
- for(i =0; i < RIF_TABLE_SIZE; i++) {
- struct rif_cache *entry, **pentry;
-
- pentry = rif_table+i;
- while((entry=*pentry) != NULL) {
- unsigned long expires
- = entry->last_used + sysctl_tr_rif_timeout;
-
- if (time_before_eq(expires, jiffies)) {
- *pentry = entry->next;
- kfree(entry);
- } else {
- pentry = &entry->next;
-
- if (time_before(expires, next_interval))
- next_interval = expires;
- }
- }
- }
-
- spin_unlock_irqrestore(&rif_lock, flags);
-
- mod_timer(&rif_timer, next_interval);
-
-}
-
-/*
- * Generate the /proc/net information for the token ring RIF
- * routing.
- */
-
-#ifdef CONFIG_PROC_FS
-
-static struct rif_cache *rif_get_idx(loff_t pos)
-{
- int i;
- struct rif_cache *entry;
- loff_t off = 0;
-
- for(i = 0; i < RIF_TABLE_SIZE; i++)
- for(entry = rif_table[i]; entry; entry = entry->next) {
- if (off == pos)
- return entry;
- ++off;
- }
-
- return NULL;
-}
-
-static void *rif_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(&rif_lock)
-{
- spin_lock_irq(&rif_lock);
-
- return *pos ? rif_get_idx(*pos - 1) : SEQ_START_TOKEN;
-}
-
-static void *rif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- int i;
- struct rif_cache *ent = v;
-
- ++*pos;
-
- if (v == SEQ_START_TOKEN) {
- i = -1;
- goto scan;
- }
-
- if (ent->next)
- return ent->next;
-
- i = rif_hash(ent->addr);
- scan:
- while (++i < RIF_TABLE_SIZE) {
- if ((ent = rif_table[i]) != NULL)
- return ent;
- }
- return NULL;
-}
-
-static void rif_seq_stop(struct seq_file *seq, void *v)
- __releases(&rif_lock)
-{
- spin_unlock_irq(&rif_lock);
-}
-
-static int rif_seq_show(struct seq_file *seq, void *v)
-{
- int j, rcf_len, segment, brdgnmb;
- struct rif_cache *entry = v;
-
- if (v == SEQ_START_TOKEN)
- seq_puts(seq,
- "if TR address TTL rcf routing segments\n");
- else {
- struct net_device *dev = dev_get_by_index(&init_net, entry->iface);
- long ttl = (long) (entry->last_used + sysctl_tr_rif_timeout)
- - (long) jiffies;
-
- seq_printf(seq, "%s %pM %7li ",
- dev?dev->name:"?",
- entry->addr,
- ttl/HZ);
-
- if (entry->local_ring)
- seq_puts(seq, "local\n");
- else {
-
- seq_printf(seq, "%04X", ntohs(entry->rcf));
- rcf_len = ((ntohs(entry->rcf) & TR_RCF_LEN_MASK)>>8)-2;
- if (rcf_len)
- rcf_len >>= 1;
- for(j = 1; j < rcf_len; j++) {
- if(j==1) {
- segment=ntohs(entry->rseg[j-1])>>4;
- seq_printf(seq," %03X",segment);
- }
-
- segment=ntohs(entry->rseg[j])>>4;
- brdgnmb=ntohs(entry->rseg[j-1])&0x00f;
- seq_printf(seq,"-%01X-%03X",brdgnmb,segment);
- }
- seq_putc(seq, '\n');
- }
-
- if (dev)
- dev_put(dev);
- }
- return 0;
-}
-
-
-static const struct seq_operations rif_seq_ops = {
- .start = rif_seq_start,
- .next = rif_seq_next,
- .stop = rif_seq_stop,
- .show = rif_seq_show,
-};
-
-static int rif_seq_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &rif_seq_ops);
-}
-
-static const struct file_operations rif_seq_fops = {
- .owner = THIS_MODULE,
- .open = rif_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-#endif
-
-static const struct header_ops tr_header_ops = {
- .create = tr_header,
- .rebuild= tr_rebuild_header,
-};
-
-static void tr_setup(struct net_device *dev)
-{
- /*
- * Configure and register
- */
-
- dev->header_ops = &tr_header_ops;
-
- dev->type = ARPHRD_IEEE802_TR;
- dev->hard_header_len = TR_HLEN;
- dev->mtu = 2000;
- dev->addr_len = TR_ALEN;
- dev->tx_queue_len = 100; /* Long queues on tr */
-
- memset(dev->broadcast,0xFF, TR_ALEN);
-
- /* New-style flags. */
- dev->flags = IFF_BROADCAST | IFF_MULTICAST ;
-}
-
-/**
- * alloc_trdev - Register token ring device
- * @sizeof_priv: Size of additional driver-private structure to be allocated
- * for this token ring device
- *
- * Fill in the fields of the device structure with token ring-generic values.
- *
- * Constructs a new net device, complete with a private data area of
- * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for
- * this private data area.
- */
-struct net_device *alloc_trdev(int sizeof_priv)
-{
- return alloc_netdev(sizeof_priv, "tr%d", tr_setup);
-}
-
-#ifdef CONFIG_SYSCTL
-static struct ctl_table tr_table[] = {
- {
- .procname = "rif_timeout",
- .data = &sysctl_tr_rif_timeout,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
- { },
-};
-
-static __initdata struct ctl_path tr_path[] = {
- { .procname = "net", },
- { .procname = "token-ring", },
- { }
-};
-#endif
-
-/*
- * Called during bootup. We don't actually have to initialise
- * too much for this.
- */
-
-static int __init rif_init(void)
-{
- rif_timer.expires = jiffies + sysctl_tr_rif_timeout;
- setup_timer(&rif_timer, rif_check_expire, 0);
- add_timer(&rif_timer);
-#ifdef CONFIG_SYSCTL
- register_sysctl_paths(tr_path, tr_table);
-#endif
- proc_net_fops_create(&init_net, "tr_rif", S_IRUGO, &rif_seq_fops);
- return 0;
-}
-
-module_init(rif_init);
-
-EXPORT_SYMBOL(tr_type_trans);
-EXPORT_SYMBOL(alloc_trdev);
-
-MODULE_LICENSE("GPL");
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index efea35b02e7..6089f0cf23b 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -266,19 +266,19 @@ static void vlan_sync_address(struct net_device *dev,
struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
/* May be called without an actual change */
- if (!compare_ether_addr(vlan->real_dev_addr, dev->dev_addr))
+ if (ether_addr_equal(vlan->real_dev_addr, dev->dev_addr))
return;
/* vlan address was different from the old address and is equal to
* the new address */
- if (compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
- !compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
+ if (!ether_addr_equal(vlandev->dev_addr, vlan->real_dev_addr) &&
+ ether_addr_equal(vlandev->dev_addr, dev->dev_addr))
dev_uc_del(dev, vlandev->dev_addr);
/* vlan address was equal to the old address and is different from
* the new address */
- if (!compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
- compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
+ if (ether_addr_equal(vlandev->dev_addr, vlan->real_dev_addr) &&
+ !ether_addr_equal(vlandev->dev_addr, dev->dev_addr))
dev_uc_add(dev, vlandev->dev_addr);
memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN);
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 4d39d802be2..8ca533c95de 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -31,8 +31,7 @@ bool vlan_do_receive(struct sk_buff **skbp, bool last_handler)
/* Our lower layer thinks this is not local, let's make sure.
* This allows the VLAN to have a different MAC than the
* underlying device, and still route correctly. */
- if (!compare_ether_addr(eth_hdr(skb)->h_dest,
- vlan_dev->dev_addr))
+ if (ether_addr_equal(eth_hdr(skb)->h_dest, vlan_dev->dev_addr))
skb->pkt_type = PACKET_HOST;
}
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 9757c193c86..da1bc9c3cf3 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -277,7 +277,7 @@ static int vlan_dev_open(struct net_device *dev)
!(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
return -ENETDOWN;
- if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) {
+ if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr)) {
err = dev_uc_add(real_dev, dev->dev_addr);
if (err < 0)
goto out;
@@ -307,7 +307,7 @@ clear_allmulti:
if (dev->flags & IFF_ALLMULTI)
dev_set_allmulti(real_dev, -1);
del_unicast:
- if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
+ if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
dev_uc_del(real_dev, dev->dev_addr);
out:
netif_carrier_off(dev);
@@ -326,7 +326,7 @@ static int vlan_dev_stop(struct net_device *dev)
if (dev->flags & IFF_PROMISC)
dev_set_promiscuity(real_dev, -1);
- if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
+ if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
dev_uc_del(real_dev, dev->dev_addr);
netif_carrier_off(dev);
@@ -345,13 +345,13 @@ static int vlan_dev_set_mac_address(struct net_device *dev, void *p)
if (!(dev->flags & IFF_UP))
goto out;
- if (compare_ether_addr(addr->sa_data, real_dev->dev_addr)) {
+ if (!ether_addr_equal(addr->sa_data, real_dev->dev_addr)) {
err = dev_uc_add(real_dev, addr->sa_data);
if (err < 0)
return err;
}
- if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
+ if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
dev_uc_del(real_dev, dev->dev_addr);
out:
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index 50711368ad6..708c80ea187 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 b23a17c431c..a170893d70e 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 fccae26fa67..6449bae1570 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/Kconfig b/net/Kconfig
index e07272d0bb2..1e47bd03dde 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -207,10 +207,10 @@ source "net/ipx/Kconfig"
source "drivers/net/appletalk/Kconfig"
source "net/x25/Kconfig"
source "net/lapb/Kconfig"
-source "net/econet/Kconfig"
source "net/wanrouter/Kconfig"
source "net/phonet/Kconfig"
source "net/ieee802154/Kconfig"
+source "net/mac802154/Kconfig"
source "net/sched/Kconfig"
source "net/dcb/Kconfig"
source "net/dns_resolver/Kconfig"
@@ -295,7 +295,7 @@ config NET_TCPPROBE
module will be called tcp_probe.
config NET_DROP_MONITOR
- boolean "Network packet drop alerting service"
+ tristate "Network packet drop alerting service"
depends on INET && EXPERIMENTAL && TRACEPOINTS
---help---
This feature provides an alerting service to userspace in the
diff --git a/net/Makefile b/net/Makefile
index ad432fa4d93..4f4ee083064 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -40,7 +40,6 @@ obj-$(CONFIG_AF_RXRPC) += rxrpc/
obj-$(CONFIG_ATM) += atm/
obj-$(CONFIG_L2TP) += l2tp/
obj-$(CONFIG_DECNET) += decnet/
-obj-$(CONFIG_ECONET) += econet/
obj-$(CONFIG_PHONET) += phonet/
ifneq ($(CONFIG_VLAN_8021Q),)
obj-y += 8021q/
@@ -60,6 +59,7 @@ ifneq ($(CONFIG_DCB),)
obj-y += dcb/
endif
obj-$(CONFIG_IEEE802154) += ieee802154/
+obj-$(CONFIG_MAC802154) += mac802154/
ifeq ($(CONFIG_NET),y)
obj-$(CONFIG_SYSCTL) += sysctl_net.o
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index bfa9ab93eda..0301b328cf0 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 04e9c0da7aa..ebb864361f7 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 353fccf1cde..4819d31533e 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/ioctl.c b/net/atm/ioctl.c
index 62dc8bfe6fe..bbd3b639992 100644
--- a/net/atm/ioctl.c
+++ b/net/atm/ioctl.c
@@ -97,9 +97,8 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
error = sock_get_timestampns(sk, argp);
goto done;
case ATM_SETSC:
- if (net_ratelimit())
- pr_warning("ATM_SETSC is obsolete; used by %s:%d\n",
- current->comm, task_pid_nr(current));
+ net_warn_ratelimited("ATM_SETSC is obsolete; used by %s:%d\n",
+ current->comm, task_pid_nr(current));
error = 0;
goto done;
case ATMSIGD_CTRL:
@@ -123,8 +122,7 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
work for 32-bit userspace. TBH I don't really want
to think about it at all. dwmw2. */
if (compat) {
- if (net_ratelimit())
- pr_warning("32-bit task cannot be atmsigd\n");
+ net_warn_ratelimited("32-bit task cannot be atmsigd\n");
error = -EINVAL;
goto done;
}
diff --git a/net/atm/lec.c b/net/atm/lec.c
index f1964caa0f8..a7d172105c9 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -26,11 +26,6 @@
#include <linux/spinlock.h>
#include <linux/seq_file.h>
-/* TokenRing if needed */
-#ifdef CONFIG_TR
-#include <linux/trdevice.h>
-#endif
-
/* And atm device */
#include <linux/atmdev.h>
#include <linux/atmlec.h>
@@ -163,50 +158,6 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
/*
- * Modelled after tr_type_trans
- * All multicast and ARE or STE frames go to BUS.
- * Non source routed frames go by destination address.
- * Last hop source routed frames go by destination address.
- * Not last hop source routed frames go by _next_ route descriptor.
- * Returns pointer to destination MAC address or fills in rdesc
- * and returns NULL.
- */
-#ifdef CONFIG_TR
-static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
-{
- struct trh_hdr *trh;
- unsigned int riflen, num_rdsc;
-
- trh = (struct trh_hdr *)packet;
- if (trh->daddr[0] & (uint8_t) 0x80)
- return bus_mac; /* multicast */
-
- if (trh->saddr[0] & TR_RII) {
- riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
- if ((ntohs(trh->rcf) >> 13) != 0)
- return bus_mac; /* ARE or STE */
- } else
- return trh->daddr; /* not source routed */
-
- if (riflen < 6)
- return trh->daddr; /* last hop, source routed */
-
- /* riflen is 6 or more, packet has more than one route descriptor */
- num_rdsc = (riflen / 2) - 1;
- memset(rdesc, 0, ETH_ALEN);
- /* offset 4 comes from LAN destination field in LE control frames */
- if (trh->rcf & htons((uint16_t) TR_RCF_DIR_BIT))
- memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(__be16));
- else {
- memcpy(&rdesc[4], &trh->rseg[1], sizeof(__be16));
- rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0));
- }
-
- return NULL;
-}
-#endif /* CONFIG_TR */
-
-/*
* Open/initialize the netdevice. This is called (in the current kernel)
* sometime after booting when the 'ifconfig' program is run.
*
@@ -257,9 +208,6 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
struct lec_arp_table *entry;
unsigned char *dst;
int min_frame_size;
-#ifdef CONFIG_TR
- unsigned char rdesc[ETH_ALEN]; /* Token Ring route descriptor */
-#endif
int is_rdesc;
pr_debug("called\n");
@@ -290,24 +238,10 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
}
skb_push(skb, 2);
- /* Put le header to place, works for TokenRing too */
+ /* Put le header to place */
lec_h = (struct lecdatahdr_8023 *)skb->data;
lec_h->le_header = htons(priv->lecid);
-#ifdef CONFIG_TR
- /*
- * Ugly. Use this to realign Token Ring packets for
- * e.g. PCA-200E driver.
- */
- if (priv->is_trdev) {
- skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
- kfree_skb(skb);
- if (skb2 == NULL)
- return NETDEV_TX_OK;
- skb = skb2;
- }
-#endif
-
#if DUMP_PACKETS >= 2
#define MAX_DUMP_SKB 99
#elif DUMP_PACKETS >= 1
@@ -321,12 +255,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
#endif /* DUMP_PACKETS >= 1 */
/* Minimum ethernet-frame size */
-#ifdef CONFIG_TR
- if (priv->is_trdev)
- min_frame_size = LEC_MINIMUM_8025_SIZE;
- else
-#endif
- min_frame_size = LEC_MINIMUM_8023_SIZE;
+ min_frame_size = LEC_MINIMUM_8023_SIZE;
if (skb->len < min_frame_size) {
if ((skb->len + skb_tailroom(skb)) < min_frame_size) {
skb2 = skb_copy_expand(skb, 0,
@@ -345,15 +274,6 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
/* Send to right vcc */
is_rdesc = 0;
dst = lec_h->h_dest;
-#ifdef CONFIG_TR
- if (priv->is_trdev) {
- dst = get_tr_dst(skb->data + 2, rdesc);
- if (dst == NULL) {
- dst = rdesc;
- is_rdesc = 1;
- }
- }
-#endif
entry = NULL;
vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
pr_debug("%s:vcc:%p vcc_flags:%lx, entry:%p\n",
@@ -710,12 +630,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
dev_kfree_skb(skb);
return;
}
-#ifdef CONFIG_TR
- if (priv->is_trdev)
- dst = ((struct lecdatahdr_8025 *)skb->data)->h_dest;
- else
-#endif
- dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest;
+ dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest;
/*
* If this is a Data Direct VCC, and the VCC does not match
@@ -723,16 +638,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
*/
spin_lock_irqsave(&priv->lec_arp_lock, flags);
if (lec_is_data_direct(vcc)) {
-#ifdef CONFIG_TR
- if (priv->is_trdev)
- src =
- ((struct lecdatahdr_8025 *)skb->data)->
- h_source;
- else
-#endif
- src =
- ((struct lecdatahdr_8023 *)skb->data)->
- h_source;
+ src = ((struct lecdatahdr_8023 *)skb->data)->h_source;
entry = lec_arp_find(priv, src);
if (entry && entry->vcc != vcc) {
lec_arp_remove(priv, entry);
@@ -750,12 +656,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
if (!hlist_empty(&priv->lec_arp_empty_ones))
lec_arp_check_empties(priv, vcc, skb);
skb_pull(skb, 2); /* skip lec_id */
-#ifdef CONFIG_TR
- if (priv->is_trdev)
- skb->protocol = tr_type_trans(skb, dev);
- else
-#endif
- skb->protocol = eth_type_trans(skb, dev);
+ skb->protocol = eth_type_trans(skb, dev);
dev->stats.rx_packets++;
dev->stats.rx_bytes += skb->len;
memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
@@ -827,27 +728,13 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
i = 0;
else
i = arg;
-#ifdef CONFIG_TR
if (arg >= MAX_LEC_ITF)
return -EINVAL;
-#else /* Reserve the top NUM_TR_DEVS for TR */
- if (arg >= (MAX_LEC_ITF - NUM_TR_DEVS))
- return -EINVAL;
-#endif
if (!dev_lec[i]) {
- int is_trdev, size;
-
- is_trdev = 0;
- if (i >= (MAX_LEC_ITF - NUM_TR_DEVS))
- is_trdev = 1;
+ int size;
size = sizeof(struct lec_priv);
-#ifdef CONFIG_TR
- if (is_trdev)
- dev_lec[i] = alloc_trdev(size);
- else
-#endif
- dev_lec[i] = alloc_etherdev(size);
+ dev_lec[i] = alloc_etherdev(size);
if (!dev_lec[i])
return -ENOMEM;
dev_lec[i]->netdev_ops = &lec_netdev_ops;
@@ -858,7 +745,6 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
}
priv = netdev_priv(dev_lec[i]);
- priv->is_trdev = is_trdev;
} else {
priv = netdev_priv(dev_lec[i]);
if (priv->lecd)
@@ -1255,7 +1141,7 @@ static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst,
struct sk_buff *skb;
struct lec_priv *priv = netdev_priv(dev);
- if (compare_ether_addr(lan_dst, dev->dev_addr))
+ if (!ether_addr_equal(lan_dst, dev->dev_addr))
return 0; /* not our mac address */
kfree(priv->tlvs); /* NULL if there was no previous association */
@@ -1662,7 +1548,7 @@ static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])];
hlist_for_each_entry(entry, node, head, next) {
- if (!compare_ether_addr(mac_addr, entry->mac_addr))
+ if (ether_addr_equal(mac_addr, entry->mac_addr))
return entry;
}
return NULL;
@@ -1849,7 +1735,7 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
case 1:
return priv->mcast_vcc;
case 2: /* LANE2 wants arp for multicast addresses */
- if (!compare_ether_addr(mac_to_find, bus_mac))
+ if (ether_addr_equal(mac_to_find, bus_mac))
return priv->mcast_vcc;
break;
default:
@@ -2372,15 +2258,7 @@ lec_arp_check_empties(struct lec_priv *priv,
struct hlist_node *node, *next;
struct lec_arp_table *entry, *tmp;
struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
- unsigned char *src;
-#ifdef CONFIG_TR
- struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
-
- if (priv->is_trdev)
- src = tr_hdr->h_source;
- else
-#endif
- src = hdr->h_source;
+ unsigned char *src = hdr->h_source;
spin_lock_irqsave(&priv->lec_arp_lock, flags);
hlist_for_each_entry_safe(entry, node, next,
diff --git a/net/atm/lec.h b/net/atm/lec.h
index dfc07196646..c730e57de19 100644
--- a/net/atm/lec.h
+++ b/net/atm/lec.h
@@ -142,7 +142,6 @@ struct lec_priv {
int itfnum; /* e.g. 2 for lec2, 5 for lec5 */
struct lane2_ops *lane2_ops; /* can be NULL for LANE v1 */
int is_proxy; /* bridge between ATM and Ethernet */
- int is_trdev; /* Device type, 0 = Ethernet, 1 = TokenRing */
};
struct lec_vcc_priv {
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index aa972409f09..d4cc1be5c36 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -592,8 +592,7 @@ static netdev_tx_t mpc_send_packet(struct sk_buff *skb,
goto non_ip;
while (i < mpc->number_of_mps_macs) {
- if (!compare_ether_addr(eth->h_dest,
- (mpc->mps_macs + i*ETH_ALEN)))
+ if (ether_addr_equal(eth->h_dest, mpc->mps_macs + i * ETH_ALEN))
if (send_via_shortcut(skb, mpc) == 0) /* try shortcut */
return NETDEV_TX_OK;
i++;
diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c
index 53e50029227..5bdd300db0f 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 614d3fc47ed..ce1e59fdae7 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 509c8ac02b6..86767ca908a 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 9d9a6a3edbd..051f7abae66 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 d0de30e8959..3d106767b27 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 846ae4e2b11..67de6b33f2c 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 ebe0ef3f1d8..d5744b75251 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 2b68d068eaf..53f5244e28f 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 4e392ebedb6..6d5c1940667 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 c3b0548b175..3b588f86d77 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;
@@ -82,8 +83,8 @@ int debug_log(struct bat_priv *bat_priv, const char *fmt, ...)
va_start(args, fmt);
vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
- fdebug_log(bat_priv->debug_log, "[%10lu] %s",
- (jiffies / HZ), tmp_log_buf);
+ fdebug_log(bat_priv->debug_log, "[%10u] %s",
+ jiffies_to_msecs(jiffies), tmp_log_buf);
va_end(args);
return 0;
@@ -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 a6d5d63fb6a..dc53798ebb4 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -30,33 +30,69 @@
#include "send.h"
#include "bat_algo.h"
-static void bat_iv_ogm_init(struct hard_iface *hard_iface)
+static struct neigh_node *bat_iv_ogm_neigh_new(struct hard_iface *hard_iface,
+ const uint8_t *neigh_addr,
+ struct orig_node *orig_node,
+ struct orig_node *orig_neigh,
+ uint32_t seqno)
+{
+ struct neigh_node *neigh_node;
+
+ neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr, seqno);
+ if (!neigh_node)
+ goto out;
+
+ INIT_LIST_HEAD(&neigh_node->bonding_list);
+
+ neigh_node->orig_node = orig_neigh;
+ neigh_node->if_incoming = hard_iface;
+
+ spin_lock_bh(&orig_node->neigh_list_lock);
+ hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
+ spin_unlock_bh(&orig_node->neigh_list_lock);
+
+out:
+ return neigh_node;
+}
+
+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_init_primary(struct hard_iface *hard_iface)
+static void bat_iv_ogm_iface_disable(struct hard_iface *hard_iface)
{
- struct batman_ogm_packet *batman_ogm_packet;
-
- batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
- batman_ogm_packet->flags = PRIMARIES_FIRST_HOP;
- batman_ogm_packet->header.ttl = TTL;
+ kfree(hard_iface->packet_buff);
+ hard_iface->packet_buff = NULL;
}
-static void bat_iv_ogm_update_mac(struct hard_iface *hard_iface)
+static void bat_iv_ogm_iface_update_mac(struct hard_iface *hard_iface)
{
struct batman_ogm_packet *batman_ogm_packet;
@@ -67,6 +103,15 @@ static void bat_iv_ogm_update_mac(struct hard_iface *hard_iface)
hard_iface->net_dev->dev_addr, ETH_ALEN);
}
+static void bat_iv_ogm_primary_iface_set(struct hard_iface *hard_iface)
+{
+ struct batman_ogm_packet *batman_ogm_packet;
+
+ batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
+ batman_ogm_packet->flags = PRIMARIES_FIRST_HOP;
+ batman_ogm_packet->header.ttl = TTL;
+}
+
/* when do we schedule our own ogm to be sent */
static unsigned long bat_iv_ogm_emit_send_time(const struct bat_priv *bat_priv)
{
@@ -92,7 +137,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 +177,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 +187,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 +236,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 +380,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 +390,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);
@@ -461,11 +505,11 @@ static void bat_iv_ogm_queue_add(struct bat_priv *bat_priv,
static void bat_iv_ogm_forward(struct orig_node *orig_node,
const struct ethhdr *ethhdr,
struct batman_ogm_packet *batman_ogm_packet,
- int directlink, struct hard_iface *if_incoming)
+ bool is_single_hop_neigh,
+ bool is_from_best_next_hop,
+ struct hard_iface *if_incoming)
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct neigh_node *router;
- uint8_t in_tq, in_ttl, tq_avg = 0;
uint8_t tt_num_changes;
if (batman_ogm_packet->header.ttl <= 1) {
@@ -473,54 +517,43 @@ static void bat_iv_ogm_forward(struct orig_node *orig_node,
return;
}
- router = orig_node_get_router(orig_node);
+ if (!is_from_best_next_hop) {
+ /* Mark the forwarded packet when it is not coming from our
+ * best next hop. We still need to forward the packet for our
+ * neighbor link quality detection to work in case the packet
+ * originated from a single hop neighbor. Otherwise we can
+ * simply drop the ogm.
+ */
+ if (is_single_hop_neigh)
+ batman_ogm_packet->flags |= NOT_BEST_NEXT_HOP;
+ else
+ return;
+ }
- in_tq = batman_ogm_packet->tq;
- in_ttl = batman_ogm_packet->header.ttl;
tt_num_changes = batman_ogm_packet->tt_num_changes;
batman_ogm_packet->header.ttl--;
memcpy(batman_ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
- /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
- * of our best tq value */
- if (router && router->tq_avg != 0) {
-
- /* rebroadcast ogm of best ranking neighbor as is */
- if (!compare_eth(router->addr, ethhdr->h_source)) {
- batman_ogm_packet->tq = router->tq_avg;
-
- if (router->last_ttl)
- batman_ogm_packet->header.ttl =
- router->last_ttl - 1;
- }
-
- tq_avg = router->tq_avg;
- }
-
- if (router)
- neigh_node_free_ref(router);
-
/* apply hop penalty */
batman_ogm_packet->tq = hop_penalty(batman_ogm_packet->tq, bat_priv);
bat_dbg(DBG_BATMAN, bat_priv,
- "Forwarding packet: tq_orig: %i, tq_avg: %i, tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n",
- in_tq, tq_avg, batman_ogm_packet->tq, in_ttl - 1,
- batman_ogm_packet->header.ttl);
+ "Forwarding packet: tq: %i, ttl: %i\n",
+ batman_ogm_packet->tq, batman_ogm_packet->header.ttl);
batman_ogm_packet->seqno = htonl(batman_ogm_packet->seqno);
batman_ogm_packet->tt_crc = htons(batman_ogm_packet->tt_crc);
/* switch of primaries first hop flag when forwarding */
batman_ogm_packet->flags &= ~PRIMARIES_FIRST_HOP;
- if (directlink)
+ if (is_single_hop_neigh)
batman_ogm_packet->flags |= DIRECTLINK;
else
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());
}
@@ -603,12 +636,12 @@ static void bat_iv_ogm_orig_update(struct bat_priv *bat_priv,
if (is_duplicate)
continue;
- spin_lock_bh(&tmp_neigh_node->tq_lock);
+ spin_lock_bh(&tmp_neigh_node->lq_update_lock);
ring_buffer_set(tmp_neigh_node->tq_recv,
&tmp_neigh_node->tq_index, 0);
tmp_neigh_node->tq_avg =
ring_buffer_avg(tmp_neigh_node->tq_recv);
- spin_unlock_bh(&tmp_neigh_node->tq_lock);
+ spin_unlock_bh(&tmp_neigh_node->lq_update_lock);
}
if (!neigh_node) {
@@ -618,8 +651,9 @@ static void bat_iv_ogm_orig_update(struct bat_priv *bat_priv,
if (!orig_tmp)
goto unlock;
- neigh_node = create_neighbor(orig_node, orig_tmp,
- ethhdr->h_source, if_incoming);
+ neigh_node = bat_iv_ogm_neigh_new(if_incoming, ethhdr->h_source,
+ orig_node, orig_tmp,
+ batman_ogm_packet->seqno);
orig_node_free_ref(orig_tmp);
if (!neigh_node)
@@ -631,14 +665,14 @@ static void bat_iv_ogm_orig_update(struct bat_priv *bat_priv,
rcu_read_unlock();
orig_node->flags = batman_ogm_packet->flags;
- neigh_node->last_valid = jiffies;
+ neigh_node->last_seen = jiffies;
- spin_lock_bh(&neigh_node->tq_lock);
+ spin_lock_bh(&neigh_node->lq_update_lock);
ring_buffer_set(neigh_node->tq_recv,
&neigh_node->tq_index,
batman_ogm_packet->tq);
neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
- spin_unlock_bh(&neigh_node->tq_lock);
+ spin_unlock_bh(&neigh_node->lq_update_lock);
if (!is_duplicate) {
orig_node->last_ttl = batman_ogm_packet->header.ttl;
@@ -744,19 +778,20 @@ static int bat_iv_ogm_calc_tq(struct orig_node *orig_node,
rcu_read_unlock();
if (!neigh_node)
- neigh_node = create_neighbor(orig_neigh_node,
- orig_neigh_node,
- orig_neigh_node->orig,
- if_incoming);
+ neigh_node = bat_iv_ogm_neigh_new(if_incoming,
+ orig_neigh_node->orig,
+ orig_neigh_node,
+ orig_neigh_node,
+ batman_ogm_packet->seqno);
if (!neigh_node)
goto out;
- /* if orig_node is direct neighbor update neigh_node last_valid */
+ /* if orig_node is direct neighbor update neigh_node last_seen */
if (orig_node == orig_neigh_node)
- neigh_node->last_valid = jiffies;
+ neigh_node->last_seen = jiffies;
- orig_node->last_valid = jiffies;
+ orig_node->last_seen = jiffies;
/* find packet count of corresponding one hop neighbor */
spin_lock_bh(&orig_node->ogm_cnt_lock);
@@ -842,7 +877,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 +886,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 +902,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;
}
@@ -897,7 +934,9 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
struct neigh_node *orig_neigh_router = NULL;
int has_directlink_flag;
int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
- int is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
+ int is_broadcast = 0, is_bidirectional;
+ bool is_single_hop_neigh = false;
+ bool is_from_best_next_hop = false;
int is_duplicate;
uint32_t if_incoming_seqno;
@@ -913,7 +952,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() */
@@ -921,11 +960,11 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
has_directlink_flag = (batman_ogm_packet->flags & DIRECTLINK ? 1 : 0);
- is_single_hop_neigh = (compare_eth(ethhdr->h_source,
- batman_ogm_packet->orig) ? 1 : 0);
+ if (compare_eth(ethhdr->h_source, batman_ogm_packet->orig))
+ is_single_hop_neigh = true;
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 +1037,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);
}
@@ -1019,6 +1058,13 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
return;
}
+ if (batman_ogm_packet->flags & NOT_BEST_NEXT_HOP) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n",
+ ethhdr->h_source);
+ return;
+ }
+
orig_node = get_orig_node(bat_priv, batman_ogm_packet->orig);
if (!orig_node)
return;
@@ -1043,6 +1089,10 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
if (router)
router_router = orig_node_get_router(router->orig_node);
+ if ((router && router->tq_avg != 0) &&
+ (compare_eth(router->addr, ethhdr->h_source)))
+ is_from_best_next_hop = true;
+
/* avoid temporary routing loops */
if (router && router_router &&
(compare_eth(router->addr, batman_ogm_packet->prev_sender)) &&
@@ -1093,7 +1143,8 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
/* mark direct link on incoming interface */
bat_iv_ogm_forward(orig_node, ethhdr, batman_ogm_packet,
- 1, if_incoming);
+ is_single_hop_neigh, is_from_best_next_hop,
+ if_incoming);
bat_dbg(DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast neighbor packet with direct link flag\n");
@@ -1116,7 +1167,8 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
bat_dbg(DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast originator packet\n");
bat_iv_ogm_forward(orig_node, ethhdr, batman_ogm_packet,
- 0, if_incoming);
+ is_single_hop_neigh, is_from_best_next_hop,
+ if_incoming);
out_neigh:
if ((orig_neigh_node) && (!is_single_hop_neigh))
@@ -1132,13 +1184,25 @@ out:
orig_node_free_ref(orig_node);
}
-static void bat_iv_ogm_receive(struct hard_iface *if_incoming,
- struct sk_buff *skb)
+static int bat_iv_ogm_receive(struct sk_buff *skb,
+ struct hard_iface *if_incoming)
{
+ struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct batman_ogm_packet *batman_ogm_packet;
struct ethhdr *ethhdr;
int buff_pos = 0, packet_len;
unsigned char *tt_buff, *packet_buff;
+ bool ret;
+
+ ret = check_management_packet(skb, if_incoming, BATMAN_OGM_HLEN);
+ if (!ret)
+ return NET_RX_DROP;
+
+ /* did we receive a B.A.T.M.A.N. IV OGM packet on an interface
+ * that does not have B.A.T.M.A.N. IV enabled ?
+ */
+ if (bat_priv->bat_algo_ops->bat_ogm_emit != bat_iv_ogm_emit)
+ return NET_RX_DROP;
packet_len = skb_headlen(skb);
ethhdr = (struct ethhdr *)skb_mac_header(skb);
@@ -1152,31 +1216,50 @@ 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 *)
(packet_buff + buff_pos);
} while (bat_iv_ogm_aggr_packet(buff_pos, packet_len,
batman_ogm_packet->tt_num_changes));
+
+ kfree_skb(skb);
+ return NET_RX_SUCCESS;
}
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_ogm_update_mac = bat_iv_ogm_update_mac,
+ .bat_iface_enable = bat_iv_ogm_iface_enable,
+ .bat_iface_disable = bat_iv_ogm_iface_disable,
+ .bat_iface_update_mac = bat_iv_ogm_iface_update_mac,
+ .bat_primary_iface_set = bat_iv_ogm_primary_iface_set,
.bat_ogm_schedule = bat_iv_ogm_schedule,
.bat_ogm_emit = bat_iv_ogm_emit,
- .bat_ogm_receive = bat_iv_ogm_receive,
};
int __init bat_iv_init(void)
{
- return bat_algo_register(&batman_iv);
+ int ret;
+
+ /* batman originator packet */
+ ret = recv_handler_register(BAT_IV_OGM, bat_iv_ogm_receive);
+ if (ret < 0)
+ goto out;
+
+ ret = bat_algo_register(&batman_iv);
+ if (ret < 0)
+ goto handler_unregister;
+
+ goto out;
+
+handler_unregister:
+ recv_handler_unregister(BAT_IV_OGM);
+out:
+ return ret;
}
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c
index 68ff759fc30..5bc7b66d32d 100644
--- a/net/batman-adv/bat_sysfs.c
+++ b/net/batman-adv/bat_sysfs.c
@@ -63,7 +63,7 @@ struct bat_attribute bat_attr_##_name = { \
.store = _store, \
};
-#define BAT_ATTR_STORE_BOOL(_name, _post_func) \
+#define BAT_ATTR_SIF_STORE_BOOL(_name, _post_func) \
ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \
char *buff, size_t count) \
{ \
@@ -73,9 +73,9 @@ ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \
&bat_priv->_name, net_dev); \
}
-#define BAT_ATTR_SHOW_BOOL(_name) \
-ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \
- char *buff) \
+#define BAT_ATTR_SIF_SHOW_BOOL(_name) \
+ssize_t show_##_name(struct kobject *kobj, \
+ struct attribute *attr, char *buff) \
{ \
struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \
return sprintf(buff, "%s\n", \
@@ -83,16 +83,17 @@ ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \
"disabled" : "enabled"); \
} \
-/* Use this, if you are going to turn a [name] in bat_priv on or off */
-#define BAT_ATTR_BOOL(_name, _mode, _post_func) \
- static BAT_ATTR_STORE_BOOL(_name, _post_func) \
- static BAT_ATTR_SHOW_BOOL(_name) \
+/* Use this, if you are going to turn a [name] in the soft-interface
+ * (bat_priv) on or off */
+#define BAT_ATTR_SIF_BOOL(_name, _mode, _post_func) \
+ static BAT_ATTR_SIF_STORE_BOOL(_name, _post_func) \
+ static BAT_ATTR_SIF_SHOW_BOOL(_name) \
static BAT_ATTR(_name, _mode, show_##_name, store_##_name)
-#define BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \
+#define BAT_ATTR_SIF_STORE_UINT(_name, _min, _max, _post_func) \
ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \
- char *buff, size_t count) \
+ char *buff, size_t count) \
{ \
struct net_device *net_dev = kobj_to_netdev(kobj); \
struct bat_priv *bat_priv = netdev_priv(net_dev); \
@@ -100,19 +101,62 @@ ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \
attr, &bat_priv->_name, net_dev); \
}
-#define BAT_ATTR_SHOW_UINT(_name) \
-ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \
- char *buff) \
+#define BAT_ATTR_SIF_SHOW_UINT(_name) \
+ssize_t show_##_name(struct kobject *kobj, \
+ struct attribute *attr, char *buff) \
{ \
struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \
return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \
} \
-/* Use this, if you are going to set [name] in bat_priv to unsigned integer
- * values only */
-#define BAT_ATTR_UINT(_name, _mode, _min, _max, _post_func) \
- static BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \
- static BAT_ATTR_SHOW_UINT(_name) \
+/* Use this, if you are going to set [name] in the soft-interface
+ * (bat_priv) to an unsigned integer value */
+#define BAT_ATTR_SIF_UINT(_name, _mode, _min, _max, _post_func) \
+ static BAT_ATTR_SIF_STORE_UINT(_name, _min, _max, _post_func) \
+ static BAT_ATTR_SIF_SHOW_UINT(_name) \
+ static BAT_ATTR(_name, _mode, show_##_name, store_##_name)
+
+
+#define BAT_ATTR_HIF_STORE_UINT(_name, _min, _max, _post_func) \
+ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \
+ char *buff, size_t count) \
+{ \
+ struct net_device *net_dev = kobj_to_netdev(kobj); \
+ struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); \
+ ssize_t length; \
+ \
+ if (!hard_iface) \
+ return 0; \
+ \
+ length = __store_uint_attr(buff, count, _min, _max, _post_func, \
+ attr, &hard_iface->_name, net_dev); \
+ \
+ hardif_free_ref(hard_iface); \
+ return length; \
+}
+
+#define BAT_ATTR_HIF_SHOW_UINT(_name) \
+ssize_t show_##_name(struct kobject *kobj, \
+ struct attribute *attr, char *buff) \
+{ \
+ struct net_device *net_dev = kobj_to_netdev(kobj); \
+ struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); \
+ ssize_t length; \
+ \
+ if (!hard_iface) \
+ return 0; \
+ \
+ length = sprintf(buff, "%i\n", atomic_read(&hard_iface->_name));\
+ \
+ hardif_free_ref(hard_iface); \
+ return length; \
+}
+
+/* Use this, if you are going to set [name] in hard_iface to an
+ * unsigned integer value*/
+#define BAT_ATTR_HIF_UINT(_name, _mode, _min, _max, _post_func) \
+ static BAT_ATTR_HIF_STORE_UINT(_name, _min, _max, _post_func) \
+ static BAT_ATTR_HIF_SHOW_UINT(_name) \
static BAT_ATTR(_name, _mode, show_##_name, store_##_name)
@@ -149,7 +193,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 +312,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 +398,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;
}
@@ -384,26 +428,32 @@ static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr,
return gw_bandwidth_set(net_dev, buff, count);
}
-BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
-BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
-BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu);
-BAT_ATTR_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL);
+BAT_ATTR_SIF_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
+BAT_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
+#ifdef CONFIG_BATMAN_ADV_BLA
+BAT_ATTR_SIF_BOOL(bridge_loop_avoidance, S_IRUGO | S_IWUSR, NULL);
+#endif
+BAT_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu);
+BAT_ATTR_SIF_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL);
static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
static BAT_ATTR(routing_algo, S_IRUGO, show_bat_algo, NULL);
static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode);
-BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL);
-BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL);
-BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
- post_gw_deselect);
+BAT_ATTR_SIF_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL);
+BAT_ATTR_SIF_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL);
+BAT_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
+ post_gw_deselect);
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_SIF_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 6d0aa216b23..07ae6e1b8ac 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 c6135728a68..1835c15cda4 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 00000000000..8bf97515a77
--- /dev/null
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -0,0 +1,1580 @@
+/*
+ * Copyright (C) 2011-2012 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 00000000000..e39f93acc28
--- /dev/null
+++ b/net/batman-adv/bridge_loop_avoidance.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011-2012 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/gateway_client.c b/net/batman-adv/gateway_client.c
index 6f9b9b78f77..47f7186dcef 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -558,10 +558,10 @@ static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
p++;
/* ...and then we jump over the data */
- if (pkt_len < *p)
+ if (pkt_len < 1 + (*p))
goto out;
- pkt_len -= *p;
- p += (*p);
+ pkt_len -= 1 + (*p);
+ p += 1 + (*p);
}
}
out:
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 377897701a8..dc334fa8984 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -28,15 +28,10 @@
#include "bat_sysfs.h"
#include "originator.h"
#include "hash.h"
+#include "bridge_loop_avoidance.h"
#include <linux/if_arp.h>
-
-static int batman_skb_recv(struct sk_buff *skb,
- struct net_device *dev,
- struct packet_type *ptype,
- struct net_device *orig_dev);
-
void hardif_free_rcu(struct rcu_head *rcu)
{
struct hard_iface *hard_iface;
@@ -107,7 +102,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 +118,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 +137,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_primary_iface_set(new_hard_iface);
+ primary_if_update_addr(bat_priv, curr_hard_iface);
- bat_priv->bat_algo_ops->bat_ogm_init_primary(new_hard_iface);
- primary_if_update_addr(bat_priv);
+out:
+ if (curr_hard_iface)
+ hardif_free_ref(curr_hard_iface);
}
static bool hardif_is_iface_up(const struct hard_iface *hard_iface)
@@ -175,9 +173,9 @@ static void check_known_mac_addr(const struct net_device *net_dev)
net_dev->dev_addr))
continue;
- pr_warning("The newly added mac address (%pM) already exists on: %s\n",
- net_dev->dev_addr, hard_iface->net_dev->name);
- pr_warning("It is strongly recommended to keep mac addresses unique to avoid problems!\n");
+ pr_warn("The newly added mac address (%pM) already exists on: %s\n",
+ net_dev->dev_addr, hard_iface->net_dev->name);
+ pr_warn("It is strongly recommended to keep mac addresses unique to avoid problems!\n");
}
rcu_read_unlock();
}
@@ -230,7 +228,7 @@ static void hardif_activate_interface(struct hard_iface *hard_iface)
bat_priv = netdev_priv(hard_iface->soft_iface);
- bat_priv->bat_algo_ops->bat_ogm_update_mac(hard_iface);
+ bat_priv->bat_algo_ops->bat_iface_update_mac(hard_iface);
hard_iface->if_status = IF_TO_BE_ACTIVATED;
/**
@@ -300,22 +298,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 +321,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 +352,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 +388,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 +440,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:
@@ -524,14 +524,14 @@ static int hard_if_event(struct notifier_block *this,
check_known_mac_addr(hard_iface->net_dev);
bat_priv = netdev_priv(hard_iface->soft_iface);
- bat_priv->bat_algo_ops->bat_ogm_update_mac(hard_iface);
+ bat_priv->bat_algo_ops->bat_iface_update_mac(hard_iface);
primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
goto hardif_put;
if (hard_iface == primary_if)
- primary_if_update_addr(bat_priv);
+ primary_if_update_addr(bat_priv, NULL);
break;
default:
break;
@@ -545,114 +545,6 @@ out:
return NOTIFY_DONE;
}
-/* incoming packets with the batman ethertype received on any active hard
- * interface */
-static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype,
- struct net_device *orig_dev)
-{
- struct bat_priv *bat_priv;
- struct batman_ogm_packet *batman_ogm_packet;
- struct hard_iface *hard_iface;
- int ret;
-
- hard_iface = container_of(ptype, struct hard_iface, batman_adv_ptype);
- skb = skb_share_check(skb, GFP_ATOMIC);
-
- /* skb was released by skb_share_check() */
- if (!skb)
- goto err_out;
-
- /* packet should hold at least type and version */
- if (unlikely(!pskb_may_pull(skb, 2)))
- goto err_free;
-
- /* expect a valid ethernet header here. */
- if (unlikely(skb->mac_len != sizeof(struct ethhdr) ||
- !skb_mac_header(skb)))
- goto err_free;
-
- if (!hard_iface->soft_iface)
- goto err_free;
-
- bat_priv = netdev_priv(hard_iface->soft_iface);
-
- if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
- goto err_free;
-
- /* discard frames on not active interfaces */
- if (hard_iface->if_status != IF_ACTIVE)
- goto err_free;
-
- batman_ogm_packet = (struct batman_ogm_packet *)skb->data;
-
- if (batman_ogm_packet->header.version != COMPAT_VERSION) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: incompatible batman version (%i)\n",
- batman_ogm_packet->header.version);
- goto err_free;
- }
-
- /* all receive handlers return whether they received or reused
- * the supplied skb. if not, we have to free the skb. */
-
- switch (batman_ogm_packet->header.packet_type) {
- /* batman originator packet */
- case BAT_OGM:
- ret = recv_bat_ogm_packet(skb, hard_iface);
- break;
-
- /* batman icmp packet */
- case BAT_ICMP:
- ret = recv_icmp_packet(skb, hard_iface);
- break;
-
- /* unicast packet */
- case BAT_UNICAST:
- ret = recv_unicast_packet(skb, hard_iface);
- break;
-
- /* fragmented unicast packet */
- case BAT_UNICAST_FRAG:
- ret = recv_ucast_frag_packet(skb, hard_iface);
- break;
-
- /* broadcast packet */
- case BAT_BCAST:
- ret = recv_bcast_packet(skb, hard_iface);
- break;
-
- /* vis packet */
- case BAT_VIS:
- ret = recv_vis_packet(skb, hard_iface);
- break;
- /* Translation table query (request or response) */
- case BAT_TT_QUERY:
- ret = recv_tt_query(skb, hard_iface);
- break;
- /* Roaming advertisement */
- case BAT_ROAM_ADV:
- ret = recv_roam_adv(skb, hard_iface);
- break;
- default:
- ret = NET_RX_DROP;
- }
-
- if (ret == NET_RX_DROP)
- kfree_skb(skb);
-
- /* return NET_RX_SUCCESS in any case as we
- * most probably dropped the packet for
- * routing-logical reasons. */
-
- return NET_RX_SUCCESS;
-
-err_free:
- kfree_skb(skb);
-err_out:
- return NET_RX_DROP;
-}
-
/* This function returns true if the interface represented by ifindex is a
* 802.11 wireless device */
bool is_wifi_iface(int ifindex)
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c
index b87518edcef..2e98a57f340 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 6d51caaf8ce..083a2993efe 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"
@@ -38,6 +39,7 @@
/* List manipulations on hardif_list have to be rtnl_lock()'ed,
* list traversals just rcu-locked */
struct list_head hardif_list;
+static int (*recv_packet_handler[256])(struct sk_buff *, struct hard_iface *);
char bat_routing_algo[20] = "BATMAN IV";
static struct hlist_head bat_algo_list;
@@ -45,11 +47,15 @@ unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
struct workqueue_struct *bat_event_workqueue;
+static void recv_handler_init(void);
+
static int __init batman_init(void)
{
INIT_LIST_HEAD(&hardif_list);
INIT_HLIST_HEAD(&bat_algo_list);
+ recv_handler_init();
+
bat_iv_init();
/* the name should not be longer than 10 chars - see
@@ -96,13 +102,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 +121,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 +151,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);
}
@@ -178,6 +184,120 @@ int is_my_mac(const uint8_t *addr)
return 0;
}
+static int recv_unhandled_packet(struct sk_buff *skb,
+ struct hard_iface *recv_if)
+{
+ return NET_RX_DROP;
+}
+
+/* incoming packets with the batman ethertype received on any active hard
+ * interface
+ */
+int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *ptype, struct net_device *orig_dev)
+{
+ struct bat_priv *bat_priv;
+ struct batman_ogm_packet *batman_ogm_packet;
+ struct hard_iface *hard_iface;
+ uint8_t idx;
+ int ret;
+
+ hard_iface = container_of(ptype, struct hard_iface, batman_adv_ptype);
+ skb = skb_share_check(skb, GFP_ATOMIC);
+
+ /* skb was released by skb_share_check() */
+ if (!skb)
+ goto err_out;
+
+ /* packet should hold at least type and version */
+ if (unlikely(!pskb_may_pull(skb, 2)))
+ goto err_free;
+
+ /* expect a valid ethernet header here. */
+ if (unlikely(skb->mac_len != ETH_HLEN || !skb_mac_header(skb)))
+ goto err_free;
+
+ if (!hard_iface->soft_iface)
+ goto err_free;
+
+ bat_priv = netdev_priv(hard_iface->soft_iface);
+
+ if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
+ goto err_free;
+
+ /* discard frames on not active interfaces */
+ if (hard_iface->if_status != IF_ACTIVE)
+ goto err_free;
+
+ batman_ogm_packet = (struct batman_ogm_packet *)skb->data;
+
+ if (batman_ogm_packet->header.version != COMPAT_VERSION) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: incompatible batman version (%i)\n",
+ batman_ogm_packet->header.version);
+ goto err_free;
+ }
+
+ /* all receive handlers return whether they received or reused
+ * the supplied skb. if not, we have to free the skb.
+ */
+ idx = batman_ogm_packet->header.packet_type;
+ ret = (*recv_packet_handler[idx])(skb, hard_iface);
+
+ if (ret == NET_RX_DROP)
+ kfree_skb(skb);
+
+ /* return NET_RX_SUCCESS in any case as we
+ * most probably dropped the packet for
+ * routing-logical reasons.
+ */
+ return NET_RX_SUCCESS;
+
+err_free:
+ kfree_skb(skb);
+err_out:
+ return NET_RX_DROP;
+}
+
+static void recv_handler_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(recv_packet_handler); i++)
+ recv_packet_handler[i] = recv_unhandled_packet;
+
+ /* batman icmp packet */
+ recv_packet_handler[BAT_ICMP] = recv_icmp_packet;
+ /* unicast packet */
+ recv_packet_handler[BAT_UNICAST] = recv_unicast_packet;
+ /* fragmented unicast packet */
+ recv_packet_handler[BAT_UNICAST_FRAG] = recv_ucast_frag_packet;
+ /* broadcast packet */
+ recv_packet_handler[BAT_BCAST] = recv_bcast_packet;
+ /* vis packet */
+ recv_packet_handler[BAT_VIS] = recv_vis_packet;
+ /* Translation table query (request or response) */
+ recv_packet_handler[BAT_TT_QUERY] = recv_tt_query;
+ /* Roaming advertisement */
+ recv_packet_handler[BAT_ROAM_ADV] = recv_roam_adv;
+}
+
+int recv_handler_register(uint8_t packet_type,
+ int (*recv_handler)(struct sk_buff *,
+ struct hard_iface *))
+{
+ if (recv_packet_handler[packet_type] != &recv_unhandled_packet)
+ return -EBUSY;
+
+ recv_packet_handler[packet_type] = recv_handler;
+ return 0;
+}
+
+void recv_handler_unregister(uint8_t packet_type)
+{
+ recv_packet_handler[packet_type] = recv_unhandled_packet;
+}
+
static struct bat_algo_ops *bat_algo_get(char *name)
{
struct bat_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp;
@@ -207,12 +327,12 @@ 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 ||
- !bat_algo_ops->bat_ogm_update_mac ||
+ if (!bat_algo_ops->bat_iface_enable ||
+ !bat_algo_ops->bat_iface_disable ||
+ !bat_algo_ops->bat_iface_update_mac ||
+ !bat_algo_ops->bat_primary_iface_set ||
!bat_algo_ops->bat_ogm_schedule ||
- !bat_algo_ops->bat_ogm_emit ||
- !bat_algo_ops->bat_ogm_receive) {
+ !bat_algo_ops->bat_ogm_emit) {
pr_info("Routing algo '%s' does not implement required ops\n",
bat_algo_ops->name);
goto out;
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 94fa1c2393a..f4a3ec00347 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -28,7 +28,7 @@
#define DRIVER_DEVICE "batman-adv"
#ifndef SOURCE_VERSION
-#define SOURCE_VERSION "2012.1.0"
+#define SOURCE_VERSION "2012.2.0"
#endif
/* B.A.T.M.A.N. parameters */
@@ -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 */
@@ -150,6 +155,12 @@ void mesh_free(struct net_device *soft_iface);
void inc_module_count(void);
void dec_module_count(void);
int is_my_mac(const uint8_t *addr);
+int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *ptype, struct net_device *orig_dev);
+int recv_handler_register(uint8_t packet_type,
+ int (*recv_handler)(struct sk_buff *,
+ struct hard_iface *));
+void recv_handler_unregister(uint8_t packet_type);
int bat_algo_register(struct bat_algo_ops *bat_algo_ops);
int bat_algo_select(struct bat_priv *bat_priv, char *name);
int bat_algo_seq_print_text(struct seq_file *seq, void *offset);
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 43c0a4f1399..41147942ba5 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -28,13 +28,15 @@
#include "hard-interface.h"
#include "unicast.h"
#include "soft-interface.h"
+#include "bridge_loop_avoidance.h"
static void purge_orig(struct work_struct *work);
static void start_purge_timer(struct bat_priv *bat_priv)
{
INIT_DELAYED_WORK(&bat_priv->orig_work, purge_orig);
- queue_delayed_work(bat_event_workqueue, &bat_priv->orig_work, 1 * HZ);
+ queue_delayed_work(bat_event_workqueue,
+ &bat_priv->orig_work, msecs_to_jiffies(1000));
}
/* returns 1 if they are the same originator */
@@ -83,35 +85,30 @@ struct neigh_node *orig_node_get_router(struct orig_node *orig_node)
return router;
}
-struct neigh_node *create_neighbor(struct orig_node *orig_node,
- struct orig_node *orig_neigh_node,
- const uint8_t *neigh,
- struct hard_iface *if_incoming)
+struct neigh_node *batadv_neigh_node_new(struct hard_iface *hard_iface,
+ const uint8_t *neigh_addr,
+ uint32_t seqno)
{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+ struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct neigh_node *neigh_node;
- bat_dbg(DBG_BATMAN, bat_priv,
- "Creating new last-hop neighbor of originator\n");
-
neigh_node = kzalloc(sizeof(*neigh_node), GFP_ATOMIC);
if (!neigh_node)
- return NULL;
+ goto out;
INIT_HLIST_NODE(&neigh_node->list);
- INIT_LIST_HEAD(&neigh_node->bonding_list);
- spin_lock_init(&neigh_node->tq_lock);
- memcpy(neigh_node->addr, neigh, ETH_ALEN);
- neigh_node->orig_node = orig_neigh_node;
- neigh_node->if_incoming = if_incoming;
+ memcpy(neigh_node->addr, neigh_addr, ETH_ALEN);
+ spin_lock_init(&neigh_node->lq_update_lock);
/* extra reference for return */
atomic_set(&neigh_node->refcount, 2);
- spin_lock_bh(&orig_node->neigh_list_lock);
- hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
- spin_unlock_bh(&orig_node->neigh_list_lock);
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Creating new neighbor %pM, initial seqno %d\n",
+ neigh_addr, seqno);
+
+out:
return neigh_node;
}
@@ -273,6 +270,7 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
struct hlist_node *node, *node_tmp;
struct neigh_node *neigh_node;
bool neigh_purged = false;
+ unsigned long last_seen;
*best_neigh_node = NULL;
@@ -282,11 +280,13 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
hlist_for_each_entry_safe(neigh_node, node, node_tmp,
&orig_node->neigh_list, list) {
- if ((has_timed_out(neigh_node->last_valid, PURGE_TIMEOUT)) ||
+ if ((has_timed_out(neigh_node->last_seen, PURGE_TIMEOUT)) ||
(neigh_node->if_incoming->if_status == IF_INACTIVE) ||
(neigh_node->if_incoming->if_status == IF_NOT_IN_USE) ||
(neigh_node->if_incoming->if_status == IF_TO_BE_REMOVED)) {
+ last_seen = neigh_node->last_seen;
+
if ((neigh_node->if_incoming->if_status ==
IF_INACTIVE) ||
(neigh_node->if_incoming->if_status ==
@@ -299,9 +299,9 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
neigh_node->if_incoming->net_dev->name);
else
bat_dbg(DBG_BATMAN, bat_priv,
- "neighbor timeout: originator %pM, neighbor: %pM, last_valid: %lu\n",
+ "neighbor timeout: originator %pM, neighbor: %pM, last_seen: %u\n",
orig_node->orig, neigh_node->addr,
- (neigh_node->last_valid / HZ));
+ jiffies_to_msecs(last_seen));
neigh_purged = true;
@@ -324,10 +324,11 @@ static bool purge_orig_node(struct bat_priv *bat_priv,
{
struct neigh_node *best_neigh_node;
- if (has_timed_out(orig_node->last_valid, 2 * PURGE_TIMEOUT)) {
+ if (has_timed_out(orig_node->last_seen, 2 * PURGE_TIMEOUT)) {
bat_dbg(DBG_BATMAN, bat_priv,
- "Originator timeout: originator %pM, last_valid %lu\n",
- orig_node->orig, (orig_node->last_valid / HZ));
+ "Originator timeout: originator %pM, last_seen %u\n",
+ orig_node->orig,
+ jiffies_to_msecs(orig_node->last_seen));
return true;
} else {
if (purge_orig_neighbors(bat_priv, orig_node,
@@ -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)
@@ -447,9 +446,9 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
goto next;
last_seen_secs = jiffies_to_msecs(jiffies -
- orig_node->last_valid) / 1000;
+ orig_node->last_seen) / 1000;
last_seen_msecs = jiffies_to_msecs(jiffies -
- orig_node->last_valid) % 1000;
+ orig_node->last_seen) % 1000;
seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:",
orig_node->orig, last_seen_secs,
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index 3fe2eda8565..f74d0d69335 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -29,10 +29,9 @@ void originator_free(struct bat_priv *bat_priv);
void purge_orig_ref(struct bat_priv *bat_priv);
void orig_node_free_ref(struct orig_node *orig_node);
struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr);
-struct neigh_node *create_neighbor(struct orig_node *orig_node,
- struct orig_node *orig_neigh_node,
- const uint8_t *neigh,
- struct hard_iface *if_incoming);
+struct neigh_node *batadv_neigh_node_new(struct hard_iface *hard_iface,
+ const uint8_t *neigh_addr,
+ uint32_t seqno);
void neigh_node_free_ref(struct neigh_node *neigh_node);
struct neigh_node *orig_node_get_router(struct orig_node *orig_node);
int orig_seq_print_text(struct seq_file *seq, void *offset);
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index 441f3db1bd9..0ee1af77079 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,8 @@ enum bat_packettype {
/* this file is included by batctl which needs these defines */
#define COMPAT_VERSION 14
-enum batman_flags {
+enum batman_iv_flags {
+ NOT_BEST_NEXT_HOP = 1 << 3,
PRIMARIES_FIRST_HOP = 1 << 4,
VIS_SERVER = 1 << 5,
DIRECTLINK = 1 << 6
@@ -90,6 +91,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 +118,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 +127,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 +146,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 +157,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 +174,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 +183,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 7f8e1589941..840e2c64a30 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();
@@ -230,51 +234,46 @@ int window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff,
{
if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) ||
(seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
- if (has_timed_out(*last_reset, RESET_PROTECTION_MS)) {
-
- *last_reset = jiffies;
- bat_dbg(DBG_BATMAN, bat_priv,
- "old packet received, start protection\n");
-
- return 0;
- } else {
+ if (!has_timed_out(*last_reset, RESET_PROTECTION_MS))
return 1;
- }
+
+ *last_reset = jiffies;
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "old packet received, start protection\n");
}
+
return 0;
}
-int recv_bat_ogm_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
+bool check_management_packet(struct sk_buff *skb,
+ struct hard_iface *hard_iface,
+ int header_len)
{
- struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct ethhdr *ethhdr;
/* drop packet if it has not necessary minimum size */
- if (unlikely(!pskb_may_pull(skb, BATMAN_OGM_LEN)))
- return NET_RX_DROP;
+ if (unlikely(!pskb_may_pull(skb, header_len)))
+ return false;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* packet with broadcast indication but unicast recipient */
if (!is_broadcast_ether_addr(ethhdr->h_dest))
- return NET_RX_DROP;
+ return false;
/* packet with broadcast sender address */
if (is_broadcast_ether_addr(ethhdr->h_source))
- return NET_RX_DROP;
+ return false;
/* create a copy of the skb, if needed, to modify it. */
if (skb_cow(skb, 0) < 0)
- return NET_RX_DROP;
+ return false;
/* keep skb linear */
if (skb_linearize(skb) < 0)
- return NET_RX_DROP;
-
- bat_priv->bat_algo_ops->bat_ogm_receive(hard_iface, skb);
+ return false;
- kfree_skb(skb);
- return NET_RX_SUCCESS;
+ return true;
}
static int recv_my_icmp_packet(struct bat_priv *bat_priv,
@@ -309,7 +308,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 +363,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 +449,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 +668,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 +804,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 +836,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;
@@ -907,12 +913,20 @@ static int check_unicast_ttvn(struct bat_priv *bat_priv,
/* Check whether I have to reroute the packet */
if (seq_before(unicast_packet->ttvn, curr_ttvn) || tt_poss_change) {
- /* Linearize the skb before accessing it */
- if (skb_linearize(skb) < 0)
+ /* check if there is enough data before accessing it */
+ if (pskb_may_pull(skb, sizeof(struct unicast_packet) +
+ ETH_HLEN) < 0)
return 0;
ethhdr = (struct ethhdr *)(skb->data +
sizeof(struct unicast_packet));
+
+ /* we don't have an updated route for this client, so we should
+ * not try to reroute the packet!!
+ */
+ if (tt_global_client_is_roaming(bat_priv, ethhdr->h_dest))
+ return 1;
+
orig_node = transtable_search(bat_priv, NULL, ethhdr->h_dest);
if (!orig_node) {
@@ -1047,8 +1061,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 +1079,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 92ac100d83d..d6bbbebb656 100644
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@ -23,15 +23,16 @@
#define _NET_BATMAN_ADV_ROUTING_H_
void slide_own_bcast_window(struct hard_iface *hard_iface);
+bool check_management_packet(struct sk_buff *skb,
+ struct hard_iface *hard_iface,
+ int header_len);
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);
int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if);
-int recv_bat_ogm_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if);
struct neigh_node *find_router(struct bat_priv *bat_priv,
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index af7a6741a68..f47299f22c6 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -45,13 +45,13 @@ int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
goto send_skb_err;
if (!(hard_iface->net_dev->flags & IFF_UP)) {
- pr_warning("Interface %s is not up - can't send packet via that interface!\n",
- hard_iface->net_dev->name);
+ pr_warn("Interface %s is not up - can't send packet via that interface!\n",
+ hard_iface->net_dev->name);
goto send_skb_err;
}
/* 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;
}
@@ -292,7 +292,7 @@ static void send_outstanding_bcast_packet(struct work_struct *work)
/* if we still have some more bcasts to send */
if (forw_packet->num_packets < 3) {
_add_bcast_packet_to_list(bat_priv, forw_packet,
- ((5 * HZ) / 1000));
+ msecs_to_jiffies(5));
return;
}
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index a5590f4193f..6e2530b0204 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 756eab5b8dd..02030067388 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 1f869212784..a66c2dcd108 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
*
- * Marek Lindner, Simon Wunderlich
+ * Marek Lindner, Simon Wunderlich, Antonio Quartulli
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
@@ -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,12 +197,17 @@ 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);
if (tt_local_entry) {
tt_local_entry->last_seen = jiffies;
+ /* possibly unset the TT_CLIENT_PENDING flag */
+ tt_local_entry->common.flags &= ~TT_CLIENT_PENDING;
goto out;
}
@@ -232,14 +252,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 +517,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 +597,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 +638,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 +709,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 +719,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 +895,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 +943,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 +1006,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 +1027,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 +1056,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 +1077,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 +1151,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 +1237,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 +1341,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 +1618,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 +1730,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 +1853,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 +2022,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 +2064,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 +2105,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:
@@ -1886,3 +2119,22 @@ request_table:
}
}
}
+
+/* returns true whether we know that the client has moved from its old
+ * originator to another one. This entry is kept is still kept for consistency
+ * purposes
+ */
+bool tt_global_client_is_roaming(struct bat_priv *bat_priv, uint8_t *addr)
+{
+ struct tt_global_entry *tt_global_entry;
+ bool ret = false;
+
+ tt_global_entry = tt_global_hash_find(bat_priv, addr);
+ if (!tt_global_entry)
+ goto out;
+
+ ret = tt_global_entry->common.flags & TT_CLIENT_ROAM;
+ tt_global_entry_free_ref(tt_global_entry);
+out:
+ return ret;
+}
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h
index c753633b1da..c43374dc364 100644
--- a/net/batman-adv/translation-table.h
+++ b/net/batman-adv/translation-table.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
*
- * Marek Lindner, Simon Wunderlich
+ * Marek Lindner, Simon Wunderlich, Antonio Quartulli
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
@@ -39,27 +39,21 @@ 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,
const unsigned char *tt_buff, uint8_t tt_num_changes,
uint8_t ttvn, uint16_t tt_crc);
+bool tt_global_client_is_roaming(struct bat_priv *bat_priv, uint8_t *addr);
+
#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 302efb52347..61308e8016f 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))))
@@ -52,7 +52,7 @@ struct hard_iface {
/**
* orig_node - structure for orig_list maintaining nodes of mesh
* @primary_addr: hosts primary interface address
- * @last_valid: when last packet from this node was received
+ * @last_seen: when last packet from this node was received
* @bcast_seqno_reset: time when the broadcast seqno window was reset
* @batman_seqno_reset: time when the batman seqno window was reset
* @gw_flags: flags related to gateway class
@@ -70,7 +70,7 @@ struct orig_node {
struct neigh_node __rcu *router; /* rcu protected pointer */
unsigned long *bcast_own;
uint8_t *bcast_own_sum;
- unsigned long last_valid;
+ unsigned long last_seen;
unsigned long bcast_seqno_reset;
unsigned long batman_seqno_reset;
uint8_t gw_flags;
@@ -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;
@@ -120,7 +120,7 @@ struct gw_node {
/**
* neigh_node
- * @last_valid: when last packet via this neighbor was received
+ * @last_seen: when last packet via this neighbor was received
*/
struct neigh_node {
struct hlist_node list;
@@ -131,15 +131,22 @@ struct neigh_node {
uint8_t tq_avg;
uint8_t last_ttl;
struct list_head bonding_list;
- unsigned long last_valid;
- unsigned long real_bits[NUM_WORDS];
+ unsigned long last_seen;
+ DECLARE_BITMAP(real_bits, TQ_LOCAL_WINDOW_SIZE);
atomic_t refcount;
struct rcu_head rcu;
struct orig_node *orig_node;
struct hard_iface *if_incoming;
- spinlock_t tq_lock; /* protects: tq_recv, tq_index */
+ spinlock_t lq_update_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,41 +374,24 @@ 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 mac addresses of the OGM belonging to this hard-interface */
- void (*bat_ogm_update_mac)(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);
+ /* (re-)init mac addresses of the protocol information
+ * belonging to this hard-interface
+ */
+ void (*bat_iface_update_mac)(struct hard_iface *hard_iface);
+ /* called when primary interface is selected / changed */
+ void (*bat_primary_iface_set)(struct hard_iface *hard_iface);
/* prepare a new outgoing OGM for the send queue */
void (*bat_ogm_schedule)(struct hard_iface *hard_iface,
int tt_num_changes);
/* send scheduled OGM */
void (*bat_ogm_emit)(struct forw_packet *forw_packet);
- /* receive incoming OGM */
- void (*bat_ogm_receive)(struct hard_iface *if_incoming,
- struct sk_buff *skb);
};
#endif /* _NET_BATMAN_ADV_TYPES_H_ */
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 676f6a626b2..74175c21085 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -331,6 +331,14 @@ find_router:
unicast_packet->ttvn =
(uint8_t)atomic_read(&orig_node->last_ttvn);
+ /* inform the destination node that we are still missing a correct route
+ * for this client. The destination will receive this packet and will
+ * try to reroute it because the ttvn contained in the header is less
+ * than the current one
+ */
+ if (tt_global_client_is_roaming(bat_priv, ethhdr->h_dest))
+ unicast_packet->ttvn = unicast_packet->ttvn - 1;
+
if (atomic_read(&bat_priv->fragmentation) &&
data_len + sizeof(*unicast_packet) >
neigh_node->if_incoming->net_dev->mtu) {
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index c4a5b8cafad..cec216fb77c 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/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index a779ec70332..88884d1d95f 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -69,7 +69,7 @@ static struct bnep_session *__bnep_get_session(u8 *dst)
BT_DBG("");
list_for_each_entry(s, &bnep_session_list, list)
- if (!compare_ether_addr(dst, s->eh.h_source))
+ if (ether_addr_equal(dst, s->eh.h_source))
return s;
return NULL;
@@ -422,10 +422,10 @@ static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
iv[il++] = (struct kvec) { &type, 1 };
len++;
- if (compress_src && !compare_ether_addr(eh->h_dest, s->eh.h_source))
+ if (compress_src && ether_addr_equal(eh->h_dest, s->eh.h_source))
type |= 0x01;
- if (compress_dst && !compare_ether_addr(eh->h_source, s->eh.h_dest))
+ if (compress_dst && ether_addr_equal(eh->h_source, s->eh.h_dest))
type |= 0x02;
if (type)
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index ba829de8442..929e48aed44 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -170,7 +170,7 @@ static int br_set_mac_address(struct net_device *dev, void *p)
return -EADDRNOTAVAIL;
spin_lock_bh(&br->lock);
- if (compare_ether_addr(dev->dev_addr, addr->sa_data)) {
+ if (!ether_addr_equal(dev->dev_addr, addr->sa_data)) {
dev->addr_assign_type &= ~NET_ADDR_RANDOM;
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
br_fdb_change_mac_address(br, addr->sa_data);
@@ -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 5ba0c844d50..d21f3238351 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -107,8 +107,8 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
struct net_bridge_port *op;
list_for_each_entry(op, &br->port_list, list) {
if (op != p &&
- !compare_ether_addr(op->dev->dev_addr,
- f->addr.addr)) {
+ ether_addr_equal(op->dev->dev_addr,
+ f->addr.addr)) {
f->dst = op;
goto insert;
}
@@ -214,8 +214,8 @@ void br_fdb_delete_by_port(struct net_bridge *br,
struct net_bridge_port *op;
list_for_each_entry(op, &br->port_list, list) {
if (op != p &&
- !compare_ether_addr(op->dev->dev_addr,
- f->addr.addr)) {
+ ether_addr_equal(op->dev->dev_addr,
+ f->addr.addr)) {
f->dst = op;
goto skip_delete;
}
@@ -237,7 +237,7 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
struct net_bridge_fdb_entry *fdb;
hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) {
- if (!compare_ether_addr(fdb->addr.addr, addr)) {
+ if (ether_addr_equal(fdb->addr.addr, addr)) {
if (unlikely(has_expired(br, fdb)))
break;
return fdb;
@@ -331,7 +331,7 @@ static struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
struct net_bridge_fdb_entry *fdb;
hlist_for_each_entry(fdb, h, head, hlist) {
- if (!compare_ether_addr(fdb->addr.addr, addr))
+ if (ether_addr_equal(fdb->addr.addr, addr))
return fdb;
}
return NULL;
@@ -344,7 +344,7 @@ static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head,
struct net_bridge_fdb_entry *fdb;
hlist_for_each_entry_rcu(fdb, h, head, hlist) {
- if (!compare_ether_addr(fdb->addr.addr, addr))
+ if (ether_addr_equal(fdb->addr.addr, addr))
return fdb;
}
return NULL;
@@ -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 a2098e3de50..e9466d41270 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_input.c b/net/bridge/br_input.c
index 5a31731be4d..76f15fda021 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -216,7 +216,7 @@ forward:
}
/* fall through */
case BR_STATE_LEARNING:
- if (!compare_ether_addr(p->br->dev->dev_addr, dest))
+ if (ether_addr_equal(p->br->dev->dev_addr, dest))
skb->pkt_type = PACKET_HOST;
NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 27ca25ed702..b66581208cb 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)
{
@@ -458,8 +460,8 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
hopopt[3] = 2; /* Length of RA Option */
hopopt[4] = 0; /* Type = 0x0000 (MLD) */
hopopt[5] = 0;
- hopopt[6] = IPV6_TLV_PAD0; /* Pad0 */
- hopopt[7] = IPV6_TLV_PAD0; /* Pad0 */
+ hopopt[6] = IPV6_TLV_PAD1; /* Pad1 */
+ hopopt[7] = IPV6_TLV_PAD1; /* Pad1 */
skb_put(skb, sizeof(*ip6h) + 8);
@@ -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,20 @@ static void br_multicast_local_router_expired(unsigned long data)
{
}
+static void br_multicast_querier_expired(unsigned long data)
+{
+ struct net_bridge *br = (void *)data;
+
+ 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 +782,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 +1298,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 +1399,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 +1565,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 +1580,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, (unsigned long)br);
setup_timer(&br->multicast_query_timer, br_multicast_query_expired,
(unsigned long)br);
}
@@ -1689,9 +1707,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 +1753,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 +1761,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 d7f49b63ab0..e41456bd3cc 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -54,12 +54,14 @@ static int brnf_call_ip6tables __read_mostly = 1;
static int brnf_call_arptables __read_mostly = 1;
static int brnf_filter_vlan_tagged __read_mostly = 0;
static int brnf_filter_pppoe_tagged __read_mostly = 0;
+static int brnf_pass_vlan_indev __read_mostly = 0;
#else
#define brnf_call_iptables 1
#define brnf_call_ip6tables 1
#define brnf_call_arptables 1
#define brnf_filter_vlan_tagged 0
#define brnf_filter_pppoe_tagged 0
+#define brnf_pass_vlan_indev 0
#endif
#define IS_IP(skb) \
@@ -503,6 +505,19 @@ bridged_dnat:
return 0;
}
+static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct net_device *dev)
+{
+ struct net_device *vlan, *br;
+
+ br = bridge_parent(dev);
+ if (brnf_pass_vlan_indev == 0 || !vlan_tx_tag_present(skb))
+ return br;
+
+ vlan = __vlan_find_dev_deep(br, vlan_tx_tag_get(skb) & VLAN_VID_MASK);
+
+ return vlan ? vlan : br;
+}
+
/* Some common code for IPv4/IPv6 */
static struct net_device *setup_pre_routing(struct sk_buff *skb)
{
@@ -515,7 +530,7 @@ static struct net_device *setup_pre_routing(struct sk_buff *skb)
nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING;
nf_bridge->physindev = skb->dev;
- skb->dev = bridge_parent(skb->dev);
+ skb->dev = brnf_get_logical_dev(skb, skb->dev);
if (skb->protocol == htons(ETH_P_8021Q))
nf_bridge->mask |= BRNF_8021Q;
else if (skb->protocol == htons(ETH_P_PPP_SES))
@@ -543,7 +558,7 @@ static int check_hbh_len(struct sk_buff *skb)
int optlen = nh[off + 1] + 2;
switch (nh[off]) {
- case IPV6_TLV_PAD0:
+ case IPV6_TLV_PAD1:
optlen = 1;
break;
@@ -774,7 +789,7 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
else
skb->protocol = htons(ETH_P_IPV6);
- NF_HOOK(pf, NF_INET_FORWARD, skb, bridge_parent(in), parent,
+ NF_HOOK(pf, NF_INET_FORWARD, skb, brnf_get_logical_dev(skb, in), parent,
br_nf_forward_finish);
return NF_STOLEN;
@@ -1002,12 +1017,13 @@ static ctl_table brnf_table[] = {
.mode = 0644,
.proc_handler = brnf_sysctl_call_tables,
},
- { }
-};
-
-static struct ctl_path brnf_path[] = {
- { .procname = "net", },
- { .procname = "bridge", },
+ {
+ .procname = "bridge-nf-pass-vlan-input-dev",
+ .data = &brnf_pass_vlan_indev,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = brnf_sysctl_call_tables,
+ },
{ }
};
#endif
@@ -1026,7 +1042,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");
@@ -1043,7 +1059,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 a1daf8227ed..2080485515f 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 e1d88225787..1a8ad4fb9a6 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 05ed9bc7e42..0c0fe36e7aa 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 8c836d96ba7..af9a12099ba 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_bpdu.c b/net/bridge/br_stp_bpdu.c
index e16aade51ae..fd30a6022de 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -167,7 +167,7 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
if (p->state == BR_STATE_DISABLED)
goto out;
- if (compare_ether_addr(dest, br->group_addr) != 0)
+ if (!ether_addr_equal(dest, br->group_addr))
goto out;
buf = skb_pull(skb, 3);
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index f494496373d..9d5a414a394 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -178,7 +178,7 @@ void br_stp_set_enabled(struct net_bridge *br, unsigned long val)
/* called under bridge lock */
void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr)
{
- /* should be aligned on 2 bytes for compare_ether_addr() */
+ /* should be aligned on 2 bytes for ether_addr_equal() */
unsigned short oldaddr_aligned[ETH_ALEN >> 1];
unsigned char *oldaddr = (unsigned char *)oldaddr_aligned;
struct net_bridge_port *p;
@@ -191,12 +191,11 @@ void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr)
memcpy(br->dev->dev_addr, addr, ETH_ALEN);
list_for_each_entry(p, &br->port_list, list) {
- if (!compare_ether_addr(p->designated_bridge.addr, oldaddr))
+ if (ether_addr_equal(p->designated_bridge.addr, oldaddr))
memcpy(p->designated_bridge.addr, addr, ETH_ALEN);
- if (!compare_ether_addr(p->designated_root.addr, oldaddr))
+ if (ether_addr_equal(p->designated_root.addr, oldaddr))
memcpy(p->designated_root.addr, addr, ETH_ALEN);
-
}
br_configuration_update(br);
@@ -205,7 +204,7 @@ void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr)
br_become_root_bridge(br);
}
-/* should be aligned on 2 bytes for compare_ether_addr() */
+/* should be aligned on 2 bytes for ether_addr_equal() */
static const unsigned short br_mac_zero_aligned[ETH_ALEN >> 1];
/* called under bridge lock */
@@ -227,7 +226,7 @@ bool br_stp_recalculate_bridge_id(struct net_bridge *br)
}
- if (compare_ether_addr(br->bridge_id.addr, addr) == 0)
+ if (ether_addr_equal(br->bridge_id.addr, addr))
return false; /* no change */
br_stp_change_bridge_id(br, addr);
diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c
index 58de2a0f997..a6747e67342 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 c236c0e4398..c5c059333ea 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/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c
index 5b33a2e634a..071d87214dd 100644
--- a/net/bridge/netfilter/ebt_stp.c
+++ b/net/bridge/netfilter/ebt_stp.c
@@ -164,8 +164,8 @@ static int ebt_stp_mt_check(const struct xt_mtchk_param *par)
!(info->bitmask & EBT_STP_MASK))
return -EINVAL;
/* Make sure the match only receives stp frames */
- if (compare_ether_addr(e->destmac, bridge_ula) ||
- compare_ether_addr(e->destmsk, msk) || !(e->bitmask & EBT_DESTMAC))
+ if (!ether_addr_equal(e->destmac, bridge_ula) ||
+ !ether_addr_equal(e->destmsk, msk) || !(e->bitmask & EBT_DESTMAC))
return -EINVAL;
return 0;
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 5016fa57b62..fb894435526 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,11 +130,10 @@ 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)) {
- if (net_ratelimit())
- pr_debug("sending flow OFF (queue len = %d %d)\n",
- atomic_read(&cf_sk->sk.sk_rmem_alloc),
- sk_rcvbuf_lowwater(cf_sk));
+ (unsigned int)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) {
+ net_dbg_ratelimited("sending flow OFF (queue len = %d %d)\n",
+ atomic_read(&cf_sk->sk.sk_rmem_alloc),
+ sk_rcvbuf_lowwater(cf_sk));
set_rx_flow_off(cf_sk);
caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ);
}
@@ -144,8 +143,7 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
return err;
if (!sk_rmem_schedule(sk, skb->truesize) && rx_flow_is_on(cf_sk)) {
set_rx_flow_off(cf_sk);
- if (net_ratelimit())
- pr_debug("sending flow OFF due to rmem_schedule\n");
+ net_dbg_ratelimited("sending flow OFF due to rmem_schedule\n");
caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ);
}
skb->dev = NULL;
@@ -505,6 +503,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 +1061,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 +1092,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 5cf52225692..047cd0eec02 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 e335ba859b9..863dedd91bb 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 4aa33d4496b..dd485f6128e 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 d09340e1523..69771c04ba8 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 3d79b127881..b41acf25668 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 e02da7a5c5a..f459e93b774 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 cc913193d99..a776f751edb 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 0a1b53bce76..67bb1f11e61 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 b79747c4b64..363f8f7e6c3 100644
--- a/net/ceph/crush/mapper.c
+++ b/net/ceph/crush/mapper.c
@@ -20,6 +20,7 @@
#include <linux/crush/crush.h>
#include <linux/crush/hash.h>
+#include <linux/crush/mapper.h>
/*
* Implement the core CRUSH mapping algorithm.
@@ -68,8 +69,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 +101,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 27d4ea315d1..54b531a0112 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 f0993af2ae4..36fa6bf6849 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 1845cde2622..10d6008d31f 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 5e254055c91..1b0ef3c4d39 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 29ad46ec9dc..56e561a6900 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 e055708b8ec..e240441a231 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 e4fbfd6e2bd..ae6acf6a3de 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 99e1d759f41..cd0981977f5 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)];
}
@@ -299,10 +300,9 @@ static const unsigned short netdev_lock_type[] =
ARPHRD_BIF, ARPHRD_SIT, ARPHRD_IPDDP, ARPHRD_IPGRE,
ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET,
ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL,
- ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211,
- ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET,
- ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154,
- ARPHRD_VOID, ARPHRD_NONE};
+ ARPHRD_FCFABRIC, ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM,
+ ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, ARPHRD_PHONET_PIPE,
+ ARPHRD_IEEE802154, ARPHRD_VOID, ARPHRD_NONE};
static const char *const netdev_lock_name[] =
{"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25",
@@ -317,10 +317,9 @@ static const char *const netdev_lock_name[] =
"_xmit_BIF", "_xmit_SIT", "_xmit_IPDDP", "_xmit_IPGRE",
"_xmit_PIMREG", "_xmit_HIPPI", "_xmit_ASH", "_xmit_ECONET",
"_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL",
- "_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211",
- "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET",
- "_xmit_PHONET_PIPE", "_xmit_IEEE802154",
- "_xmit_VOID", "_xmit_NONE"};
+ "_xmit_FCFABRIC", "_xmit_IEEE80211", "_xmit_IEEE80211_PRISM",
+ "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", "_xmit_PHONET_PIPE",
+ "_xmit_IEEE802154", "_xmit_VOID", "_xmit_NONE"};
static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)];
static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)];
@@ -1676,10 +1675,9 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
if (skb_network_header(skb2) < skb2->data ||
skb2->network_header > skb2->tail) {
- if (net_ratelimit())
- pr_crit("protocol %04x is buggy, dev %s\n",
- ntohs(skb2->protocol),
- dev->name);
+ net_crit_ratelimited("protocol %04x is buggy, dev %s\n",
+ ntohs(skb2->protocol),
+ dev->name);
skb_reset_network_header(skb2);
}
@@ -2316,11 +2314,9 @@ EXPORT_SYMBOL(__skb_tx_hash);
static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index)
{
if (unlikely(queue_index >= dev->real_num_tx_queues)) {
- if (net_ratelimit()) {
- pr_warn("%s selects TX queue %d, but real number of TX queues is %d\n",
- dev->name, queue_index,
- dev->real_num_tx_queues);
- }
+ net_warn_ratelimited("%s selects TX queue %d, but real number of TX queues is %d\n",
+ dev->name, queue_index,
+ dev->real_num_tx_queues);
return 0;
}
return queue_index;
@@ -2562,17 +2558,15 @@ int dev_queue_xmit(struct sk_buff *skb)
}
}
HARD_TX_UNLOCK(dev, txq);
- if (net_ratelimit())
- pr_crit("Virtual device %s asks to queue packet!\n",
- dev->name);
+ net_crit_ratelimited("Virtual device %s asks to queue packet!\n",
+ dev->name);
} else {
/* Recursion is detected! It is possible,
* unfortunately
*/
recursion_alert:
- if (net_ratelimit())
- pr_crit("Dead loop on virtual device %s, fix it urgently!\n",
- dev->name);
+ net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n",
+ dev->name);
}
}
@@ -3053,9 +3047,8 @@ static int ing_filter(struct sk_buff *skb, struct netdev_queue *rxq)
struct Qdisc *q;
if (unlikely(MAX_RED_LOOP < ttl++)) {
- if (net_ratelimit())
- pr_warn("Redir loop detected Dropping packet (%d->%d)\n",
- skb->skb_iif, dev->ifindex);
+ net_warn_ratelimited("Redir loop detected Dropping packet (%d->%d)\n",
+ skb->skb_iif, dev->ifindex);
return TC_ACT_SHOT;
}
@@ -3515,10 +3508,16 @@ 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:
+ if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD)
+ kmem_cache_free(skbuff_head_cache, skb);
+ else
+ __kfree_skb(skb);
+ break;
+
case GRO_HELD:
case GRO_MERGED:
break;
@@ -3603,7 +3602,7 @@ gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb,
}
EXPORT_SYMBOL(napi_frags_finish);
-struct sk_buff *napi_frags_skb(struct napi_struct *napi)
+static struct sk_buff *napi_frags_skb(struct napi_struct *napi)
{
struct sk_buff *skb = napi->skb;
struct ethhdr *eth;
@@ -3638,7 +3637,6 @@ struct sk_buff *napi_frags_skb(struct napi_struct *napi)
out:
return skb;
}
-EXPORT_SYMBOL(napi_frags_skb);
gro_result_t napi_gro_frags(struct napi_struct *napi)
{
@@ -4592,9 +4590,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 626698f0db8..c4cc2bc49f0 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/drop_monitor.c b/net/core/drop_monitor.c
index a7cad741df0..3252e7e0a00 100644
--- a/net/core/drop_monitor.c
+++ b/net/core/drop_monitor.c
@@ -4,6 +4,8 @@
* Copyright (C) 2009 Neil Horman <nhorman@tuxdriver.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/string.h>
@@ -22,6 +24,7 @@
#include <linux/timer.h>
#include <linux/bitops.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <net/genetlink.h>
#include <net/netevent.h>
@@ -261,9 +264,15 @@ static int set_all_monitor_traces(int state)
switch (state) {
case TRACE_ON:
+ if (!try_module_get(THIS_MODULE)) {
+ rc = -ENODEV;
+ break;
+ }
+
rc |= register_trace_kfree_skb(trace_kfree_skb_hit, NULL);
rc |= register_trace_napi_poll(trace_napi_poll_hit, NULL);
break;
+
case TRACE_OFF:
rc |= unregister_trace_kfree_skb(trace_kfree_skb_hit, NULL);
rc |= unregister_trace_napi_poll(trace_napi_poll_hit, NULL);
@@ -279,6 +288,9 @@ static int set_all_monitor_traces(int state)
kfree_rcu(new_stat, rcu);
}
}
+
+ module_put(THIS_MODULE);
+
break;
default:
rc = 1;
@@ -381,10 +393,10 @@ static int __init init_net_drop_monitor(void)
struct per_cpu_dm_data *data;
int cpu, rc;
- printk(KERN_INFO "Initializing network drop monitor service\n");
+ pr_info("Initializing network drop monitor service\n");
if (sizeof(void *) > 8) {
- printk(KERN_ERR "Unable to store program counters on this arch, Drop monitor failed\n");
+ pr_err("Unable to store program counters on this arch, Drop monitor failed\n");
return -ENOSPC;
}
@@ -392,19 +404,19 @@ static int __init init_net_drop_monitor(void)
dropmon_ops,
ARRAY_SIZE(dropmon_ops));
if (rc) {
- printk(KERN_ERR "Could not create drop monitor netlink family\n");
+ pr_err("Could not create drop monitor netlink family\n");
return rc;
}
rc = register_netdevice_notifier(&dropmon_net_notifier);
if (rc < 0) {
- printk(KERN_CRIT "Failed to register netdevice notifier\n");
+ pr_crit("Failed to register netdevice notifier\n");
goto out_unreg;
}
rc = 0;
- for_each_present_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
data = &per_cpu(dm_cpu_data, cpu);
data->cpu = cpu;
INIT_WORK(&data->dm_alert_work, send_dm_alert);
@@ -423,4 +435,36 @@ out:
return rc;
}
-late_initcall(init_net_drop_monitor);
+static void exit_net_drop_monitor(void)
+{
+ struct per_cpu_dm_data *data;
+ int cpu;
+
+ BUG_ON(unregister_netdevice_notifier(&dropmon_net_notifier));
+
+ /*
+ * Because of the module_get/put we do in the trace state change path
+ * we are guarnateed not to have any current users when we get here
+ * all we need to do is make sure that we don't have any running timers
+ * or pending schedule calls
+ */
+
+ for_each_possible_cpu(cpu) {
+ data = &per_cpu(dm_cpu_data, cpu);
+ del_timer_sync(&data->send_timer);
+ cancel_work_sync(&data->dm_alert_work);
+ /*
+ * At this point, we should have exclusive access
+ * to this struct and can free the skb inside it
+ */
+ kfree_skb(data->skb);
+ }
+
+ BUG_ON(genl_unregister_family(&net_drop_monitor_family));
+}
+
+module_init(init_net_drop_monitor);
+module_exit(exit_net_drop_monitor);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Neil Horman <nhorman@tuxdriver.com>");
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 6d6d7d25caa..9c2afb48027 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)
@@ -738,18 +751,17 @@ static int ethtool_get_link(struct net_device *dev, char __user *useraddr)
return 0;
}
-static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
+static int ethtool_get_any_eeprom(struct net_device *dev, void __user *useraddr,
+ int (*getter)(struct net_device *,
+ struct ethtool_eeprom *, u8 *),
+ u32 total_len)
{
struct ethtool_eeprom eeprom;
- const struct ethtool_ops *ops = dev->ethtool_ops;
void __user *userbuf = useraddr + sizeof(eeprom);
u32 bytes_remaining;
u8 *data;
int ret = 0;
- if (!ops->get_eeprom || !ops->get_eeprom_len)
- return -EOPNOTSUPP;
-
if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
return -EFAULT;
@@ -758,7 +770,7 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
return -EINVAL;
/* Check for exceeding total eeprom len */
- if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
+ if (eeprom.offset + eeprom.len > total_len)
return -EINVAL;
data = kmalloc(PAGE_SIZE, GFP_USER);
@@ -769,7 +781,7 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
while (bytes_remaining > 0) {
eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
- ret = ops->get_eeprom(dev, &eeprom, data);
+ ret = getter(dev, &eeprom, data);
if (ret)
break;
if (copy_to_user(userbuf, data, eeprom.len)) {
@@ -790,6 +802,17 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
return ret;
}
+static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
+{
+ const struct ethtool_ops *ops = dev->ethtool_ops;
+
+ if (!ops->get_eeprom || !ops->get_eeprom_len)
+ return -EOPNOTSUPP;
+
+ return ethtool_get_any_eeprom(dev, useraddr, ops->get_eeprom,
+ ops->get_eeprom_len(dev));
+}
+
static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
{
struct ethtool_eeprom eeprom;
@@ -1278,6 +1301,81 @@ 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;
+}
+
+static int ethtool_get_module_info(struct net_device *dev,
+ void __user *useraddr)
+{
+ int ret;
+ struct ethtool_modinfo modinfo;
+ const struct ethtool_ops *ops = dev->ethtool_ops;
+
+ if (!ops->get_module_info)
+ return -EOPNOTSUPP;
+
+ if (copy_from_user(&modinfo, useraddr, sizeof(modinfo)))
+ return -EFAULT;
+
+ ret = ops->get_module_info(dev, &modinfo);
+ if (ret)
+ return ret;
+
+ if (copy_to_user(useraddr, &modinfo, sizeof(modinfo)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int ethtool_get_module_eeprom(struct net_device *dev,
+ void __user *useraddr)
+{
+ int ret;
+ struct ethtool_modinfo modinfo;
+ const struct ethtool_ops *ops = dev->ethtool_ops;
+
+ if (!ops->get_module_info || !ops->get_module_eeprom)
+ return -EOPNOTSUPP;
+
+ ret = ops->get_module_info(dev, &modinfo);
+ if (ret)
+ return ret;
+
+ return ethtool_get_any_eeprom(dev, useraddr, ops->get_module_eeprom,
+ modinfo.eeprom_len);
+}
+
/* The main entry point in this file. Called from net/core/dev.c */
int dev_ethtool(struct net *net, struct ifreq *ifr)
@@ -1295,11 +1393,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 +1430,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 +1597,15 @@ 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;
+ case ETHTOOL_GMODULEINFO:
+ rc = ethtool_get_module_info(dev, useraddr);
+ break;
+ case ETHTOOL_GMODULEEEPROM:
+ rc = ethtool_get_module_eeprom(dev, useraddr);
+ break;
default:
rc = -EOPNOTSUPP;
}
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index c02e63c908d..72cceb79d0d 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 6f755cca452..47a5f055e7f 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 0452eb27a27..ddedf211e58 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 52d0a445904..00000000000
--- 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 0a68045782d..eb09f8bbbf0 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -15,6 +15,8 @@
* Harald Welte Add neighbour cache statistics like rtstat
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -712,14 +714,13 @@ void neigh_destroy(struct neighbour *neigh)
NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
if (!neigh->dead) {
- printk(KERN_WARNING
- "Destroying alive neighbour %p\n", neigh);
+ pr_warn("Destroying alive neighbour %p\n", neigh);
dump_stack();
return;
}
if (neigh_del_timer(neigh))
- printk(KERN_WARNING "Impossible event.\n");
+ pr_warn("Impossible event\n");
skb_queue_purge(&neigh->arp_queue);
neigh->arp_queue_len_bytes = 0;
@@ -890,7 +891,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 +1501,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 +1539,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)
{
@@ -1555,8 +1555,8 @@ void neigh_table_init(struct neigh_table *tbl)
write_unlock(&neigh_tbl_lock);
if (unlikely(tmp)) {
- printk(KERN_ERR "NEIGH: Registering multiple tables for "
- "family %d\n", tbl->family);
+ pr_err("Registering multiple tables for family %d\n",
+ tbl->family);
dump_stack();
}
}
@@ -1572,7 +1572,7 @@ int neigh_table_clear(struct neigh_table *tbl)
pneigh_queue_purge(&tbl->proxy_queue);
neigh_ifdown(tbl, NULL);
if (atomic_read(&tbl->entries))
- printk(KERN_CRIT "neighbour leakage\n");
+ pr_crit("neighbour leakage\n");
write_lock(&neigh_tbl_lock);
for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
if (*tp == tbl) {
@@ -1768,29 +1768,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 +1815,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 +1841,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 +1867,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 +2139,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 +2160,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 +2191,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 +2800,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 +2925,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 +2953,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 +2976,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 +2998,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 495586232aa..fdf9e61d065 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/net_namespace.c b/net/core/net_namespace.c
index 31a5ae51a45..dddbacb8f28 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/workqueue.h>
#include <linux/rtnetlink.h>
#include <linux/cache.h>
@@ -212,8 +214,8 @@ static void net_free(struct net *net)
{
#ifdef NETNS_REFCNT_DEBUG
if (unlikely(atomic_read(&net->use_count) != 0)) {
- printk(KERN_EMERG "network namespace not free! Usage: %d\n",
- atomic_read(&net->use_count));
+ pr_emerg("network namespace not free! Usage: %d\n",
+ atomic_read(&net->use_count));
return;
}
#endif
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index ba6900f7390..09eda68b676 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -9,6 +9,8 @@
* Authors: Neil Horman <nhorman@tuxdriver.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -88,7 +90,7 @@ static void extend_netdev_table(struct net_device *dev, u32 new_len)
old_priomap = rtnl_dereference(dev->priomap);
if (!new_priomap) {
- printk(KERN_WARNING "Unable to alloc new priomap!\n");
+ pr_warn("Unable to alloc new priomap!\n");
return;
}
@@ -136,7 +138,7 @@ static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp)
ret = get_prioidx(&cs->prioidx);
if (ret != 0) {
- printk(KERN_WARNING "No space in priority index array\n");
+ pr_warn("No space in priority index array\n");
kfree(cs);
return ERR_PTR(ret);
}
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index b81369b6ddc..cce9e53528b 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;
@@ -891,8 +891,8 @@ static ssize_t pktgen_if_write(struct file *file,
if (copy_from_user(tb, user_buffer, copy))
return -EFAULT;
tb[copy] = 0;
- printk(KERN_DEBUG "pktgen: %s,%lu buffer -:%s:-\n", name,
- (unsigned long)count, tb);
+ pr_debug("%s,%lu buffer -:%s:-\n",
+ name, (unsigned long)count, tb);
}
if (!strcmp(name, "min_pkt_size")) {
@@ -1261,8 +1261,7 @@ static ssize_t pktgen_if_write(struct file *file,
pkt_dev->cur_daddr = pkt_dev->daddr_min;
}
if (debug)
- printk(KERN_DEBUG "pktgen: dst_min set to: %s\n",
- pkt_dev->dst_min);
+ pr_debug("dst_min set to: %s\n", pkt_dev->dst_min);
i += len;
sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min);
return count;
@@ -1284,8 +1283,7 @@ static ssize_t pktgen_if_write(struct file *file,
pkt_dev->cur_daddr = pkt_dev->daddr_max;
}
if (debug)
- printk(KERN_DEBUG "pktgen: dst_max set to: %s\n",
- pkt_dev->dst_max);
+ pr_debug("dst_max set to: %s\n", pkt_dev->dst_max);
i += len;
sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max);
return count;
@@ -1307,7 +1305,7 @@ static ssize_t pktgen_if_write(struct file *file,
pkt_dev->cur_in6_daddr = pkt_dev->in6_daddr;
if (debug)
- printk(KERN_DEBUG "pktgen: dst6 set to: %s\n", buf);
+ pr_debug("dst6 set to: %s\n", buf);
i += len;
sprintf(pg_result, "OK: dst6=%s", buf);
@@ -1329,7 +1327,7 @@ static ssize_t pktgen_if_write(struct file *file,
pkt_dev->cur_in6_daddr = pkt_dev->min_in6_daddr;
if (debug)
- printk(KERN_DEBUG "pktgen: dst6_min set to: %s\n", buf);
+ pr_debug("dst6_min set to: %s\n", buf);
i += len;
sprintf(pg_result, "OK: dst6_min=%s", buf);
@@ -1350,7 +1348,7 @@ static ssize_t pktgen_if_write(struct file *file,
snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr);
if (debug)
- printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf);
+ pr_debug("dst6_max set to: %s\n", buf);
i += len;
sprintf(pg_result, "OK: dst6_max=%s", buf);
@@ -1373,7 +1371,7 @@ static ssize_t pktgen_if_write(struct file *file,
pkt_dev->cur_in6_saddr = pkt_dev->in6_saddr;
if (debug)
- printk(KERN_DEBUG "pktgen: src6 set to: %s\n", buf);
+ pr_debug("src6 set to: %s\n", buf);
i += len;
sprintf(pg_result, "OK: src6=%s", buf);
@@ -1394,8 +1392,7 @@ static ssize_t pktgen_if_write(struct file *file,
pkt_dev->cur_saddr = pkt_dev->saddr_min;
}
if (debug)
- printk(KERN_DEBUG "pktgen: src_min set to: %s\n",
- pkt_dev->src_min);
+ pr_debug("src_min set to: %s\n", pkt_dev->src_min);
i += len;
sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min);
return count;
@@ -1415,8 +1412,7 @@ static ssize_t pktgen_if_write(struct file *file,
pkt_dev->cur_saddr = pkt_dev->saddr_max;
}
if (debug)
- printk(KERN_DEBUG "pktgen: src_max set to: %s\n",
- pkt_dev->src_max);
+ pr_debug("src_max set to: %s\n", pkt_dev->src_max);
i += len;
sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max);
return count;
@@ -1510,7 +1506,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)
@@ -1527,7 +1523,7 @@ static ssize_t pktgen_if_write(struct file *file,
pkt_dev->svlan_id = 0xffff;
if (debug)
- printk(KERN_DEBUG "pktgen: VLAN/SVLAN auto turned off\n");
+ pr_debug("VLAN/SVLAN auto turned off\n");
}
return count;
}
@@ -1542,10 +1538,10 @@ static ssize_t pktgen_if_write(struct file *file,
pkt_dev->vlan_id = value; /* turn on VLAN */
if (debug)
- printk(KERN_DEBUG "pktgen: VLAN turned on\n");
+ pr_debug("VLAN turned on\n");
if (debug && pkt_dev->nr_labels)
- printk(KERN_DEBUG "pktgen: MPLS auto turned off\n");
+ pr_debug("MPLS auto turned off\n");
pkt_dev->nr_labels = 0; /* turn off MPLS */
sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id);
@@ -1554,7 +1550,7 @@ static ssize_t pktgen_if_write(struct file *file,
pkt_dev->svlan_id = 0xffff;
if (debug)
- printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n");
+ pr_debug("VLAN/SVLAN turned off\n");
}
return count;
}
@@ -1599,10 +1595,10 @@ static ssize_t pktgen_if_write(struct file *file,
pkt_dev->svlan_id = value; /* turn on SVLAN */
if (debug)
- printk(KERN_DEBUG "pktgen: SVLAN turned on\n");
+ pr_debug("SVLAN turned on\n");
if (debug && pkt_dev->nr_labels)
- printk(KERN_DEBUG "pktgen: MPLS auto turned off\n");
+ pr_debug("MPLS auto turned off\n");
pkt_dev->nr_labels = 0; /* turn off MPLS */
sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id);
@@ -1611,7 +1607,7 @@ static ssize_t pktgen_if_write(struct file *file,
pkt_dev->svlan_id = 0xffff;
if (debug)
- printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n");
+ pr_debug("VLAN/SVLAN turned off\n");
}
return count;
}
@@ -1779,8 +1775,7 @@ static ssize_t pktgen_thread_write(struct file *file,
i += len;
if (debug)
- printk(KERN_DEBUG "pktgen: t=%s, count=%lu\n",
- name, (unsigned long)count);
+ pr_debug("t=%s, count=%lu\n", name, (unsigned long)count);
if (!t) {
pr_err("ERROR: No thread\n");
@@ -2324,7 +2319,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 +2545,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;
@@ -2934,8 +2929,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
if (datalen < sizeof(struct pktgen_hdr)) {
datalen = sizeof(struct pktgen_hdr);
- if (net_ratelimit())
- pr_info("increased datalen to %d\n", datalen);
+ net_info_ratelimited("increased datalen to %d\n", datalen);
}
udph->source = htons(pkt_dev->cur_udp_src);
@@ -3365,8 +3359,8 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
pkt_dev->errors++;
break;
default: /* Drivers are not supposed to return other values! */
- if (net_ratelimit())
- pr_info("%s xmit error: %d\n", pkt_dev->odevname, ret);
+ net_info_ratelimited("%s xmit error: %d\n",
+ pkt_dev->odevname, ret);
pkt_dev->errors++;
/* fallthru */
case NETDEV_TX_LOCKED:
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 90430b776ec..21318d15bbc 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);
@@ -1516,11 +1524,9 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
err = 0;
errout:
- if (err < 0 && modified && net_ratelimit())
- printk(KERN_WARNING "A link change request failed with "
- "some changes committed already. Interface %s may "
- "have been left with an inconsistent configuration, "
- "please check.\n", dev->name);
+ if (err < 0 && modified)
+ net_warn_ratelimited("A link change request failed with some changes committed already. Interface %s may have been left with an inconsistent configuration, please check.\n",
+ dev->name);
if (send_addr_notify)
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
@@ -1634,14 +1640,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 +1953,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 +1978,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 +2309,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 +2411,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 e59840010d4..016694d6248 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -36,6 +36,8 @@
* The functions in this file will not compile correctly with gcc 2.4.x
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -67,10 +69,9 @@
#include <asm/uaccess.h>
#include <trace/events/skb.h>
+#include <linux/highmem.h>
-#include "kmap_skb.h"
-
-static struct kmem_cache *skbuff_head_cache __read_mostly;
+struct kmem_cache *skbuff_head_cache __read_mostly;
static struct kmem_cache *skbuff_fclone_cache __read_mostly;
static void sock_pipe_buf_release(struct pipe_inode_info *pipe,
@@ -119,11 +120,10 @@ static const struct pipe_buf_operations sock_pipe_buf_ops = {
*/
static void skb_over_panic(struct sk_buff *skb, int sz, void *here)
{
- printk(KERN_EMERG "skb_over_panic: text:%p len:%d put:%d head:%p "
- "data:%p tail:%#lx end:%#lx dev:%s\n",
- here, skb->len, sz, skb->head, skb->data,
- (unsigned long)skb->tail, (unsigned long)skb->end,
- skb->dev ? skb->dev->name : "<NULL>");
+ pr_emerg("%s: text:%p len:%d put:%d head:%p data:%p tail:%#lx end:%#lx dev:%s\n",
+ __func__, here, skb->len, sz, skb->head, skb->data,
+ (unsigned long)skb->tail, (unsigned long)skb->end,
+ skb->dev ? skb->dev->name : "<NULL>");
BUG();
}
@@ -138,11 +138,10 @@ static void skb_over_panic(struct sk_buff *skb, int sz, void *here)
static void skb_under_panic(struct sk_buff *skb, int sz, void *here)
{
- printk(KERN_EMERG "skb_under_panic: text:%p len:%d put:%d head:%p "
- "data:%p tail:%#lx end:%#lx dev:%s\n",
- here, skb->len, sz, skb->head, skb->data,
- (unsigned long)skb->tail, (unsigned long)skb->end,
- skb->dev ? skb->dev->name : "<NULL>");
+ pr_emerg("%s: text:%p len:%d put:%d head:%p data:%p tail:%#lx end:%#lx dev:%s\n",
+ __func__, here, skb->len, sz, skb->head, skb->data,
+ (unsigned long)skb->tail, (unsigned long)skb->end,
+ skb->dev ? skb->dev->name : "<NULL>");
BUG();
}
@@ -246,6 +245,7 @@ EXPORT_SYMBOL(__alloc_skb);
/**
* build_skb - build a network buffer
* @data: data buffer provided by caller
+ * @frag_size: size of fragment, or 0 if head was kmalloced
*
* Allocate a new &sk_buff. Caller provides space holding head and
* skb_shared_info. @data must have been allocated by kmalloc()
@@ -259,20 +259,21 @@ EXPORT_SYMBOL(__alloc_skb);
* before giving packet to stack.
* RX rings only contains data buffers, not full skbs.
*/
-struct sk_buff *build_skb(void *data)
+struct sk_buff *build_skb(void *data, unsigned int frag_size)
{
struct skb_shared_info *shinfo;
struct sk_buff *skb;
- unsigned int size;
+ unsigned int size = frag_size ? : ksize(data);
skb = kmem_cache_alloc(skbuff_head_cache, GFP_ATOMIC);
if (!skb)
return NULL;
- size = ksize(data) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ size -= SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
memset(skb, 0, offsetof(struct sk_buff, tail));
skb->truesize = SKB_TRUESIZE(size);
+ skb->head_frag = frag_size != 0;
atomic_set(&skb->users, 1);
skb->head = data;
skb->data = data;
@@ -292,6 +293,46 @@ struct sk_buff *build_skb(void *data)
}
EXPORT_SYMBOL(build_skb);
+struct netdev_alloc_cache {
+ struct page *page;
+ unsigned int offset;
+};
+static DEFINE_PER_CPU(struct netdev_alloc_cache, netdev_alloc_cache);
+
+/**
+ * netdev_alloc_frag - allocate a page fragment
+ * @fragsz: fragment size
+ *
+ * Allocates a frag from a page for receive buffer.
+ * Uses GFP_ATOMIC allocations.
+ */
+void *netdev_alloc_frag(unsigned int fragsz)
+{
+ struct netdev_alloc_cache *nc;
+ void *data = NULL;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ nc = &__get_cpu_var(netdev_alloc_cache);
+ if (unlikely(!nc->page)) {
+refill:
+ nc->page = alloc_page(GFP_ATOMIC | __GFP_COLD);
+ nc->offset = 0;
+ }
+ if (likely(nc->page)) {
+ if (nc->offset + fragsz > PAGE_SIZE) {
+ put_page(nc->page);
+ goto refill;
+ }
+ data = page_address(nc->page) + nc->offset;
+ nc->offset += fragsz;
+ get_page(nc->page);
+ }
+ local_irq_restore(flags);
+ return data;
+}
+EXPORT_SYMBOL(netdev_alloc_frag);
+
/**
* __netdev_alloc_skb - allocate an skbuff for rx on a specific device
* @dev: network device to receive on
@@ -306,11 +347,23 @@ EXPORT_SYMBOL(build_skb);
* %NULL is returned if there is no free memory.
*/
struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
- unsigned int length, gfp_t gfp_mask)
+ unsigned int length, gfp_t gfp_mask)
{
- struct sk_buff *skb;
+ struct sk_buff *skb = NULL;
+ unsigned int fragsz = SKB_DATA_ALIGN(length + NET_SKB_PAD) +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ if (fragsz <= PAGE_SIZE && !(gfp_mask & __GFP_WAIT)) {
+ void *data = netdev_alloc_frag(fragsz);
- skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, NUMA_NO_NODE);
+ if (likely(data)) {
+ skb = build_skb(data, fragsz);
+ if (unlikely(!skb))
+ put_page(virt_to_head_page(data));
+ }
+ } else {
+ skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, NUMA_NO_NODE);
+ }
if (likely(skb)) {
skb_reserve(skb, NET_SKB_PAD);
skb->dev = dev;
@@ -329,28 +382,6 @@ void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
}
EXPORT_SYMBOL(skb_add_rx_frag);
-/**
- * dev_alloc_skb - allocate an skbuff for receiving
- * @length: length to allocate
- *
- * Allocate a new &sk_buff and assign it a usage count of one. The
- * buffer has unspecified headroom built in. Users should allocate
- * the headroom they think they need without accounting for the
- * built in space. The built in space is used for optimisations.
- *
- * %NULL is returned if there is no free memory. Although this function
- * allocates memory it can be called from an interrupt.
- */
-struct sk_buff *dev_alloc_skb(unsigned int length)
-{
- /*
- * There is more code here than it seems:
- * __dev_alloc_skb is an inline
- */
- return __dev_alloc_skb(length, GFP_ATOMIC);
-}
-EXPORT_SYMBOL(dev_alloc_skb);
-
static void skb_drop_list(struct sk_buff **listp)
{
struct sk_buff *list = *listp;
@@ -377,6 +408,14 @@ static void skb_clone_fraglist(struct sk_buff *skb)
skb_get(list);
}
+static void skb_free_head(struct sk_buff *skb)
+{
+ if (skb->head_frag)
+ put_page(virt_to_head_page(skb->head));
+ else
+ kfree(skb->head);
+}
+
static void skb_release_data(struct sk_buff *skb)
{
if (!skb->cloned ||
@@ -403,7 +442,7 @@ static void skb_release_data(struct sk_buff *skb)
if (skb_has_frag_list(skb))
skb_drop_fraglist(skb);
- kfree(skb->head);
+ skb_free_head(skb);
}
}
@@ -645,6 +684,7 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
C(tail);
C(end);
C(head);
+ C(head_frag);
C(data);
C(truesize);
atomic_set(&n->users, 1);
@@ -707,10 +747,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;
}
@@ -819,7 +859,7 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
{
int headerlen = skb_headroom(skb);
- unsigned int size = (skb_end_pointer(skb) - skb->head) + skb->data_len;
+ unsigned int size = skb_end_offset(skb) + skb->data_len;
struct sk_buff *n = alloc_skb(size, gfp_mask);
if (!n)
@@ -920,9 +960,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
{
int i;
u8 *data;
- int size = nhead + (skb_end_pointer(skb) - skb->head) + ntail;
+ int size = nhead + skb_end_offset(skb) + ntail;
long off;
- bool fastpath;
BUG_ON(nhead < 0);
@@ -931,27 +970,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
size = SKB_DATA_ALIGN(size);
- /* Check if we can avoid taking references on fragments if we own
- * the last reference on skb->head. (see skb_release_data())
- */
- if (!skb->cloned)
- fastpath = true;
- else {
- int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
- fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
- }
-
- if (fastpath &&
- size + sizeof(struct skb_shared_info) <= ksize(skb->head)) {
- memmove(skb->head + size, skb_shinfo(skb),
- offsetof(struct skb_shared_info,
- frags[skb_shinfo(skb)->nr_frags]));
- memmove(skb->head + nhead, skb->head,
- skb_tail_pointer(skb) - skb->head);
- off = nhead;
- goto adjust_others;
- }
-
data = kmalloc(size + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)),
gfp_mask);
if (!data)
@@ -967,9 +985,12 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
skb_shinfo(skb),
offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
- if (fastpath) {
- kfree(skb->head);
- } else {
+ /*
+ * if shinfo is shared we must drop the old head gracefully, but if it
+ * is not we can just drop the old head and let the existing refcount
+ * be since all we did is relocate the values
+ */
+ if (skb_cloned(skb)) {
/* copy this zero copy skb frags */
if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
if (skb_copy_ubufs(skb, gfp_mask))
@@ -982,11 +1003,13 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
skb_clone_fraglist(skb);
skb_release_data(skb);
+ } else {
+ skb_free_head(skb);
}
off = (data + nhead) - skb->head;
skb->head = data;
-adjust_others:
+ skb->head_frag = 0;
skb->data += off;
#ifdef NET_SKBUFF_DATA_USES_OFFSET
skb->end = size;
@@ -1275,7 +1298,7 @@ drop_pages:
return -ENOMEM;
nfrag->next = frag->next;
- kfree_skb(frag);
+ consume_skb(frag);
frag = nfrag;
*fragp = frag;
}
@@ -1487,21 +1510,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 +1571,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 +1589,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 +1605,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, bool 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 +1663,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, bool 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,34 +1692,38 @@ 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;
- /*
- * map the linear part
+ /* map the linear part :
+ * If skb->head_frag is set, this 'linear' part is backed by a
+ * fragment, and if the head is not shared with any clones then
+ * we can avoid a copy since we own the head portion of this page.
*/
if (__splice_segment(virt_to_page(skb->data),
(unsigned long) skb->data & (PAGE_SIZE - 1),
skb_headlen(skb),
- offset, len, skb, spd, 1, sk, pipe))
- return 1;
+ offset, len, skb, spd,
+ skb_head_is_locked(skb),
+ sk, pipe))
+ return true;
/*
* then map the fragments
@@ -1690,11 +1733,11 @@ 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;
+ offset, len, skb, spd, false, sk, pipe))
+ return true;
}
- return 0;
+ return false;
}
/*
@@ -1707,8 +1750,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 +1763,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 +1798,6 @@ done:
lock_sock(sk);
}
- splice_shrink_spd(pipe, &spd);
return ret;
}
@@ -1806,10 +1845,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 +1908,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 +1994,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 +2519,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 +2528,7 @@ next_skb:
}
if (st->frag_data) {
- kunmap_skb_frag(st->frag_data);
+ kunmap_atomic(st->frag_data);
st->frag_data = NULL;
}
@@ -2498,7 +2537,7 @@ next_skb:
}
if (st->frag_data) {
- kunmap_skb_frag(st->frag_data);
+ kunmap_atomic(st->frag_data);
st->frag_data = NULL;
}
@@ -2526,7 +2565,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);
@@ -2718,14 +2757,13 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
if (unlikely(!nskb))
goto err;
- hsize = skb_end_pointer(nskb) - nskb->head;
+ hsize = skb_end_offset(nskb);
if (skb_cow_head(nskb, doffset + headroom)) {
kfree_skb(nskb);
goto err;
}
- nskb->truesize += skb_end_pointer(nskb) - nskb->head -
- hsize;
+ nskb->truesize += skb_end_offset(nskb) - hsize;
skb_release_head_state(nskb);
__skb_push(nskb, doffset);
} else {
@@ -2843,6 +2881,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
unsigned int len = skb_gro_len(skb);
unsigned int offset = skb_gro_offset(skb);
unsigned int headlen = skb_headlen(skb);
+ unsigned int delta_truesize;
if (p->len + len >= 65536)
return -E2BIG;
@@ -2872,11 +2911,41 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
frag->page_offset += offset;
skb_frag_size_sub(frag, offset);
+ /* all fragments truesize : remove (head size + sk_buff) */
+ delta_truesize = skb->truesize -
+ SKB_TRUESIZE(skb_end_offset(skb));
+
skb->truesize -= skb->data_len;
skb->len -= skb->data_len;
skb->data_len = 0;
- NAPI_GRO_CB(skb)->free = 1;
+ NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE;
+ goto done;
+ } else if (skb->head_frag) {
+ int nr_frags = pinfo->nr_frags;
+ skb_frag_t *frag = pinfo->frags + nr_frags;
+ struct page *page = virt_to_head_page(skb->head);
+ unsigned int first_size = headlen - offset;
+ unsigned int first_offset;
+
+ if (nr_frags + 1 + skbinfo->nr_frags > MAX_SKB_FRAGS)
+ return -E2BIG;
+
+ first_offset = skb->data -
+ (unsigned char *)page_address(page) +
+ offset;
+
+ pinfo->nr_frags = nr_frags + 1 + skbinfo->nr_frags;
+
+ frag->page.p = page;
+ frag->page_offset = first_offset;
+ skb_frag_size_set(frag, first_size);
+
+ memcpy(frag + 1, skbinfo->frags, sizeof(*frag) * skbinfo->nr_frags);
+ /* We dont need to clear skbinfo->nr_frags here */
+
+ delta_truesize = skb->truesize - SKB_DATA_ALIGN(sizeof(struct sk_buff));
+ NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE_STOLEN_HEAD;
goto done;
} else if (skb_gro_len(p) != pinfo->gso_size)
return -E2BIG;
@@ -2918,7 +2987,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
p = nskb;
merge:
- p->truesize += skb->truesize - len;
+ delta_truesize = skb->truesize;
if (offset > headlen) {
unsigned int eat = offset - headlen;
@@ -2938,7 +3007,7 @@ merge:
done:
NAPI_GRO_CB(p)->count++;
p->data_len += len;
- p->truesize += len;
+ p->truesize += delta_truesize;
p->len += len;
NAPI_GRO_CB(skb)->same_flow = 1;
@@ -3166,7 +3235,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);
@@ -3260,10 +3329,8 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off)
{
if (unlikely(start > skb_headlen(skb)) ||
unlikely((int)start + off > skb_headlen(skb) - 2)) {
- if (net_ratelimit())
- printk(KERN_WARNING
- "bad partial csum: csum=%u/%u len=%u\n",
- start, off, skb_headlen(skb));
+ net_warn_ratelimited("bad partial csum: csum=%u/%u len=%u\n",
+ start, off, skb_headlen(skb));
return false;
}
skb->ip_summed = CHECKSUM_PARTIAL;
@@ -3275,8 +3342,93 @@ EXPORT_SYMBOL_GPL(skb_partial_csum_set);
void __skb_warn_lro_forwarding(const struct sk_buff *skb)
{
- if (net_ratelimit())
- pr_warning("%s: received packets cannot be forwarded"
- " while LRO is enabled\n", skb->dev->name);
+ net_warn_ratelimited("%s: received packets cannot be forwarded while LRO is enabled\n",
+ skb->dev->name);
}
EXPORT_SYMBOL(__skb_warn_lro_forwarding);
+
+void kfree_skb_partial(struct sk_buff *skb, bool head_stolen)
+{
+ if (head_stolen)
+ kmem_cache_free(skbuff_head_cache, skb);
+ else
+ __kfree_skb(skb);
+}
+EXPORT_SYMBOL(kfree_skb_partial);
+
+/**
+ * skb_try_coalesce - try to merge skb to prior one
+ * @to: prior buffer
+ * @from: buffer to add
+ * @fragstolen: pointer to boolean
+ *
+ */
+bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
+ bool *fragstolen, int *delta_truesize)
+{
+ int i, delta, len = from->len;
+
+ *fragstolen = false;
+
+ if (skb_cloned(to))
+ return false;
+
+ if (len <= skb_tailroom(to)) {
+ BUG_ON(skb_copy_bits(from, 0, skb_put(to, len), len));
+ *delta_truesize = 0;
+ return true;
+ }
+
+ if (skb_has_frag_list(to) || skb_has_frag_list(from))
+ return false;
+
+ if (skb_headlen(from) != 0) {
+ struct page *page;
+ unsigned int offset;
+
+ if (skb_shinfo(to)->nr_frags +
+ skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS)
+ return false;
+
+ if (skb_head_is_locked(from))
+ return false;
+
+ delta = from->truesize - SKB_DATA_ALIGN(sizeof(struct sk_buff));
+
+ page = virt_to_head_page(from->head);
+ offset = from->data - (unsigned char *)page_address(page);
+
+ skb_fill_page_desc(to, skb_shinfo(to)->nr_frags,
+ page, offset, skb_headlen(from));
+ *fragstolen = true;
+ } else {
+ if (skb_shinfo(to)->nr_frags +
+ skb_shinfo(from)->nr_frags > MAX_SKB_FRAGS)
+ return false;
+
+ delta = from->truesize -
+ SKB_TRUESIZE(skb_end_pointer(from) - from->head);
+ }
+
+ 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;
+
+ if (!skb_cloned(from))
+ skb_shinfo(from)->nr_frags = 0;
+
+ /* if the skb is cloned this does nothing since we set nr_frags to 0 */
+ for (i = 0; i < skb_shinfo(from)->nr_frags; i++)
+ skb_frag_ref(from, i);
+
+ to->truesize += delta;
+ to->len += len;
+ to->data_len += len;
+
+ *delta_truesize = delta;
+ return true;
+}
+EXPORT_SYMBOL(skb_try_coalesce);
diff --git a/net/core/sock.c b/net/core/sock.c
index b2e14c07d92..5efcd6307fa 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -89,6 +89,8 @@
* 2 of the License, or (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/types.h>
@@ -113,6 +115,7 @@
#include <linux/user_namespace.h>
#include <linux/static_key.h>
#include <linux/memcontrol.h>
+#include <linux/prefetch.h>
#include <asm/uaccess.h>
@@ -258,7 +261,9 @@ static struct lock_class_key af_callback_keys[AF_MAX];
/* Run time adjustable parameters. */
__u32 sysctl_wmem_max __read_mostly = SK_WMEM_MAX;
+EXPORT_SYMBOL(sysctl_wmem_max);
__u32 sysctl_rmem_max __read_mostly = SK_RMEM_MAX;
+EXPORT_SYMBOL(sysctl_rmem_max);
__u32 sysctl_wmem_default __read_mostly = SK_WMEM_MAX;
__u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX;
@@ -294,9 +299,8 @@ static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen)
*timeo_p = 0;
if (warned < 10 && net_ratelimit()) {
warned++;
- printk(KERN_INFO "sock_set_timeout: `%s' (pid %d) "
- "tries to set negative timeout\n",
- current->comm, task_pid_nr(current));
+ pr_info("%s: `%s' (pid %d) tries to set negative timeout\n",
+ __func__, current->comm, task_pid_nr(current));
}
return 0;
}
@@ -314,8 +318,8 @@ static void sock_warn_obsolete_bsdism(const char *name)
static char warncomm[TASK_COMM_LEN];
if (strcmp(warncomm, current->comm) && warned < 5) {
strcpy(warncomm, current->comm);
- printk(KERN_WARNING "process `%s' is using obsolete "
- "%s SO_BSDCOMPAT\n", warncomm, name);
+ pr_warn("process `%s' is using obsolete %s SO_BSDCOMPAT\n",
+ warncomm, name);
warned++;
}
}
@@ -389,7 +393,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 +410,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 +565,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:
@@ -577,23 +581,15 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
break;
case SO_SNDBUF:
/* Don't error on this BSD doesn't and if you think
- about it this is right. Otherwise apps have to
- play 'guess the biggest size' games. RCVBUF/SNDBUF
- are treated in BSD as hints */
-
- if (val > sysctl_wmem_max)
- val = sysctl_wmem_max;
+ * about it this is right. Otherwise apps have to
+ * play 'guess the biggest size' games. RCVBUF/SNDBUF
+ * are treated in BSD as hints
+ */
+ val = min_t(u32, val, sysctl_wmem_max);
set_sndbuf:
sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
- if ((val * 2) < SOCK_MIN_SNDBUF)
- sk->sk_sndbuf = SOCK_MIN_SNDBUF;
- else
- sk->sk_sndbuf = val * 2;
-
- /*
- * Wake up sending tasks if we
- * upped the value.
- */
+ sk->sk_sndbuf = max_t(u32, val * 2, SOCK_MIN_SNDBUF);
+ /* Wake up sending tasks if we upped the value. */
sk->sk_write_space(sk);
break;
@@ -606,12 +602,11 @@ set_sndbuf:
case SO_RCVBUF:
/* Don't error on this BSD doesn't and if you think
- about it this is right. Otherwise apps have to
- play 'guess the biggest size' games. RCVBUF/SNDBUF
- are treated in BSD as hints */
-
- if (val > sysctl_rmem_max)
- val = sysctl_rmem_max;
+ * about it this is right. Otherwise apps have to
+ * play 'guess the biggest size' games. RCVBUF/SNDBUF
+ * are treated in BSD as hints
+ */
+ val = min_t(u32, val, sysctl_rmem_max);
set_rcvbuf:
sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
/*
@@ -629,10 +624,7 @@ set_rcvbuf:
* returning the value we actually used in getsockopt
* is the most desirable behavior.
*/
- if ((val * 2) < SOCK_MIN_RCVBUF)
- sk->sk_rcvbuf = SOCK_MIN_RCVBUF;
- else
- sk->sk_rcvbuf = val * 2;
+ sk->sk_rcvbuf = max_t(u32, val * 2, SOCK_MIN_RCVBUF);
break;
case SO_RCVBUFFORCE:
@@ -858,7 +850,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
break;
case SO_BROADCAST:
- v.val = !!sock_flag(sk, SOCK_BROADCAST);
+ v.val = sock_flag(sk, SOCK_BROADCAST);
break;
case SO_SNDBUF:
@@ -874,7 +866,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
break;
case SO_KEEPALIVE:
- v.val = !!sock_flag(sk, SOCK_KEEPOPEN);
+ v.val = sock_flag(sk, SOCK_KEEPOPEN);
break;
case SO_TYPE:
@@ -896,7 +888,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
break;
case SO_OOBINLINE:
- v.val = !!sock_flag(sk, SOCK_URGINLINE);
+ v.val = sock_flag(sk, SOCK_URGINLINE);
break;
case SO_NO_CHECK:
@@ -909,7 +901,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
case SO_LINGER:
lv = sizeof(v.ling);
- v.ling.l_onoff = !!sock_flag(sk, SOCK_LINGER);
+ v.ling.l_onoff = sock_flag(sk, SOCK_LINGER);
v.ling.l_linger = sk->sk_lingertime / HZ;
break;
@@ -975,7 +967,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
break;
case SO_PASSCRED:
- v.val = test_bit(SOCK_PASSCRED, &sock->flags) ? 1 : 0;
+ v.val = !!test_bit(SOCK_PASSCRED, &sock->flags);
break;
case SO_PEERCRED:
@@ -1010,7 +1002,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
break;
case SO_PASSSEC:
- v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0;
+ v.val = !!test_bit(SOCK_PASSSEC, &sock->flags);
break;
case SO_PEERSEC:
@@ -1021,11 +1013,11 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
break;
case SO_RXQ_OVFL:
- v.val = !!sock_flag(sk, SOCK_RXQ_OVFL);
+ v.val = sock_flag(sk, SOCK_RXQ_OVFL);
break;
case SO_WIFI_STATUS:
- v.val = !!sock_flag(sk, SOCK_WIFI_STATUS);
+ v.val = sock_flag(sk, SOCK_WIFI_STATUS);
break;
case SO_PEEK_OFF:
@@ -1035,7 +1027,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
v.val = sk->sk_peek_off;
break;
case SO_NOFCS:
- v.val = !!sock_flag(sk, SOCK_NOFCS);
+ v.val = sock_flag(sk, SOCK_NOFCS);
break;
default:
return -ENOPROTOOPT;
@@ -1247,8 +1239,8 @@ static void __sk_free(struct sock *sk)
sock_disable_timestamp(sk, SK_FLAGS_TIMESTAMP);
if (atomic_read(&sk->sk_omem_alloc))
- printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n",
- __func__, atomic_read(&sk->sk_omem_alloc));
+ pr_debug("%s: optmem leakage (%d bytes) detected\n",
+ __func__, atomic_read(&sk->sk_omem_alloc));
if (sk->sk_peer_cred)
put_cred(sk->sk_peer_cred);
@@ -1534,7 +1526,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
@@ -1712,6 +1704,7 @@ static void __release_sock(struct sock *sk)
do {
struct sk_buff *next = skb->next;
+ prefetch(next);
WARN_ON_ONCE(skb_dst_is_noref(skb));
skb->next = NULL;
sk_backlog_rcv(sk, skb);
@@ -2432,7 +2425,7 @@ static void assign_proto_idx(struct proto *prot)
prot->inuse_idx = find_first_zero_bit(proto_inuse_idx, PROTO_INUSE_NR);
if (unlikely(prot->inuse_idx == PROTO_INUSE_NR - 1)) {
- printk(KERN_ERR "PROTO_INUSE_NR exhausted\n");
+ pr_err("PROTO_INUSE_NR exhausted\n");
return;
}
@@ -2462,8 +2455,8 @@ int proto_register(struct proto *prot, int alloc_slab)
NULL);
if (prot->slab == NULL) {
- printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n",
- prot->name);
+ pr_crit("%s: Can't create sock SLAB cache!\n",
+ prot->name);
goto out;
}
@@ -2477,8 +2470,8 @@ int proto_register(struct proto *prot, int alloc_slab)
SLAB_HWCACHE_ALIGN, NULL);
if (prot->rsk_prot->slab == NULL) {
- printk(KERN_CRIT "%s: Can't create request sock SLAB cache!\n",
- prot->name);
+ pr_crit("%s: Can't create request sock SLAB cache!\n",
+ prot->name);
goto out_free_request_sock_slab_name;
}
}
@@ -2576,7 +2569,7 @@ static char proto_method_implemented(const void *method)
}
static long sock_prot_memory_allocated(struct proto *proto)
{
- return proto->memory_allocated != NULL ? proto_memory_allocated(proto): -1L;
+ return proto->memory_allocated != NULL ? proto_memory_allocated(proto) : -1L;
}
static char *sock_prot_memory_pressure(struct proto *proto)
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index b9868e1fd62..5fd146720f3 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -10,7 +10,7 @@
#include <linux/inet_diag.h>
#include <linux/sock_diag.h>
-static struct sock_diag_handler *sock_diag_handlers[AF_MAX];
+static const struct sock_diag_handler *sock_diag_handlers[AF_MAX];
static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);
static DEFINE_MUTEX(sock_diag_table_mutex);
@@ -70,7 +70,7 @@ void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlms
}
EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat);
-int sock_diag_register(struct sock_diag_handler *hndl)
+int sock_diag_register(const struct sock_diag_handler *hndl)
{
int err = 0;
@@ -88,7 +88,7 @@ int sock_diag_register(struct sock_diag_handler *hndl)
}
EXPORT_SYMBOL_GPL(sock_diag_register);
-void sock_diag_unregister(struct sock_diag_handler *hnld)
+void sock_diag_unregister(const struct sock_diag_handler *hnld)
{
int family = hnld->family;
@@ -102,7 +102,7 @@ void sock_diag_unregister(struct sock_diag_handler *hnld)
}
EXPORT_SYMBOL_GPL(sock_diag_unregister);
-static inline struct sock_diag_handler *sock_diag_lock_handler(int family)
+static const inline struct sock_diag_handler *sock_diag_lock_handler(int family)
{
if (sock_diag_handlers[family] == NULL)
request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
@@ -112,7 +112,7 @@ static inline struct sock_diag_handler *sock_diag_lock_handler(int family)
return sock_diag_handlers[family];
}
-static inline void sock_diag_unlock_handler(struct sock_diag_handler *h)
+static inline void sock_diag_unlock_handler(const struct sock_diag_handler *h)
{
mutex_unlock(&sock_diag_table_mutex);
}
@@ -121,7 +121,7 @@ static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
int err;
struct sock_diag_req *req = NLMSG_DATA(nlh);
- struct sock_diag_handler *hndl;
+ const struct sock_diag_handler *hndl;
if (nlmsg_len(nlh) < sizeof(*req))
return -EINVAL;
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 0c285087425..a7c36845b12 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 dc3c3faff2f..39895a65e54 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 d86053002c1..656c7c75b19 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] = {
@@ -703,6 +704,7 @@ static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb,
ret = dcbnl_reply(err, RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP,
pid, seq, flags);
+ dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SAPP, seq, 0);
out:
return ret;
}
@@ -935,6 +937,7 @@ static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
+ dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SET_ALL, seq, 0);
return ret;
}
@@ -1205,13 +1208,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 +1235,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 +1244,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 +1296,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 +1360,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 +1377,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 +1395,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 +1423,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 +1477,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 +1488,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 +1615,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 70bfaf2d196..8c67bedf85b 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 29d6bb629a6..9040be049d8 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 51d5fe5fffb..bc93a333931 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 caf6e1734b6..07f5579ca75 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 4dc588f520e..fa9512d86f3 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/proto.c b/net/dccp/proto.c
index 7065c0ae1e7..6c7c78b8394 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -848,7 +848,7 @@ int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
default:
dccp_pr_debug("packet_type=%s\n",
dccp_packet_name(dh->dccph_type));
- sk_eat_skb(sk, skb, 0);
+ sk_eat_skb(sk, skb, false);
}
verify_sock_status:
if (sock_flag(sk, SOCK_DONE)) {
@@ -905,7 +905,7 @@ verify_sock_status:
len = skb->len;
found_fin_ok:
if (!(flags & MSG_PEEK))
- sk_eat_skb(sk, skb, 0);
+ sk_eat_skb(sk, skb, false);
break;
} while (1);
out:
diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c
index 42348824ee3..607ab71b5a0 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 4136987d94d..2ba1a2814c2 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 c00e3077988..f3924ab1e01 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 9e885f180b6..7eaf9879972 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);
}
@@ -437,9 +438,8 @@ int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowidn
res->fi = NULL;
return 1;
default:
- if (net_ratelimit())
- printk("DECnet: impossible routing event : dn_fib_semantic_match type=%d\n",
- type);
+ net_err_ratelimited("DECnet: impossible routing event : dn_fib_semantic_match type=%d\n",
+ type);
res->fi = NULL;
return -EINVAL;
}
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index ee7013f24fc..ac90f658586 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -162,8 +162,8 @@ static int dn_neigh_construct(struct neighbour *neigh)
else if ((dev->type == ARPHRD_ETHER) || (dev->type == ARPHRD_LOOPBACK))
dn_dn2eth(neigh->ha, dn->addr);
else {
- if (net_ratelimit())
- printk(KERN_DEBUG "Trying to create neigh for hw %d\n", dev->type);
+ net_dbg_ratelimited("Trying to create neigh for hw %d\n",
+ dev->type);
return -EINVAL;
}
@@ -236,15 +236,13 @@ static int dn_long_output(struct neighbour *neigh, struct sk_buff *skb)
if (skb_headroom(skb) < headroom) {
struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
if (skb2 == NULL) {
- if (net_ratelimit())
- printk(KERN_CRIT "dn_long_output: no memory\n");
+ net_crit_ratelimited("dn_long_output: no memory\n");
kfree_skb(skb);
return -ENOBUFS;
}
kfree_skb(skb);
skb = skb2;
- if (net_ratelimit())
- printk(KERN_INFO "dn_long_output: Increasing headroom\n");
+ net_info_ratelimited("dn_long_output: Increasing headroom\n");
}
data = skb_push(skb, sizeof(struct dn_long_packet) + 3);
@@ -281,15 +279,13 @@ static int dn_short_output(struct neighbour *neigh, struct sk_buff *skb)
if (skb_headroom(skb) < headroom) {
struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
if (skb2 == NULL) {
- if (net_ratelimit())
- printk(KERN_CRIT "dn_short_output: no memory\n");
+ net_crit_ratelimited("dn_short_output: no memory\n");
kfree_skb(skb);
return -ENOBUFS;
}
kfree_skb(skb);
skb = skb2;
- if (net_ratelimit())
- printk(KERN_INFO "dn_short_output: Increasing headroom\n");
+ net_info_ratelimited("dn_short_output: Increasing headroom\n");
}
data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
@@ -322,15 +318,13 @@ static int dn_phase3_output(struct neighbour *neigh, struct sk_buff *skb)
if (skb_headroom(skb) < headroom) {
struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
if (skb2 == NULL) {
- if (net_ratelimit())
- printk(KERN_CRIT "dn_phase3_output: no memory\n");
+ net_crit_ratelimited("dn_phase3_output: no memory\n");
kfree_skb(skb);
return -ENOBUFS;
}
kfree_skb(skb);
skb = skb2;
- if (net_ratelimit())
- printk(KERN_INFO "dn_phase3_output: Increasing headroom\n");
+ net_info_ratelimited("dn_phase3_output: Increasing headroom\n");
}
data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
index f6544b2c91b..c344163e6ac 100644
--- a/net/decnet/dn_nsp_in.c
+++ b/net/decnet/dn_nsp_in.c
@@ -80,12 +80,15 @@ extern int decnet_log_martians;
static void dn_log_martian(struct sk_buff *skb, const char *msg)
{
- if (decnet_log_martians && net_ratelimit()) {
+ if (decnet_log_martians) {
char *devname = skb->dev ? skb->dev->name : "???";
struct dn_skb_cb *cb = DN_SKB_CB(skb);
- printk(KERN_INFO "DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n",
- msg, devname, le16_to_cpu(cb->src), le16_to_cpu(cb->dst),
- le16_to_cpu(cb->src_port), le16_to_cpu(cb->dst_port));
+ net_info_ratelimited("DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n",
+ msg, devname,
+ le16_to_cpu(cb->src),
+ le16_to_cpu(cb->dst),
+ le16_to_cpu(cb->src_port),
+ le16_to_cpu(cb->dst_port));
}
}
@@ -588,7 +591,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 e446e85e64a..564a6ad13ce 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -1,4 +1,3 @@
-
/*
* DECnet An implementation of the DECnet protocol suite for the LINUX
* operating system. DECnet is implemented using the BSD Socket
@@ -209,7 +208,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 +239,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
@@ -554,8 +553,8 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
unsigned char *msg;
if ((dst == NULL) || (rem == 0)) {
- if (net_ratelimit())
- printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", le16_to_cpu(rem), dst);
+ net_dbg_ratelimited("DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n",
+ le16_to_cpu(rem), dst);
return;
}
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 80a3de4906d..586302e557a 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;
@@ -748,8 +748,7 @@ static int dn_output(struct sk_buff *skb)
dn_to_neigh_output);
error:
- if (net_ratelimit())
- printk(KERN_DEBUG "dn_output: This should not happen\n");
+ net_dbg_ratelimited("dn_output: This should not happen\n");
kfree_skb(skb);
@@ -807,12 +806,10 @@ drop:
*/
static int dn_rt_bug(struct sk_buff *skb)
{
- if (net_ratelimit()) {
- struct dn_skb_cb *cb = DN_SKB_CB(skb);
+ struct dn_skb_cb *cb = DN_SKB_CB(skb);
- printk(KERN_DEBUG "dn_rt_bug: skb from:%04x to:%04x\n",
- le16_to_cpu(cb->src), le16_to_cpu(cb->dst));
- }
+ net_dbg_ratelimited("dn_rt_bug: skb from:%04x to:%04x\n",
+ le16_to_cpu(cb->src), le16_to_cpu(cb->dst));
kfree_skb(skb);
@@ -934,8 +931,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 +1206,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 +1272,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;
@@ -1327,9 +1324,7 @@ static int dn_route_input_slow(struct sk_buff *skb)
out_dev = DN_FIB_RES_DEV(res);
if (out_dev == NULL) {
- if (net_ratelimit())
- printk(KERN_CRIT "Bug in dn_route_input_slow() "
- "No output device\n");
+ net_crit_ratelimited("Bug in dn_route_input_slow() No output device\n");
goto e_inval;
}
dev_hold(out_dev);
@@ -1490,7 +1485,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 f65c9ddaee4..e65f2c856e0 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/dn_table.c b/net/decnet/dn_table.c
index a9a62f225a6..650f3380c98 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -836,8 +836,8 @@ struct dn_fib_table *dn_fib_get_table(u32 n, int create)
if (!create)
return NULL;
- if (in_interrupt() && net_ratelimit()) {
- printk(KERN_DEBUG "DECnet: BUG! Attempt to create routing table from interrupt\n");
+ if (in_interrupt()) {
+ net_dbg_ratelimited("DECnet: BUG! Attempt to create routing table from interrupt\n");
return NULL;
}
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index 1531135130d..44b890936fc 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -57,8 +57,7 @@ nlmsg_failure:
if (skb)
kfree_skb(skb);
*errp = -ENOMEM;
- if (net_ratelimit())
- printk(KERN_ERR "dn_rtmsg: error creating netlink message\n");
+ net_err_ratelimited("dn_rtmsg: error creating netlink message\n");
return NULL;
}
diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c
index 02e75d11cfb..a55eeccaa72 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 c73bba326d7..6f70ea935b0 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 189ca9e9b78..17c7886b5b3 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/dsa/slave.c b/net/dsa/slave.c
index 56cf9b8e1c7..e32083d5d8f 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -66,7 +66,7 @@ static int dsa_slave_open(struct net_device *dev)
if (!(master->flags & IFF_UP))
return -ENETDOWN;
- if (compare_ether_addr(dev->dev_addr, master->dev_addr)) {
+ if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) {
err = dev_uc_add(master, dev->dev_addr);
if (err < 0)
goto out;
@@ -89,7 +89,7 @@ clear_allmulti:
if (dev->flags & IFF_ALLMULTI)
dev_set_allmulti(master, -1);
del_unicast:
- if (compare_ether_addr(dev->dev_addr, master->dev_addr))
+ if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
dev_uc_del(master, dev->dev_addr);
out:
return err;
@@ -107,7 +107,7 @@ static int dsa_slave_close(struct net_device *dev)
if (dev->flags & IFF_PROMISC)
dev_set_promiscuity(master, -1);
- if (compare_ether_addr(dev->dev_addr, master->dev_addr))
+ if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
dev_uc_del(master, dev->dev_addr);
return 0;
@@ -146,13 +146,13 @@ static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
if (!(dev->flags & IFF_UP))
goto out;
- if (compare_ether_addr(addr->sa_data, master->dev_addr)) {
+ if (!ether_addr_equal(addr->sa_data, master->dev_addr)) {
err = dev_uc_add(master, addr->sa_data);
if (err < 0)
return err;
}
- if (compare_ether_addr(dev->dev_addr, master->dev_addr))
+ if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
dev_uc_del(master, dev->dev_addr);
out:
diff --git a/net/econet/Kconfig b/net/econet/Kconfig
deleted file mode 100644
index 39a2d2975e0..00000000000
--- a/net/econet/Kconfig
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# Acorn Econet/AUN protocols
-#
-
-config ECONET
- tristate "Acorn Econet/AUN protocols (EXPERIMENTAL)"
- depends on EXPERIMENTAL && INET
- ---help---
- Econet is a fairly old and slow networking protocol mainly used by
- Acorn computers to access file and print servers. It uses native
- Econet network cards. AUN is an implementation of the higher level
- parts of Econet that runs over ordinary Ethernet connections, on
- top of the UDP packet protocol, which in turn runs on top of the
- Internet protocol IP.
-
- If you say Y here, you can choose with the next two options whether
- to send Econet/AUN traffic over a UDP Ethernet connection or over
- a native Econet network card.
-
- To compile this driver as a module, choose M here: the module
- will be called econet.
-
-config ECONET_AUNUDP
- bool "AUN over UDP"
- depends on ECONET
- help
- Say Y here if you want to send Econet/AUN traffic over a UDP
- connection (UDP is a packet based protocol that runs on top of the
- Internet protocol IP) using an ordinary Ethernet network card.
-
-config ECONET_NATIVE
- bool "Native Econet"
- depends on ECONET
- help
- Say Y here if you have a native Econet network card installed in
- your computer.
diff --git a/net/econet/Makefile b/net/econet/Makefile
deleted file mode 100644
index 05fae8be2fe..00000000000
--- a/net/econet/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for Econet support code.
-#
-
-obj-$(CONFIG_ECONET) += econet.o
-
-econet-y := af_econet.o
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
deleted file mode 100644
index 71b5edcee40..00000000000
--- a/net/econet/af_econet.c
+++ /dev/null
@@ -1,1172 +0,0 @@
-/*
- * An implementation of the Acorn Econet and AUN protocols.
- * Philip Blundell <philb@gnu.org>
- *
- * 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.
- *
- */
-
-#define pr_fmt(fmt) fmt
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/route.h>
-#include <linux/inet.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <linux/skbuff.h>
-#include <linux/udp.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <net/sock.h>
-#include <net/inet_common.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#include <linux/if_ec.h>
-#include <net/udp.h>
-#include <net/ip.h>
-#include <linux/spinlock.h>
-#include <linux/rcupdate.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-
-#include <linux/uaccess.h>
-
-static const struct proto_ops econet_ops;
-static struct hlist_head econet_sklist;
-static DEFINE_SPINLOCK(econet_lock);
-static DEFINE_MUTEX(econet_mutex);
-
-/* Since there are only 256 possible network numbers (or fewer, depends
- how you count) it makes sense to use a simple lookup table. */
-static struct net_device *net2dev_map[256];
-
-#define EC_PORT_IP 0xd2
-
-#ifdef CONFIG_ECONET_AUNUDP
-static DEFINE_SPINLOCK(aun_queue_lock);
-static struct socket *udpsock;
-#define AUN_PORT 0x8000
-
-struct aunhdr {
- unsigned char code; /* AUN magic protocol byte */
- unsigned char port;
- unsigned char cb;
- unsigned char pad;
- unsigned long handle;
-};
-
-static unsigned long aun_seq;
-
-/* Queue of packets waiting to be transmitted. */
-static struct sk_buff_head aun_queue;
-static struct timer_list ab_cleanup_timer;
-
-#endif /* CONFIG_ECONET_AUNUDP */
-
-/* Per-packet information */
-struct ec_cb {
- struct sockaddr_ec sec;
- unsigned long cookie; /* Supplied by user. */
-#ifdef CONFIG_ECONET_AUNUDP
- int done;
- unsigned long seq; /* Sequencing */
- unsigned long timeout; /* Timeout */
- unsigned long start; /* jiffies */
-#endif
-#ifdef CONFIG_ECONET_NATIVE
- void (*sent)(struct sk_buff *, int result);
-#endif
-};
-
-static void econet_remove_socket(struct hlist_head *list, struct sock *sk)
-{
- spin_lock_bh(&econet_lock);
- sk_del_node_init(sk);
- spin_unlock_bh(&econet_lock);
-}
-
-static void econet_insert_socket(struct hlist_head *list, struct sock *sk)
-{
- spin_lock_bh(&econet_lock);
- sk_add_node(sk, list);
- spin_unlock_bh(&econet_lock);
-}
-
-/*
- * Pull a packet from our receive queue and hand it to the user.
- * If necessary we block.
- */
-
-static int econet_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len, int flags)
-{
- struct sock *sk = sock->sk;
- struct sk_buff *skb;
- size_t copied;
- int err;
-
- msg->msg_namelen = sizeof(struct sockaddr_ec);
-
- mutex_lock(&econet_mutex);
-
- /*
- * Call the generic datagram receiver. This handles all sorts
- * of horrible races and re-entrancy so we can forget about it
- * in the protocol layers.
- *
- * Now it will return ENETDOWN, if device have just gone down,
- * but then it will block.
- */
-
- skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
-
- /*
- * An error occurred so return it. Because skb_recv_datagram()
- * handles the blocking we don't see and worry about blocking
- * retries.
- */
-
- if (skb == NULL)
- goto out;
-
- /*
- * You lose any data beyond the buffer you gave. If it worries a
- * user program they can ask the device for its MTU anyway.
- */
-
- copied = skb->len;
- if (copied > len) {
- copied = len;
- msg->msg_flags |= MSG_TRUNC;
- }
-
- /* We can't use skb_copy_datagram here */
- err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
- if (err)
- goto out_free;
- sk->sk_stamp = skb->tstamp;
-
- if (msg->msg_name)
- memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
-
- /*
- * Free or return the buffer as appropriate. Again this
- * hides all the races and re-entrancy issues from us.
- */
- err = copied;
-
-out_free:
- skb_free_datagram(sk, skb);
-out:
- mutex_unlock(&econet_mutex);
- return err;
-}
-
-/*
- * Bind an Econet socket.
- */
-
-static int econet_bind(struct socket *sock, struct sockaddr *uaddr,
- int addr_len)
-{
- struct sockaddr_ec *sec = (struct sockaddr_ec *)uaddr;
- struct sock *sk;
- struct econet_sock *eo;
-
- /*
- * Check legality
- */
-
- if (addr_len < sizeof(struct sockaddr_ec) ||
- sec->sec_family != AF_ECONET)
- return -EINVAL;
-
- mutex_lock(&econet_mutex);
-
- sk = sock->sk;
- eo = ec_sk(sk);
-
- eo->cb = sec->cb;
- eo->port = sec->port;
- eo->station = sec->addr.station;
- eo->net = sec->addr.net;
-
- mutex_unlock(&econet_mutex);
-
- return 0;
-}
-
-#if defined(CONFIG_ECONET_AUNUDP) || defined(CONFIG_ECONET_NATIVE)
-/*
- * Queue a transmit result for the user to be told about.
- */
-
-static void tx_result(struct sock *sk, unsigned long cookie, int result)
-{
- struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
- struct ec_cb *eb;
- struct sockaddr_ec *sec;
-
- if (skb == NULL) {
- pr_debug("econet: memory squeeze, transmit result dropped\n");
- return;
- }
-
- eb = (struct ec_cb *)&skb->cb;
- sec = (struct sockaddr_ec *)&eb->sec;
- memset(sec, 0, sizeof(struct sockaddr_ec));
- sec->cookie = cookie;
- sec->type = ECTYPE_TRANSMIT_STATUS | result;
- sec->sec_family = AF_ECONET;
-
- if (sock_queue_rcv_skb(sk, skb) < 0)
- kfree_skb(skb);
-}
-#endif
-
-#ifdef CONFIG_ECONET_NATIVE
-/*
- * Called by the Econet hardware driver when a packet transmit
- * has completed. Tell the user.
- */
-
-static void ec_tx_done(struct sk_buff *skb, int result)
-{
- struct ec_cb *eb = (struct ec_cb *)&skb->cb;
- tx_result(skb->sk, eb->cookie, result);
-}
-#endif
-
-/*
- * Send a packet. We have to work out which device it's going out on
- * and hence whether to use real Econet or the UDP emulation.
- */
-
-static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len)
-{
- struct sockaddr_ec *saddr = (struct sockaddr_ec *)msg->msg_name;
- struct net_device *dev;
- struct ec_addr addr;
- int err;
- unsigned char port, cb;
-#if defined(CONFIG_ECONET_AUNUDP) || defined(CONFIG_ECONET_NATIVE)
- struct sock *sk = sock->sk;
- struct sk_buff *skb;
- struct ec_cb *eb;
-#endif
-#ifdef CONFIG_ECONET_AUNUDP
- struct msghdr udpmsg;
- struct iovec iov[2];
- struct aunhdr ah;
- struct sockaddr_in udpdest;
- __kernel_size_t size;
- mm_segment_t oldfs;
- char *userbuf;
-#endif
-
- /*
- * Check the flags.
- */
-
- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
- return -EINVAL;
-
- /*
- * Get and verify the address.
- */
-
- mutex_lock(&econet_mutex);
-
- if (saddr == NULL || msg->msg_namelen < sizeof(struct sockaddr_ec)) {
- mutex_unlock(&econet_mutex);
- return -EINVAL;
- }
- addr.station = saddr->addr.station;
- addr.net = saddr->addr.net;
- port = saddr->port;
- cb = saddr->cb;
-
- /* Look for a device with the right network number. */
- dev = net2dev_map[addr.net];
-
- /* If not directly reachable, use some default */
- if (dev == NULL) {
- dev = net2dev_map[0];
- /* No interfaces at all? */
- if (dev == NULL) {
- mutex_unlock(&econet_mutex);
- return -ENETDOWN;
- }
- }
-
- if (dev->type == ARPHRD_ECONET) {
- /* Real hardware Econet. We're not worthy etc. */
-#ifdef CONFIG_ECONET_NATIVE
- unsigned short proto = 0;
- int hlen, tlen;
- int res;
-
- if (len + 15 > dev->mtu) {
- mutex_unlock(&econet_mutex);
- return -EMSGSIZE;
- }
-
- dev_hold(dev);
-
- hlen = LL_RESERVED_SPACE(dev);
- tlen = dev->needed_tailroom;
- skb = sock_alloc_send_skb(sk, len + hlen + tlen,
- msg->msg_flags & MSG_DONTWAIT, &err);
- if (skb == NULL)
- goto out_unlock;
-
- skb_reserve(skb, hlen);
- skb_reset_network_header(skb);
-
- eb = (struct ec_cb *)&skb->cb;
-
- eb->cookie = saddr->cookie;
- eb->sec = *saddr;
- eb->sent = ec_tx_done;
-
- err = -EINVAL;
- res = dev_hard_header(skb, dev, ntohs(proto), &addr, NULL, len);
- if (res < 0)
- goto out_free;
- if (res > 0) {
- struct ec_framehdr *fh;
- /* Poke in our control byte and
- port number. Hack, hack. */
- fh = (struct ec_framehdr *)skb->data;
- fh->cb = cb;
- fh->port = port;
- if (sock->type != SOCK_DGRAM) {
- skb_reset_tail_pointer(skb);
- skb->len = 0;
- }
- }
-
- /* Copy the data. Returns -EFAULT on error */
- err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
- skb->protocol = proto;
- skb->dev = dev;
- skb->priority = sk->sk_priority;
- if (err)
- goto out_free;
-
- err = -ENETDOWN;
- if (!(dev->flags & IFF_UP))
- goto out_free;
-
- /*
- * Now send it
- */
-
- dev_queue_xmit(skb);
- dev_put(dev);
- mutex_unlock(&econet_mutex);
- return len;
-
-out_free:
- kfree_skb(skb);
-out_unlock:
- if (dev)
- dev_put(dev);
-#else
- err = -EPROTOTYPE;
-#endif
- mutex_unlock(&econet_mutex);
-
- return err;
- }
-
-#ifdef CONFIG_ECONET_AUNUDP
- /* AUN virtual Econet. */
-
- if (udpsock == NULL) {
- mutex_unlock(&econet_mutex);
- return -ENETDOWN; /* No socket - can't send */
- }
-
- if (len > 32768) {
- err = -E2BIG;
- goto error;
- }
-
- /* Make up a UDP datagram and hand it off to some higher intellect. */
-
- memset(&udpdest, 0, sizeof(udpdest));
- udpdest.sin_family = AF_INET;
- udpdest.sin_port = htons(AUN_PORT);
-
- /* At the moment we use the stupid Acorn scheme of Econet address
- y.x maps to IP a.b.c.x. This should be replaced with something
- more flexible and more aware of subnet masks. */
- {
- struct in_device *idev;
- unsigned long network = 0;
-
- rcu_read_lock();
- idev = __in_dev_get_rcu(dev);
- if (idev) {
- if (idev->ifa_list)
- network = ntohl(idev->ifa_list->ifa_address) &
- 0xffffff00; /* !!! */
- }
- rcu_read_unlock();
- udpdest.sin_addr.s_addr = htonl(network | addr.station);
- }
-
- memset(&ah, 0, sizeof(ah));
- ah.port = port;
- ah.cb = cb & 0x7f;
- ah.code = 2; /* magic */
-
- /* tack our header on the front of the iovec */
- size = sizeof(struct aunhdr);
- iov[0].iov_base = (void *)&ah;
- iov[0].iov_len = size;
-
- userbuf = vmalloc(len);
- if (userbuf == NULL) {
- err = -ENOMEM;
- goto error;
- }
-
- iov[1].iov_base = userbuf;
- iov[1].iov_len = len;
- err = memcpy_fromiovec(userbuf, msg->msg_iov, len);
- if (err)
- goto error_free_buf;
-
- /* Get a skbuff (no data, just holds our cb information) */
- skb = sock_alloc_send_skb(sk, 0, msg->msg_flags & MSG_DONTWAIT, &err);
- if (skb == NULL)
- goto error_free_buf;
-
- eb = (struct ec_cb *)&skb->cb;
-
- eb->cookie = saddr->cookie;
- eb->timeout = 5 * HZ;
- eb->start = jiffies;
- ah.handle = aun_seq;
- eb->seq = (aun_seq++);
- eb->sec = *saddr;
-
- skb_queue_tail(&aun_queue, skb);
-
- udpmsg.msg_name = (void *)&udpdest;
- udpmsg.msg_namelen = sizeof(udpdest);
- udpmsg.msg_iov = &iov[0];
- udpmsg.msg_iovlen = 2;
- udpmsg.msg_control = NULL;
- udpmsg.msg_controllen = 0;
- udpmsg.msg_flags = 0;
-
- oldfs = get_fs();
- set_fs(KERNEL_DS); /* More privs :-) */
- err = sock_sendmsg(udpsock, &udpmsg, size);
- set_fs(oldfs);
-
-error_free_buf:
- vfree(userbuf);
-error:
-#else
- err = -EPROTOTYPE;
-#endif
- mutex_unlock(&econet_mutex);
-
- return err;
-}
-
-/*
- * Look up the address of a socket.
- */
-
-static int econet_getname(struct socket *sock, struct sockaddr *uaddr,
- int *uaddr_len, int peer)
-{
- struct sock *sk;
- struct econet_sock *eo;
- struct sockaddr_ec *sec = (struct sockaddr_ec *)uaddr;
-
- if (peer)
- return -EOPNOTSUPP;
-
- memset(sec, 0, sizeof(*sec));
- mutex_lock(&econet_mutex);
-
- sk = sock->sk;
- eo = ec_sk(sk);
-
- sec->sec_family = AF_ECONET;
- sec->port = eo->port;
- sec->addr.station = eo->station;
- sec->addr.net = eo->net;
-
- mutex_unlock(&econet_mutex);
-
- *uaddr_len = sizeof(*sec);
- return 0;
-}
-
-static void econet_destroy_timer(unsigned long data)
-{
- struct sock *sk = (struct sock *)data;
-
- if (!sk_has_allocations(sk)) {
- sk_free(sk);
- return;
- }
-
- sk->sk_timer.expires = jiffies + 10 * HZ;
- add_timer(&sk->sk_timer);
- pr_debug("econet: socket destroy delayed\n");
-}
-
-/*
- * Close an econet socket.
- */
-
-static int econet_release(struct socket *sock)
-{
- struct sock *sk;
-
- mutex_lock(&econet_mutex);
-
- sk = sock->sk;
- if (!sk)
- goto out_unlock;
-
- econet_remove_socket(&econet_sklist, sk);
-
- /*
- * Now the socket is dead. No more input will appear.
- */
-
- sk->sk_state_change(sk); /* It is useless. Just for sanity. */
-
- sock_orphan(sk);
-
- /* Purge queues */
-
- skb_queue_purge(&sk->sk_receive_queue);
-
- if (sk_has_allocations(sk)) {
- sk->sk_timer.data = (unsigned long)sk;
- sk->sk_timer.expires = jiffies + HZ;
- sk->sk_timer.function = econet_destroy_timer;
- add_timer(&sk->sk_timer);
-
- goto out_unlock;
- }
-
- sk_free(sk);
-
-out_unlock:
- mutex_unlock(&econet_mutex);
- return 0;
-}
-
-static struct proto econet_proto = {
- .name = "ECONET",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct econet_sock),
-};
-
-/*
- * Create an Econet socket
- */
-
-static int econet_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
- struct econet_sock *eo;
- int err;
-
- if (!net_eq(net, &init_net))
- return -EAFNOSUPPORT;
-
- /* Econet only provides datagram services. */
- if (sock->type != SOCK_DGRAM)
- return -ESOCKTNOSUPPORT;
-
- sock->state = SS_UNCONNECTED;
-
- err = -ENOBUFS;
- sk = sk_alloc(net, PF_ECONET, GFP_KERNEL, &econet_proto);
- if (sk == NULL)
- goto out;
-
- sk->sk_reuse = 1;
- sock->ops = &econet_ops;
- sock_init_data(sock, sk);
-
- eo = ec_sk(sk);
- sock_reset_flag(sk, SOCK_ZAPPED);
- sk->sk_family = PF_ECONET;
- eo->num = protocol;
-
- econet_insert_socket(&econet_sklist, sk);
- return 0;
-out:
- return err;
-}
-
-/*
- * Handle Econet specific ioctls
- */
-
-static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void __user *arg)
-{
- struct ifreq ifr;
- struct ec_device *edev;
- struct net_device *dev;
- struct sockaddr_ec *sec;
- int err;
-
- /*
- * Fetch the caller's info block into kernel space
- */
-
- if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
- return -EFAULT;
-
- dev = dev_get_by_name(&init_net, ifr.ifr_name);
- if (dev == NULL)
- return -ENODEV;
-
- sec = (struct sockaddr_ec *)&ifr.ifr_addr;
-
- mutex_lock(&econet_mutex);
-
- err = 0;
- switch (cmd) {
- case SIOCSIFADDR:
- if (!capable(CAP_NET_ADMIN)) {
- err = -EPERM;
- break;
- }
-
- edev = dev->ec_ptr;
- if (edev == NULL) {
- /* Magic up a new one. */
- edev = kzalloc(sizeof(struct ec_device), GFP_KERNEL);
- if (edev == NULL) {
- err = -ENOMEM;
- break;
- }
- dev->ec_ptr = edev;
- } else
- net2dev_map[edev->net] = NULL;
- edev->station = sec->addr.station;
- edev->net = sec->addr.net;
- net2dev_map[sec->addr.net] = dev;
- if (!net2dev_map[0])
- net2dev_map[0] = dev;
- break;
-
- case SIOCGIFADDR:
- edev = dev->ec_ptr;
- if (edev == NULL) {
- err = -ENODEV;
- break;
- }
- memset(sec, 0, sizeof(struct sockaddr_ec));
- sec->addr.station = edev->station;
- sec->addr.net = edev->net;
- sec->sec_family = AF_ECONET;
- dev_put(dev);
- if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
- err = -EFAULT;
- break;
-
- default:
- err = -EINVAL;
- break;
- }
-
- mutex_unlock(&econet_mutex);
-
- dev_put(dev);
-
- return err;
-}
-
-/*
- * Handle generic ioctls
- */
-
-static int econet_ioctl(struct socket *sock, unsigned int cmd,
- unsigned long arg)
-{
- struct sock *sk = sock->sk;
- void __user *argp = (void __user *)arg;
-
- switch (cmd) {
- case SIOCGSTAMP:
- return sock_get_timestamp(sk, argp);
-
- case SIOCGSTAMPNS:
- return sock_get_timestampns(sk, argp);
-
- case SIOCSIFADDR:
- case SIOCGIFADDR:
- return ec_dev_ioctl(sock, cmd, argp);
-
- }
-
- return -ENOIOCTLCMD;
-}
-
-static const struct net_proto_family econet_family_ops = {
- .family = PF_ECONET,
- .create = econet_create,
- .owner = THIS_MODULE,
-};
-
-static const struct proto_ops econet_ops = {
- .family = PF_ECONET,
- .owner = THIS_MODULE,
- .release = econet_release,
- .bind = econet_bind,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .getname = econet_getname,
- .poll = datagram_poll,
- .ioctl = econet_ioctl,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .sendmsg = econet_sendmsg,
- .recvmsg = econet_recvmsg,
- .mmap = sock_no_mmap,
- .sendpage = sock_no_sendpage,
-};
-
-#if defined(CONFIG_ECONET_AUNUDP) || defined(CONFIG_ECONET_NATIVE)
-/*
- * Find the listening socket, if any, for the given data.
- */
-
-static struct sock *ec_listening_socket(unsigned char port, unsigned char
- station, unsigned char net)
-{
- struct sock *sk;
- struct hlist_node *node;
-
- spin_lock(&econet_lock);
- sk_for_each(sk, node, &econet_sklist) {
- struct econet_sock *opt = ec_sk(sk);
- if ((opt->port == port || opt->port == 0) &&
- (opt->station == station || opt->station == 0) &&
- (opt->net == net || opt->net == 0)) {
- sock_hold(sk);
- goto found;
- }
- }
- sk = NULL;
-found:
- spin_unlock(&econet_lock);
- return sk;
-}
-
-/*
- * Queue a received packet for a socket.
- */
-
-static int ec_queue_packet(struct sock *sk, struct sk_buff *skb,
- unsigned char stn, unsigned char net,
- unsigned char cb, unsigned char port)
-{
- struct ec_cb *eb = (struct ec_cb *)&skb->cb;
- struct sockaddr_ec *sec = (struct sockaddr_ec *)&eb->sec;
-
- memset(sec, 0, sizeof(struct sockaddr_ec));
- sec->sec_family = AF_ECONET;
- sec->type = ECTYPE_PACKET_RECEIVED;
- sec->port = port;
- sec->cb = cb;
- sec->addr.net = net;
- sec->addr.station = stn;
-
- return sock_queue_rcv_skb(sk, skb);
-}
-#endif
-
-#ifdef CONFIG_ECONET_AUNUDP
-/*
- * Send an AUN protocol response.
- */
-
-static void aun_send_response(__u32 addr, unsigned long seq, int code, int cb)
-{
- struct sockaddr_in sin = {
- .sin_family = AF_INET,
- .sin_port = htons(AUN_PORT),
- .sin_addr = {.s_addr = addr}
- };
- struct aunhdr ah = {.code = code, .cb = cb, .handle = seq};
- struct kvec iov = {.iov_base = (void *)&ah, .iov_len = sizeof(ah)};
- struct msghdr udpmsg;
-
- udpmsg.msg_name = (void *)&sin;
- udpmsg.msg_namelen = sizeof(sin);
- udpmsg.msg_control = NULL;
- udpmsg.msg_controllen = 0;
- udpmsg.msg_flags = 0;
-
- kernel_sendmsg(udpsock, &udpmsg, &iov, 1, sizeof(ah));
-}
-
-
-/*
- * Handle incoming AUN packets. Work out if anybody wants them,
- * and send positive or negative acknowledgements as appropriate.
- */
-
-static void aun_incoming(struct sk_buff *skb, struct aunhdr *ah, size_t len)
-{
- struct iphdr *ip = ip_hdr(skb);
- unsigned char stn = ntohl(ip->saddr) & 0xff;
- struct dst_entry *dst = skb_dst(skb);
- struct ec_device *edev = NULL;
- struct sock *sk = NULL;
- struct sk_buff *newskb;
-
- if (dst)
- edev = dst->dev->ec_ptr;
-
- if (!edev)
- goto bad;
-
- sk = ec_listening_socket(ah->port, stn, edev->net);
- if (sk == NULL)
- goto bad; /* Nobody wants it */
-
- newskb = alloc_skb((len - sizeof(struct aunhdr) + 15) & ~15,
- GFP_ATOMIC);
- if (newskb == NULL) {
- pr_debug("AUN: memory squeeze, dropping packet\n");
- /* Send nack and hope sender tries again */
- goto bad;
- }
-
- memcpy(skb_put(newskb, len - sizeof(struct aunhdr)), (void *)(ah + 1),
- len - sizeof(struct aunhdr));
-
- if (ec_queue_packet(sk, newskb, stn, edev->net, ah->cb, ah->port)) {
- /* Socket is bankrupt. */
- kfree_skb(newskb);
- goto bad;
- }
-
- aun_send_response(ip->saddr, ah->handle, 3, 0);
- sock_put(sk);
- return;
-
-bad:
- aun_send_response(ip->saddr, ah->handle, 4, 0);
- if (sk)
- sock_put(sk);
-}
-
-/*
- * Handle incoming AUN transmit acknowledgements. If the sequence
- * number matches something in our backlog then kill it and tell
- * the user. If the remote took too long to reply then we may have
- * dropped the packet already.
- */
-
-static void aun_tx_ack(unsigned long seq, int result)
-{
- struct sk_buff *skb;
- unsigned long flags;
- struct ec_cb *eb;
-
- spin_lock_irqsave(&aun_queue_lock, flags);
- skb_queue_walk(&aun_queue, skb) {
- eb = (struct ec_cb *)&skb->cb;
- if (eb->seq == seq)
- goto foundit;
- }
- spin_unlock_irqrestore(&aun_queue_lock, flags);
- pr_debug("AUN: unknown sequence %ld\n", seq);
- return;
-
-foundit:
- tx_result(skb->sk, eb->cookie, result);
- skb_unlink(skb, &aun_queue);
- spin_unlock_irqrestore(&aun_queue_lock, flags);
- kfree_skb(skb);
-}
-
-/*
- * Deal with received AUN frames - sort out what type of thing it is
- * and hand it to the right function.
- */
-
-static void aun_data_available(struct sock *sk, int slen)
-{
- int err;
- struct sk_buff *skb;
- unsigned char *data;
- struct aunhdr *ah;
- size_t len;
-
- while ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL) {
- if (err == -EAGAIN) {
- pr_err("AUN: no data available?!\n");
- return;
- }
- pr_debug("AUN: recvfrom() error %d\n", -err);
- }
-
- data = skb_transport_header(skb) + sizeof(struct udphdr);
- ah = (struct aunhdr *)data;
- len = skb->len - sizeof(struct udphdr);
-
- switch (ah->code) {
- case 2:
- aun_incoming(skb, ah, len);
- break;
- case 3:
- aun_tx_ack(ah->handle, ECTYPE_TRANSMIT_OK);
- break;
- case 4:
- aun_tx_ack(ah->handle, ECTYPE_TRANSMIT_NOT_LISTENING);
- break;
- default:
- pr_debug("AUN: unknown packet type: %d\n", data[0]);
- }
-
- skb_free_datagram(sk, skb);
-}
-
-/*
- * Called by the timer to manage the AUN transmit queue. If a packet
- * was sent to a dead or nonexistent host then we will never get an
- * acknowledgement back. After a few seconds we need to spot this and
- * drop the packet.
- */
-
-static void ab_cleanup(unsigned long h)
-{
- struct sk_buff *skb, *n;
- unsigned long flags;
-
- spin_lock_irqsave(&aun_queue_lock, flags);
- skb_queue_walk_safe(&aun_queue, skb, n) {
- struct ec_cb *eb = (struct ec_cb *)&skb->cb;
- if ((jiffies - eb->start) > eb->timeout) {
- tx_result(skb->sk, eb->cookie,
- ECTYPE_TRANSMIT_NOT_PRESENT);
- skb_unlink(skb, &aun_queue);
- kfree_skb(skb);
- }
- }
- spin_unlock_irqrestore(&aun_queue_lock, flags);
-
- mod_timer(&ab_cleanup_timer, jiffies + (HZ * 2));
-}
-
-static int __init aun_udp_initialise(void)
-{
- int error;
- struct sockaddr_in sin;
-
- skb_queue_head_init(&aun_queue);
- setup_timer(&ab_cleanup_timer, ab_cleanup, 0);
- ab_cleanup_timer.expires = jiffies + (HZ * 2);
- add_timer(&ab_cleanup_timer);
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_port = htons(AUN_PORT);
-
- /* We can count ourselves lucky Acorn machines are too dim to
- speak IPv6. :-) */
- error = sock_create_kern(PF_INET, SOCK_DGRAM, 0, &udpsock);
- if (error < 0) {
- pr_err("AUN: socket error %d\n", -error);
- return error;
- }
-
- udpsock->sk->sk_reuse = 1;
- udpsock->sk->sk_allocation = GFP_ATOMIC; /* we're going to call it
- from interrupts */
-
- error = udpsock->ops->bind(udpsock, (struct sockaddr *)&sin,
- sizeof(sin));
- if (error < 0) {
- pr_err("AUN: bind error %d\n", -error);
- goto release;
- }
-
- udpsock->sk->sk_data_ready = aun_data_available;
-
- return 0;
-
-release:
- sock_release(udpsock);
- udpsock = NULL;
- return error;
-}
-#endif
-
-#ifdef CONFIG_ECONET_NATIVE
-
-/*
- * Receive an Econet frame from a device.
- */
-
-static int econet_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
-{
- struct ec_framehdr *hdr;
- struct sock *sk = NULL;
- struct ec_device *edev = dev->ec_ptr;
-
- if (!net_eq(dev_net(dev), &init_net))
- goto drop;
-
- if (skb->pkt_type == PACKET_OTHERHOST)
- goto drop;
-
- if (!edev)
- goto drop;
-
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (skb == NULL)
- return NET_RX_DROP;
-
- if (!pskb_may_pull(skb, sizeof(struct ec_framehdr)))
- goto drop;
-
- hdr = (struct ec_framehdr *)skb->data;
-
- /* First check for encapsulated IP */
- if (hdr->port == EC_PORT_IP) {
- skb->protocol = htons(ETH_P_IP);
- skb_pull(skb, sizeof(struct ec_framehdr));
- netif_rx(skb);
- return NET_RX_SUCCESS;
- }
-
- sk = ec_listening_socket(hdr->port, hdr->src_stn, hdr->src_net);
- if (!sk)
- goto drop;
-
- if (ec_queue_packet(sk, skb, edev->net, hdr->src_stn, hdr->cb,
- hdr->port))
- goto drop;
- sock_put(sk);
- return NET_RX_SUCCESS;
-
-drop:
- if (sk)
- sock_put(sk);
- kfree_skb(skb);
- return NET_RX_DROP;
-}
-
-static struct packet_type econet_packet_type __read_mostly = {
- .type = cpu_to_be16(ETH_P_ECONET),
- .func = econet_rcv,
-};
-
-static void econet_hw_initialise(void)
-{
- dev_add_pack(&econet_packet_type);
-}
-
-#endif
-
-static int econet_notifier(struct notifier_block *this, unsigned long msg,
- void *data)
-{
- struct net_device *dev = data;
- struct ec_device *edev;
-
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
- switch (msg) {
- case NETDEV_UNREGISTER:
- /* A device has gone down - kill any data we hold for it. */
- edev = dev->ec_ptr;
- if (edev) {
- if (net2dev_map[0] == dev)
- net2dev_map[0] = NULL;
- net2dev_map[edev->net] = NULL;
- kfree(edev);
- dev->ec_ptr = NULL;
- }
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block econet_netdev_notifier = {
- .notifier_call = econet_notifier,
-};
-
-static void __exit econet_proto_exit(void)
-{
-#ifdef CONFIG_ECONET_AUNUDP
- del_timer(&ab_cleanup_timer);
- if (udpsock)
- sock_release(udpsock);
-#endif
- unregister_netdevice_notifier(&econet_netdev_notifier);
-#ifdef CONFIG_ECONET_NATIVE
- dev_remove_pack(&econet_packet_type);
-#endif
- sock_unregister(econet_family_ops.family);
- proto_unregister(&econet_proto);
-}
-
-static int __init econet_proto_init(void)
-{
- int err = proto_register(&econet_proto, 0);
-
- if (err != 0)
- goto out;
- sock_register(&econet_family_ops);
-#ifdef CONFIG_ECONET_AUNUDP
- aun_udp_initialise();
-#endif
-#ifdef CONFIG_ECONET_NATIVE
- econet_hw_initialise();
-#endif
- register_netdevice_notifier(&econet_netdev_notifier);
-out:
- return err;
-}
-
-module_init(econet_proto_init);
-module_exit(econet_proto_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NETPROTO(PF_ECONET);
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index bf10a311cf1..36e58800a9e 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);
@@ -164,7 +164,7 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
eth = eth_hdr(skb);
if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
- if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast))
+ if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast))
skb->pkt_type = PACKET_BROADCAST;
else
skb->pkt_type = PACKET_MULTICAST;
@@ -179,7 +179,8 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
*/
else if (1 /*dev->flags&IFF_PROMISC */ ) {
- if (unlikely(compare_ether_addr_64bits(eth->h_dest, dev->dev_addr)))
+ if (unlikely(!ether_addr_equal_64bits(eth->h_dest,
+ dev->dev_addr)))
skb->pkt_type = PACKET_OTHERHOST;
}
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 840821b90bc..32eb4179e8f 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -196,7 +196,7 @@ lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, const struct in6_addr *ipaddr,
static void
lowpan_uip_ds6_set_addr_iid(struct in6_addr *ipaddr, unsigned char *lladdr)
{
- memcpy(&ipaddr->s6_addr[8], lladdr, IEEE802154_ALEN);
+ memcpy(&ipaddr->s6_addr[8], lladdr, IEEE802154_ADDR_LEN);
/* second bit-flip (Universe/Local) is done according RFC2464 */
ipaddr->s6_addr[8] ^= 0x02;
}
@@ -221,7 +221,7 @@ lowpan_uncompress_addr(struct sk_buff *skb, struct in6_addr *ipaddr,
if (lladdr)
lowpan_raw_dump_inline(__func__, "linklocal address",
- lladdr, IEEE802154_ALEN);
+ lladdr, IEEE802154_ADDR_LEN);
if (prefcount > 0)
memcpy(ipaddr, prefix, prefcount);
@@ -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;
@@ -650,6 +650,53 @@ static void lowpan_fragment_timer_expired(unsigned long entry_addr)
kfree(entry);
}
+static struct lowpan_fragment *
+lowpan_alloc_new_frame(struct sk_buff *skb, u8 iphc0, u8 len, u8 tag)
+{
+ struct lowpan_fragment *frame;
+
+ frame = kzalloc(sizeof(struct lowpan_fragment),
+ GFP_ATOMIC);
+ if (!frame)
+ goto frame_err;
+
+ INIT_LIST_HEAD(&frame->list);
+
+ frame->length = (iphc0 & 7) | (len << 3);
+ frame->tag = tag;
+
+ /* allocate buffer for frame assembling */
+ frame->skb = alloc_skb(frame->length +
+ sizeof(struct ipv6hdr), GFP_ATOMIC);
+
+ if (!frame->skb)
+ goto skb_err;
+
+ frame->skb->priority = skb->priority;
+ frame->skb->dev = skb->dev;
+
+ /* reserve headroom for uncompressed ipv6 header */
+ skb_reserve(frame->skb, sizeof(struct ipv6hdr));
+ skb_put(frame->skb, frame->length);
+
+ init_timer(&frame->timer);
+ /* time out is the same as for ipv6 - 60 sec */
+ frame->timer.expires = jiffies + LOWPAN_FRAG_TIMEOUT;
+ frame->timer.data = (unsigned long)frame;
+ frame->timer.function = lowpan_fragment_timer_expired;
+
+ add_timer(&frame->timer);
+
+ list_add_tail(&frame->list, &lowpan_fragments);
+
+ return frame;
+
+skb_err:
+ kfree(frame);
+frame_err:
+ return NULL;
+}
+
static int
lowpan_process_data(struct sk_buff *skb)
{
@@ -692,41 +739,9 @@ lowpan_process_data(struct sk_buff *skb)
/* alloc new frame structure */
if (!found) {
- frame = kzalloc(sizeof(struct lowpan_fragment),
- GFP_ATOMIC);
+ frame = lowpan_alloc_new_frame(skb, iphc0, len, tag);
if (!frame)
goto unlock_and_drop;
-
- INIT_LIST_HEAD(&frame->list);
-
- frame->length = (iphc0 & 7) | (len << 3);
- frame->tag = tag;
-
- /* allocate buffer for frame assembling */
- frame->skb = alloc_skb(frame->length +
- sizeof(struct ipv6hdr), GFP_ATOMIC);
-
- if (!frame->skb) {
- kfree(frame);
- goto unlock_and_drop;
- }
-
- frame->skb->priority = skb->priority;
- frame->skb->dev = skb->dev;
-
- /* reserve headroom for uncompressed ipv6 header */
- skb_reserve(frame->skb, sizeof(struct ipv6hdr));
- skb_put(frame->skb, frame->length);
-
- init_timer(&frame->timer);
- /* time out is the same as for ipv6 - 60 sec */
- frame->timer.expires = jiffies + LOWPAN_FRAG_TIMEOUT;
- frame->timer.data = (unsigned long)frame;
- frame->timer.function = lowpan_fragment_timer_expired;
-
- add_timer(&frame->timer);
-
- list_add_tail(&frame->list, &lowpan_fragments);
}
if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1)
diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
index aeff3f31048..8c2251fb0a3 100644
--- a/net/ieee802154/6lowpan.h
+++ b/net/ieee802154/6lowpan.h
@@ -53,9 +53,6 @@
#ifndef __6LOWPAN_H__
#define __6LOWPAN_H__
-/* need to know address length to manipulate with it */
-#define IEEE802154_ALEN 8
-
#define UIP_802154_SHORTADDR_LEN 2 /* compressed ipv6 address length */
#define UIP_IPH_LEN 40 /* ipv6 fixed header size */
#define UIP_PROTO_UDP 17 /* ipv6 next header value for UDP */
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
index 1b09eaabaac..6fbb2ad7bb6 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 adaf4621490..ca92587720f 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-&