summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/8021q/vlan.c28
-rw-r--r--net/8021q/vlan.h2
-rw-r--r--net/8021q/vlan_core.c85
-rw-r--r--net/8021q/vlan_dev.c223
-rw-r--r--net/8021q/vlanproc.c2
-rw-r--r--net/9p/client.c11
-rw-r--r--net/9p/trans_common.c4
-rw-r--r--net/9p/util.c2
-rw-r--r--net/Kconfig14
-rw-r--r--net/atm/br2684.c2
-rw-r--r--net/atm/lec.c4
-rw-r--r--net/atm/lec.h2
-rw-r--r--net/ax25/af_ax25.c16
-rw-r--r--net/ax25/ax25_iface.c3
-rw-r--r--net/batman-adv/aggregation.c1
-rw-r--r--net/batman-adv/gateway_client.c296
-rw-r--r--net/batman-adv/gateway_client.h2
-rw-r--r--net/batman-adv/hard-interface.c83
-rw-r--r--net/batman-adv/hard-interface.h18
-rw-r--r--net/batman-adv/icmp_socket.c37
-rw-r--r--net/batman-adv/main.h2
-rw-r--r--net/batman-adv/originator.c72
-rw-r--r--net/batman-adv/originator.h1
-rw-r--r--net/batman-adv/routing.c412
-rw-r--r--net/batman-adv/send.c37
-rw-r--r--net/batman-adv/soft-interface.c192
-rw-r--r--net/batman-adv/translation-table.c57
-rw-r--r--net/batman-adv/types.h9
-rw-r--r--net/batman-adv/unicast.c18
-rw-r--r--net/batman-adv/vis.c128
-rw-r--r--net/bluetooth/hci_core.c2
-rw-r--r--net/bluetooth/l2cap_core.c2
-rw-r--r--net/bluetooth/l2cap_sock.c2
-rw-r--r--net/bridge/br.c1
-rw-r--r--net/bridge/br_device.c100
-rw-r--r--net/bridge/br_fdb.c313
-rw-r--r--net/bridge/br_if.c104
-rw-r--r--net/bridge/br_input.c7
-rw-r--r--net/bridge/br_ioctl.c42
-rw-r--r--net/bridge/br_multicast.c12
-rw-r--r--net/bridge/br_netfilter.c10
-rw-r--r--net/bridge/br_netlink.c60
-rw-r--r--net/bridge/br_notify.c11
-rw-r--r--net/bridge/br_private.h22
-rw-r--r--net/bridge/br_private_stp.h13
-rw-r--r--net/bridge/br_stp.c48
-rw-r--r--net/bridge/br_stp_if.c21
-rw-r--r--net/bridge/br_sysfs_br.c39
-rw-r--r--net/bridge/br_sysfs_if.c26
-rw-r--r--net/caif/caif_config_util.c6
-rw-r--r--net/caif/caif_dev.c56
-rw-r--r--net/caif/caif_socket.c37
-rw-r--r--net/caif/cfcnfg.c2
-rw-r--r--net/caif/cfctrl.c75
-rw-r--r--net/caif/cfdgml.c13
-rw-r--r--net/caif/cffrml.c8
-rw-r--r--net/caif/cfmuxl.c49
-rw-r--r--net/caif/cfpkt_skbuff.c178
-rw-r--r--net/caif/cfserl.c7
-rw-r--r--net/caif/cfsrvl.c7
-rw-r--r--net/caif/cfutill.c7
-rw-r--r--net/caif/cfveil.c5
-rw-r--r--net/caif/cfvidl.c5
-rw-r--r--net/can/af_can.c52
-rw-r--r--net/can/bcm.c9
-rw-r--r--net/can/raw.c7
-rw-r--r--net/ceph/Kconfig1
-rw-r--r--net/ceph/auth.c8
-rw-r--r--net/ceph/auth_x.c8
-rw-r--r--net/ceph/ceph_common.c112
-rw-r--r--net/ceph/crypto.c73
-rw-r--r--net/ceph/crypto.h4
-rw-r--r--net/ceph/mon_client.c2
-rw-r--r--net/ceph/osd_client.c14
-rw-r--r--net/core/dev.c150
-rw-r--r--net/core/dst.c34
-rw-r--r--net/core/ethtool.c106
-rw-r--r--net/core/fib_rules.c3
-rw-r--r--net/core/filter.c67
-rw-r--r--net/core/link_watch.c2
-rw-r--r--net/core/net-sysfs.c24
-rw-r--r--net/core/net_namespace.c12
-rw-r--r--net/core/netpoll.c2
-rw-r--r--net/core/pktgen.c37
-rw-r--r--net/core/rtnetlink.c16
-rw-r--r--net/core/skbuff.c2
-rw-r--r--net/core/sock.c10
-rw-r--r--net/core/sysctl_net_core.c9
-rw-r--r--net/dccp/ipv4.c30
-rw-r--r--net/dccp/ipv6.c10
-rw-r--r--net/dccp/output.c2
-rw-r--r--net/decnet/dn_dev.c10
-rw-r--r--net/decnet/dn_route.c15
-rw-r--r--net/decnet/dn_table.c4
-rw-r--r--net/dsa/mv88e6131.c25
-rw-r--r--net/dsa/mv88e6xxx.h2
-rw-r--r--net/dsa/slave.c1
-rw-r--r--net/econet/af_econet.c8
-rw-r--r--net/ieee802154/Makefile2
-rw-r--r--net/ipv4/af_inet.c29
-rw-r--r--net/ipv4/ah4.c7
-rw-r--r--net/ipv4/cipso_ipv4.c121
-rw-r--r--net/ipv4/datagram.c9
-rw-r--r--net/ipv4/esp4.c7
-rw-r--r--net/ipv4/fib_frontend.c16
-rw-r--r--net/ipv4/fib_trie.c112
-rw-r--r--net/ipv4/icmp.c37
-rw-r--r--net/ipv4/igmp.c22
-rw-r--r--net/ipv4/inet_connection_sock.c27
-rw-r--r--net/ipv4/inet_diag.c2
-rw-r--r--net/ipv4/inet_lro.c4
-rw-r--r--net/ipv4/inetpeer.c13
-rw-r--r--net/ipv4/ip_gre.c65
-rw-r--r--net/ipv4/ip_input.c4
-rw-r--r--net/ipv4/ip_options.c44
-rw-r--r--net/ipv4/ip_output.c71
-rw-r--r--net/ipv4/ip_sockglue.c37
-rw-r--r--net/ipv4/ipcomp.c4
-rw-r--r--net/ipv4/ipconfig.c2
-rw-r--r--net/ipv4/ipip.c31
-rw-r--r--net/ipv4/ipmr.c39
-rw-r--r--net/ipv4/netfilter.c5
-rw-r--r--net/ipv4/netfilter/arp_tables.c22
-rw-r--r--net/ipv4/netfilter/ip_tables.c30
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_helper.c2
-rw-r--r--net/ipv4/raw.c49
-rw-r--r--net/ipv4/route.c340
-rw-r--r--net/ipv4/syncookies.c22
-rw-r--r--net/ipv4/sysctl_net_ipv4.c3
-rw-r--r--net/ipv4/tcp.c7
-rw-r--r--net/ipv4/tcp_ipv4.c58
-rw-r--r--net/ipv4/tcp_lp.c2
-rw-r--r--net/ipv4/tcp_output.c2
-rw-r--r--net/ipv4/tcp_yeah.c2
-rw-r--r--net/ipv4/udp.c43
-rw-r--r--net/ipv4/xfrm4_policy.c5
-rw-r--r--net/ipv4/xfrm4_state.c2
-rw-r--r--net/ipv6/addrconf.c22
-rw-r--r--net/ipv6/af_inet6.c4
-rw-r--r--net/ipv6/anycast.c16
-rw-r--r--net/ipv6/esp6.c5
-rw-r--r--net/ipv6/icmp.c8
-rw-r--r--net/ipv6/inet6_connection_sock.c2
-rw-r--r--net/ipv6/ip6_fib.c20
-rw-r--r--net/ipv6/ip6_input.c6
-rw-r--r--net/ipv6/ip6_output.c18
-rw-r--r--net/ipv6/ip6_tunnel.c41
-rw-r--r--net/ipv6/ip6mr.c4
-rw-r--r--net/ipv6/ipcomp6.c5
-rw-r--r--net/ipv6/mcast.c36
-rw-r--r--net/ipv6/mip6.c8
-rw-r--r--net/ipv6/ndisc.c51
-rw-r--r--net/ipv6/netfilter.c23
-rw-r--r--net/ipv6/netfilter/ip6_tables.c23
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c3
-rw-r--r--net/ipv6/netfilter/nf_defrag_ipv6_hooks.c2
-rw-r--r--net/ipv6/raw.c14
-rw-r--r--net/ipv6/reassembly.c4
-rw-r--r--net/ipv6/route.c165
-rw-r--r--net/ipv6/sit.c35
-rw-r--r--net/ipv6/syncookies.c13
-rw-r--r--net/ipv6/tcp_ipv6.c55
-rw-r--r--net/ipv6/udp.c27
-rw-r--r--net/ipv6/xfrm6_mode_beet.c2
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c6
-rw-r--r--net/ipv6/xfrm6_policy.c2
-rw-r--r--net/ipv6/xfrm6_tunnel.c10
-rw-r--r--net/irda/af_irda.c3
-rw-r--r--net/irda/irlap.c2
-rw-r--r--net/irda/irlap_event.c11
-rw-r--r--net/irda/irlap_frame.c2
-rw-r--r--net/irda/irlmp_event.c2
-rw-r--r--net/irda/irnet/irnet.h2
-rw-r--r--net/irda/irproc.c5
-rw-r--r--net/irda/irqueue.c2
-rw-r--r--net/irda/irttp.c2
-rw-r--r--net/irda/qos.c8
-rw-r--r--net/irda/timer.c2
-rw-r--r--net/iucv/af_iucv.c2
-rw-r--r--net/iucv/iucv.c4
-rw-r--r--net/key/af_key.c2
-rw-r--r--net/l2tp/l2tp_ip.c29
-rw-r--r--net/l2tp/l2tp_netlink.c3
-rw-r--r--net/llc/llc_input.c3
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/mesh_pathtbl.c2
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c2
-rw-r--r--net/mac80211/rc80211_pid.h2
-rw-r--r--net/mac80211/rx.c2
-rw-r--r--net/mac80211/sta_info.c4
-rw-r--r--net/mac80211/sta_info.h2
-rw-r--r--net/netfilter/Kconfig1
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ip.c3
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ipmac.c7
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_port.c3
-rw-r--r--net/netfilter/ipset/ip_set_core.c129
-rw-r--r--net/netfilter/ipset/ip_set_getport.c16
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c2
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c2
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c2
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c2
-rw-r--r--net/netfilter/ipset/ip_set_list_set.c53
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c5
-rw-r--r--net/netfilter/ipvs/ip_vs_lblc.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_lblcr.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c8
-rw-r--r--net/netfilter/nf_conntrack_core.c4
-rw-r--r--net/netfilter/nf_conntrack_h323_asn1.c2
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c16
-rw-r--r--net/netfilter/nf_conntrack_proto_dccp.c2
-rw-r--r--net/netfilter/nf_conntrack_proto_sctp.c6
-rw-r--r--net/netfilter/nf_conntrack_sip.c2
-rw-r--r--net/netfilter/nf_conntrack_standalone.c2
-rw-r--r--net/netfilter/nf_queue.c2
-rw-r--r--net/netfilter/nfnetlink_log.c2
-rw-r--r--net/netfilter/x_tables.c9
-rw-r--r--net/netfilter/xt_TCPMSS.c2
-rw-r--r--net/netfilter/xt_addrtype.c42
-rw-r--r--net/netfilter/xt_conntrack.c2
-rw-r--r--net/netfilter/xt_set.c18
-rw-r--r--net/netlabel/netlabel_cipso_v4.c4
-rw-r--r--net/netlabel/netlabel_domainhash.c10
-rw-r--r--net/netlabel/netlabel_mgmt.c2
-rw-r--r--net/netrom/af_netrom.c12
-rw-r--r--net/packet/af_packet.c2
-rw-r--r--net/phonet/pn_dev.c6
-rw-r--r--net/phonet/pn_netlink.c4
-rw-r--r--net/phonet/socket.c45
-rw-r--r--net/rds/ib_send.c2
-rw-r--r--net/rds/iw_cm.c2
-rw-r--r--net/rds/iw_rdma.c2
-rw-r--r--net/rds/iw_send.c2
-rw-r--r--net/rds/send.c2
-rw-r--r--net/rose/af_rose.c16
-rw-r--r--net/rose/rose_route.c2
-rw-r--r--net/rxrpc/ar-peer.c3
-rw-r--r--net/sched/Kconfig11
-rw-r--r--net/sched/Makefile1
-rw-r--r--net/sched/act_api.c2
-rw-r--r--net/sched/act_pedit.c2
-rw-r--r--net/sched/em_meta.c2
-rw-r--r--net/sched/sch_htb.c2
-rw-r--r--net/sched/sch_netem.c6
-rw-r--r--net/sched/sch_qfq.c1137
-rw-r--r--net/sched/sch_sfq.c2
-rw-r--r--net/sctp/associola.c6
-rw-r--r--net/sctp/auth.c6
-rw-r--r--net/sctp/debug.c1
-rw-r--r--net/sctp/endpointola.c20
-rw-r--r--net/sctp/input.c21
-rw-r--r--net/sctp/ipv6.c185
-rw-r--r--net/sctp/output.c2
-rw-r--r--net/sctp/outqueue.c25
-rw-r--r--net/sctp/protocol.c63
-rw-r--r--net/sctp/sm_make_chunk.c62
-rw-r--r--net/sctp/sm_sideeffect.c11
-rw-r--r--net/sctp/sm_statefuns.c109
-rw-r--r--net/sctp/sm_statetable.c78
-rw-r--r--net/sctp/socket.c84
-rw-r--r--net/sctp/transport.c28
-rw-r--r--net/sctp/ulpevent.c32
-rw-r--r--net/sctp/ulpqueue.c2
-rw-r--r--net/socket.c16
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c2
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c2
-rw-r--r--net/sunrpc/xprtsock.c4
-rw-r--r--net/tipc/link.c2
-rw-r--r--net/tipc/name_distr.c2
-rw-r--r--net/unix/af_unix.c2
-rw-r--r--net/wanrouter/wanproc.c2
-rw-r--r--net/wireless/reg.c4
-rw-r--r--net/x25/x25_facilities.c2
-rw-r--r--net/x25/x25_forward.c4
-rw-r--r--net/xfrm/xfrm_policy.c3
-rw-r--r--net/xfrm/xfrm_state.c12
-rw-r--r--net/xfrm/xfrm_user.c6
278 files changed, 5100 insertions, 3288 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 7850412..969e700 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -49,11 +49,6 @@ const char vlan_version[] = DRV_VERSION;
static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
static const char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
-static struct packet_type vlan_packet_type __read_mostly = {
- .type = cpu_to_be16(ETH_P_8021Q),
- .func = vlan_skb_recv, /* VLAN receive method */
-};
-
/* End of global variables definitions. */
static void vlan_group_free(struct vlan_group *grp)
@@ -327,10 +322,6 @@ static void vlan_sync_address(struct net_device *dev,
static void vlan_transfer_features(struct net_device *dev,
struct net_device *vlandev)
{
- u32 old_features = vlandev->features;
-
- vlandev->features &= ~dev->vlan_features;
- vlandev->features |= dev->features & dev->vlan_features;
vlandev->gso_max_size = dev->gso_max_size;
if (dev->features & NETIF_F_HW_VLAN_TX)
@@ -341,8 +332,8 @@ static void vlan_transfer_features(struct net_device *dev,
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid;
#endif
- if (old_features != vlandev->features)
- netdev_features_change(vlandev);
+
+ netdev_update_features(vlandev);
}
static void __vlan_device_event(struct net_device *dev, unsigned long event)
@@ -508,6 +499,18 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_PRE_TYPE_CHANGE:
/* Forbid underlaying device to change its type. */
return NOTIFY_BAD;
+
+ case NETDEV_NOTIFY_PEERS:
+ case NETDEV_BONDING_FAILOVER:
+ /* Propagate to vlan devices */
+ for (i = 0; i < VLAN_N_VID; i++) {
+ vlandev = vlan_group_get_device(grp, i);
+ if (!vlandev)
+ continue;
+
+ call_netdevice_notifiers(event, vlandev);
+ }
+ break;
}
out:
@@ -688,7 +691,6 @@ static int __init vlan_proto_init(void)
if (err < 0)
goto err4;
- dev_add_pack(&vlan_packet_type);
vlan_ioctl_set(vlan_ioctl_handler);
return 0;
@@ -709,8 +711,6 @@ static void __exit vlan_cleanup_module(void)
unregister_netdevice_notifier(&vlan_notifier_block);
- dev_remove_pack(&vlan_packet_type);
-
unregister_pernet_subsys(&vlan_net_ops);
rcu_barrier(); /* Wait for completion of call_rcu()'s */
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 5687c9b..c3408de 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -75,8 +75,6 @@ static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev)
}
/* found in vlan_dev.c */
-int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype, struct net_device *orig_dev);
void vlan_dev_set_ingress_priority(const struct net_device *dev,
u32 skb_prio, u16 vlan_prio);
int vlan_dev_set_egress_priority(const struct net_device *dev,
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index ce8e3ab..41495dc2 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -4,7 +4,7 @@
#include <linux/netpoll.h>
#include "vlan.h"
-bool vlan_hwaccel_do_receive(struct sk_buff **skbp)
+bool vlan_do_receive(struct sk_buff **skbp)
{
struct sk_buff *skb = *skbp;
u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;
@@ -88,3 +88,86 @@ gro_result_t vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
return napi_gro_frags(napi);
}
EXPORT_SYMBOL(vlan_gro_frags);
+
+static struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
+{
+ if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) {
+ if (skb_cow(skb, skb_headroom(skb)) < 0)
+ skb = NULL;
+ if (skb) {
+ /* Lifted from Gleb's VLAN code... */
+ memmove(skb->data - ETH_HLEN,
+ skb->data - VLAN_ETH_HLEN, 12);
+ skb->mac_header += VLAN_HLEN;
+ }
+ }
+ return skb;
+}
+
+static void vlan_set_encap_proto(struct sk_buff *skb, struct vlan_hdr *vhdr)
+{
+ __be16 proto;
+ unsigned char *rawp;
+
+ /*
+ * Was a VLAN packet, grab the encapsulated protocol, which the layer
+ * three protocols care about.
+ */
+
+ proto = vhdr->h_vlan_encapsulated_proto;
+ if (ntohs(proto) >= 1536) {
+ skb->protocol = proto;
+ return;
+ }
+
+ rawp = skb->data;
+ if (*(unsigned short *) rawp == 0xFFFF)
+ /*
+ * This is a magic hack to spot IPX packets. Older Novell
+ * breaks the protocol design and runs IPX over 802.3 without
+ * an 802.2 LLC layer. We look for FFFF which isn't a used
+ * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
+ * but does for the rest.
+ */
+ skb->protocol = htons(ETH_P_802_3);
+ else
+ /*
+ * Real 802.2 LLC
+ */
+ skb->protocol = htons(ETH_P_802_2);
+}
+
+struct sk_buff *vlan_untag(struct sk_buff *skb)
+{
+ struct vlan_hdr *vhdr;
+ u16 vlan_tci;
+
+ if (unlikely(vlan_tx_tag_present(skb))) {
+ /* vlan_tci is already set-up so leave this for another time */
+ return skb;
+ }
+
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (unlikely(!skb))
+ goto err_free;
+
+ if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
+ goto err_free;
+
+ vhdr = (struct vlan_hdr *) skb->data;
+ vlan_tci = ntohs(vhdr->h_vlan_TCI);
+ __vlan_hwaccel_put_tag(skb, vlan_tci);
+
+ skb_pull_rcsum(skb, VLAN_HLEN);
+ vlan_set_encap_proto(skb, vhdr);
+
+ skb = vlan_check_reorder_header(skb);
+ if (unlikely(!skb))
+ goto err_free;
+
+ return skb;
+
+err_free:
+ kfree_skb(skb);
+ return NULL;
+}
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index e34ea9e..d174c31 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -65,179 +65,6 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb)
return 0;
}
-static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
-{
- if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) {
- if (skb_cow(skb, skb_headroom(skb)) < 0)
- skb = NULL;
- if (skb) {
- /* Lifted from Gleb's VLAN code... */
- memmove(skb->data - ETH_HLEN,
- skb->data - VLAN_ETH_HLEN, 12);
- skb->mac_header += VLAN_HLEN;
- }
- }
-
- return skb;
-}
-
-static inline void vlan_set_encap_proto(struct sk_buff *skb,
- struct vlan_hdr *vhdr)
-{
- __be16 proto;
- unsigned char *rawp;
-
- /*
- * Was a VLAN packet, grab the encapsulated protocol, which the layer
- * three protocols care about.
- */
-
- proto = vhdr->h_vlan_encapsulated_proto;
- if (ntohs(proto) >= 1536) {
- skb->protocol = proto;
- return;
- }
-
- rawp = skb->data;
- if (*(unsigned short *)rawp == 0xFFFF)
- /*
- * This is a magic hack to spot IPX packets. Older Novell
- * breaks the protocol design and runs IPX over 802.3 without
- * an 802.2 LLC layer. We look for FFFF which isn't a used
- * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
- * but does for the rest.
- */
- skb->protocol = htons(ETH_P_802_3);
- else
- /*
- * Real 802.2 LLC
- */
- skb->protocol = htons(ETH_P_802_2);
-}
-
-/*
- * Determine the packet's protocol ID. The rule here is that we
- * assume 802.3 if the type field is short enough to be a length.
- * This is normal practice and works for any 'now in use' protocol.
- *
- * Also, at this point we assume that we ARE dealing exclusively with
- * VLAN packets, or packets that should be made into VLAN packets based
- * on a default VLAN ID.
- *
- * NOTE: Should be similar to ethernet/eth.c.
- *
- * SANITY NOTE: This method is called when a packet is moving up the stack
- * towards userland. To get here, it would have already passed
- * through the ethernet/eth.c eth_type_trans() method.
- * SANITY NOTE 2: We are referencing to the VLAN_HDR frields, which MAY be
- * stored UNALIGNED in the memory. RISC systems don't like
- * such cases very much...
- * SANITY NOTE 2a: According to Dave Miller & Alexey, it will always be
- * aligned, so there doesn't need to be any of the unaligned
- * stuff. It has been commented out now... --Ben
- *
- */
-int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype, struct net_device *orig_dev)
-{
- struct vlan_hdr *vhdr;
- struct vlan_pcpu_stats *rx_stats;
- struct net_device *vlan_dev;
- u16 vlan_id;
- u16 vlan_tci;
-
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (skb == NULL)
- goto err_free;
-
- if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
- goto err_free;
-
- vhdr = (struct vlan_hdr *)skb->data;
- vlan_tci = ntohs(vhdr->h_vlan_TCI);
- vlan_id = vlan_tci & VLAN_VID_MASK;
-
- rcu_read_lock();
- vlan_dev = vlan_find_dev(dev, vlan_id);
-
- /* If the VLAN device is defined, we use it.
- * If not, and the VID is 0, it is a 802.1p packet (not
- * really a VLAN), so we will just netif_rx it later to the
- * original interface, but with the skb->proto set to the
- * wrapped proto: we do nothing here.
- */
-
- if (!vlan_dev) {
- if (vlan_id) {
- pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
- __func__, vlan_id, dev->name);
- goto err_unlock;
- }
- rx_stats = NULL;
- } else {
- skb->dev = vlan_dev;
-
- rx_stats = this_cpu_ptr(vlan_dev_info(skb->dev)->vlan_pcpu_stats);
-
- u64_stats_update_begin(&rx_stats->syncp);
- rx_stats->rx_packets++;
- rx_stats->rx_bytes += skb->len;
-
- skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);
-
- pr_debug("%s: priority: %u for TCI: %hu\n",
- __func__, skb->priority, vlan_tci);
-
- switch (skb->pkt_type) {
- case PACKET_BROADCAST:
- /* Yeah, stats collect these together.. */
- /* stats->broadcast ++; // no such counter :-( */
- break;
-
- case PACKET_MULTICAST:
- rx_stats->rx_multicast++;
- break;
-
- case PACKET_OTHERHOST:
- /* 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,
- skb->dev->dev_addr))
- skb->pkt_type = PACKET_HOST;
- break;
- default:
- break;
- }
- u64_stats_update_end(&rx_stats->syncp);
- }
-
- skb_pull_rcsum(skb, VLAN_HLEN);
- vlan_set_encap_proto(skb, vhdr);
-
- if (vlan_dev) {
- skb = vlan_check_reorder_header(skb);
- if (!skb) {
- rx_stats->rx_errors++;
- goto err_unlock;
- }
- }
-
- netif_rx(skb);
-
- rcu_read_unlock();
- return NET_RX_SUCCESS;
-
-err_unlock:
- rcu_read_unlock();
-err_free:
- atomic_long_inc(&dev->rx_dropped);
- kfree_skb(skb);
- return NET_RX_DROP;
-}
-
static inline u16
vlan_dev_get_egress_qos_mask(struct net_device *dev, struct sk_buff *skb)
{
@@ -704,8 +531,8 @@ static int vlan_dev_init(struct net_device *dev)
(1<<__LINK_STATE_DORMANT))) |
(1<<__LINK_STATE_PRESENT);
- dev->features |= real_dev->features & real_dev->vlan_features;
- dev->features |= NETIF_F_LLTX;
+ dev->hw_features = real_dev->vlan_features & NETIF_F_ALL_TX_OFFLOADS;
+ dev->features |= real_dev->vlan_features | NETIF_F_LLTX;
dev->gso_max_size = real_dev->gso_max_size;
/* ipv6 shared card related stuff */
@@ -759,6 +586,17 @@ static void vlan_dev_uninit(struct net_device *dev)
}
}
+static u32 vlan_dev_fix_features(struct net_device *dev, u32 features)
+{
+ struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
+
+ features &= (real_dev->features | NETIF_F_LLTX);
+ if (dev_ethtool_get_rx_csum(real_dev))
+ features |= NETIF_F_RXCSUM;
+
+ return features;
+}
+
static int vlan_ethtool_get_settings(struct net_device *dev,
struct ethtool_cmd *cmd)
{
@@ -774,18 +612,6 @@ static void vlan_ethtool_get_drvinfo(struct net_device *dev,
strcpy(info->fw_version, "N/A");
}
-static u32 vlan_ethtool_get_rx_csum(struct net_device *dev)
-{
- const struct vlan_dev_info *vlan = vlan_dev_info(dev);
- return dev_ethtool_get_rx_csum(vlan->real_dev);
-}
-
-static u32 vlan_ethtool_get_flags(struct net_device *dev)
-{
- const struct vlan_dev_info *vlan = vlan_dev_info(dev);
- return dev_ethtool_get_flags(vlan->real_dev);
-}
-
static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
@@ -823,32 +649,10 @@ static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, st
return stats;
}
-static int vlan_ethtool_set_tso(struct net_device *dev, u32 data)
-{
- if (data) {
- struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
-
- /* Underlying device must support TSO for VLAN-tagged packets
- * and must have TSO enabled now.
- */
- if (!(real_dev->vlan_features & NETIF_F_TSO))
- return -EOPNOTSUPP;
- if (!(real_dev->features & NETIF_F_TSO))
- return -EINVAL;
- dev->features |= NETIF_F_TSO;
- } else {
- dev->features &= ~NETIF_F_TSO;
- }
- return 0;
-}
-
static const struct ethtool_ops vlan_ethtool_ops = {
.get_settings = vlan_ethtool_get_settings,
.get_drvinfo = vlan_ethtool_get_drvinfo,
.get_link = ethtool_op_get_link,
- .get_rx_csum = vlan_ethtool_get_rx_csum,
- .get_flags = vlan_ethtool_get_flags,
- .set_tso = vlan_ethtool_set_tso,
};
static const struct net_device_ops vlan_netdev_ops = {
@@ -874,6 +678,7 @@ static const struct net_device_ops vlan_netdev_ops = {
.ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn,
.ndo_fcoe_ddp_target = vlan_dev_fcoe_ddp_target,
#endif
+ .ndo_fix_features = vlan_dev_fix_features,
};
void vlan_setup(struct net_device *dev)
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index d1314cf..d940c49 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -54,7 +54,7 @@ static const char name_conf[] = "config";
/*
* Structures for interfacing with the /proc filesystem.
- * VLAN creates its own directory /proc/net/vlan with the folowing
+ * VLAN creates its own directory /proc/net/vlan with the following
* entries:
* config device status/configuration
* <device> entry for each device
diff --git a/net/9p/client.c b/net/9p/client.c
index 2ccbf04..0ce9592 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -178,7 +178,7 @@ free_and_return:
* @tag: numeric id for transaction
*
* this is a simple array lookup, but will grow the
- * request_slots as necessary to accomodate transaction
+ * request_slots as necessary to accommodate transaction
* ids which did not previously have a slot.
*
* this code relies on the client spinlock to manage locks, its
@@ -1302,7 +1302,7 @@ int
p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
u32 count)
{
- int err, rsize, total;
+ int err, rsize;
struct p9_client *clnt;
struct p9_req_t *req;
char *dataptr;
@@ -1311,7 +1311,6 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
(long long unsigned) offset, count);
err = 0;
clnt = fid->clnt;
- total = 0;
rsize = fid->iounit;
if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
@@ -1367,7 +1366,7 @@ int
p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
u64 offset, u32 count)
{
- int err, rsize, total;
+ int err, rsize;
struct p9_client *clnt;
struct p9_req_t *req;
@@ -1375,7 +1374,6 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
fid->fid, (long long unsigned) offset, count);
err = 0;
clnt = fid->clnt;
- total = 0;
rsize = fid->iounit;
if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
@@ -1766,7 +1764,7 @@ EXPORT_SYMBOL_GPL(p9_client_xattrcreate);
int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
{
- int err, rsize, total;
+ int err, rsize;
struct p9_client *clnt;
struct p9_req_t *req;
char *dataptr;
@@ -1776,7 +1774,6 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
err = 0;
clnt = fid->clnt;
- total = 0;
rsize = fid->iounit;
if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ)
diff --git a/net/9p/trans_common.c b/net/9p/trans_common.c
index 9172ab7..d47880e 100644
--- a/net/9p/trans_common.c
+++ b/net/9p/trans_common.c
@@ -36,7 +36,7 @@ p9_release_req_pages(struct trans_rpage_info *rpinfo)
EXPORT_SYMBOL(p9_release_req_pages);
/**
- * p9_nr_pages - Return number of pages needed to accomodate the payload.
+ * p9_nr_pages - Return number of pages needed to accommodate the payload.
*/
int
p9_nr_pages(struct p9_req_t *req)
@@ -55,7 +55,7 @@ EXPORT_SYMBOL(p9_nr_pages);
* @req: Request to be sent to server.
* @pdata_off: data offset into the first page after translation (gup).
* @pdata_len: Total length of the IO. gup may not return requested # of pages.
- * @nr_pages: number of pages to accomodate the payload
+ * @nr_pages: number of pages to accommodate the payload
* @rw: Indicates if the pages are for read or write.
*/
int
diff --git a/net/9p/util.c b/net/9p/util.c
index b84619b..da6af81 100644
--- a/net/9p/util.c
+++ b/net/9p/util.c
@@ -67,7 +67,7 @@ EXPORT_SYMBOL(p9_idpool_create);
/**
* p9_idpool_destroy - create a new per-connection id pool
- * @p: idpool to destory
+ * @p: idpool to destroy
*/
void p9_idpool_destroy(struct p9_idpool *p)
diff --git a/net/Kconfig b/net/Kconfig
index 79cabf1..878151c 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -232,6 +232,20 @@ config XPS
depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS
default y
+config HAVE_BPF_JIT
+ bool
+
+config BPF_JIT
+ bool "enable BPF Just In Time compiler"
+ depends on HAVE_BPF_JIT
+ depends on MODULES
+ ---help---
+ Berkeley Packet Filter filtering capabilities are normally handled
+ by an interpreter. This option allows kernel to generate a native
+ code when filter is loaded in memory. This should speedup
+ packet sniffing (libpcap/tcpdump). Note : Admin should enable
+ this feature changing /proc/sys/net/core/bpf_jit_enable
+
menu "Network testing"
config NET_PKTGEN
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index fce2eae..2252c20 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -509,7 +509,7 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
write_lock_irq(&devs_lock);
net_dev = br2684_find_dev(&be.ifspec);
if (net_dev == NULL) {
- pr_err("tried to attach to non-existant device\n");
+ pr_err("tried to attach to non-existent device\n");
err = -ENXIO;
goto error;
}
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 38754fd..25073b6 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -129,7 +129,6 @@ static struct net_device *dev_lec[MAX_LEC_ITF];
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
{
- struct ethhdr *eth;
char *buff;
struct lec_priv *priv;
@@ -138,7 +137,6 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
* LE_TOPOLOGY_REQUEST with the same value of Topology Change bit
* as the Config BPDU has
*/
- eth = (struct ethhdr *)skb->data;
buff = skb->data + skb->dev->hard_header_len;
if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
struct sock *sk;
@@ -1180,7 +1178,6 @@ static int __init lane_module_init(void)
static void __exit lane_module_cleanup(void)
{
int i;
- struct lec_priv *priv;
remove_proc_entry("lec", atm_proc_root);
@@ -1188,7 +1185,6 @@ static void __exit lane_module_cleanup(void)
for (i = 0; i < MAX_LEC_ITF; i++) {
if (dev_lec[i] != NULL) {
- priv = netdev_priv(dev_lec[i]);
unregister_netdev(dev_lec[i]);
free_netdev(dev_lec[i]);
dev_lec[i] = NULL;
diff --git a/net/atm/lec.h b/net/atm/lec.h
index 9d14d19..dfc0719 100644
--- a/net/atm/lec.h
+++ b/net/atm/lec.h
@@ -35,7 +35,7 @@ struct lecdatahdr_8025 {
* Operations that LANE2 capable device can do. Two first functions
* are used to make the device do things. See spec 3.1.3 and 3.1.4.
*
- * The third function is intented for the MPOA component sitting on
+ * The third function is intended for the MPOA component sitting on
* top of the LANE device. The MPOA component assigns it's own function
* to (*associate_indicator)() and the LANE device will use that
* function to tell about TLVs it sees floating through.
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 6da5dae..e7c69f4 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1538,8 +1538,6 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
}
/* Build a packet */
- SOCK_DEBUG(sk, "AX.25: sendto: Addresses built. Building packet.\n");
-
/* Assume the worst case */
size = len + ax25->ax25_dev->dev->hard_header_len;
@@ -1549,8 +1547,6 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
skb_reserve(skb, size - len);
- SOCK_DEBUG(sk, "AX.25: Appending user data\n");
-
/* User data follows immediately after the AX.25 data */
if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
err = -EFAULT;
@@ -1564,8 +1560,6 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
if (!ax25->pidincl)
*skb_push(skb, 1) = sk->sk_protocol;
- SOCK_DEBUG(sk, "AX.25: Transmitting buffer\n");
-
if (sk->sk_type == SOCK_SEQPACKET) {
/* Connected mode sockets go via the LAPB machine */
if (sk->sk_state != TCP_ESTABLISHED) {
@@ -1583,22 +1577,14 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
skb_push(skb, 1 + ax25_addr_size(dp));
- SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp);
-
- if (dp != NULL)
- SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi);
+ /* Building AX.25 Header */
/* Build an AX.25 header */
lv = ax25_addr_build(skb->data, &ax25->source_addr, &sax.sax25_call,
dp, AX25_COMMAND, AX25_MODULUS);
- SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv);
-
skb_set_transport_header(skb, lv);
- SOCK_DEBUG(sk, "base=%p pos=%p\n",
- skb->data, skb_transport_header(skb));
-
*skb_transport_header(skb) = AX25_UI;
/* Datagram frames go straight out of the door as UI */
diff --git a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c
index 5a0dda8..60b545e 100644
--- a/net/ax25/ax25_iface.c
+++ b/net/ax25/ax25_iface.c
@@ -58,7 +58,7 @@ EXPORT_SYMBOL_GPL(ax25_register_pid);
void ax25_protocol_release(unsigned int pid)
{
- struct ax25_protocol *s, *protocol;
+ struct ax25_protocol *protocol;
write_lock_bh(&protocol_list_lock);
protocol = protocol_list;
@@ -72,7 +72,6 @@ void ax25_protocol_release(unsigned int pid)
while (protocol != NULL && protocol->next != NULL) {
if (protocol->next->pid == pid) {
- s = protocol->next;
protocol->next = protocol->next->next;
goto out;
}
diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c
index af45d6b..c11788c 100644
--- a/net/batman-adv/aggregation.c
+++ b/net/batman-adv/aggregation.c
@@ -95,7 +95,6 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet,
return false;
}
-#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
/* create a new aggregated packet and add this packet to it */
static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
unsigned long send_time, bool direct_link,
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 3cc4355..65f3953 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -23,6 +23,7 @@
#include "gateway_client.h"
#include "gateway_common.h"
#include "hard-interface.h"
+#include "originator.h"
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
@@ -42,61 +43,76 @@ static void gw_node_free_ref(struct gw_node *gw_node)
call_rcu(&gw_node->rcu, gw_node_free_rcu);
}
-void *gw_get_selected(struct bat_priv *bat_priv)
+static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv)
{
- struct gw_node *curr_gateway_tmp;
- struct orig_node *orig_node = NULL;
+ struct gw_node *gw_node;
rcu_read_lock();
- curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw);
- if (!curr_gateway_tmp)
- goto out;
-
- orig_node = curr_gateway_tmp->orig_node;
- if (!orig_node)
+ gw_node = rcu_dereference(bat_priv->curr_gw);
+ if (!gw_node)
goto out;
- if (!atomic_inc_not_zero(&orig_node->refcount))
- orig_node = NULL;
+ if (!atomic_inc_not_zero(&gw_node->refcount))
+ gw_node = NULL;
out:
rcu_read_unlock();
- return orig_node;
+ return gw_node;
}
-void gw_deselect(struct bat_priv *bat_priv)
+struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv)
{
struct gw_node *gw_node;
+ struct orig_node *orig_node = NULL;
- spin_lock_bh(&bat_priv->gw_list_lock);
- gw_node = rcu_dereference(bat_priv->curr_gw);
- rcu_assign_pointer(bat_priv->curr_gw, NULL);
- spin_unlock_bh(&bat_priv->gw_list_lock);
+ gw_node = gw_get_selected_gw_node(bat_priv);
+ if (!gw_node)
+ goto out;
+
+ rcu_read_lock();
+ orig_node = gw_node->orig_node;
+ if (!orig_node)
+ goto unlock;
+
+ if (!atomic_inc_not_zero(&orig_node->refcount))
+ orig_node = NULL;
+unlock:
+ rcu_read_unlock();
+out:
if (gw_node)
gw_node_free_ref(gw_node);
+ return orig_node;
}
static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
{
struct gw_node *curr_gw_node;
+ spin_lock_bh(&bat_priv->gw_list_lock);
+
if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
new_gw_node = NULL;
- spin_lock_bh(&bat_priv->gw_list_lock);
- curr_gw_node = rcu_dereference(bat_priv->curr_gw);
+ curr_gw_node = bat_priv->curr_gw;
rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
- spin_unlock_bh(&bat_priv->gw_list_lock);
if (curr_gw_node)
gw_node_free_ref(curr_gw_node);
+
+ spin_unlock_bh(&bat_priv->gw_list_lock);
+}
+
+void gw_deselect(struct bat_priv *bat_priv)
+{
+ gw_select(bat_priv, NULL);
}
void gw_election(struct bat_priv *bat_priv)
{
struct hlist_node *node;
- struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL;
+ struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
+ struct neigh_node *router;
uint8_t max_tq = 0;
uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
int down, up;
@@ -110,32 +126,25 @@ void gw_election(struct bat_priv *bat_priv)
if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
return;
- rcu_read_lock();
- curr_gw = rcu_dereference(bat_priv->curr_gw);
- if (curr_gw) {
- rcu_read_unlock();
- return;
- }
+ curr_gw = gw_get_selected_gw_node(bat_priv);
+ if (curr_gw)
+ goto out;
+ rcu_read_lock();
if (hlist_empty(&bat_priv->gw_list)) {
-
- if (curr_gw) {
- rcu_read_unlock();
- bat_dbg(DBG_BATMAN, bat_priv,
- "Removing selected gateway - "
- "no gateway in range\n");
- gw_deselect(bat_priv);
- } else
- rcu_read_unlock();
-
- return;
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Removing selected gateway - "
+ "no gateway in range\n");
+ gw_deselect(bat_priv);
+ goto unlock;
}
hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
- if (!gw_node->orig_node->router)
+ if (gw_node->deleted)
continue;
- if (gw_node->deleted)
+ router = orig_node_get_router(gw_node->orig_node);
+ if (!router)
continue;
switch (atomic_read(&bat_priv->gw_sel_class)) {
@@ -143,15 +152,14 @@ void gw_election(struct bat_priv *bat_priv)
gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
&down, &up);
- tmp_gw_factor = (gw_node->orig_node->router->tq_avg *
- gw_node->orig_node->router->tq_avg *
+ tmp_gw_factor = (router->tq_avg * router->tq_avg *
down * 100 * 100) /
(TQ_LOCAL_WINDOW_SIZE *
TQ_LOCAL_WINDOW_SIZE * 64);
if ((tmp_gw_factor > max_gw_factor) ||
((tmp_gw_factor == max_gw_factor) &&
- (gw_node->orig_node->router->tq_avg > max_tq)))
+ (router->tq_avg > max_tq)))
curr_gw_tmp = gw_node;
break;
@@ -163,19 +171,25 @@ void gw_election(struct bat_priv *bat_priv)
* soon as a better gateway appears which has
* $routing_class more tq points)
**/
- if (gw_node->orig_node->router->tq_avg > max_tq)
+ if (router->tq_avg > max_tq)
curr_gw_tmp = gw_node;
break;
}
- if (gw_node->orig_node->router->tq_avg > max_tq)
- max_tq = gw_node->orig_node->router->tq_avg;
+ if (router->tq_avg > max_tq)
+ max_tq = router->tq_avg;
if (tmp_gw_factor > max_gw_factor)
max_gw_factor = tmp_gw_factor;
+
+ neigh_node_free_ref(router);
}
if (curr_gw != curr_gw_tmp) {
+ router = orig_node_get_router(curr_gw_tmp->orig_node);
+ if (!router)
+ goto unlock;
+
if ((curr_gw) && (!curr_gw_tmp))
bat_dbg(DBG_BATMAN, bat_priv,
"Removing selected gateway - "
@@ -186,48 +200,50 @@ void gw_election(struct bat_priv *bat_priv)
"(gw_flags: %i, tq: %i)\n",
curr_gw_tmp->orig_node->orig,
curr_gw_tmp->orig_node->gw_flags,
- curr_gw_tmp->orig_node->router->tq_avg);
+ router->tq_avg);
else
bat_dbg(DBG_BATMAN, bat_priv,
"Changing route to gateway %pM "
"(gw_flags: %i, tq: %i)\n",
curr_gw_tmp->orig_node->orig,
curr_gw_tmp->orig_node->gw_flags,
- curr_gw_tmp->orig_node->router->tq_avg);
+ router->tq_avg);
+ neigh_node_free_ref(router);
gw_select(bat_priv, curr_gw_tmp);
}
+unlock:
rcu_read_unlock();
+out:
+ if (curr_gw)
+ gw_node_free_ref(curr_gw);
}
void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
{
- struct gw_node *curr_gateway_tmp;
+ struct orig_node *curr_gw_orig;
+ struct neigh_node *router_gw = NULL, *router_orig = NULL;
uint8_t gw_tq_avg, orig_tq_avg;
- rcu_read_lock();
- curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw);
- if (!curr_gateway_tmp)
- goto out_rcu;
-
- if (!curr_gateway_tmp->orig_node)
- goto deselect_rcu;
+ curr_gw_orig = gw_get_selected_orig(bat_priv);
+ if (!curr_gw_orig)
+ goto deselect;
- if (!curr_gateway_tmp->orig_node->router)
- goto deselect_rcu;
+ router_gw = orig_node_get_router(curr_gw_orig);
+ if (!router_gw)
+ goto deselect;
/* this node already is the gateway */
- if (curr_gateway_tmp->orig_node == orig_node)
- goto out_rcu;
-
- if (!orig_node->router)
- goto out_rcu;
+ if (curr_gw_orig == orig_node)
+ goto out;
- gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg;
- rcu_read_unlock();
+ router_orig = orig_node_get_router(orig_node);
+ if (!router_orig)
+ goto out;
- orig_tq_avg = orig_node->router->tq_avg;
+ gw_tq_avg = router_gw->tq_avg;
+ orig_tq_avg = router_orig->tq_avg;
/* the TQ value has to be better */
if (orig_tq_avg < gw_tq_avg)
@@ -245,16 +261,17 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
"Restarting gateway selection: better gateway found (tq curr: "
"%i, tq new: %i)\n",
gw_tq_avg, orig_tq_avg);
- goto deselect;
-out_rcu:
- rcu_read_unlock();
- goto out;
-deselect_rcu:
- rcu_read_unlock();
deselect:
gw_deselect(bat_priv);
out:
+ if (curr_gw_orig)
+ orig_node_free_ref(curr_gw_orig);
+ if (router_gw)
+ neigh_node_free_ref(router_gw);
+ if (router_orig)
+ neigh_node_free_ref(router_orig);
+
return;
}
@@ -291,7 +308,15 @@ void gw_node_update(struct bat_priv *bat_priv,
struct orig_node *orig_node, uint8_t new_gwflags)
{
struct hlist_node *node;
- struct gw_node *gw_node;
+ struct gw_node *gw_node, *curr_gw;
+
+ /**
+ * Note: We don't need a NULL check here, since curr_gw never gets
+ * dereferenced. If curr_gw is NULL we also should not exit as we may
+ * have this gateway in our list (duplication check!) even though we
+ * have no currently selected gateway.
+ */
+ curr_gw = gw_get_selected_gw_node(bat_priv);
rcu_read_lock();
hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
@@ -312,22 +337,26 @@ void gw_node_update(struct bat_priv *bat_priv,
"Gateway %pM removed from gateway list\n",
orig_node->orig);
- if (gw_node == rcu_dereference(bat_priv->curr_gw)) {
- rcu_read_unlock();
- gw_deselect(bat_priv);
- return;
- }
+ if (gw_node == curr_gw)
+ goto deselect;
}
- rcu_read_unlock();
- return;
+ goto unlock;
}
- rcu_read_unlock();
if (new_gwflags == 0)
- return;
+ goto unlock;
gw_node_add(bat_priv, orig_node, new_gwflags);
+ goto unlock;
+
+deselect:
+ gw_deselect(bat_priv);
+unlock:
+ rcu_read_unlock();
+
+ if (curr_gw)
+ gw_node_free_ref(curr_gw);
}
void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
@@ -337,9 +366,12 @@ void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
void gw_node_purge(struct bat_priv *bat_priv)
{
- struct gw_node *gw_node;
+ struct gw_node *gw_node, *curr_gw;
struct hlist_node *node, *node_tmp;
unsigned long timeout = 2 * PURGE_TIMEOUT * HZ;
+ char do_deselect = 0;
+
+ curr_gw = gw_get_selected_gw_node(bat_priv);
spin_lock_bh(&bat_priv->gw_list_lock);
@@ -350,41 +382,56 @@ void gw_node_purge(struct bat_priv *bat_priv)
atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)
continue;
- if (rcu_dereference(bat_priv->curr_gw) == gw_node)
- gw_deselect(bat_priv);
+ if (curr_gw == gw_node)
+ do_deselect = 1;
hlist_del_rcu(&gw_node->list);
gw_node_free_ref(gw_node);
}
-
spin_unlock_bh(&bat_priv->gw_list_lock);
+
+ /* gw_deselect() needs to acquire the gw_list_lock */
+ if (do_deselect)
+ gw_deselect(bat_priv);
+
+ if (curr_gw)
+ gw_node_free_ref(curr_gw);
}
+/**
+ * fails if orig_node has no router
+ */
static int _write_buffer_text(struct bat_priv *bat_priv,
struct seq_file *seq, struct gw_node *gw_node)
{
struct gw_node *curr_gw;
- int down, up, ret;
+ struct neigh_node *router;
+ int down, up, ret = -1;
gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
- rcu_read_lock();
- curr_gw = rcu_dereference(bat_priv->curr_gw);
+ router = orig_node_get_router(gw_node->orig_node);
+ if (!router)
+ goto out;
- ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
- (curr_gw == gw_node ? "=>" : " "),
- gw_node->orig_node->orig,
- gw_node->orig_node->router->tq_avg,
- gw_node->orig_node->router->addr,
- gw_node->orig_node->router->if_incoming->net_dev->name,
- gw_node->orig_node->gw_flags,
- (down > 2048 ? down / 1024 : down),
- (down > 2048 ? "MBit" : "KBit"),
- (up > 2048 ? up / 1024 : up),
- (up > 2048 ? "MBit" : "KBit"));
+ curr_gw = gw_get_selected_gw_node(bat_priv);
- rcu_read_unlock();
+ ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
+ (curr_gw == gw_node ? "=>" : " "),
+ gw_node->orig_node->orig,
+ router->tq_avg, router->addr,
+ router->if_incoming->net_dev->name,
+ gw_node->orig_node->gw_flags,
+ (down > 2048 ? down / 1024 : down),
+ (down > 2048 ? "MBit" : "KBit"),
+ (up > 2048 ? up / 1024 : up),
+ (up > 2048 ? "MBit" : "KBit"));
+
+ neigh_node_free_ref(router);
+ if (curr_gw)
+ gw_node_free_ref(curr_gw);
+out:
return ret;
}
@@ -392,40 +439,42 @@ int gw_client_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 hard_iface *primary_if;
struct gw_node *gw_node;
struct hlist_node *node;
- int gw_count = 0;
-
- if (!bat_priv->primary_if) {
+ int gw_count = 0, ret = 0;
- return seq_printf(seq, "BATMAN mesh %s disabled - please "
- "specify interfaces to enable it\n",
- net_dev->name);
+ 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 (bat_priv->primary_if->if_status != IF_ACTIVE) {
-
- return seq_printf(seq, "BATMAN mesh %s disabled - "
- "primary interface not active\n",
- net_dev->name);
+ 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, " %-12s (%s/%i) %17s [%10s]: gw_class ... "
"[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
"Gateway", "#", TQ_MAX_VALUE, "Nexthop",
"outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR,
- bat_priv->primary_if->net_dev->name,
- bat_priv->primary_if->net_dev->dev_addr, net_dev->name);
+ primary_if->net_dev->name,
+ primary_if->net_dev->dev_addr, net_dev->name);
rcu_read_lock();
hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
if (gw_node->deleted)
continue;
- if (!gw_node->orig_node->router)
+ /* fails if orig_node has no router */
+ if (_write_buffer_text(bat_priv, seq, gw_node) < 0)
continue;
- _write_buffer_text(bat_priv, seq, gw_node);
gw_count++;
}
rcu_read_unlock();
@@ -433,7 +482,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
if (gw_count == 0)
seq_printf(seq, "No gateways in range ...\n");
- return 0;
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ return ret;
}
int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
@@ -442,6 +494,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
struct iphdr *iphdr;
struct ipv6hdr *ipv6hdr;
struct udphdr *udphdr;
+ struct gw_node *curr_gw;
unsigned int header_len = 0;
if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
@@ -506,12 +559,11 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)
return -1;
- rcu_read_lock();
- if (!rcu_dereference(bat_priv->curr_gw)) {
- rcu_read_unlock();
+ curr_gw = gw_get_selected_gw_node(bat_priv);
+ if (!curr_gw)
return 0;
- }
- rcu_read_unlock();
+ if (curr_gw)
+ gw_node_free_ref(curr_gw);
return 1;
}
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h
index 2aa4391..1ce8c60 100644
--- a/net/batman-adv/gateway_client.h
+++ b/net/batman-adv/gateway_client.h
@@ -24,7 +24,7 @@
void gw_deselect(struct bat_priv *bat_priv);
void gw_election(struct bat_priv *bat_priv);
-void *gw_get_selected(struct bat_priv *bat_priv);
+struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv);
void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node);
void gw_node_update(struct bat_priv *bat_priv,
struct orig_node *orig_node, uint8_t new_gwflags);
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index b3058e4..3e888f1 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -110,47 +110,60 @@ out:
return hard_iface;
}
-static void update_primary_addr(struct bat_priv *bat_priv)
+static void primary_if_update_addr(struct bat_priv *bat_priv)
{
struct vis_packet *vis_packet;
+ struct hard_iface *primary_if;
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
vis_packet = (struct vis_packet *)
bat_priv->my_vis_info->skb_packet->data;
- memcpy(vis_packet->vis_orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+ memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
memcpy(vis_packet->sender_orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+ primary_if->net_dev->dev_addr, ETH_ALEN);
+
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
}
-static void set_primary_if(struct bat_priv *bat_priv,
- struct hard_iface *hard_iface)
+static void primary_if_select(struct bat_priv *bat_priv,
+ struct hard_iface *new_hard_iface)
{
+ struct hard_iface *curr_hard_iface;
struct batman_packet *batman_packet;
- struct hard_iface *old_if;
- if (hard_iface && !atomic_inc_not_zero(&hard_iface->refcount))
- hard_iface = NULL;
+ spin_lock_bh(&hardif_list_lock);
- old_if = bat_priv->primary_if;
- bat_priv->primary_if = hard_iface;
+ if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount))
+ new_hard_iface = NULL;
- if (old_if)
- hardif_free_ref(old_if);
+ curr_hard_iface = bat_priv->primary_if;
+ rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
- if (!bat_priv->primary_if)
- return;
+ if (curr_hard_iface)
+ hardif_free_ref(curr_hard_iface);
- batman_packet = (struct batman_packet *)(hard_iface->packet_buff);
+ if (!new_hard_iface)
+ goto out;
+
+ batman_packet = (struct batman_packet *)(new_hard_iface->packet_buff);
batman_packet->flags = PRIMARIES_FIRST_HOP;
batman_packet->ttl = TTL;
- update_primary_addr(bat_priv);
+ primary_if_update_addr(bat_priv);
/***
* hacky trick to make sure that we send the HNA information via
* our new primary interface
*/
atomic_set(&bat_priv->hna_local_changed, 1);
+
+out:
+ spin_unlock_bh(&hardif_list_lock);
}
static bool hardif_is_iface_up(struct hard_iface *hard_iface)
@@ -236,9 +249,10 @@ void update_min_mtu(struct net_device *soft_iface)
static void hardif_activate_interface(struct hard_iface *hard_iface)
{
struct bat_priv *bat_priv;
+ struct hard_iface *primary_if = NULL;
if (hard_iface->if_status != IF_INACTIVE)
- return;
+ goto out;
bat_priv = netdev_priv(hard_iface->soft_iface);
@@ -249,14 +263,18 @@ static void hardif_activate_interface(struct hard_iface *hard_iface)
* the first active interface becomes our primary interface or
* the next active interface after the old primay interface was removed
*/
- if (!bat_priv->primary_if)
- set_primary_if(bat_priv, hard_iface);
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ primary_if_select(bat_priv, hard_iface);
bat_info(hard_iface->soft_iface, "Interface activated: %s\n",
hard_iface->net_dev->name);
update_min_mtu(hard_iface->soft_iface);
- return;
+
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
}
static void hardif_deactivate_interface(struct hard_iface *hard_iface)
@@ -386,12 +404,13 @@ err:
void hardif_disable_interface(struct hard_iface *hard_iface)
{
struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+ struct hard_iface *primary_if = NULL;
if (hard_iface->if_status == IF_ACTIVE)
hardif_deactivate_interface(hard_iface);
if (hard_iface->if_status != IF_INACTIVE)
- return;
+ goto out;
bat_info(hard_iface->soft_iface, "Removing interface: %s\n",
hard_iface->net_dev->name);
@@ -400,11 +419,12 @@ void hardif_disable_interface(struct hard_iface *hard_iface)
bat_priv->num_ifaces--;
orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
- if (hard_iface == bat_priv->primary_if) {
+ primary_if = primary_if_get_selected(bat_priv);
+ if (hard_iface == primary_if) {
struct hard_iface *new_if;
new_if = hardif_get_active(hard_iface->soft_iface);
- set_primary_if(bat_priv, new_if);
+ primary_if_select(bat_priv, new_if);
if (new_if)
hardif_free_ref(new_if);
@@ -425,6 +445,10 @@ void hardif_disable_interface(struct hard_iface *hard_iface)
hard_iface->soft_iface = NULL;
hardif_free_ref(hard_iface);
+
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
}
static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
@@ -514,6 +538,7 @@ static int hard_if_event(struct notifier_block *this,
{
struct net_device *net_dev = (struct net_device *)ptr;
struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
+ struct hard_iface *primary_if = NULL;
struct bat_priv *bat_priv;
if (!hard_iface && event == NETDEV_REGISTER)
@@ -549,8 +574,12 @@ static int hard_if_event(struct notifier_block *this,
update_mac_addresses(hard_iface);
bat_priv = netdev_priv(hard_iface->soft_iface);
- if (hard_iface == bat_priv->primary_if)
- update_primary_addr(bat_priv);
+ 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);
break;
default:
break;
@@ -559,6 +588,8 @@ static int hard_if_event(struct notifier_block *this,
hardif_put:
hardif_free_ref(hard_iface);
out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
return NOTIFY_DONE;
}
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index a9ddf36..6426599 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -45,4 +45,22 @@ static inline void hardif_free_ref(struct hard_iface *hard_iface)
call_rcu(&hard_iface->rcu, hardif_free_rcu);
}
+static inline struct hard_iface *primary_if_get_selected(
+ struct bat_priv *bat_priv)
+{
+ struct hard_iface *hard_iface;
+
+ rcu_read_lock();
+ hard_iface = rcu_dereference(bat_priv->primary_if);
+ if (!hard_iface)
+ goto out;
+
+ if (!atomic_inc_not_zero(&hard_iface->refcount))
+ hard_iface = NULL;
+
+out:
+ rcu_read_unlock();
+ return hard_iface;
+}
+
#endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c
index 34ce56c..fa22ba2 100644
--- a/net/batman-adv/icmp_socket.c
+++ b/net/batman-adv/icmp_socket.c
@@ -153,6 +153,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
{
struct socket_client *socket_client = file->private_data;
struct bat_priv *bat_priv = socket_client->bat_priv;
+ struct hard_iface *primary_if = NULL;
struct sk_buff *skb;
struct icmp_packet_rr *icmp_packet;
@@ -167,15 +168,21 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
return -EINVAL;
}
- if (!bat_priv->primary_if)
- return -EFAULT;
+ primary_if = primary_if_get_selected(bat_priv);
+
+ if (!primary_if) {
+ len = -EFAULT;
+ goto out;
+ }
if (len >= sizeof(struct icmp_packet_rr))
packet_len = sizeof(struct icmp_packet_rr);
skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr));
- if (!skb)
- return -ENOMEM;
+ if (!skb) {
+ len = -ENOMEM;
+ goto out;
+ }
skb_reserve(skb, sizeof(struct ethhdr));
icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len);
@@ -218,23 +225,13 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
goto dst_unreach;
- rcu_read_lock();
orig_node = orig_hash_find(bat_priv, icmp_packet->dst);
-
if (!orig_node)
- goto unlock;
-
- neigh_node = orig_node->router;
+ goto dst_unreach;
+ neigh_node = orig_node_get_router(orig_node);
if (!neigh_node)
- goto unlock;
-
- if (!atomic_inc_not_zero(&neigh_node->refcount)) {
- neigh_node = NULL;
- goto unlock;
- }
-
- rcu_read_unlock();
+ goto dst_unreach;
if (!neigh_node->if_incoming)
goto dst_unreach;
@@ -243,7 +240,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
goto dst_unreach;
memcpy(icmp_packet->orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+ primary_if->net_dev->dev_addr, ETH_ALEN);
if (packet_len == sizeof(struct icmp_packet_rr))
memcpy(icmp_packet->rr,
@@ -252,14 +249,14 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
goto out;
-unlock:
- rcu_read_unlock();
dst_unreach:
icmp_packet->msg_type = DESTINATION_UNREACHABLE;
bat_socket_add_packet(socket_client, icmp_packet, packet_len);
free_skb:
kfree_skb(skb);
out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
if (neigh_node)
neigh_node_free_ref(neigh_node);
if (orig_node)
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index dc24869..ace7285 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -175,4 +175,6 @@ static inline int compare_eth(void *data1, void *data2)
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
+
#endif /* _NET_BATMAN_ADV_MAIN_H_ */
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 0b91330..ef4a9be 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -70,6 +70,21 @@ void neigh_node_free_ref(struct neigh_node *neigh_node)
call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
}
+/* increases the refcounter of a found router */
+struct neigh_node *orig_node_get_router(struct orig_node *orig_node)
+{
+ struct neigh_node *router;
+
+ rcu_read_lock();
+ router = rcu_dereference(orig_node->router);
+
+ if (router && !atomic_inc_not_zero(&router->refcount))
+ router = NULL;
+
+ rcu_read_unlock();
+ return router;
+}
+
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
uint8_t *neigh,
@@ -87,6 +102,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
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;
@@ -389,29 +405,34 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
struct hashtable_t *hash = bat_priv->orig_hash;
struct hlist_node *node, *node_tmp;
struct hlist_head *head;
+ struct hard_iface *primary_if;
struct orig_node *orig_node;
- struct neigh_node *neigh_node;
+ struct neigh_node *neigh_node, *neigh_node_tmp;
int batman_count = 0;
int last_seen_secs;
int last_seen_msecs;
- int i;
+ int i, ret = 0;
- if ((!bat_priv->primary_if) ||
- (bat_priv->primary_if->if_status != IF_ACTIVE)) {
- if (!bat_priv->primary_if)
- return seq_printf(seq, "BATMAN mesh %s disabled - "
- "please specify interfaces to enable it\n",
- net_dev->name);
+ 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;
+ }
- return seq_printf(seq, "BATMAN mesh %s "
- "disabled - primary interface not active\n",
- net_dev->name);
+ 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, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
SOURCE_VERSION, REVISION_VERSION_STR,
- bat_priv->primary_if->net_dev->name,
- bat_priv->primary_if->net_dev->dev_addr, net_dev->name);
+ primary_if->net_dev->name,
+ primary_if->net_dev->dev_addr, net_dev->name);
seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
"Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop",
"outgoingIF", "Potential nexthops");
@@ -421,40 +442,47 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
- if (!orig_node->router)
+ neigh_node = orig_node_get_router(orig_node);
+ if (!neigh_node)
continue;
- if (orig_node->router->tq_avg == 0)
- continue;
+ if (neigh_node->tq_avg == 0)
+ goto next;
last_seen_secs = jiffies_to_msecs(jiffies -
orig_node->last_valid) / 1000;
last_seen_msecs = jiffies_to_msecs(jiffies -
orig_node->last_valid) % 1000;
- neigh_node = orig_node->router;
seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:",
orig_node->orig, last_seen_secs,
last_seen_msecs, neigh_node->tq_avg,
neigh_node->addr,
neigh_node->if_incoming->net_dev->name);
- hlist_for_each_entry_rcu(neigh_node, node_tmp,
+ hlist_for_each_entry_rcu(neigh_node_tmp, node_tmp,
&orig_node->neigh_list, list) {
- seq_printf(seq, " %pM (%3i)", neigh_node->addr,
- neigh_node->tq_avg);
+ seq_printf(seq, " %pM (%3i)",
+ neigh_node_tmp->addr,
+ neigh_node_tmp->tq_avg);
}
seq_printf(seq, "\n");
batman_count++;
+
+next:
+ neigh_node_free_ref(neigh_node);
}
rcu_read_unlock();
}
- if ((batman_count == 0))
+ if (batman_count == 0)
seq_printf(seq, "No batman nodes in range ...\n");
- return 0;
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ return ret;
}
static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index 5cc0110..e1d641f 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -34,6 +34,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
uint8_t *neigh,
struct hard_iface *if_incoming);
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);
int orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num);
int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num);
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index c172f5d..49f5715 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -87,18 +87,20 @@ static void update_route(struct bat_priv *bat_priv,
struct neigh_node *neigh_node,
unsigned char *hna_buff, int hna_buff_len)
{
- struct neigh_node *neigh_node_tmp;
+ struct neigh_node *curr_router;
+
+ curr_router = orig_node_get_router(orig_node);
/* route deleted */
- if ((orig_node->router) && (!neigh_node)) {
+ if ((curr_router) && (!neigh_node)) {
bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
orig_node->orig);
hna_global_del_orig(bat_priv, orig_node,
"originator timed out");
- /* route added */
- } else if ((!orig_node->router) && (neigh_node)) {
+ /* route added */
+ } else if ((!curr_router) && (neigh_node)) {
bat_dbg(DBG_ROUTES, bat_priv,
"Adding route towards: %pM (via %pM)\n",
@@ -106,21 +108,29 @@ static void update_route(struct bat_priv *bat_priv,
hna_global_add_orig(bat_priv, orig_node,
hna_buff, hna_buff_len);
- /* route changed */
+ /* route changed */
} else {
bat_dbg(DBG_ROUTES, bat_priv,
"Changing route towards: %pM "
"(now via %pM - was via %pM)\n",
orig_node->orig, neigh_node->addr,
- orig_node->router->addr);
+ curr_router->addr);
}
+ if (curr_router)
+ neigh_node_free_ref(curr_router);
+
+ /* increase refcount of new best neighbor */
if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount))
neigh_node = NULL;
- neigh_node_tmp = orig_node->router;
- orig_node->router = neigh_node;
- if (neigh_node_tmp)
- neigh_node_free_ref(neigh_node_tmp);
+
+ spin_lock_bh(&orig_node->neigh_list_lock);
+ rcu_assign_pointer(orig_node->router, neigh_node);
+ spin_unlock_bh(&orig_node->neigh_list_lock);
+
+ /* decrease refcount of previous best neighbor */
+ if (curr_router)
+ neigh_node_free_ref(curr_router);
}
@@ -128,16 +138,23 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
struct neigh_node *neigh_node, unsigned char *hna_buff,
int hna_buff_len)
{
+ struct neigh_node *router = NULL;
if (!orig_node)
- return;
+ goto out;
+
+ router = orig_node_get_router(orig_node);
- if (orig_node->router != neigh_node)
+ if (router != neigh_node)
update_route(bat_priv, orig_node, neigh_node,
hna_buff, hna_buff_len);
/* may be just HNA changed */
else
update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len);
+
+out:
+ if (router)
+ neigh_node_free_ref(router);
}
static int is_bidirectional_neigh(struct orig_node *orig_node,
@@ -288,8 +305,8 @@ static void bonding_candidate_add(struct orig_node *orig_node,
struct neigh_node *neigh_node)
{
struct hlist_node *node;
- struct neigh_node *tmp_neigh_node;
- uint8_t best_tq, interference_candidate = 0;
+ struct neigh_node *tmp_neigh_node, *router = NULL;
+ uint8_t interference_candidate = 0;
spin_lock_bh(&orig_node->neigh_list_lock);
@@ -298,13 +315,12 @@ static void bonding_candidate_add(struct orig_node *orig_node,
neigh_node->orig_node->primary_addr))
goto candidate_del;
- if (!orig_node->router)
+ router = orig_node_get_router(orig_node);
+ if (!router)
goto candidate_del;
- best_tq = orig_node->router->tq_avg;
-
/* ... and is good enough to be considered */
- if (neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD)
+ if (neigh_node->tq_avg < router->tq_avg - BONDING_TQ_THRESHOLD)
goto candidate_del;
/**
@@ -350,7 +366,9 @@ candidate_del:
out:
spin_unlock_bh(&orig_node->neigh_list_lock);
- return;
+
+ if (router)
+ neigh_node_free_ref(router);
}
/* copy primary address for bonding */
@@ -373,6 +391,7 @@ static void update_orig(struct bat_priv *bat_priv,
char is_duplicate)
{
struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
+ struct neigh_node *router = NULL;
struct orig_node *orig_node_tmp;
struct hlist_node *node;
int tmp_hna_buff_len;
@@ -396,10 +415,12 @@ static void update_orig(struct bat_priv *bat_priv,
if (is_duplicate)
continue;
+ spin_lock_bh(&tmp_neigh_node->tq_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);
}
if (!neigh_node) {
@@ -424,10 +445,12 @@ static void update_orig(struct bat_priv *bat_priv,
orig_node->flags = batman_packet->flags;
neigh_node->last_valid = jiffies;
+ spin_lock_bh(&neigh_node->tq_lock);
ring_buffer_set(neigh_node->tq_recv,
&neigh_node->tq_index,
batman_packet->tq);
neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
+ spin_unlock_bh(&neigh_node->tq_lock);
if (!is_duplicate) {
orig_node->last_ttl = batman_packet->ttl;
@@ -441,19 +464,18 @@ static void update_orig(struct bat_priv *bat_priv,
/* if this neighbor already is our next hop there is nothing
* to change */
- if (orig_node->router == neigh_node)
+ router = orig_node_get_router(orig_node);
+ if (router == neigh_node)
goto update_hna;
/* if this neighbor does not offer a better TQ we won't consider it */
- if ((orig_node->router) &&
- (orig_node->router->tq_avg > neigh_node->tq_avg))
+ if (router && (router->tq_avg > neigh_node->tq_avg))
goto update_hna;
/* if the TQ is the same and the link not more symetric we
* won't consider it either */
- if ((orig_node->router) &&
- (neigh_node->tq_avg == orig_node->router->tq_avg)) {
- orig_node_tmp = orig_node->router->orig_node;
+ if (router && (neigh_node->tq_avg == router->tq_avg)) {
+ orig_node_tmp = router->orig_node;
spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
bcast_own_sum_orig =
orig_node_tmp->bcast_own_sum[if_incoming->if_num];
@@ -474,7 +496,7 @@ static void update_orig(struct bat_priv *bat_priv,
goto update_gw;
update_hna:
- update_routes(bat_priv, orig_node, orig_node->router,
+ update_routes(bat_priv, orig_node, router,
hna_buff, tmp_hna_buff_len);
update_gw:
@@ -496,6 +518,8 @@ unlock:
out:
if (neigh_node)
neigh_node_free_ref(neigh_node);
+ if (router)
+ neigh_node_free_ref(router);
}
/* checks whether the host restarted and is in the protection time.
@@ -603,6 +627,8 @@ void receive_bat_packet(struct ethhdr *ethhdr,
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct hard_iface *hard_iface;
struct orig_node *orig_neigh_node, *orig_node;
+ struct neigh_node *router = NULL, *router_router = NULL;
+ struct neigh_node *orig_neigh_router = NULL;
char has_directlink_flag;
char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
@@ -747,14 +773,15 @@ void receive_bat_packet(struct ethhdr *ethhdr,
goto out;
}
+ router = orig_node_get_router(orig_node);
+ if (router)
+ router_router = orig_node_get_router(router->orig_node);
+
/* avoid temporary routing loops */
- if ((orig_node->router) &&
- (orig_node->router->orig_node->router) &&
- (compare_eth(orig_node->router->addr,
- batman_packet->prev_sender)) &&
+ if (router && router_router &&
+ (compare_eth(router->addr, batman_packet->prev_sender)) &&
!(compare_eth(batman_packet->orig, batman_packet->prev_sender)) &&
- (compare_eth(orig_node->router->addr,
- orig_node->router->orig_node->router->addr))) {
+ (compare_eth(router->addr, router_router->addr))) {
bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: ignoring all rebroadcast packets that "
"may make me loop (sender: %pM)\n", ethhdr->h_source);
@@ -769,9 +796,11 @@ void receive_bat_packet(struct ethhdr *ethhdr,
if (!orig_neigh_node)
goto out;
+ orig_neigh_router = orig_node_get_router(orig_neigh_node);
+
/* drop packet if sender is not a direct neighbor and if we
* don't route towards it */
- if (!is_single_hop_neigh && (!orig_neigh_node->router)) {
+ if (!is_single_hop_neigh && (!orig_neigh_router)) {
bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: OGM via unknown neighbor!\n");
goto out_neigh;
@@ -825,6 +854,13 @@ out_neigh:
if ((orig_neigh_node) && (!is_single_hop_neigh))
orig_node_free_ref(orig_neigh_node);
out:
+ if (router)
+ neigh_node_free_ref(router);
+ if (router_router)
+ neigh_node_free_ref(router_router);
+ if (orig_neigh_router)
+ neigh_node_free_ref(orig_neigh_router);
+
orig_node_free_ref(orig_node);
}
@@ -868,8 +904,9 @@ int recv_bat_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
static int recv_my_icmp_packet(struct bat_priv *bat_priv,
struct sk_buff *skb, size_t icmp_len)
{
+ struct hard_iface *primary_if = NULL;
struct orig_node *orig_node = NULL;
- struct neigh_node *neigh_node = NULL;
+ struct neigh_node *router = NULL;
struct icmp_packet_rr *icmp_packet;
int ret = NET_RX_DROP;
@@ -881,28 +918,19 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
goto out;
}
- if (!bat_priv->primary_if)
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
goto out;
/* answer echo request (ping) */
/* get routing information */
- rcu_read_lock();
orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
-
if (!orig_node)
- goto unlock;
-
- neigh_node = orig_node->router;
-
- if (!neigh_node)
- goto unlock;
-
- if (!atomic_inc_not_zero(&neigh_node->refcount)) {
- neigh_node = NULL;
- goto unlock;
- }
+ goto out;
- rcu_read_unlock();
+ router = orig_node_get_router(orig_node);
+ if (!router)
+ goto out;
/* create a copy of the skb, if needed, to modify it. */
if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
@@ -911,20 +939,18 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
icmp_packet = (struct icmp_packet_rr *)skb->data;
memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
- memcpy(icmp_packet->orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+ memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
icmp_packet->msg_type = ECHO_REPLY;
icmp_packet->ttl = TTL;
- send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+ send_skb_packet(skb, router->if_incoming, router->addr);
ret = NET_RX_SUCCESS;
- goto out;
-unlock:
- rcu_read_unlock();
out:
- if (neigh_node)
- neigh_node_free_ref(neigh_node);
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ if (router)
+ neigh_node_free_ref(router);
if (orig_node)
orig_node_free_ref(orig_node);
return ret;
@@ -933,8 +959,9 @@ out:
static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
struct sk_buff *skb)
{
+ struct hard_iface *primary_if = NULL;
struct orig_node *orig_node = NULL;
- struct neigh_node *neigh_node = NULL;
+ struct neigh_node *router = NULL;
struct icmp_packet *icmp_packet;
int ret = NET_RX_DROP;
@@ -948,27 +975,18 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
goto out;
}
- if (!bat_priv->primary_if)
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
goto out;
/* get routing information */
- rcu_read_lock();
orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
-
if (!orig_node)
- goto unlock;
-
- neigh_node = orig_node->router;
-
- if (!neigh_node)
- goto unlock;
-
- if (!atomic_inc_not_zero(&neigh_node->refcount)) {
- neigh_node = NULL;
- goto unlock;
- }
+ goto out;
- rcu_read_unlock();
+ router = orig_node_get_router(orig_node);
+ if (!router)
+ goto out;
/* create a copy of the skb, if needed, to modify it. */
if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
@@ -977,20 +995,18 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
icmp_packet = (struct icmp_packet *)skb->data;
memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
- memcpy(icmp_packet->orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+ memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
icmp_packet->msg_type = TTL_EXCEEDED;
icmp_packet->ttl = TTL;
- send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+ send_skb_packet(skb, router->if_incoming, router->addr);
ret = NET_RX_SUCCESS;
- goto out;
-unlock:
- rcu_read_unlock();
out:
- if (neigh_node)
- neigh_node_free_ref(neigh_node);
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ if (router)
+ neigh_node_free_ref(router);
if (orig_node)
orig_node_free_ref(orig_node);
return ret;
@@ -1003,7 +1019,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
struct icmp_packet_rr *icmp_packet;
struct ethhdr *ethhdr;
struct orig_node *orig_node = NULL;
- struct neigh_node *neigh_node = NULL;
+ struct neigh_node *router = NULL;
int hdr_size = sizeof(struct icmp_packet);
int ret = NET_RX_DROP;
@@ -1050,23 +1066,13 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
return recv_icmp_ttl_exceeded(bat_priv, skb);
/* get routing information */
- rcu_read_lock();
orig_node = orig_hash_find(bat_priv, icmp_packet->dst);
-
if (!orig_node)
- goto unlock;
-
- neigh_node = orig_node->router;
-
- if (!neigh_node)
- goto unlock;
-
- if (!atomic_inc_not_zero(&neigh_node->refcount)) {
- neigh_node = NULL;
- goto unlock;
- }
+ goto out;
- rcu_read_unlock();
+ router = orig_node_get_router(orig_node);
+ if (!router)
+ goto out;
/* create a copy of the skb, if needed, to modify it. */
if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
@@ -1078,20 +1084,117 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
icmp_packet->ttl--;
/* route it */
- send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+ send_skb_packet(skb, router->if_incoming, router->addr);
ret = NET_RX_SUCCESS;
- goto out;
-unlock:
- rcu_read_unlock();
out:
- if (neigh_node)
- neigh_node_free_ref(neigh_node);
+ if (router)
+ neigh_node_free_ref(router);
if (orig_node)
orig_node_free_ref(orig_node);
return ret;
}
+/* In the bonding case, send the packets in a round
+ * robin fashion over the remaining interfaces.
+ *
+ * This method rotates the bonding list and increases the
+ * returned router's refcount. */
+static struct neigh_node *find_bond_router(struct orig_node *primary_orig,
+ struct hard_iface *recv_if)
+{
+ struct neigh_node *tmp_neigh_node;
+ struct neigh_node *router = NULL, *first_candidate = NULL;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
+ bonding_list) {
+ if (!first_candidate)
+ first_candidate = tmp_neigh_node;
+
+ /* recv_if == NULL on the first node. */
+ if (tmp_neigh_node->if_incoming == recv_if)
+ continue;
+
+ if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
+ continue;
+
+ router = tmp_neigh_node;
+ break;
+ }
+
+ /* use the first candidate if nothing was found. */
+ if (!router && first_candidate &&
+ atomic_inc_not_zero(&first_candidate->refcount))
+ router = first_candidate;
+
+ if (!router)
+ goto out;
+
+ /* selected should point to the next element
+ * after the current router */
+ spin_lock_bh(&primary_orig->neigh_list_lock);
+ /* this is a list_move(), which unfortunately
+ * does not exist as rcu version */
+ list_del_rcu(&primary_orig->bond_list);
+ list_add_rcu(&primary_orig->bond_list,
+ &router->bonding_list);
+ spin_unlock_bh(&primary_orig->neigh_list_lock);
+
+out:
+ rcu_read_unlock();
+ return router;
+}
+
+/* Interface Alternating: Use the best of the
+ * remaining candidates which are not using
+ * this interface.
+ *
+ * Increases the returned router's refcount */
+static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
+ struct hard_iface *recv_if)
+{
+ struct neigh_node *tmp_neigh_node;
+ struct neigh_node *router = NULL, *first_candidate = NULL;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
+ bonding_list) {
+ if (!first_candidate)
+ first_candidate = tmp_neigh_node;
+
+ /* recv_if == NULL on the first node. */
+ if (tmp_neigh_node->if_incoming == recv_if)
+ continue;
+
+ if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
+ continue;
+
+ /* if we don't have a router yet
+ * or this one is better, choose it. */
+ if ((!router) ||
+ (tmp_neigh_node->tq_avg > router->tq_avg)) {
+ /* decrement refcount of
+ * previously selected router */
+ if (router)
+ neigh_node_free_ref(router);
+
+ router = tmp_neigh_node;
+ atomic_inc_not_zero(&router->refcount);
+ }
+
+ neigh_node_free_ref(tmp_neigh_node);
+ }
+
+ /* use the first candidate if nothing was found. */
+ if (!router && first_candidate &&
+ atomic_inc_not_zero(&first_candidate->refcount))
+ router = first_candidate;
+
+ rcu_read_unlock();
+ return router;
+}
+
/* find a suitable router for this originator, and use
* bonding if possible. increases the found neighbors
* refcount.*/
@@ -1101,14 +1204,15 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
{
struct orig_node *primary_orig_node;
struct orig_node *router_orig;
- struct neigh_node *router, *first_candidate, *tmp_neigh_node;
+ struct neigh_node *router;
static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
int bonding_enabled;
if (!orig_node)
return NULL;
- if (!orig_node->router)
+ router = orig_node_get_router(orig_node);
+ if (!router)
return NULL;
/* without bonding, the first node should
@@ -1117,9 +1221,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
rcu_read_lock();
/* select default router to output */
- router = orig_node->router;
- router_orig = orig_node->router->orig_node;
- if (!router_orig || !atomic_inc_not_zero(&router->refcount)) {
+ router_orig = router->orig_node;
+ if (!router_orig) {
rcu_read_unlock();
return NULL;
}
@@ -1151,88 +1254,17 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
if (atomic_read(&primary_orig_node->bond_candidates) < 2)
goto return_router;
-
/* all nodes between should choose a candidate which
* is is not on the interface where the packet came
* in. */
neigh_node_free_ref(router);
- first_candidate = NULL;
- router = NULL;
-
- if (bonding_enabled) {
- /* in the bonding case, send the packets in a round
- * robin fashion over the remaining interfaces. */
-
- list_for_each_entry_rcu(tmp_neigh_node,
- &primary_orig_node->bond_list, bonding_list) {
- if (!first_candidate)
- first_candidate = tmp_neigh_node;
- /* recv_if == NULL on the first node. */
- if (tmp_neigh_node->if_incoming != recv_if &&
- atomic_inc_not_zero(&tmp_neigh_node->refcount)) {
- router = tmp_neigh_node;
- break;
- }
- }
-
- /* use the first candidate if nothing was found. */
- if (!router && first_candidate &&
- atomic_inc_not_zero(&first_candidate->refcount))
- router = first_candidate;
-
- if (!router) {
- rcu_read_unlock();
- return NULL;
- }
-
- /* selected should point to the next element
- * after the current router */
- spin_lock_bh(&primary_orig_node->neigh_list_lock);
- /* this is a list_move(), which unfortunately
- * does not exist as rcu version */
- list_del_rcu(&primary_orig_node->bond_list);
- list_add_rcu(&primary_orig_node->bond_list,
- &router->bonding_list);
- spin_unlock_bh(&primary_orig_node->neigh_list_lock);
-
- } else {
- /* if bonding is disabled, use the best of the
- * remaining candidates which are not using
- * this interface. */
- list_for_each_entry_rcu(tmp_neigh_node,
- &primary_orig_node->bond_list, bonding_list) {
- if (!first_candidate)
- first_candidate = tmp_neigh_node;
-
- /* recv_if == NULL on the first node. */
- if (tmp_neigh_node->if_incoming == recv_if)
- continue;
-
- if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
- continue;
-
- /* if we don't have a router yet
- * or this one is better, choose it. */
- if ((!router) ||
- (tmp_neigh_node->tq_avg > router->tq_avg)) {
- /* decrement refcount of
- * previously selected router */
- if (router)
- neigh_node_free_ref(router);
- router = tmp_neigh_node;
- atomic_inc_not_zero(&router->refcount);
- }
-
- neigh_node_free_ref(tmp_neigh_node);
- }
+ if (bonding_enabled)
+ router = find_bond_router(primary_orig_node, recv_if);
+ else
+ router = find_ifalter_router(primary_orig_node, recv_if);
- /* use the first candidate if nothing was found. */
- if (!router && first_candidate &&
- atomic_inc_not_zero(&first_candidate->refcount))
- router = first_candidate;
- }
return_router:
rcu_read_unlock();
return router;
@@ -1284,13 +1316,10 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
}
/* get routing information */
- rcu_read_lock();
orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
if (!orig_node)
- goto unlock;
-
- rcu_read_unlock();
+ goto out;
/* find_router() increases neigh_nodes refcount if found. */
neigh_node = find_router(bat_priv, orig_node, recv_if);
@@ -1336,10 +1365,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
/* route it */
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = NET_RX_SUCCESS;
- goto out;
-unlock:
- rcu_read_unlock();
out:
if (neigh_node)
neigh_node_free_ref(neigh_node);
@@ -1438,13 +1464,10 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
if (bcast_packet->ttl < 2)
goto out;
- rcu_read_lock();
orig_node = orig_hash_find(bat_priv, bcast_packet->orig);
if (!orig_node)
- goto rcu_unlock;
-
- rcu_read_unlock();
+ goto out;
spin_lock_bh(&orig_node->bcast_seqno_lock);
@@ -1475,9 +1498,6 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
ret = NET_RX_SUCCESS;
goto out;
-rcu_unlock:
- rcu_read_unlock();
- goto out;
spin_unlock:
spin_unlock_bh(&orig_node->bcast_seqno_lock);
out:
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index d49e54d..02b541a6 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -244,6 +244,7 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv,
void schedule_own_packet(struct hard_iface *hard_iface)
{
struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+ struct hard_iface *primary_if;
unsigned long send_time;
struct batman_packet *batman_packet;
int vis_server;
@@ -253,6 +254,7 @@ void schedule_own_packet(struct hard_iface *hard_iface)
return;
vis_server = atomic_read(&bat_priv->vis_mode);
+ primary_if = primary_if_get_selected(bat_priv);
/**
* the interface gets activated here to avoid race conditions between
@@ -266,7 +268,7 @@ void schedule_own_packet(struct hard_iface *hard_iface)
/* if local hna has changed and interface is a primary interface */
if ((atomic_read(&bat_priv->hna_local_changed)) &&
- (hard_iface == bat_priv->primary_if))
+ (hard_iface == primary_if))
rebuild_batman_packet(bat_priv, hard_iface);
/**
@@ -284,7 +286,7 @@ void schedule_own_packet(struct hard_iface *hard_iface)
else
batman_packet->flags &= ~VIS_SERVER;
- if ((hard_iface == bat_priv->primary_if) &&
+ if ((hard_iface == primary_if) &&
(atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER))
batman_packet->gw_flags =
(uint8_t)atomic_read(&bat_priv->gw_bandwidth);
@@ -299,6 +301,9 @@ void schedule_own_packet(struct hard_iface *hard_iface)
hard_iface->packet_buff,
hard_iface->packet_len,
hard_iface, 1, send_time);
+
+ if (primary_if)
+ hardif_free_ref(primary_if);
}
void schedule_forward_packet(struct orig_node *orig_node,
@@ -308,6 +313,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
struct hard_iface *if_incoming)
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+ struct neigh_node *router;
unsigned char in_tq, in_ttl, tq_avg = 0;
unsigned long send_time;
@@ -316,6 +322,8 @@ void schedule_forward_packet(struct orig_node *orig_node,
return;
}
+ router = orig_node_get_router(orig_node);
+
in_tq = batman_packet->tq;
in_ttl = batman_packet->ttl;
@@ -324,20 +332,22 @@ void schedule_forward_packet(struct orig_node *orig_node,
/* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
* of our best tq value */
- if ((orig_node->router) && (orig_node->router->tq_avg != 0)) {
+ if (router && router->tq_avg != 0) {
/* rebroadcast ogm of best ranking neighbor as is */
- if (!compare_eth(orig_node->router->addr, ethhdr->h_source)) {
- batman_packet->tq = orig_node->router->tq_avg;
+ if (!compare_eth(router->addr, ethhdr->h_source)) {
+ batman_packet->tq = router->tq_avg;
- if (orig_node->router->last_ttl)
- batman_packet->ttl = orig_node->router->last_ttl
- - 1;
+ if (router->last_ttl)
+ batman_packet->ttl = router->last_ttl - 1;
}
- tq_avg = orig_node->router->tq_avg;
+ tq_avg = router->tq_avg;
}
+ if (router)
+ neigh_node_free_ref(router);
+
/* apply hop penalty */
batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv);
@@ -388,7 +398,6 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
send_time);
}
-#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
/* add a broadcast packet to the queue and setup timers. broadcast packets
* are sent multiple times to increase probability for beeing received.
*
@@ -399,6 +408,7 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
* skb is freed. */
int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
{
+ struct hard_iface *primary_if = NULL;
struct forw_packet *forw_packet;
struct bcast_packet *bcast_packet;
@@ -407,7 +417,8 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
goto out;
}
- if (!bat_priv->primary_if)
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
goto out;
forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
@@ -426,7 +437,7 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
skb_reset_mac_header(skb);
forw_packet->skb = skb;
- forw_packet->if_incoming = bat_priv->primary_if;
+ forw_packet->if_incoming = primary_if;
/* how often did we send the bcast packet ? */
forw_packet->num_packets = 0;
@@ -439,6 +450,8 @@ packet_free:
out_and_inc:
atomic_inc(&bat_priv->bcast_queue_left);
out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
return NETDEV_TX_BUSY;
}
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 9ed2614..9e5fcd1 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -43,8 +43,6 @@ static void bat_get_drvinfo(struct net_device *dev,
static u32 bat_get_msglevel(struct net_device *dev);
static void bat_set_msglevel(struct net_device *dev, u32 value);
static u32 bat_get_link(struct net_device *dev);
-static u32 bat_get_rx_csum(struct net_device *dev);
-static int bat_set_rx_csum(struct net_device *dev, u32 data);
static const struct ethtool_ops bat_ethtool_ops = {
.get_settings = bat_get_settings,
@@ -52,8 +50,6 @@ static const struct ethtool_ops bat_ethtool_ops = {
.get_msglevel = bat_get_msglevel,
.set_msglevel = bat_set_msglevel,
.get_link = bat_get_link,
- .get_rx_csum = bat_get_rx_csum,
- .set_rx_csum = bat_set_rx_csum
};
int my_skb_head_push(struct sk_buff *skb, unsigned int len)
@@ -90,10 +86,51 @@ static void softif_neigh_free_ref(struct softif_neigh *softif_neigh)
call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu);
}
+static struct softif_neigh *softif_neigh_get_selected(struct bat_priv *bat_priv)
+{
+ struct softif_neigh *neigh;
+
+ rcu_read_lock();
+ neigh = rcu_dereference(bat_priv->softif_neigh);
+
+ if (neigh && !atomic_inc_not_zero(&neigh->refcount))
+ neigh = NULL;
+
+ rcu_read_unlock();
+ return neigh;
+}
+
+static void softif_neigh_select(struct bat_priv *bat_priv,
+ struct softif_neigh *new_neigh)
+{
+ struct softif_neigh *curr_neigh;
+
+ spin_lock_bh(&bat_priv->softif_neigh_lock);
+
+ if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount))
+ new_neigh = NULL;
+
+ curr_neigh = bat_priv->softif_neigh;
+ rcu_assign_pointer(bat_priv->softif_neigh, new_neigh);
+
+ if (curr_neigh)
+ softif_neigh_free_ref(curr_neigh);
+
+ spin_unlock_bh(&bat_priv->softif_neigh_lock);
+}
+
+static void softif_neigh_deselect(struct bat_priv *bat_priv)
+{
+ softif_neigh_select(bat_priv, NULL);
+}
+
void softif_neigh_purge(struct bat_priv *bat_priv)
{
- struct softif_neigh *softif_neigh, *softif_neigh_tmp;
+ struct softif_neigh *softif_neigh, *curr_softif_neigh;
struct hlist_node *node, *node_tmp;
+ char do_deselect = 0;
+
+ curr_softif_neigh = softif_neigh_get_selected(bat_priv);
spin_lock_bh(&bat_priv->softif_neigh_lock);
@@ -105,22 +142,26 @@ void softif_neigh_purge(struct bat_priv *bat_priv)
(atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE))
continue;
- hlist_del_rcu(&softif_neigh->list);
-
- if (bat_priv->softif_neigh == softif_neigh) {
+ if (curr_softif_neigh == softif_neigh) {
bat_dbg(DBG_ROUTES, bat_priv,
"Current mesh exit point '%pM' vanished "
"(vid: %d).\n",
softif_neigh->addr, softif_neigh->vid);
- softif_neigh_tmp = bat_priv->softif_neigh;
- bat_priv->softif_neigh = NULL;
- softif_neigh_free_ref(softif_neigh_tmp);
+ 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_deselect() needs to acquire the softif_neigh_lock */
+ if (do_deselect)
+ softif_neigh_deselect(bat_priv);
+
+ if (curr_softif_neigh)
+ softif_neigh_free_ref(curr_softif_neigh);
}
static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
@@ -170,26 +211,44 @@ 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 *softif_neigh;
+ struct hard_iface *primary_if;
struct hlist_node *node;
+ struct softif_neigh *curr_softif_neigh;
+ 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 (!bat_priv->primary_if) {
- return seq_printf(seq, "BATMAN mesh %s disabled - "
- "please specify interfaces to enable it\n",
- net_dev->name);
+ 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);
+ curr_softif_neigh = softif_neigh_get_selected(bat_priv);
rcu_read_lock();
hlist_for_each_entry_rcu(softif_neigh, node,
&bat_priv->softif_neigh_list, list)
seq_printf(seq, "%s %pM (vid: %d)\n",
- bat_priv->softif_neigh == softif_neigh
+ curr_softif_neigh == softif_neigh
? "=>" : " ", softif_neigh->addr,
softif_neigh->vid);
rcu_read_unlock();
+ if (curr_softif_neigh)
+ softif_neigh_free_ref(curr_softif_neigh);
- return 0;
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ return ret;
}
static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
@@ -198,7 +257,9 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
struct bat_priv *bat_priv = netdev_priv(dev);
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct batman_packet *batman_packet;
- struct softif_neigh *softif_neigh, *softif_neigh_tmp;
+ 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_packet = (struct batman_packet *)
@@ -207,63 +268,72 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN);
if (batman_packet->version != COMPAT_VERSION)
- goto err;
+ goto out;
if (batman_packet->packet_type != BAT_PACKET)
- goto err;
+ goto out;
if (!(batman_packet->flags & PRIMARIES_FIRST_HOP))
- goto err;
+ goto out;
if (is_my_mac(batman_packet->orig))
- goto err;
+ goto out;
softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid);
-
if (!softif_neigh)
- goto err;
+ goto out;
+
+ curr_softif_neigh = softif_neigh_get_selected(bat_priv);
+ if (!curr_softif_neigh)
+ goto out;
+
+ if (curr_softif_neigh == softif_neigh)
+ goto out;
- if (bat_priv->softif_neigh == softif_neigh)
+ 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(bat_priv->primary_if->net_dev->dev_addr,
+ if (memcmp(primary_if->net_dev->dev_addr,
softif_neigh->addr, ETH_ALEN) < 0)
goto out;
/* switch to new 'smallest neighbor' */
- if ((bat_priv->softif_neigh) &&
- (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr,
+ if ((curr_softif_neigh) &&
+ (memcmp(softif_neigh->addr, curr_softif_neigh->addr,
ETH_ALEN) < 0)) {
bat_dbg(DBG_ROUTES, bat_priv,
"Changing mesh exit point from %pM (vid: %d) "
"to %pM (vid: %d).\n",
- bat_priv->softif_neigh->addr,
- bat_priv->softif_neigh->vid,
+ curr_softif_neigh->addr,
+ curr_softif_neigh->vid,
softif_neigh->addr, softif_neigh->vid);
- softif_neigh_tmp = bat_priv->softif_neigh;
- bat_priv->softif_neigh = softif_neigh;
- softif_neigh_free_ref(softif_neigh_tmp);
- /* we need to hold the additional reference */
- goto err;
+
+ softif_neigh_select(bat_priv, softif_neigh);
+ goto out;
}
/* close own batX device and use softif_neigh as exit node */
- if ((!bat_priv->softif_neigh) &&
+ if ((!curr_softif_neigh) &&
(memcmp(softif_neigh->addr,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) {
+ primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) {
bat_dbg(DBG_ROUTES, bat_priv,
"Setting mesh exit point to %pM (vid: %d).\n",
softif_neigh->addr, softif_neigh->vid);
- bat_priv->softif_neigh = softif_neigh;
- /* we need to hold the additional reference */
- goto err;
+
+ softif_neigh_select(bat_priv, softif_neigh);
+ goto out;
}
out:
- softif_neigh_free_ref(softif_neigh);
-err:
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;
}
@@ -319,8 +389,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
{
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct bat_priv *bat_priv = netdev_priv(soft_iface);
+ struct hard_iface *primary_if = NULL;
struct bcast_packet *bcast_packet;
struct vlan_ethhdr *vhdr;
+ struct softif_neigh *curr_softif_neigh = NULL;
int data_len = skb->len, ret;
short vid = -1;
bool do_bcast = false;
@@ -348,7 +420,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
* if we have a another chosen mesh exit node in range
* it will transport the packets to the mesh
*/
- if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid))
+ curr_softif_neigh = softif_neigh_get_selected(bat_priv);
+ if ((curr_softif_neigh) && (curr_softif_neigh->vid == vid))
goto dropped;
/* TODO: check this for locks */
@@ -366,7 +439,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
/* ethernet packet should be broadcasted */
if (do_bcast) {
- if (!bat_priv->primary_if)
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
goto dropped;
if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0)
@@ -382,7 +456,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
/* hw address of first interface is the orig mac because only
* this mac is known throughout the mesh */
memcpy(bcast_packet->orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+ primary_if->net_dev->dev_addr, ETH_ALEN);
/* set broadcast sequence number */
bcast_packet->seqno =
@@ -410,6 +484,10 @@ 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;
}
@@ -421,6 +499,7 @@ void interface_rx(struct net_device *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;
@@ -450,7 +529,8 @@ void interface_rx(struct net_device *soft_iface,
* if we have a another chosen mesh exit node in range
* it will transport the packets to the non-mesh network
*/
- if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) {
+ curr_softif_neigh = softif_neigh_get_selected(bat_priv);
+ if (curr_softif_neigh && (curr_softif_neigh->vid == vid)) {
skb_push(skb, hdr_size);
unicast_packet = (struct unicast_packet *)skb->data;
@@ -461,7 +541,7 @@ void interface_rx(struct net_device *soft_iface,
skb_reset_mac_header(skb);
memcpy(unicast_packet->dest,
- bat_priv->softif_neigh->addr, ETH_ALEN);
+ curr_softif_neigh->addr, ETH_ALEN);
ret = route_unicast_packet(skb, recv_if);
if (ret == NET_RX_DROP)
goto dropped;
@@ -474,7 +554,7 @@ void interface_rx(struct net_device *soft_iface,
goto dropped;
skb->protocol = eth_type_trans(skb, soft_iface);
- /* should not be neccesary anymore as we use skb_pull_rcsum()
+ /* should not be necessary anymore as we use skb_pull_rcsum()
* TODO: please verify this and remove this TODO
* -- Dec 21st 2009, Simon Wunderlich */
@@ -486,11 +566,13 @@ void interface_rx(struct net_device *soft_iface,
soft_iface->last_rx = jiffies;
netif_rx(skb);
- return;
+ goto out;
dropped:
kfree_skb(skb);
out:
+ if (curr_softif_neigh)
+ softif_neigh_free_ref(curr_softif_neigh);
return;
}
@@ -524,6 +606,7 @@ static void interface_setup(struct net_device *dev)
dev->hard_start_xmit = interface_tx;
#endif
dev->destructor = free_netdev;
+ dev->tx_queue_len = 0;
/**
* can't call min_mtu, because the needed variables
@@ -640,7 +723,7 @@ static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
cmd->supported = 0;
cmd->advertising = 0;
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
cmd->duplex = DUPLEX_FULL;
cmd->port = PORT_TP;
cmd->phy_address = 0;
@@ -675,12 +758,3 @@ static u32 bat_get_link(struct net_device *dev)
return 1;
}
-static u32 bat_get_rx_csum(struct net_device *dev)
-{
- return 0;
-}
-
-static int bat_set_rx_csum(struct net_device *dev, u32 data)
-{
- return -EOPNOTSUPP;
-}
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 8d15b48..f931830 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -22,6 +22,7 @@
#include "main.h"
#include "translation-table.h"
#include "soft-interface.h"
+#include "hard-interface.h"
#include "hash.h"
#include "originator.h"
@@ -237,16 +238,26 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset)
struct bat_priv *bat_priv = netdev_priv(net_dev);
struct hashtable_t *hash = bat_priv->hna_local_hash;
struct hna_local_entry *hna_local_entry;
+ struct hard_iface *primary_if;
struct hlist_node *node;
struct hlist_head *head;
size_t buf_size, pos;
char *buff;
- int i;
+ int i, ret = 0;
- if (!bat_priv->primary_if) {
- return seq_printf(seq, "BATMAN mesh %s disabled - "
- "please specify interfaces to enable it\n",
- net_dev->name);
+ 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, "Locally retrieved addresses (from %s) "
@@ -269,7 +280,8 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset)
buff = kmalloc(buf_size, GFP_ATOMIC);
if (!buff) {
spin_unlock_bh(&bat_priv->hna_lhash_lock);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
buff[0] = '\0';
@@ -291,7 +303,10 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset)
seq_printf(seq, "%s", buff);
kfree(buff);
- return 0;
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ return ret;
}
static void _hna_local_del(struct hlist_node *node, void *arg)
@@ -468,16 +483,26 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset)
struct bat_priv *bat_priv = netdev_priv(net_dev);
struct hashtable_t *hash = bat_priv->hna_global_hash;
struct hna_global_entry *hna_global_entry;
+ struct hard_iface *primary_if;
struct hlist_node *node;
struct hlist_head *head;
size_t buf_size, pos;
char *buff;
- int i;
+ int i, ret = 0;
- if (!bat_priv->primary_if) {
- return seq_printf(seq, "BATMAN mesh %s disabled - "
- "please specify interfaces to enable it\n",
- net_dev->name);
+ 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, "Globally announced HNAs received via the mesh %s\n",
@@ -499,7 +524,8 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset)
buff = kmalloc(buf_size, GFP_ATOMIC);
if (!buff) {
spin_unlock_bh(&bat_priv->hna_ghash_lock);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
buff[0] = '\0';
pos = 0;
@@ -522,7 +548,10 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset)
seq_printf(seq, "%s", buff);
kfree(buff);
- return 0;
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ return ret;
}
static void _hna_global_del_orig(struct bat_priv *bat_priv,
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 83445cf..947bafc 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -67,7 +67,7 @@ struct hard_iface {
struct orig_node {
uint8_t orig[ETH_ALEN];
uint8_t primary_addr[ETH_ALEN];
- struct neigh_node *router;
+ struct neigh_node __rcu *router; /* rcu protected pointer */
unsigned long *bcast_own;
uint8_t *bcast_own_sum;
unsigned long last_valid;
@@ -83,7 +83,7 @@ struct orig_node {
uint32_t last_bcast_seqno;
struct hlist_head neigh_list;
struct list_head frag_list;
- spinlock_t neigh_list_lock; /* protects neighbor list */
+ spinlock_t neigh_list_lock; /* protects neigh_list and router */
atomic_t refcount;
struct rcu_head rcu;
struct hlist_node hash_entry;
@@ -125,6 +125,7 @@ struct neigh_node {
struct rcu_head rcu;
struct orig_node *orig_node;
struct hard_iface *if_incoming;
+ spinlock_t tq_lock; /* protects: tq_recv, tq_index */
};
@@ -146,9 +147,8 @@ struct bat_priv {
atomic_t batman_queue_left;
char num_ifaces;
struct hlist_head softif_neigh_list;
- struct softif_neigh *softif_neigh;
+ struct softif_neigh __rcu *softif_neigh;
struct debug_log *debug_log;
- struct hard_iface *primary_if;
struct kobject *mesh_obj;
struct dentry *debug_dir;
struct hlist_head forw_bat_list;
@@ -173,6 +173,7 @@ struct bat_priv {
struct delayed_work orig_work;
struct delayed_work vis_work;
struct gw_node __rcu *curr_gw; /* rcu protected pointer */
+ struct hard_iface __rcu *primary_if; /* rcu protected pointer */
struct vis_info *my_vis_info;
};
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 19f84bd..b46cbf1 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -221,15 +221,17 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
struct hard_iface *hard_iface, uint8_t dstaddr[])
{
struct unicast_packet tmp_uc, *unicast_packet;
+ struct hard_iface *primary_if;
struct sk_buff *frag_skb;
struct unicast_frag_packet *frag1, *frag2;
int uc_hdr_len = sizeof(struct unicast_packet);
int ucf_hdr_len = sizeof(struct unicast_frag_packet);
int data_len = skb->len - uc_hdr_len;
- int large_tail = 0;
+ int large_tail = 0, ret = NET_RX_DROP;
uint16_t seqno;
- if (!bat_priv->primary_if)
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
goto dropped;
frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len);
@@ -254,7 +256,7 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
frag1->version = COMPAT_VERSION;
frag1->packet_type = BAT_UNICAST_FRAG;
- memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+ memcpy(frag1->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
memcpy(frag2, frag1, sizeof(struct unicast_frag_packet));
if (data_len & 1)
@@ -269,13 +271,17 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
send_skb_packet(skb, hard_iface, dstaddr);
send_skb_packet(frag_skb, hard_iface, dstaddr);
- return NET_RX_SUCCESS;
+ ret = NET_RX_SUCCESS;
+ goto out;
drop_frag:
kfree_skb(frag_skb);
dropped:
kfree_skb(skb);
- return NET_RX_DROP;
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ return ret;
}
int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
@@ -289,7 +295,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
/* get routing information */
if (is_multicast_ether_addr(ethhdr->h_dest)) {
- orig_node = (struct orig_node *)gw_get_selected(bat_priv);
+ orig_node = (struct orig_node *)gw_get_selected_orig(bat_priv);
if (orig_node)
goto find_router;
}
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index f90212f..c8f571d 100644
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@ -204,6 +204,7 @@ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry,
int vis_seq_print_text(struct seq_file *seq, void *offset)
{
+ struct hard_iface *primary_if;
struct hlist_node *node;
struct hlist_head *head;
struct vis_info *info;
@@ -215,15 +216,18 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
HLIST_HEAD(vis_if_list);
struct if_list_entry *entry;
struct hlist_node *pos, *n;
- int i, j;
+ int i, j, ret = 0;
int vis_server = atomic_read(&bat_priv->vis_mode);
size_t buff_pos, buf_size;
char *buff;
int compare;
- if ((!bat_priv->primary_if) ||
- (vis_server == VIS_TYPE_CLIENT_UPDATE))
- return 0;
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ if (vis_server == VIS_TYPE_CLIENT_UPDATE)
+ goto out;
buf_size = 1;
/* Estimate length */
@@ -270,7 +274,8 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
buff = kmalloc(buf_size, GFP_ATOMIC);
if (!buff) {
spin_unlock_bh(&bat_priv->vis_hash_lock);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
buff[0] = '\0';
buff_pos = 0;
@@ -328,7 +333,10 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
seq_printf(seq, "%s", buff);
kfree(buff);
- return 0;
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ return ret;
}
/* add the info packet to the send list, if it was not
@@ -558,6 +566,7 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
struct vis_info *info)
{
struct hashtable_t *hash = bat_priv->orig_hash;
+ struct neigh_node *router;
struct hlist_node *node;
struct hlist_head *head;
struct orig_node *orig_node;
@@ -571,13 +580,17 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
- if ((orig_node) && (orig_node->router) &&
- (orig_node->flags & VIS_SERVER) &&
- (orig_node->router->tq_avg > best_tq)) {
- best_tq = orig_node->router->tq_avg;
+ router = orig_node_get_router(orig_node);
+ if (!router)
+ continue;
+
+ if ((orig_node->flags & VIS_SERVER) &&
+ (router->tq_avg > best_tq)) {
+ best_tq = router->tq_avg;
memcpy(packet->target_orig, orig_node->orig,
ETH_ALEN);
}
+ neigh_node_free_ref(router);
}
rcu_read_unlock();
}
@@ -605,7 +618,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
struct hlist_node *node;
struct hlist_head *head;
struct orig_node *orig_node;
- struct neigh_node *neigh_node;
+ struct neigh_node *router;
struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info;
struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data;
struct vis_info_entry *entry;
@@ -633,30 +646,32 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
- neigh_node = orig_node->router;
-
- if (!neigh_node)
+ router = orig_node_get_router(orig_node);
+ if (!router)
continue;
- if (!compare_eth(neigh_node->addr, orig_node->orig))
- continue;
+ if (!compare_eth(router->addr, orig_node->orig))
+ goto next;
- if (neigh_node->if_incoming->if_status != IF_ACTIVE)
- continue;
+ if (router->if_incoming->if_status != IF_ACTIVE)
+ goto next;
- if (neigh_node->tq_avg < 1)
- continue;
+ if (router->tq_avg < 1)
+ goto next;
/* fill one entry into buffer. */
entry = (struct vis_info_entry *)
skb_put(info->skb_packet, sizeof(*entry));
memcpy(entry->src,
- neigh_node->if_incoming->net_dev->dev_addr,
+ router->if_incoming->net_dev->dev_addr,
ETH_ALEN);
memcpy(entry->dest, orig_node->orig, ETH_ALEN);
- entry->quality = neigh_node->tq_avg;
+ entry->quality = router->tq_avg;
packet->entries++;
+next:
+ neigh_node_free_ref(router);
+
if (vis_packet_full(info))
goto unlock;
}
@@ -725,6 +740,7 @@ static void purge_vis_packets(struct bat_priv *bat_priv)
static void broadcast_vis_packet(struct bat_priv *bat_priv,
struct vis_info *info)
{
+ struct neigh_node *router;
struct hashtable_t *hash = bat_priv->orig_hash;
struct hlist_node *node;
struct hlist_head *head;
@@ -745,19 +761,26 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv,
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
/* if it's a vis server and reachable, send it. */
- if ((!orig_node) || (!orig_node->router))
- continue;
if (!(orig_node->flags & VIS_SERVER))
continue;
+
+ router = orig_node_get_router(orig_node);
+ if (!router)
+ continue;
+
/* don't send it if we already received the packet from
- * this node. */
+ * this node. */
if (recv_list_is_in(bat_priv, &info->recv_list,
- orig_node->orig))
+ orig_node->orig)) {
+ neigh_node_free_ref(router);
continue;
+ }
memcpy(packet->target_orig, orig_node->orig, ETH_ALEN);
- hard_iface = orig_node->router->if_incoming;
- memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ hard_iface = router->if_incoming;
+ memcpy(dstaddr, router->addr, ETH_ALEN);
+
+ neigh_node_free_ref(router);
skb = skb_clone(info->skb_packet, GFP_ATOMIC);
if (skb)
@@ -772,60 +795,48 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
struct vis_info *info)
{
struct orig_node *orig_node;
- struct neigh_node *neigh_node = NULL;
+ struct neigh_node *router = NULL;
struct sk_buff *skb;
struct vis_packet *packet;
packet = (struct vis_packet *)info->skb_packet->data;
- rcu_read_lock();
orig_node = orig_hash_find(bat_priv, packet->target_orig);
-
if (!orig_node)
- goto unlock;
-
- neigh_node = orig_node->router;
+ goto out;
- if (!neigh_node)
- goto unlock;
-
- if (!atomic_inc_not_zero(&neigh_node->refcount)) {
- neigh_node = NULL;
- goto unlock;
- }
-
- rcu_read_unlock();
+ router = orig_node_get_router(orig_node);
+ if (!router)
+ goto out;
skb = skb_clone(info->skb_packet, GFP_ATOMIC);
if (skb)
- send_skb_packet(skb, neigh_node->if_incoming,
- neigh_node->addr);
+ send_skb_packet(skb, router->if_incoming, router->addr);
- goto out;
-
-unlock:
- rcu_read_unlock();
out:
- if (neigh_node)
- neigh_node_free_ref(neigh_node);
+ if (router)
+ neigh_node_free_ref(router);
if (orig_node)
orig_node_free_ref(orig_node);
- return;
}
/* only send one vis packet. called from send_vis_packets() */
static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info)
{
+ struct hard_iface *primary_if;
struct vis_packet *packet;
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
packet = (struct vis_packet *)info->skb_packet->data;
if (packet->ttl < 2) {
pr_debug("Error - can't send vis packet: ttl exceeded\n");
- return;
+ goto out;
}
- memcpy(packet->sender_orig, bat_priv->primary_if->net_dev->dev_addr,
- ETH_ALEN);
+ memcpy(packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
packet->ttl--;
if (is_broadcast_ether_addr(packet->target_orig))
@@ -833,6 +844,10 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info)
else
unicast_vis_packet(bat_priv, info);
packet->ttl++; /* restore TTL */
+
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
}
/* called from timer; send (and maybe generate) vis packet. */
@@ -859,8 +874,7 @@ static void send_vis_packets(struct work_struct *work)
kref_get(&info->refcount);
spin_unlock_bh(&bat_priv->vis_hash_lock);
- if (bat_priv->primary_if)
- send_vis_packet(bat_priv, info);
+ send_vis_packet(bat_priv, info);
spin_lock_bh(&bat_priv->vis_hash_lock);
send_list_del(info);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 4487bbd..815269b 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2004,7 +2004,7 @@ static void hci_tx_task(unsigned long arg)
read_unlock(&hci_task_lock);
}
-/* ----- HCI RX task (incoming data proccessing) ----- */
+/* ----- HCI RX task (incoming data processing) ----- */
/* ACL data packet */
static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 338d8c3..a378acc 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3595,7 +3595,7 @@ drop:
static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
{
struct l2cap_chan *chan;
- struct sock *sk;
+ struct sock *sk = NULL;
struct l2cap_pinfo *pi;
u16 control;
u8 tx_seq;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 09cc7a0..7c4a9ae 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -693,7 +693,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
if (opt == BT_FLUSHABLE_OFF) {
struct l2cap_conn *conn = chan->conn;
- /* proceed futher only when we have l2cap_conn and
+ /* proceed further only when we have l2cap_conn and
No Flush support in the LM */
if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) {
err = -EINVAL;
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 84bbb82..f20c4fd 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -104,3 +104,4 @@ module_init(br_init)
module_exit(br_deinit)
MODULE_LICENSE("GPL");
MODULE_VERSION(BR_VERSION);
+MODULE_ALIAS_RTNL_LINK("bridge");
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 21e5901..a6b2f86 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -74,13 +74,23 @@ out:
return NETDEV_TX_OK;
}
+static int br_dev_init(struct net_device *dev)
+{
+ struct net_bridge *br = netdev_priv(dev);
+
+ br->stats = alloc_percpu(struct br_cpu_netstats);
+ if (!br->stats)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int br_dev_open(struct net_device *dev)
{
struct net_bridge *br = netdev_priv(dev);
netif_carrier_off(dev);
-
- br_features_recompute(br);
+ netdev_update_features(dev);
netif_start_queue(dev);
br_stp_enable_bridge(br);
br_multicast_open(br);
@@ -177,48 +187,11 @@ static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info)
strcpy(info->bus_info, "N/A");
}
-static int br_set_sg(struct net_device *dev, u32 data)
-{
- struct net_bridge *br = netdev_priv(dev);
-
- if (data)
- br->feature_mask |= NETIF_F_SG;
- else
- br->feature_mask &= ~NETIF_F_SG;
-
- br_features_recompute(br);
- return 0;
-}
-
-static int br_set_tso(struct net_device *dev, u32 data)
-{
- struct net_bridge *br = netdev_priv(dev);
-
- if (data)
- br->feature_mask |= NETIF_F_TSO;
- else
- br->feature_mask &= ~NETIF_F_TSO;
-
- br_features_recompute(br);
- return 0;
-}
-
-static int br_set_tx_csum(struct net_device *dev, u32 data)
+static u32 br_fix_features(struct net_device *dev, u32 features)
{
struct net_bridge *br = netdev_priv(dev);
- if (data)
- br->feature_mask |= NETIF_F_NO_CSUM;
- else
- br->feature_mask &= ~NETIF_F_ALL_CSUM;
-
- br_features_recompute(br);
- return 0;
-}
-
-static int br_set_flags(struct net_device *netdev, u32 data)
-{
- return ethtool_op_set_flags(netdev, data, ETH_FLAG_TXVLAN);
+ return br_features_recompute(br, features);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -319,21 +292,12 @@ static int br_del_slave(struct net_device *dev, struct net_device *slave_dev)
static const struct ethtool_ops br_ethtool_ops = {
.get_drvinfo = br_getinfo,
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = br_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = br_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = br_set_tso,
- .get_ufo = ethtool_op_get_ufo,
- .set_ufo = ethtool_op_set_ufo,
- .get_flags = ethtool_op_get_flags,
- .set_flags = br_set_flags,
};
static const struct net_device_ops br_netdev_ops = {
.ndo_open = br_dev_open,
.ndo_stop = br_dev_stop,
+ .ndo_init = br_dev_init,
.ndo_start_xmit = br_dev_xmit,
.ndo_get_stats64 = br_get_stats64,
.ndo_set_mac_address = br_set_mac_address,
@@ -347,6 +311,7 @@ static const struct net_device_ops br_netdev_ops = {
#endif
.ndo_add_slave = br_add_slave,
.ndo_del_slave = br_del_slave,
+ .ndo_fix_features = br_fix_features,
};
static void br_dev_free(struct net_device *dev)
@@ -357,18 +322,49 @@ static void br_dev_free(struct net_device *dev)
free_netdev(dev);
}
+static struct device_type br_type = {
+ .name = "bridge",
+};
+
void br_dev_setup(struct net_device *dev)
{
+ struct net_bridge *br = netdev_priv(dev);
+
random_ether_addr(dev->dev_addr);
ether_setup(dev);
dev->netdev_ops = &br_netdev_ops;
dev->destructor = br_dev_free;
SET_ETHTOOL_OPS(dev, &br_ethtool_ops);
+ SET_NETDEV_DEVTYPE(dev, &br_type);
dev->tx_queue_len = 0;
dev->priv_flags = IFF_EBRIDGE;
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX |
- NETIF_F_NETNS_LOCAL | NETIF_F_GSO | NETIF_F_HW_VLAN_TX;
+ NETIF_F_NETNS_LOCAL | NETIF_F_HW_VLAN_TX;
+ dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
+ NETIF_F_GSO_MASK | NETIF_F_NO_CSUM |
+ NETIF_F_HW_VLAN_TX;
+
+ br->dev = dev;
+ spin_lock_init(&br->lock);
+ INIT_LIST_HEAD(&br->port_list);
+ spin_lock_init(&br->hash_lock);
+
+ br->bridge_id.prio[0] = 0x80;
+ br->bridge_id.prio[1] = 0x00;
+
+ memcpy(br->group_addr, br_group_address, ETH_ALEN);
+
+ br->stp_enabled = BR_NO_STP;
+ br->designated_root = br->bridge_id;
+ br->bridge_max_age = br->max_age = 20 * HZ;
+ br->bridge_hello_time = br->hello_time = 2 * HZ;
+ br->bridge_forward_delay = br->forward_delay = 15 * HZ;
+ br->ageing_time = 300 * HZ;
+
+ br_netfilter_rtable_init(br);
+ br_stp_timer_init(br);
+ br_multicast_init(br);
}
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 88485cc..e0dfbc1 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -28,6 +28,7 @@
static struct kmem_cache *br_fdb_cache __read_mostly;
static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
const unsigned char *addr);
+static void fdb_notify(const struct net_bridge_fdb_entry *, int);
static u32 fdb_salt __read_mostly;
@@ -62,7 +63,7 @@ static inline int has_expired(const struct net_bridge *br,
const struct net_bridge_fdb_entry *fdb)
{
return !fdb->is_static &&
- time_before_eq(fdb->ageing_timer + hold_time(br), jiffies);
+ time_before_eq(fdb->updated + hold_time(br), jiffies);
}
static inline int br_mac_hash(const unsigned char *mac)
@@ -81,6 +82,7 @@ static void fdb_rcu_free(struct rcu_head *head)
static inline void fdb_delete(struct net_bridge_fdb_entry *f)
{
+ fdb_notify(f, RTM_DELNEIGH);
hlist_del_rcu(&f->hlist);
call_rcu(&f->rcu, fdb_rcu_free);
}
@@ -140,7 +142,7 @@ void br_fdb_cleanup(unsigned long _data)
unsigned long this_timer;
if (f->is_static)
continue;
- this_timer = f->ageing_timer + delay;
+ this_timer = f->updated + delay;
if (time_before_eq(this_timer, jiffies))
fdb_delete(f);
else if (time_before(this_timer, next_timer))
@@ -169,7 +171,7 @@ void br_fdb_flush(struct net_bridge *br)
spin_unlock_bh(&br->hash_lock);
}
-/* Flush all entries refering to a specific port.
+/* Flush all entries referring to a specific port.
* if do_all is set also flush static entries
*/
void br_fdb_delete_by_port(struct net_bridge *br,
@@ -293,7 +295,7 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
fe->is_local = f->is_local;
if (!f->is_static)
- fe->ageing_timer_value = jiffies_to_clock_t(jiffies - f->ageing_timer);
+ fe->ageing_timer_value = jiffies_to_clock_t(jiffies - f->updated);
++fe;
++num;
}
@@ -305,8 +307,21 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
return num;
}
-static inline struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
- const unsigned char *addr)
+static struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
+ const unsigned char *addr)
+{
+ struct hlist_node *h;
+ struct net_bridge_fdb_entry *fdb;
+
+ hlist_for_each_entry(fdb, h, head, hlist) {
+ if (!compare_ether_addr(fdb->addr.addr, addr))
+ return fdb;
+ }
+ return NULL;
+}
+
+static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head,
+ const unsigned char *addr)
{
struct hlist_node *h;
struct net_bridge_fdb_entry *fdb;
@@ -320,8 +335,7 @@ static inline struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
struct net_bridge_port *source,
- const unsigned char *addr,
- int is_local)
+ const unsigned char *addr)
{
struct net_bridge_fdb_entry *fdb;
@@ -329,11 +343,11 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
if (fdb) {
memcpy(fdb->addr.addr, addr, ETH_ALEN);
fdb->dst = source;
- fdb->is_local = is_local;
- fdb->is_static = is_local;
- fdb->ageing_timer = jiffies;
-
+ fdb->is_local = 0;
+ fdb->is_static = 0;
+ fdb->updated = fdb->used = jiffies;
hlist_add_head_rcu(&fdb->hlist, head);
+ fdb_notify(fdb, RTM_NEWNEIGH);
}
return fdb;
}
@@ -360,12 +374,15 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
fdb_delete(fdb);
}
- if (!fdb_create(head, source, addr, 1))
+ fdb = fdb_create(head, source, addr);
+ if (!fdb)
return -ENOMEM;
+ fdb->is_local = fdb->is_static = 1;
return 0;
}
+/* Add entry for local address of interface */
int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
const unsigned char *addr)
{
@@ -392,7 +409,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
source->state == BR_STATE_FORWARDING))
return;
- fdb = fdb_find(head, addr);
+ fdb = fdb_find_rcu(head, addr);
if (likely(fdb)) {
/* attempt to update an entry for a local interface */
if (unlikely(fdb->is_local)) {
@@ -403,15 +420,277 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
} else {
/* fastpath: update of existing entry */
fdb->dst = source;
- fdb->ageing_timer = jiffies;
+ fdb->updated = jiffies;
}
} else {
spin_lock(&br->hash_lock);
- if (!fdb_find(head, addr))
- fdb_create(head, source, addr, 0);
+ if (likely(!fdb_find(head, addr)))
+ fdb_create(head, source, addr);
+
/* else we lose race and someone else inserts
* it first, don't bother updating
*/
spin_unlock(&br->hash_lock);
}
}
+
+static int fdb_to_nud(const struct net_bridge_fdb_entry *fdb)
+{
+ if (fdb->is_local)
+ return NUD_PERMANENT;
+ else if (fdb->is_static)
+ return NUD_NOARP;
+ else if (has_expired(fdb->dst->br, fdb))
+ return NUD_STALE;
+ else
+ return NUD_REACHABLE;
+}
+
+static int fdb_fill_info(struct sk_buff *skb,
+ const struct net_bridge_fdb_entry *fdb,
+ u32 pid, u32 seq, int type, unsigned int flags)
+{
+ unsigned long now = jiffies;
+ struct nda_cacheinfo ci;
+ struct nlmsghdr *nlh;
+ struct ndmsg *ndm;
+
+ nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
+ if (nlh == NULL)
+ return -EMSGSIZE;
+
+
+ ndm = nlmsg_data(nlh);
+ ndm->ndm_family = AF_BRIDGE;
+ ndm->ndm_pad1 = 0;
+ ndm->ndm_pad2 = 0;
+ ndm->ndm_flags = 0;
+ ndm->ndm_type = 0;
+ ndm->ndm_ifindex = fdb->dst->dev->ifindex;
+ ndm->ndm_state = fdb_to_nud(fdb);
+
+ NLA_PUT(skb, NDA_LLADDR, ETH_ALEN, &fdb->addr);
+
+ 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);
+
+ return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+}
+
+static inline size_t fdb_nlmsg_size(void)
+{
+ return NLMSG_ALIGN(sizeof(struct ndmsg))
+ + nla_total_size(ETH_ALEN) /* NDA_LLADDR */
+ + nla_total_size(sizeof(struct nda_cacheinfo));
+}
+
+static void fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
+{
+ struct net *net = dev_net(fdb->dst->dev);
+ struct sk_buff *skb;
+ int err = -ENOBUFS;
+
+ skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC);
+ if (skb == NULL)
+ goto errout;
+
+ err = fdb_fill_info(skb, fdb, 0, 0, type, 0);
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in fdb_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
+ rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
+ return;
+errout:
+ if (err < 0)
+ rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
+}
+
+/* Dump information about entries, in response to GETNEIGH */
+int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ 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;
+
+ if (!(dev->priv_flags & IFF_EBRIDGE))
+ continue;
+
+ 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;
+
+ if (fdb_fill_info(skb, f,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWNEIGH,
+ NLM_F_MULTI) < 0)
+ break;
+skip:
+ ++idx;
+ }
+ }
+ }
+ rcu_read_unlock();
+
+ cb->args[0] = idx;
+
+ return skb->len;
+}
+
+/* Create new static fdb entry */
+static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
+ __u16 state)
+{
+ struct net_bridge *br = source->br;
+ struct hlist_head *head = &br->hash[br_mac_hash(addr)];
+ struct net_bridge_fdb_entry *fdb;
+
+ fdb = fdb_find(head, addr);
+ if (fdb)
+ return -EEXIST;
+
+ fdb = fdb_create(head, source, addr);
+ if (!fdb)
+ return -ENOMEM;
+
+ if (state & NUD_PERMANENT)
+ fdb->is_local = fdb->is_static = 1;
+ else if (state & NUD_NOARP)
+ fdb->is_static = 1;
+ return 0;
+}
+
+/* Add new permanent fdb entry with RTM_NEWNEIGH */
+int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ 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;
+ }
+
+ p = br_port_get_rtnl(dev);
+ if (p == NULL) {
+ pr_info("bridge: RTM_NEWNEIGH %s not a bridge port\n",
+ dev->name);
+ return -EINVAL;
+ }
+
+ spin_lock_bh(&p->br->hash_lock);
+ err = fdb_add_entry(p, addr, ndm->ndm_state);
+ spin_unlock_bh(&p->br->hash_lock);
+
+ return err;
+}
+
+static int fdb_delete_by_addr(struct net_bridge_port *p, const u8 *addr)
+{
+ struct net_bridge *br = p->br;
+ struct hlist_head *head = &br->hash[br_mac_hash(addr)];
+ struct net_bridge_fdb_entry *fdb;
+
+ fdb = fdb_find(head, addr);
+ if (!fdb)
+ return -ENOENT;
+
+ fdb_delete(fdb);
+ return 0;
+}
+
+/* Remove neighbor entry with RTM_DELNEIGH */
+int br_fdb_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ 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",
+ dev->name);
+ return -EINVAL;
+ }
+
+ spin_lock_bh(&p->br->hash_lock);
+ err = fdb_delete_by_addr(p, addr);
+ spin_unlock_bh(&p->br->hash_lock);
+
+ return err;
+}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 718b603..5dbdfdf 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -36,8 +36,8 @@ static int port_cost(struct net_device *dev)
if (dev->ethtool_ops && dev->ethtool_ops->get_settings) {
struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET, };
- if (!dev->ethtool_ops->get_settings(dev, &ecmd)) {
- switch(ecmd.speed) {
+ if (!dev_ethtool_get_settings(dev, &ecmd)) {
+ switch (ethtool_cmd_speed(&ecmd)) {
case SPEED_10000:
return 2;
case SPEED_1000:
@@ -175,56 +175,6 @@ static void del_br(struct net_bridge *br, struct list_head *head)
unregister_netdevice_queue(br->dev, head);
}
-static struct net_device *new_bridge_dev(struct net *net, const char *name)
-{
- struct net_bridge *br;
- struct net_device *dev;
-
- dev = alloc_netdev(sizeof(struct net_bridge), name,
- br_dev_setup);
-
- if (!dev)
- return NULL;
- dev_net_set(dev, net);
-
- br = netdev_priv(dev);
- br->dev = dev;
-
- br->stats = alloc_percpu(struct br_cpu_netstats);
- if (!br->stats) {
- free_netdev(dev);
- return NULL;
- }
-
- spin_lock_init(&br->lock);
- INIT_LIST_HEAD(&br->port_list);
- spin_lock_init(&br->hash_lock);
-
- br->bridge_id.prio[0] = 0x80;
- br->bridge_id.prio[1] = 0x00;
-
- memcpy(br->group_addr, br_group_address, ETH_ALEN);
-
- br->feature_mask = dev->features;
- br->stp_enabled = BR_NO_STP;
- br->designated_root = br->bridge_id;
- br->root_path_cost = 0;
- br->root_port = 0;
- br->bridge_max_age = br->max_age = 20 * HZ;
- br->bridge_hello_time = br->hello_time = 2 * HZ;
- br->bridge_forward_delay = br->forward_delay = 15 * HZ;
- br->topology_change = 0;
- br->topology_change_detected = 0;
- br->ageing_time = 300 * HZ;
-
- br_netfilter_rtable_init(br);
-
- br_stp_timer_init(br);
- br_multicast_init(br);
-
- return dev;
-}
-
/* find an available port number */
static int find_portno(struct net_bridge *br)
{
@@ -277,42 +227,19 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
return p;
}
-static struct device_type br_type = {
- .name = "bridge",
-};
-
int br_add_bridge(struct net *net, const char *name)
{
struct net_device *dev;
- int ret;
- dev = new_bridge_dev(net, name);
+ dev = alloc_netdev(sizeof(struct net_bridge), name,
+ br_dev_setup);
+
if (!dev)
return -ENOMEM;
- rtnl_lock();
- if (strchr(dev->name, '%')) {
- ret = dev_alloc_name(dev, dev->name);
- if (ret < 0)
- goto out_free;
- }
-
- SET_NETDEV_DEVTYPE(dev, &br_type);
-
- ret = register_netdevice(dev);
- if (ret)
- goto out_free;
-
- ret = br_sysfs_addbr(dev);
- if (ret)
- unregister_netdevice(dev);
- out:
- rtnl_unlock();
- return ret;
+ dev_net_set(dev, net);
-out_free:
- free_netdev(dev);
- goto out;
+ return register_netdev(dev);
}
int br_del_bridge(struct net *net, const char *name)
@@ -364,15 +291,15 @@ int br_min_mtu(const struct net_bridge *br)
/*
* Recomputes features using slave's features
*/
-void br_features_recompute(struct net_bridge *br)
+u32 br_features_recompute(struct net_bridge *br, u32 features)
{
struct net_bridge_port *p;
- u32 features, mask;
+ u32 mask;
- features = mask = br->feature_mask;
if (list_empty(&br->port_list))
- goto done;
+ return features;
+ mask = features;
features &= ~NETIF_F_ONE_FOR_ALL;
list_for_each_entry(p, &br->port_list, list) {
@@ -380,8 +307,7 @@ void br_features_recompute(struct net_bridge *br)
p->dev->features, mask);
}
-done:
- br->dev->features = netdev_fix_features(br->dev, features);
+ return features;
}
/* called with RTNL */
@@ -446,9 +372,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
list_add_rcu(&p->list, &br->port_list);
+ netdev_update_features(br->dev);
+
spin_lock_bh(&br->lock);
changed_addr = br_stp_recalculate_bridge_id(br);
- br_features_recompute(br);
if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
(br->dev->flags & IFF_UP))
@@ -496,9 +423,10 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
spin_lock_bh(&br->lock);
br_stp_recalculate_bridge_id(br);
- br_features_recompute(br);
spin_unlock_bh(&br->lock);
+ netdev_update_features(br->dev);
+
return 0;
}
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index e216079..f3ac1e8 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -98,9 +98,10 @@ int br_handle_frame_finish(struct sk_buff *skb)
}
if (skb) {
- if (dst)
+ if (dst) {
+ dst->used = jiffies;
br_forward(dst->dst, skb, skb2);
- else
+ } else
br_flood_forward(br, skb, skb2);
}
@@ -164,7 +165,7 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
goto drop;
/* If STP is turned off, then forward */
- if (p->br->stp_enabled == BR_NO_STP)
+ if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0)
goto forward;
if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index cb43312..7222fe1 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -106,7 +106,7 @@ static int add_del_if(struct net_bridge *br, int ifindex, int isadd)
/*
* Legacy ioctl's through SIOCDEVPRIVATE
* This interface is deprecated because it was too difficult to
- * to do the translation for 32/64bit ioctl compatability.
+ * to do the translation for 32/64bit ioctl compatibility.
*/
static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
@@ -181,40 +181,19 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- spin_lock_bh(&br->lock);
- br->bridge_forward_delay = clock_t_to_jiffies(args[1]);
- if (br_is_root_bridge(br))
- br->forward_delay = br->bridge_forward_delay;
- spin_unlock_bh(&br->lock);
- return 0;
+ return br_set_forward_delay(br, args[1]);
case BRCTL_SET_BRIDGE_HELLO_TIME:
- {
- unsigned long t = clock_t_to_jiffies(args[1]);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (t < HZ)
- return -EINVAL;
-
- spin_lock_bh(&br->lock);
- br->bridge_hello_time = t;
- if (br_is_root_bridge(br))
- br->hello_time = br->bridge_hello_time;
- spin_unlock_bh(&br->lock);
- return 0;
- }
+ return br_set_hello_time(br, args[1]);
case BRCTL_SET_BRIDGE_MAX_AGE:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- spin_lock_bh(&br->lock);
- br->bridge_max_age = clock_t_to_jiffies(args[1]);
- if (br_is_root_bridge(br))
- br->max_age = br->bridge_max_age;
- spin_unlock_bh(&br->lock);
- return 0;
+ return br_set_max_age(br, args[1]);
case BRCTL_SET_AGEING_TIME:
if (!capable(CAP_NET_ADMIN))
@@ -275,19 +254,16 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case BRCTL_SET_PORT_PRIORITY:
{
struct net_bridge_port *p;
- int ret = 0;
+ int ret;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (args[2] >= (1<<(16-BR_PORT_BITS)))
- return -ERANGE;
-
spin_lock_bh(&br->lock);
if ((p = br_get_port(br, args[1])) == NULL)
ret = -EINVAL;
else
- br_stp_set_port_priority(p, args[2]);
+ ret = br_stp_set_port_priority(p, args[2]);
spin_unlock_bh(&br->lock);
return ret;
}
@@ -295,15 +271,17 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case BRCTL_SET_PATH_COST:
{
struct net_bridge_port *p;
- int ret = 0;
+ int ret;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ spin_lock_bh(&br->lock);
if ((p = br_get_port(br, args[1])) == NULL)
ret = -EINVAL;
else
- br_stp_set_path_cost(p, args[2]);
+ ret = br_stp_set_path_cost(p, args[2]);
+ spin_unlock_bh(&br->lock);
return ret;
}
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 59660c9..2f14eaf 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -413,7 +413,7 @@ out:
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
- struct in6_addr *group)
+ const struct in6_addr *group)
{
struct sk_buff *skb;
struct ipv6hdr *ip6h;
@@ -1115,7 +1115,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
struct net_bridge_port *port,
struct sk_buff *skb)
{
- struct iphdr *iph = ip_hdr(skb);
+ const struct iphdr *iph = ip_hdr(skb);
struct igmphdr *ih = igmp_hdr(skb);
struct net_bridge_mdb_entry *mp;
struct igmpv3_query *ih3;
@@ -1190,7 +1190,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
struct net_bridge_port *port,
struct sk_buff *skb)
{
- struct ipv6hdr *ip6h = ipv6_hdr(skb);
+ const struct ipv6hdr *ip6h = ipv6_hdr(skb);
struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb);
struct net_bridge_mdb_entry *mp;
struct mld2_query *mld2q;
@@ -1198,7 +1198,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
struct net_bridge_port_group __rcu **pp;
unsigned long max_delay;
unsigned long now = jiffies;
- struct in6_addr *group = NULL;
+ const struct in6_addr *group = NULL;
int err = 0;
spin_lock(&br->multicast_lock);
@@ -1356,7 +1356,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
struct sk_buff *skb)
{
struct sk_buff *skb2 = skb;
- struct iphdr *iph;
+ const struct iphdr *iph;
struct igmphdr *ih;
unsigned len;
unsigned offset;
@@ -1452,7 +1452,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
struct sk_buff *skb)
{
struct sk_buff *skb2;
- struct ipv6hdr *ip6h;
+ const struct ipv6hdr *ip6h;
struct icmp6hdr *icmp6h;
u8 nexthdr;
unsigned len;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 008ff6c..5614907 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -219,7 +219,7 @@ static inline void nf_bridge_update_protocol(struct sk_buff *skb)
static int br_parse_ip_options(struct sk_buff *skb)
{
struct ip_options *opt;
- struct iphdr *iph;
+ const struct iphdr *iph;
struct net_device *dev = skb->dev;
u32 len;
@@ -249,11 +249,9 @@ static int br_parse_ip_options(struct sk_buff *skb)
goto drop;
}
- /* Zero out the CB buffer if no options present */
- if (iph->ihl == 5) {
- memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+ memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+ if (iph->ihl == 5)
return 0;
- }
opt->optlen = iph->ihl*4 - sizeof(struct iphdr);
if (ip_options_compile(dev_net(dev), opt, skb))
@@ -556,7 +554,7 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- struct ipv6hdr *hdr;
+ const struct ipv6hdr *hdr;
u32 pkt_len;
if (skb->len < sizeof(struct ipv6hdr))
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index f8bf4c7..ffb0dc4 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -12,9 +12,11 @@
#include <linux/kernel.h>
#include <linux/slab.h>
+#include <linux/etherdevice.h>
#include <net/rtnetlink.h>
#include <net/net_namespace.h>
#include <net/sock.h>
+
#include "br_private.h"
static inline size_t br_nlmsg_size(void)
@@ -118,8 +120,9 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
int idx;
idx = 0;
- for_each_netdev(net, dev) {
- struct net_bridge_port *port = br_port_get_rtnl(dev);
+ rcu_read_lock();
+ for_each_netdev_rcu(net, dev) {
+ struct net_bridge_port *port = br_port_get_rcu(dev);
/* not a bridge port */
if (!port || idx < cb->args[0])
@@ -133,7 +136,7 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
skip:
++idx;
}
-
+ rcu_read_unlock();
cb->args[0] = idx;
return skb->len;
@@ -188,20 +191,61 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
return 0;
}
+static int br_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+ if (tb[IFLA_ADDRESS]) {
+ if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+ return -EINVAL;
+ if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+ return -EADDRNOTAVAIL;
+ }
+
+ return 0;
+}
+
+static struct rtnl_link_ops br_link_ops __read_mostly = {
+ .kind = "bridge",
+ .priv_size = sizeof(struct net_bridge),
+ .setup = br_dev_setup,
+ .validate = br_validate,
+};
int __init br_netlink_init(void)
{
- if (__rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo))
- return -ENOBUFS;
+ int err;
- /* Only the first call to __rtnl_register can fail */
- __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL);
+ err = rtnl_link_register(&br_link_ops);
+ if (err < 0)
+ goto err1;
+
+ err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo);
+ if (err)
+ goto err2;
+ err = __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL);
+ if (err)
+ goto err3;
+ err = __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, br_fdb_add, NULL);
+ if (err)
+ goto err3;
+ err = __rtnl_register(PF_BRIDGE, RTM_DELNEIGH, br_fdb_delete, NULL);
+ if (err)
+ goto err3;
+ err = __rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, br_fdb_dump);
+ if (err)
+ goto err3;
return 0;
+
+err3:
+ rtnl_unregister_all(PF_BRIDGE);
+err2:
+ rtnl_link_unregister(&br_link_ops);
+err1:
+ return err;
}
void __exit br_netlink_fini(void)
{
+ rtnl_link_unregister(&br_link_ops);
rtnl_unregister_all(PF_BRIDGE);
}
-
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 7d337c9..6545ee9 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -36,6 +36,12 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
struct net_bridge *br;
int err;
+ /* register of bridge completed, add sysfs entries */
+ if ((dev->priv_flags & IFF_EBRIDGE) && event == NETDEV_REGISTER) {
+ br_sysfs_addbr(dev);
+ return NOTIFY_DONE;
+ }
+
/* not a port of a bridge */
p = br_port_get_rtnl(dev);
if (!p)
@@ -60,10 +66,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
break;
case NETDEV_FEAT_CHANGE:
- spin_lock_bh(&br->lock);
- if (netif_running(br->dev))
- br_features_recompute(br);
- spin_unlock_bh(&br->lock);
+ netdev_update_features(br->dev);
break;
case NETDEV_DOWN:
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 387013d..54578f2 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -64,7 +64,8 @@ struct net_bridge_fdb_entry
struct net_bridge_port *dst;
struct rcu_head rcu;
- unsigned long ageing_timer;
+ unsigned long updated;
+ unsigned long used;
mac_addr addr;
unsigned char is_local;
unsigned char is_static;
@@ -182,7 +183,6 @@ struct net_bridge
struct br_cpu_netstats __percpu *stats;
spinlock_t hash_lock;
struct hlist_head hash[BR_HASH_SIZE];
- u32 feature_mask;
#ifdef CONFIG_BRIDGE_NETFILTER
struct rtable fake_rtable;
bool nf_call_iptables;
@@ -353,6 +353,9 @@ 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);
/* br_forward.c */
extern void br_deliver(const struct net_bridge_port *to,
@@ -375,7 +378,7 @@ extern int br_add_if(struct net_bridge *br,
extern int br_del_if(struct net_bridge *br,
struct net_device *dev);
extern int br_min_mtu(const struct net_bridge *br);
-extern void br_features_recompute(struct net_bridge *br);
+extern u32 br_features_recompute(struct net_bridge *br, u32 features);
/* br_input.c */
extern int br_handle_frame_finish(struct sk_buff *skb);
@@ -491,6 +494,11 @@ extern struct net_bridge_port *br_get_port(struct net_bridge *br,
extern void br_init_port(struct net_bridge_port *p);
extern void br_become_designated_port(struct net_bridge_port *p);
+extern int br_set_forward_delay(struct net_bridge *br, unsigned long x);
+extern int br_set_hello_time(struct net_bridge *br, unsigned long x);
+extern int br_set_max_age(struct net_bridge *br, unsigned long x);
+
+
/* br_stp_if.c */
extern void br_stp_enable_bridge(struct net_bridge *br);
extern void br_stp_disable_bridge(struct net_bridge *br);
@@ -501,10 +509,10 @@ extern bool br_stp_recalculate_bridge_id(struct net_bridge *br);
extern void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *a);
extern void br_stp_set_bridge_priority(struct net_bridge *br,
u16 newprio);
-extern void br_stp_set_port_priority(struct net_bridge_port *p,
- u8 newprio);
-extern void br_stp_set_path_cost(struct net_bridge_port *p,
- u32 path_cost);
+extern int br_stp_set_port_priority(struct net_bridge_port *p,
+ unsigned long newprio);
+extern int br_stp_set_path_cost(struct net_bridge_port *p,
+ unsigned long path_cost);
extern ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id);
/* br_stp_bpdu.c */
diff --git a/net/bridge/br_private_stp.h b/net/bridge/br_private_stp.h
index 8b650f7..642ef47 100644
--- a/net/bridge/br_private_stp.h
+++ b/net/bridge/br_private_stp.h
@@ -16,6 +16,19 @@
#define BPDU_TYPE_CONFIG 0
#define BPDU_TYPE_TCN 0x80
+/* IEEE 802.1D-1998 timer values */
+#define BR_MIN_HELLO_TIME (1*HZ)
+#define BR_MAX_HELLO_TIME (10*HZ)
+
+#define BR_MIN_FORWARD_DELAY (2*HZ)
+#define BR_MAX_FORWARD_DELAY (30*HZ)
+
+#define BR_MIN_MAX_AGE (6*HZ)
+#define BR_MAX_MAX_AGE (40*HZ)
+
+#define BR_MIN_PATH_COST 1
+#define BR_MAX_PATH_COST 65535
+
struct br_config_bpdu
{
unsigned topology_change:1;
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index 7370d14..bb4383e 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -484,3 +484,51 @@ void br_received_tcn_bpdu(struct net_bridge_port *p)
br_topology_change_acknowledge(p);
}
}
+
+/* Change bridge STP parameter */
+int br_set_hello_time(struct net_bridge *br, unsigned long val)
+{
+ unsigned long t = clock_t_to_jiffies(val);
+
+ if (t < BR_MIN_HELLO_TIME || t > BR_MAX_HELLO_TIME)
+ return -ERANGE;
+
+ spin_lock_bh(&br->lock);
+ br->bridge_hello_time = t;
+ if (br_is_root_bridge(br))
+ br->hello_time = br->bridge_hello_time;
+ spin_unlock_bh(&br->lock);
+ return 0;
+}
+
+int br_set_max_age(struct net_bridge *br, unsigned long val)
+{
+ unsigned long t = clock_t_to_jiffies(val);
+
+ if (t < BR_MIN_MAX_AGE || t > BR_MAX_MAX_AGE)
+ return -ERANGE;
+
+ spin_lock_bh(&br->lock);
+ br->bridge_max_age = t;
+ if (br_is_root_bridge(br))
+ br->max_age = br->bridge_max_age;
+ spin_unlock_bh(&br->lock);
+ return 0;
+
+}
+
+int br_set_forward_delay(struct net_bridge *br, unsigned long val)
+{
+ unsigned long t = clock_t_to_jiffies(val);
+
+ if (br->stp_enabled != BR_NO_STP &&
+ (t < BR_MIN_FORWARD_DELAY || t > BR_MAX_FORWARD_DELAY))
+ return -ERANGE;
+
+ spin_lock_bh(&br->lock);
+ br->bridge_forward_delay = t;
+ if (br_is_root_bridge(br))
+ br->forward_delay = br->bridge_forward_delay;
+ spin_unlock_bh(&br->lock);
+ return 0;
+}
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 9b61d09..6f615b8 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -20,7 +20,7 @@
/* Port id is composed of priority and port number.
- * NB: least significant bits of priority are dropped to
+ * NB: some bits of priority are dropped to
* make room for more ports.
*/
static inline port_id br_make_port_id(__u8 priority, __u16 port_no)
@@ -29,6 +29,8 @@ static inline port_id br_make_port_id(__u8 priority, __u16 port_no)
| (port_no & ((1<<BR_PORT_BITS)-1));
}
+#define BR_MAX_PORT_PRIORITY ((u16)~0 >> BR_PORT_BITS)
+
/* called under bridge lock */
void br_init_port(struct net_bridge_port *p)
{
@@ -255,10 +257,14 @@ void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio)
}
/* called under bridge lock */
-void br_stp_set_port_priority(struct net_bridge_port *p, u8 newprio)
+int br_stp_set_port_priority(struct net_bridge_port *p, unsigned long newprio)
{
- port_id new_port_id = br_make_port_id(newprio, p->port_no);
+ port_id new_port_id;
+
+ if (newprio > BR_MAX_PORT_PRIORITY)
+ return -ERANGE;
+ new_port_id = br_make_port_id(newprio, p->port_no);
if (br_is_designated_port(p))
p->designated_port = new_port_id;
@@ -269,14 +275,21 @@ void br_stp_set_port_priority(struct net_bridge_port *p, u8 newprio)
br_become_designated_port(p);
br_port_state_selection(p->br);
}
+
+ return 0;
}
/* called under bridge lock */
-void br_stp_set_path_cost(struct net_bridge_port *p, u32 path_cost)
+int br_stp_set_path_cost(struct net_bridge_port *p, unsigned long path_cost)
{
+ if (path_cost < BR_MIN_PATH_COST ||
+ path_cost > BR_MAX_PATH_COST)
+ return -ERANGE;
+
p->path_cost = path_cost;
br_configuration_update(p->br);
br_port_state_selection(p->br);
+ return 0;
}
ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id)
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 5c1e555..68b893e 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -43,9 +43,7 @@ static ssize_t store_bridge_parm(struct device *d,
if (endp == buf)
return -EINVAL;
- spin_lock_bh(&br->lock);
err = (*set)(br, val);
- spin_unlock_bh(&br->lock);
return err ? err : len;
}
@@ -57,20 +55,11 @@ static ssize_t show_forward_delay(struct device *d,
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
}
-static int set_forward_delay(struct net_bridge *br, unsigned long val)
-{
- unsigned long delay = clock_t_to_jiffies(val);
- br->forward_delay = delay;
- if (br_is_root_bridge(br))
- br->bridge_forward_delay = delay;
- return 0;
-}
-
static ssize_t store_forward_delay(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
- return store_bridge_parm(d, buf, len, set_forward_delay);
+ return store_bridge_parm(d, buf, len, br_set_forward_delay);
}
static DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
show_forward_delay, store_forward_delay);
@@ -82,24 +71,11 @@ static ssize_t show_hello_time(struct device *d, struct device_attribute *attr,
jiffies_to_clock_t(to_bridge(d)->hello_time));
}
-static int set_hello_time(struct net_bridge *br, unsigned long val)
-{
- unsigned long t = clock_t_to_jiffies(val);
-
- if (t < HZ)
- return -EINVAL;
-
- br->hello_time = t;
- if (br_is_root_bridge(br))
- br->bridge_hello_time = t;
- return 0;
-}
-
static ssize_t store_hello_time(struct device *d,
struct device_attribute *attr, const char *buf,
size_t len)
{
- return store_bridge_parm(d, buf, len, set_hello_time);
+ return store_bridge_parm(d, buf, len, br_set_hello_time);
}
static DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
store_hello_time);
@@ -111,19 +87,10 @@ static ssize_t show_max_age(struct device *d, struct device_attribute *attr,
jiffies_to_clock_t(to_bridge(d)->max_age));
}
-static int set_max_age(struct net_bridge *br, unsigned long val)
-{
- unsigned long t = clock_t_to_jiffies(val);
- br->max_age = t;
- if (br_is_root_bridge(br))
- br->bridge_max_age = t;
- return 0;
-}
-
static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
const char *buf, size_t len)
{
- return store_bridge_parm(d, buf, len, set_max_age);
+ return store_bridge_parm(d, buf, len, br_set_max_age);
}
static DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index fd5799c..6229b62 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -23,7 +23,7 @@
struct brport_attribute {
struct attribute attr;
ssize_t (*show)(struct net_bridge_port *, char *);
- ssize_t (*store)(struct net_bridge_port *, unsigned long);
+ int (*store)(struct net_bridge_port *, unsigned long);
};
#define BRPORT_ATTR(_name,_mode,_show,_store) \
@@ -38,27 +38,17 @@ static ssize_t show_path_cost(struct net_bridge_port *p, char *buf)
{
return sprintf(buf, "%d\n", p->path_cost);
}
-static ssize_t store_path_cost(struct net_bridge_port *p, unsigned long v)
-{
- br_stp_set_path_cost(p, v);
- return 0;
-}
+
static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR,
- show_path_cost, store_path_cost);
+ show_path_cost, br_stp_set_path_cost);
static ssize_t show_priority(struct net_bridge_port *p, char *buf)
{
return sprintf(buf, "%d\n", p->priority);
}
-static ssize_t store_priority(struct net_bridge_port *p, unsigned long v)
-{
- if (v >= (1<<(16-BR_PORT_BITS)))
- return -ERANGE;
- br_stp_set_port_priority(p, v);
- return 0;
-}
+
static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR,
- show_priority, store_priority);
+ show_priority, br_stp_set_port_priority);
static ssize_t show_designated_root(struct net_bridge_port *p, char *buf)
{
@@ -136,7 +126,7 @@ static ssize_t show_hold_timer(struct net_bridge_port *p,
}
static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL);
-static ssize_t store_flush(struct net_bridge_port *p, unsigned long v)
+static int store_flush(struct net_bridge_port *p, unsigned long v)
{
br_fdb_delete_by_port(p->br, p, 0); // Don't delete local entry
return 0;
@@ -148,7 +138,7 @@ static ssize_t show_hairpin_mode(struct net_bridge_port *p, char *buf)
int hairpin_mode = (p->flags & BR_HAIRPIN_MODE) ? 1 : 0;
return sprintf(buf, "%d\n", hairpin_mode);
}
-static ssize_t store_hairpin_mode(struct net_bridge_port *p, unsigned long v)
+static int store_hairpin_mode(struct net_bridge_port *p, unsigned long v)
{
if (v)
p->flags |= BR_HAIRPIN_MODE;
@@ -165,7 +155,7 @@ static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
return sprintf(buf, "%d\n", p->multicast_router);
}
-static ssize_t store_multicast_router(struct net_bridge_port *p,
+static int store_multicast_router(struct net_bridge_port *p,
unsigned long v)
{
return br_multicast_set_port_router(p, v);
diff --git a/net/caif/caif_config_util.c b/net/caif/caif_config_util.c
index d522d8c..9b63e4e 100644
--- a/net/caif/caif_config_util.c
+++ b/net/caif/caif_config_util.c
@@ -10,9 +10,9 @@
#include <net/caif/cfcnfg.h>
#include <net/caif/caif_dev.h>
-int connect_req_to_link_param(struct cfcnfg *cnfg,
- struct caif_connect_request *s,
- struct cfctrl_link_param *l)
+int caif_connect_req_to_link_param(struct cfcnfg *cnfg,
+ struct caif_connect_request *s,
+ struct cfctrl_link_param *l)
{
struct dev_info *dev_info;
enum cfcnfg_phy_preference pref;
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
index a42a408..75e00d5 100644
--- a/net/caif/caif_dev.c
+++ b/net/caif/caif_dev.c
@@ -120,25 +120,12 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt)
{
struct caif_device_entry *caifd =
container_of(layer, struct caif_device_entry, layer);
- struct sk_buff *skb, *skb2;
- int ret = -EINVAL;
+ struct sk_buff *skb;
+
skb = cfpkt_tonative(pkt);
skb->dev = caifd->netdev;
- /*
- * Don't allow SKB to be destroyed upon error, but signal resend
- * notification to clients. We can't rely on the return value as
- * congestion (NET_XMIT_CN) sometimes drops the packet, sometimes don't.
- */
- if (netif_queue_stopped(caifd->netdev))
- return -EAGAIN;
- skb2 = skb_get(skb);
-
- ret = dev_queue_xmit(skb2);
-
- if (!ret)
- kfree_skb(skb);
- else
- return -EAGAIN;
+
+ dev_queue_xmit(skb);
return 0;
}
@@ -146,9 +133,7 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt)
static int modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
{
struct caif_device_entry *caifd;
- struct caif_dev_common *caifdev;
caifd = container_of(layr, struct caif_device_entry, layer);
- caifdev = netdev_priv(caifd->netdev);
if (ctrl == _CAIF_MODEMCMD_PHYIF_USEFULL) {
atomic_set(&caifd->in_use, 1);
wake_up_interruptible(&caifd->event);
@@ -167,10 +152,8 @@ static int modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
static int receive(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pkttype, struct net_device *orig_dev)
{
- struct net *net;
struct cfpkt *pkt;
struct caif_device_entry *caifd;
- net = dev_net(dev);
pkt = cfpkt_fromnative(CAIF_DIR_IN, skb);
caifd = caif_get(dev);
if (!caifd || !caifd->layer.up || !caifd->layer.up->receive)
@@ -208,7 +191,6 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
struct caif_device_entry *caifd = NULL;
struct caif_dev_common *caifdev;
enum cfcnfg_phy_preference pref;
- int res = -EINVAL;
enum cfcnfg_phy_type phy_type;
if (dev->type != ARPHRD_CAIF)
@@ -223,7 +205,6 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
caifdev = netdev_priv(dev);
caifdev->flowctrl = dev_flowctrl;
atomic_set(&caifd->state, what);
- res = 0;
break;
case NETDEV_UP:
@@ -257,7 +238,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
break;
}
dev_hold(dev);
- cfcnfg_add_phy_layer(get_caif_conf(),
+ cfcnfg_add_phy_layer(cfg,
phy_type,
dev,
&caifd->layer,
@@ -287,7 +268,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
_CAIF_CTRLCMD_PHYIF_DOWN_IND,
caifd->layer.id);
might_sleep();
- res = wait_event_interruptible_timeout(caifd->event,
+ wait_event_interruptible_timeout(caifd->event,
atomic_read(&caifd->in_use) == 0,
TIMEOUT);
break;
@@ -300,7 +281,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
if (atomic_read(&caifd->in_use))
netdev_warn(dev,
"Unregistering an active CAIF device\n");
- cfcnfg_del_phy_layer(get_caif_conf(), &caifd->layer);
+ cfcnfg_del_phy_layer(cfg, &caifd->layer);
dev_put(dev);
atomic_set(&caifd->state, what);
break;
@@ -322,24 +303,18 @@ static struct notifier_block caif_device_notifier = {
.priority = 0,
};
-
-struct cfcnfg *get_caif_conf(void)
-{
- return cfg;
-}
-EXPORT_SYMBOL(get_caif_conf);
-
int caif_connect_client(struct caif_connect_request *conn_req,
struct cflayer *client_layer, int *ifindex,
int *headroom, int *tailroom)
{
struct cfctrl_link_param param;
int ret;
- ret = connect_req_to_link_param(get_caif_conf(), conn_req, &param);
+
+ ret = caif_connect_req_to_link_param(cfg, conn_req, &param);
if (ret)
return ret;
/* Hook up the adaptation layer. */
- return cfcnfg_add_adaptation_layer(get_caif_conf(), &param,
+ return cfcnfg_add_adaptation_layer(cfg, &param,
client_layer, ifindex,
headroom, tailroom);
}
@@ -347,16 +322,10 @@ EXPORT_SYMBOL(caif_connect_client);
int caif_disconnect_client(struct cflayer *adap_layer)
{
- return cfcnfg_disconn_adapt_layer(get_caif_conf(), adap_layer);
+ return cfcnfg_disconn_adapt_layer(cfg, adap_layer);
}
EXPORT_SYMBOL(caif_disconnect_client);
-void caif_release_client(struct cflayer *adap_layer)
-{
- cfcnfg_release_adap_layer(adap_layer);
-}
-EXPORT_SYMBOL(caif_release_client);
-
/* Per-namespace Caif devices handling */
static int caif_init_net(struct net *net)
{
@@ -369,12 +338,11 @@ static int caif_init_net(struct net *net)
static void caif_exit_net(struct net *net)
{
struct net_device *dev;
- int res;
rtnl_lock();
for_each_netdev(net, dev) {
if (dev->type != ARPHRD_CAIF)
continue;
- res = dev_close(dev);
+ dev_close(dev);
caif_device_destroy(dev);
}
rtnl_unlock();
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 8184c03..2021242 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -519,43 +519,14 @@ static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk,
int noblock, long timeo)
{
struct cfpkt *pkt;
- int ret, loopcnt = 0;
pkt = cfpkt_fromnative(CAIF_DIR_OUT, skb);
memset(cfpkt_info(pkt), 0, sizeof(struct caif_payload_info));
- do {
-
- ret = -ETIMEDOUT;
- /* Slight paranoia, probably not needed. */
- if (unlikely(loopcnt++ > 1000)) {
- pr_warn("transmit retries failed, error = %d\n", ret);
- break;
- }
+ if (cf_sk->layer.dn == NULL)
+ return -EINVAL;
- if (cf_sk->layer.dn != NULL)
- ret = cf_sk->layer.dn->transmit(cf_sk->layer.dn, pkt);
- if (likely(ret >= 0))
- break;
- /* if transmit return -EAGAIN, then retry */
- if (noblock && ret == -EAGAIN)
- break;
- timeo = caif_wait_for_flow_on(cf_sk, 0, timeo, &ret);
- if (signal_pending(current)) {
- ret = sock_intr_errno(timeo);
- break;
- }
- if (ret)
- break;
- if (cf_sk->sk.sk_state != CAIF_CONNECTED ||
- sock_flag(&cf_sk->sk, SOCK_DEAD) ||
- (cf_sk->sk.sk_shutdown & RCV_SHUTDOWN)) {
- ret = -EPIPE;
- cf_sk->sk.sk_err = EPIPE;
- break;
- }
- } while (ret == -EAGAIN);
- return ret;
+ return cf_sk->layer.dn->transmit(cf_sk->layer.dn, pkt);
}
/* Copied from af_unix:unix_dgram_sendmsg, and adapted to CAIF */
@@ -852,7 +823,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
sock->state = SS_CONNECTING;
sk->sk_state = CAIF_CONNECTING;
- /* Check priority value comming from socket */
+ /* Check priority value coming from socket */
/* if priority value is out of range it will be ajusted */
if (cf_sk->sk.sk_priority > CAIF_PRIO_MAX)
cf_sk->conn_req.priority = CAIF_PRIO_MAX;
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index f1f98d9..25c0b19 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -253,7 +253,7 @@ static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
{
}
-int protohead[CFCTRL_SRV_MASK] = {
+static const int protohead[CFCTRL_SRV_MASK] = {
[CFCTRL_SRV_VEI] = 4,
[CFCTRL_SRV_DATAGRAM] = 7,
[CFCTRL_SRV_UTIL] = 4,
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index 3cd8f97..397a2c0 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -58,7 +58,8 @@ struct cflayer *cfctrl_create(void)
return &this->serv.layer;
}
-static bool param_eq(struct cfctrl_link_param *p1, struct cfctrl_link_param *p2)
+static bool param_eq(const struct cfctrl_link_param *p1,
+ const struct cfctrl_link_param *p2)
{
bool eq =
p1->linktype == p2->linktype &&
@@ -100,8 +101,8 @@ static bool param_eq(struct cfctrl_link_param *p1, struct cfctrl_link_param *p2)
return false;
}
-bool cfctrl_req_eq(struct cfctrl_request_info *r1,
- struct cfctrl_request_info *r2)
+static bool cfctrl_req_eq(const struct cfctrl_request_info *r1,
+ const struct cfctrl_request_info *r2)
{
if (r1->cmd != r2->cmd)
return false;
@@ -112,7 +113,7 @@ bool cfctrl_req_eq(struct cfctrl_request_info *r1,
}
/* Insert request at the end */
-void cfctrl_insert_req(struct cfctrl *ctrl,
+static void cfctrl_insert_req(struct cfctrl *ctrl,
struct cfctrl_request_info *req)
{
spin_lock(&ctrl->info_list_lock);
@@ -123,8 +124,8 @@ void cfctrl_insert_req(struct cfctrl *ctrl,
}
/* Compare and remove request */
-struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
- struct cfctrl_request_info *req)
+static struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
+ struct cfctrl_request_info *req)
{
struct cfctrl_request_info *p, *tmp, *first;
@@ -154,16 +155,6 @@ struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer)
return &this->res;
}
-void cfctrl_set_dnlayer(struct cflayer *this, struct cflayer *dn)
-{
- this->dn = dn;
-}
-
-void cfctrl_set_uplayer(struct cflayer *this, struct cflayer *up)
-{
- this->up = up;
-}
-
static void init_info(struct caif_payload_info *info, struct cfctrl *cfctrl)
{
info->hdr_len = 0;
@@ -304,58 +295,6 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
return ret;
}
-void cfctrl_sleep_req(struct cflayer *layer)
-{
- int ret;
- struct cfctrl *cfctrl = container_obj(layer);
- struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
- if (!pkt) {
- pr_warn("Out of memory\n");
- return;
- }
- cfpkt_addbdy(pkt, CFCTRL_CMD_SLEEP);
- init_info(cfpkt_info(pkt), cfctrl);
- ret =
- cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
- if (ret < 0)
- cfpkt_destroy(pkt);
-}
-
-void cfctrl_wake_req(struct cflayer *layer)
-{
- int ret;
- struct cfctrl *cfctrl = container_obj(layer);
- struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
- if (!pkt) {
- pr_warn("Out of memory\n");
- return;
- }
- cfpkt_addbdy(pkt, CFCTRL_CMD_WAKE);
- init_info(cfpkt_info(pkt), cfctrl);
- ret =
- cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
- if (ret < 0)
- cfpkt_destroy(pkt);
-}
-
-void cfctrl_getstartreason_req(struct cflayer *layer)
-{
- int ret;
- struct cfctrl *cfctrl = container_obj(layer);
- struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
- if (!pkt) {
- pr_warn("Out of memory\n");
- return;
- }
- cfpkt_addbdy(pkt, CFCTRL_CMD_START_REASON);
- init_info(cfpkt_info(pkt), cfctrl);
- ret =
- cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
- if (ret < 0)
- cfpkt_destroy(pkt);
-}
-
-
void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
{
struct cfctrl_request_info *p, *tmp;
diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c
index 27dab26..0382dec 100644
--- a/net/caif/cfdgml.c
+++ b/net/caif/cfdgml.c
@@ -13,6 +13,7 @@
#include <net/caif/cfsrvl.h>
#include <net/caif/cfpkt.h>
+
#define container_obj(layr) ((struct cfsrvl *) layr)
#define DGM_CMD_BIT 0x80
@@ -83,6 +84,7 @@ static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt)
static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt)
{
+ u8 packet_type;
u32 zero = 0;
struct caif_payload_info *info;
struct cfsrvl *service = container_obj(layr);
@@ -94,7 +96,9 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt)
if (cfpkt_getlen(pkt) > DGM_MTU)
return -EMSGSIZE;
- cfpkt_add_head(pkt, &zero, 4);
+ cfpkt_add_head(pkt, &zero, 3);
+ packet_type = 0x08; /* B9 set - UNCLASSIFIED */
+ cfpkt_add_head(pkt, &packet_type, 1);
/* Add info for MUX-layer to route the packet out. */
info = cfpkt_info(pkt);
@@ -104,10 +108,5 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt)
*/
info->hdr_len = 4;
info->dev_info = &service->dev_info;
- ret = layr->dn->transmit(layr->dn, pkt);
- if (ret < 0) {
- u32 tmp32;
- cfpkt_extr_head(pkt, &tmp32, 4);
- }
- return ret;
+ return layr->dn->transmit(layr->dn, pkt);
}
diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c
index a445043..2423fed 100644
--- a/net/caif/cffrml.c
+++ b/net/caif/cffrml.c
@@ -120,7 +120,6 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt)
int tmp;
u16 chks;
u16 len;
- int ret;
struct cffrml *this = container_obj(layr);
if (this->dofcs) {
chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
@@ -137,12 +136,7 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt)
pr_err("Packet is erroneous!\n");
return -EPROTO;
}
- ret = layr->dn->transmit(layr->dn, pkt);
- if (ret < 0) {
- /* Remove header on faulty packet. */
- cfpkt_extr_head(pkt, &tmp, 2);
- }
- return ret;
+ return layr->dn->transmit(layr->dn, pkt);
}
static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c
index 46f34b2..fc24974 100644
--- a/net/caif/cfmuxl.c
+++ b/net/caif/cfmuxl.c
@@ -71,41 +71,6 @@ int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid)
return 0;
}
-bool cfmuxl_is_phy_inuse(struct cflayer *layr, u8 phyid)
-{
- struct list_head *node;
- struct cflayer *layer;
- struct cfmuxl *muxl = container_obj(layr);
- bool match = false;
- spin_lock(&muxl->receive_lock);
-
- list_for_each(node, &muxl->srvl_list) {
- layer = list_entry(node, struct cflayer, node);
- if (cfsrvl_phyid_match(layer, phyid)) {
- match = true;
- break;
- }
-
- }
- spin_unlock(&muxl->receive_lock);
- return match;
-}
-
-u8 cfmuxl_get_phyid(struct cflayer *layr, u8 channel_id)
-{
- struct cflayer *up;
- int phyid;
- struct cfmuxl *muxl = container_obj(layr);
- spin_lock(&muxl->receive_lock);
- up = get_up(muxl, channel_id);
- if (up != NULL)
- phyid = cfsrvl_getphyid(up);
- else
- phyid = 0;
- spin_unlock(&muxl->receive_lock);
- return phyid;
-}
-
int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *dn, u8 phyid)
{
struct cfmuxl *muxl = (struct cfmuxl *) layr;
@@ -219,12 +184,12 @@ static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt)
static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt)
{
- int ret;
struct cfmuxl *muxl = container_obj(layr);
u8 linkid;
struct cflayer *dn;
struct caif_payload_info *info = cfpkt_info(pkt);
- dn = get_dn(muxl, cfpkt_info(pkt)->dev_info);
+ BUG_ON(!info);
+ dn = get_dn(muxl, info->dev_info);
if (dn == NULL) {
pr_warn("Send data on unknown phy ID = %d (0x%x)\n",
info->dev_info->id, info->dev_info->id);
@@ -233,20 +198,16 @@ static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt)
info->hdr_len += 1;
linkid = info->channel_id;
cfpkt_add_head(pkt, &linkid, 1);
- ret = dn->transmit(dn, pkt);
- /* Remove MUX protocol header upon error. */
- if (ret < 0)
- cfpkt_extr_head(pkt, &linkid, 1);
- return ret;
+ return dn->transmit(dn, pkt);
}
static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
int phyid)
{
struct cfmuxl *muxl = container_obj(layr);
- struct list_head *node;
+ struct list_head *node, *next;
struct cflayer *layer;
- list_for_each(node, &muxl->srvl_list) {
+ list_for_each_safe(node, next, &muxl->srvl_list) {
layer = list_entry(node, struct cflayer, node);
if (cfsrvl_phyid_match(layer, phyid))
layer->ctrlcmd(layer, ctrl, phyid);
diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c
index d7e865e..20c6cb3 100644
--- a/net/caif/cfpkt_skbuff.c
+++ b/net/caif/cfpkt_skbuff.c
@@ -42,22 +42,22 @@ struct cfpkt_priv_data {
bool erronous;
};
-inline struct cfpkt_priv_data *cfpkt_priv(struct cfpkt *pkt)
+static inline struct cfpkt_priv_data *cfpkt_priv(struct cfpkt *pkt)
{
return (struct cfpkt_priv_data *) pkt->skb.cb;
}
-inline bool is_erronous(struct cfpkt *pkt)
+static inline bool is_erronous(struct cfpkt *pkt)
{
return cfpkt_priv(pkt)->erronous;
}
-inline struct sk_buff *pkt_to_skb(struct cfpkt *pkt)
+static inline struct sk_buff *pkt_to_skb(struct cfpkt *pkt)
{
return &pkt->skb;
}
-inline struct cfpkt *skb_to_pkt(struct sk_buff *skb)
+static inline struct cfpkt *skb_to_pkt(struct sk_buff *skb)
{
return (struct cfpkt *) skb;
}
@@ -317,17 +317,6 @@ int cfpkt_setlen(struct cfpkt *pkt, u16 len)
}
EXPORT_SYMBOL(cfpkt_setlen);
-struct cfpkt *cfpkt_create_uplink(const unsigned char *data, unsigned int len)
-{
- struct cfpkt *pkt = cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX);
- if (!pkt)
- return NULL;
- if (unlikely(data != NULL))
- cfpkt_add_body(pkt, data, len);
- return pkt;
-}
-EXPORT_SYMBOL(cfpkt_create_uplink);
-
struct cfpkt *cfpkt_append(struct cfpkt *dstpkt,
struct cfpkt *addpkt,
u16 expectlen)
@@ -408,169 +397,12 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos)
}
EXPORT_SYMBOL(cfpkt_split);
-char *cfpkt_log_pkt(struct cfpkt *pkt, char *buf, int buflen)
-{
- struct sk_buff *skb = pkt_to_skb(pkt);
- char *p = buf;
- int i;
-
- /*
- * Sanity check buffer length, it needs to be at least as large as
- * the header info: ~=50+ bytes
- */
- if (buflen < 50)
- return NULL;
-
- snprintf(buf, buflen, "%s: pkt:%p len:%ld(%ld+%ld) {%ld,%ld} data: [",
- is_erronous(pkt) ? "ERRONOUS-SKB" :
- (skb->data_len != 0 ? "COMPLEX-SKB" : "SKB"),
- skb,
- (long) skb->len,
- (long) (skb_tail_pointer(skb) - skb->data),
- (long) skb->data_len,
- (long) (skb->data - skb->head),
- (long) (skb_tail_pointer(skb) - skb->head));
- p = buf + strlen(buf);
-
- for (i = 0; i < skb_tail_pointer(skb) - skb->data && i < 300; i++) {
- if (p > buf + buflen - 10) {
- sprintf(p, "...");
- p = buf + strlen(buf);
- break;
- }
- sprintf(p, "%02x,", skb->data[i]);
- p = buf + strlen(buf);
- }
- sprintf(p, "]\n");
- return buf;
-}
-EXPORT_SYMBOL(cfpkt_log_pkt);
-
-int cfpkt_raw_append(struct cfpkt *pkt, void **buf, unsigned int buflen)
-{
- struct sk_buff *skb = pkt_to_skb(pkt);
- struct sk_buff *lastskb;
-
- caif_assert(buf != NULL);
- if (unlikely(is_erronous(pkt)))
- return -EPROTO;
- /* Make sure SKB is writable */
- if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) {
- PKT_ERROR(pkt, "skb_cow_data failed\n");
- return -EPROTO;
- }
-
- if (unlikely(skb_linearize(skb) != 0)) {
- PKT_ERROR(pkt, "linearize failed\n");
- return -EPROTO;
- }
-
- if (unlikely(skb_tailroom(skb) < buflen)) {
- PKT_ERROR(pkt, "buffer too short - failed\n");
- return -EPROTO;
- }
-
- *buf = skb_put(skb, buflen);
- return 1;
-}
-EXPORT_SYMBOL(cfpkt_raw_append);
-
-int cfpkt_raw_extract(struct cfpkt *pkt, void **buf, unsigned int buflen)
-{
- struct sk_buff *skb = pkt_to_skb(pkt);
-
- caif_assert(buf != NULL);
- if (unlikely(is_erronous(pkt)))
- return -EPROTO;
-
- if (unlikely(buflen > skb->len)) {
- PKT_ERROR(pkt, "buflen too large - failed\n");
- return -EPROTO;
- }
-
- if (unlikely(buflen > skb_headlen(skb))) {
- if (unlikely(skb_linearize(skb) != 0)) {
- PKT_ERROR(pkt, "linearize failed\n");
- return -EPROTO;
- }
- }
-
- *buf = skb->data;
- skb_pull(skb, buflen);
-
- return 1;
-}
-EXPORT_SYMBOL(cfpkt_raw_extract);
-
-inline bool cfpkt_erroneous(struct cfpkt *pkt)
+bool cfpkt_erroneous(struct cfpkt *pkt)
{
return cfpkt_priv(pkt)->erronous;
}
EXPORT_SYMBOL(cfpkt_erroneous);
-struct cfpktq *cfpktq_create(void)
-{
- struct cfpktq *q = kmalloc(sizeof(struct cfpktq), GFP_ATOMIC);
- if (!q)
- return NULL;
- skb_queue_head_init(&q->head);
- atomic_set(&q->count, 0);
- spin_lock_init(&q->lock);
- return q;
-}
-EXPORT_SYMBOL(cfpktq_create);
-
-void cfpkt_queue(struct cfpktq *pktq, struct cfpkt *pkt, unsigned short prio)
-{
- atomic_inc(&pktq->count);
- spin_lock(&pktq->lock);
- skb_queue_tail(&pktq->head, pkt_to_skb(pkt));
- spin_unlock(&pktq->lock);
-
-}
-EXPORT_SYMBOL(cfpkt_queue);
-
-struct cfpkt *cfpkt_qpeek(struct cfpktq *pktq)
-{
- struct cfpkt *tmp;
- spin_lock(&pktq->lock);
- tmp = skb_to_pkt(skb_peek(&pktq->head));
- spin_unlock(&pktq->lock);
- return tmp;
-}
-EXPORT_SYMBOL(cfpkt_qpeek);
-
-struct cfpkt *cfpkt_dequeue(struct cfpktq *pktq)
-{
- struct cfpkt *pkt;
- spin_lock(&pktq->lock);
- pkt = skb_to_pkt(skb_dequeue(&pktq->head));
- if (pkt) {
- atomic_dec(&pktq->count);
- caif_assert(atomic_read(&pktq->count) >= 0);
- }
- spin_unlock(&pktq->lock);
- return pkt;
-}
-EXPORT_SYMBOL(cfpkt_dequeue);
-
-int cfpkt_qcount(struct cfpktq *pktq)
-{
- return atomic_read(&pktq->count);
-}
-EXPORT_SYMBOL(cfpkt_qcount);
-
-struct cfpkt *cfpkt_clone_release(struct cfpkt *pkt)
-{
- struct cfpkt *clone;
- clone = skb_to_pkt(skb_clone(pkt_to_skb(pkt), GFP_ATOMIC));
- /* Free original packet. */
- cfpkt_destroy(pkt);
- if (!clone)
- return NULL;
- return clone;
-}
-EXPORT_SYMBOL(cfpkt_clone_release);
struct caif_payload_info *cfpkt_info(struct cfpkt *pkt)
{
diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c
index 8303fe3..2715c84 100644
--- a/net/caif/cfserl.c
+++ b/net/caif/cfserl.c
@@ -179,15 +179,10 @@ static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt)
static int cfserl_transmit(struct cflayer *layer, struct cfpkt *newpkt)
{
struct cfserl *layr = container_obj(layer);
- int ret;
u8 tmp8 = CFSERL_STX;
if (layr->usestx)
cfpkt_add_head(newpkt, &tmp8, 1);
- ret = layer->dn->transmit(layer->dn, newpkt);
- if (ret < 0)
- cfpkt_extr_head(newpkt, &tmp8, 1);
-
- return ret;
+ return layer->dn->transmit(layer->dn, newpkt);
}
static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c
index ab5e542..24ba392 100644
--- a/net/caif/cfsrvl.c
+++ b/net/caif/cfsrvl.c
@@ -151,12 +151,7 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
return -EINVAL;
}
-void cfservl_destroy(struct cflayer *layer)
-{
- kfree(layer);
-}
-
-void cfsrvl_release(struct kref *kref)
+static void cfsrvl_release(struct kref *kref)
{
struct cfsrvl *service = container_of(kref, struct cfsrvl, ref);
kfree(service);
diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c
index 315c0d6..98e027d 100644
--- a/net/caif/cfutill.c
+++ b/net/caif/cfutill.c
@@ -100,10 +100,5 @@ static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt)
*/
info->hdr_len = 1;
info->dev_info = &service->dev_info;
- ret = layr->dn->transmit(layr->dn, pkt);
- if (ret < 0) {
- u32 tmp32;
- cfpkt_extr_head(pkt, &tmp32, 4);
- }
- return ret;
+ return layr->dn->transmit(layr->dn, pkt);
}
diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c
index c3b1dec..1a588cd 100644
--- a/net/caif/cfveil.c
+++ b/net/caif/cfveil.c
@@ -96,8 +96,5 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt)
info->channel_id = service->layer.id;
info->hdr_len = 1;
info->dev_info = &service->dev_info;
- ret = layr->dn->transmit(layr->dn, pkt);
- if (ret < 0)
- cfpkt_extr_head(pkt, &tmp, 1);
- return ret;
+ return layr->dn->transmit(layr->dn, pkt);
}
diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c
index bf6fef2..b2f5989 100644
--- a/net/caif/cfvidl.c
+++ b/net/caif/cfvidl.c
@@ -60,8 +60,5 @@ static int cfvidl_transmit(struct cflayer *layr, struct cfpkt *pkt)
info = cfpkt_info(pkt);
info->channel_id = service->layer.id;
info->dev_info = &service->dev_info;
- ret = layr->dn->transmit(layr->dn, pkt);
- if (ret < 0)
- cfpkt_extr_head(pkt, &videoheader, 4);
- return ret;
+ return layr->dn->transmit(layr->dn, pkt);
}
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 733d66f..a8dcaa4 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -85,7 +85,7 @@ static struct kmem_cache *rcv_cache __read_mostly;
/* table of registered CAN protocols */
static struct can_proto *proto_tab[CAN_NPROTO] __read_mostly;
-static DEFINE_SPINLOCK(proto_tab_lock);
+static DEFINE_MUTEX(proto_tab_lock);
struct timer_list can_stattimer; /* timer for statistics update */
struct s_stats can_stats; /* packet statistics */
@@ -115,6 +115,19 @@ static void can_sock_destruct(struct sock *sk)
skb_queue_purge(&sk->sk_receive_queue);
}
+static struct can_proto *can_try_module_get(int protocol)
+{
+ struct can_proto *cp;
+
+ rcu_read_lock();
+ cp = rcu_dereference(proto_tab[protocol]);
+ if (cp && !try_module_get(cp->prot->owner))
+ cp = NULL;
+ rcu_read_unlock();
+
+ return cp;
+}
+
static int can_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
@@ -130,9 +143,12 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
if (!net_eq(net, &init_net))
return -EAFNOSUPPORT;
+ cp = can_try_module_get(protocol);
+
#ifdef CONFIG_MODULES
- /* try to load protocol module kernel is modular */
- if (!proto_tab[protocol]) {
+ if (!cp) {
+ /* try to load protocol module if kernel is modular */
+
err = request_module("can-proto-%d", protocol);
/*
@@ -143,22 +159,18 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
if (err && printk_ratelimit())
printk(KERN_ERR "can: request_module "
"(can-proto-%d) failed.\n", protocol);
+
+ cp = can_try_module_get(protocol);
}
#endif
- spin_lock(&proto_tab_lock);
- cp = proto_tab[protocol];
- if (cp && !try_module_get(cp->prot->owner))
- cp = NULL;
- spin_unlock(&proto_tab_lock);
-
/* check for available protocol and correct usage */
if (!cp)
return -EPROTONOSUPPORT;
if (cp->type != sock->type) {
- err = -EPROTONOSUPPORT;
+ err = -EPROTOTYPE;
goto errout;
}
@@ -694,15 +706,16 @@ int can_proto_register(struct can_proto *cp)
if (err < 0)
return err;
- spin_lock(&proto_tab_lock);
+ mutex_lock(&proto_tab_lock);
+
if (proto_tab[proto]) {
printk(KERN_ERR "can: protocol %d already registered\n",
proto);
err = -EBUSY;
} else
- proto_tab[proto] = cp;
+ rcu_assign_pointer(proto_tab[proto], cp);
- spin_unlock(&proto_tab_lock);
+ mutex_unlock(&proto_tab_lock);
if (err < 0)
proto_unregister(cp->prot);
@@ -719,13 +732,12 @@ void can_proto_unregister(struct can_proto *cp)
{
int proto = cp->protocol;
- spin_lock(&proto_tab_lock);
- if (!proto_tab[proto]) {
- printk(KERN_ERR "BUG: can: protocol %d is not registered\n",
- proto);
- }
- proto_tab[proto] = NULL;
- spin_unlock(&proto_tab_lock);
+ mutex_lock(&proto_tab_lock);
+ BUG_ON(proto_tab[proto] != cp);
+ rcu_assign_pointer(proto_tab[proto], NULL);
+ mutex_unlock(&proto_tab_lock);
+
+ synchronize_rcu();
proto_unregister(cp->prot);
}
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 871a0ad..8a6a05e 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -387,7 +387,7 @@ static void bcm_tx_timeout_tsklet(unsigned long data)
}
/*
- * bcm_tx_timeout_handler - performes cyclic CAN frame transmissions
+ * bcm_tx_timeout_handler - performs cyclic CAN frame transmissions
*/
static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
{
@@ -1427,9 +1427,14 @@ static int bcm_init(struct sock *sk)
static int bcm_release(struct socket *sock)
{
struct sock *sk = sock->sk;
- struct bcm_sock *bo = bcm_sk(sk);
+ struct bcm_sock *bo;
struct bcm_op *op, *next;
+ if (sk == NULL)
+ return 0;
+
+ bo = bcm_sk(sk);
+
/* remove bcm_ops, timer, rx_unregister(), etc. */
unregister_netdevice_notifier(&bo->notifier);
diff --git a/net/can/raw.c b/net/can/raw.c
index 649acfa..0eb39a7 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -305,7 +305,12 @@ static int raw_init(struct sock *sk)
static int raw_release(struct socket *sock)
{
struct sock *sk = sock->sk;
- struct raw_sock *ro = raw_sk(sk);
+ struct raw_sock *ro;
+
+ if (!sk)
+ return 0;
+
+ ro = raw_sk(sk);
unregister_netdevice_notifier(&ro->notifier);
diff --git a/net/ceph/Kconfig b/net/ceph/Kconfig
index ad42404..be683f2 100644
--- a/net/ceph/Kconfig
+++ b/net/ceph/Kconfig
@@ -4,6 +4,7 @@ config CEPH_LIB
select LIBCRC32C
select CRYPTO_AES
select CRYPTO
+ select KEYS
default n
help
Choose Y or M here to include cephlib, which provides the
diff --git a/net/ceph/auth.c b/net/ceph/auth.c
index 549c1f4..b4bf4ac 100644
--- a/net/ceph/auth.c
+++ b/net/ceph/auth.c
@@ -35,12 +35,12 @@ static int ceph_auth_init_protocol(struct ceph_auth_client *ac, int protocol)
/*
* setup, teardown.
*/
-struct ceph_auth_client *ceph_auth_init(const char *name, const char *secret)
+struct ceph_auth_client *ceph_auth_init(const char *name, const struct ceph_crypto_key *key)
{
struct ceph_auth_client *ac;
int ret;
- dout("auth_init name '%s' secret '%s'\n", name, secret);
+ dout("auth_init name '%s'\n", name);
ret = -ENOMEM;
ac = kzalloc(sizeof(*ac), GFP_NOFS);
@@ -52,8 +52,8 @@ struct ceph_auth_client *ceph_auth_init(const char *name, const char *secret)
ac->name = name;
else
ac->name = CEPH_AUTH_NAME_DEFAULT;
- dout("auth_init name %s secret %s\n", ac->name, secret);
- ac->secret = secret;
+ dout("auth_init name %s\n", ac->name);
+ ac->key = key;
return ac;
out:
diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
index 7fd5dfc..1587dc6 100644
--- a/net/ceph/auth_x.c
+++ b/net/ceph/auth_x.c
@@ -662,14 +662,16 @@ int ceph_x_init(struct ceph_auth_client *ac)
goto out;
ret = -EINVAL;
- if (!ac->secret) {
+ if (!ac->key) {
pr_err("no secret set (for auth_x protocol)\n");
goto out_nomem;
}
- ret = ceph_crypto_key_unarmor(&xi->secret, ac->secret);
- if (ret)
+ ret = ceph_crypto_key_clone(&xi->secret, ac->key);
+ if (ret < 0) {
+ pr_err("cannot clone key: %d\n", ret);
goto out_nomem;
+ }
xi->starting = true;
xi->ticket_handlers = RB_ROOT;
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index 95f96ab..132963a 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -5,6 +5,8 @@
#include <linux/fs.h>
#include <linux/inet.h>
#include <linux/in6.h>
+#include <linux/key.h>
+#include <keys/ceph-type.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/parser.h>
@@ -20,6 +22,7 @@
#include <linux/ceph/decode.h>
#include <linux/ceph/mon_client.h>
#include <linux/ceph/auth.h>
+#include "crypto.h"
@@ -117,9 +120,29 @@ int ceph_compare_options(struct ceph_options *new_opt,
if (ret)
return ret;
- ret = strcmp_null(opt1->secret, opt2->secret);
- if (ret)
- return ret;
+ if (opt1->key && !opt2->key)
+ return -1;
+ if (!opt1->key && opt2->key)
+ return 1;
+ if (opt1->key && opt2->key) {
+ if (opt1->key->type != opt2->key->type)
+ return -1;
+ if (opt1->key->created.tv_sec != opt2->key->created.tv_sec)
+ return -1;
+ if (opt1->key->created.tv_nsec != opt2->key->created.tv_nsec)
+ return -1;
+ if (opt1->key->len != opt2->key->len)
+ return -1;
+ if (opt1->key->key && !opt2->key->key)
+ return -1;
+ if (!opt1->key->key && opt2->key->key)
+ return 1;
+ if (opt1->key->key && opt2->key->key) {
+ ret = memcmp(opt1->key->key, opt2->key->key, opt1->key->len);
+ if (ret)
+ return ret;
+ }
+ }
/* any matching mon ip implies a match */
for (i = 0; i < opt1->num_mon; i++) {
@@ -176,6 +199,7 @@ enum {
Opt_fsid,
Opt_name,
Opt_secret,
+ Opt_key,
Opt_ip,
Opt_last_string,
/* string args above */
@@ -192,6 +216,7 @@ static match_table_t opt_tokens = {
{Opt_fsid, "fsid=%s"},
{Opt_name, "name=%s"},
{Opt_secret, "secret=%s"},
+ {Opt_key, "key=%s"},
{Opt_ip, "ip=%s"},
/* string args above */
{Opt_noshare, "noshare"},
@@ -203,11 +228,56 @@ void ceph_destroy_options(struct ceph_options *opt)
{
dout("destroy_options %p\n", opt);
kfree(opt->name);
- kfree(opt->secret);
+ if (opt->key) {
+ ceph_crypto_key_destroy(opt->key);
+ kfree(opt->key);
+ }
kfree(opt);
}
EXPORT_SYMBOL(ceph_destroy_options);
+/* get secret from key store */
+static int get_secret(struct ceph_crypto_key *dst, const char *name) {
+ struct key *ukey;
+ int key_err;
+ int err = 0;
+ struct ceph_crypto_key *ckey;
+
+ ukey = request_key(&key_type_ceph, name, NULL);
+ if (!ukey || IS_ERR(ukey)) {
+ /* request_key errors don't map nicely to mount(2)
+ errors; don't even try, but still printk */
+ key_err = PTR_ERR(ukey);
+ switch (key_err) {
+ case -ENOKEY:
+ pr_warning("ceph: Mount failed due to key not found: %s\n", name);
+ break;
+ case -EKEYEXPIRED:
+ pr_warning("ceph: Mount failed due to expired key: %s\n", name);
+ break;
+ case -EKEYREVOKED:
+ pr_warning("ceph: Mount failed due to revoked key: %s\n", name);
+ break;
+ default:
+ pr_warning("ceph: Mount failed due to unknown key error"
+ " %d: %s\n", key_err, name);
+ }
+ err = -EPERM;
+ goto out;
+ }
+
+ ckey = ukey->payload.data;
+ err = ceph_crypto_key_clone(dst, ckey);
+ if (err)
+ goto out_key;
+ /* pass through, err is 0 */
+
+out_key:
+ key_put(ukey);
+out:
+ return err;
+}
+
int ceph_parse_options(struct ceph_options **popt, char *options,
const char *dev_name, const char *dev_name_end,
int (*parse_extra_token)(char *c, void *private),
@@ -295,9 +365,24 @@ int ceph_parse_options(struct ceph_options **popt, char *options,
GFP_KERNEL);
break;
case Opt_secret:
- opt->secret = kstrndup(argstr[0].from,
- argstr[0].to-argstr[0].from,
- GFP_KERNEL);
+ opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
+ if (!opt->key) {
+ err = -ENOMEM;
+ goto out;
+ }
+ err = ceph_crypto_key_unarmor(opt->key, argstr[0].from);
+ if (err < 0)
+ goto out;
+ break;
+ case Opt_key:
+ opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
+ if (!opt->key) {
+ err = -ENOMEM;
+ goto out;
+ }
+ err = get_secret(opt->key, argstr[0].from);
+ if (err < 0)
+ goto out;
break;
/* misc */
@@ -394,8 +479,8 @@ void ceph_destroy_client(struct ceph_client *client)
ceph_osdc_stop(&client->osdc);
/*
- * make sure mds and osd connections close out before destroying
- * the auth module, which is needed to free those connections'
+ * make sure osd connections close out before destroying the
+ * auth module, which is needed to free those connections'
* ceph_authorizers.
*/
ceph_msgr_flush();
@@ -496,10 +581,14 @@ static int __init init_ceph_lib(void)
if (ret < 0)
goto out;
- ret = ceph_msgr_init();
+ ret = ceph_crypto_init();
if (ret < 0)
goto out_debugfs;
+ ret = ceph_msgr_init();
+ if (ret < 0)
+ goto out_crypto;
+
pr_info("loaded (mon/osd proto %d/%d, osdmap %d/%d %d/%d)\n",
CEPH_MONC_PROTOCOL, CEPH_OSDC_PROTOCOL,
CEPH_OSDMAP_VERSION, CEPH_OSDMAP_VERSION_EXT,
@@ -507,6 +596,8 @@ static int __init init_ceph_lib(void)
return 0;
+out_crypto:
+ ceph_crypto_shutdown();
out_debugfs:
ceph_debugfs_cleanup();
out:
@@ -517,6 +608,7 @@ static void __exit exit_ceph_lib(void)
{
dout("exit_ceph_lib\n");
ceph_msgr_exit();
+ ceph_crypto_shutdown();
ceph_debugfs_cleanup();
}
diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c
index 7b505b0..5a8009c 100644
--- a/net/ceph/crypto.c
+++ b/net/ceph/crypto.c
@@ -5,10 +5,23 @@
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <crypto/hash.h>
+#include <linux/key-type.h>
+#include <keys/ceph-type.h>
#include <linux/ceph/decode.h>
#include "crypto.h"
+int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
+ const struct ceph_crypto_key *src)
+{
+ memcpy(dst, src, sizeof(struct ceph_crypto_key));
+ dst->key = kmalloc(src->len, GFP_NOFS);
+ if (!dst->key)
+ return -ENOMEM;
+ memcpy(dst->key, src->key, src->len);
+ return 0;
+}
+
int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end)
{
if (*p + sizeof(u16) + sizeof(key->created) +
@@ -410,3 +423,63 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
return -EINVAL;
}
}
+
+int ceph_key_instantiate(struct key *key, const void *data, size_t datalen)
+{
+ struct ceph_crypto_key *ckey;
+ int ret;
+ void *p;
+
+ ret = -EINVAL;
+ if (datalen <= 0 || datalen > 32767 || !data)
+ goto err;
+
+ ret = key_payload_reserve(key, datalen);
+ if (ret < 0)
+ goto err;
+
+ ret = -ENOMEM;
+ ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
+ if (!ckey)
+ goto err;
+
+ /* TODO ceph_crypto_key_decode should really take const input */
+ p = (void*)data;
+ ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen);
+ if (ret < 0)
+ goto err_ckey;
+
+ key->payload.data = ckey;
+ return 0;
+
+err_ckey:
+ kfree(ckey);
+err:
+ return ret;
+}
+
+int ceph_key_match(const struct key *key, const void *description)
+{
+ return strcmp(key->description, description) == 0;
+}
+
+void ceph_key_destroy(struct key *key) {
+ struct ceph_crypto_key *ckey = key->payload.data;
+
+ ceph_crypto_key_destroy(ckey);
+}
+
+struct key_type key_type_ceph = {
+ .name = "ceph",
+ .instantiate = ceph_key_instantiate,
+ .match = ceph_key_match,
+ .destroy = ceph_key_destroy,
+};
+
+int ceph_crypto_init(void) {
+ return register_key_type(&key_type_ceph);
+}
+
+void ceph_crypto_shutdown(void) {
+ unregister_key_type(&key_type_ceph);
+}
diff --git a/net/ceph/crypto.h b/net/ceph/crypto.h
index f9eccac..1919d15 100644
--- a/net/ceph/crypto.h
+++ b/net/ceph/crypto.h
@@ -19,6 +19,8 @@ static inline void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
kfree(key->key);
}
+extern int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
+ const struct ceph_crypto_key *src);
extern int ceph_crypto_key_encode(struct ceph_crypto_key *key,
void **p, void *end);
extern int ceph_crypto_key_decode(struct ceph_crypto_key *key,
@@ -40,6 +42,8 @@ extern int ceph_encrypt2(struct ceph_crypto_key *secret,
void *dst, size_t *dst_len,
const void *src1, size_t src1_len,
const void *src2, size_t src2_len);
+extern int ceph_crypto_init(void);
+extern void ceph_crypto_shutdown(void);
/* armor.c */
extern int ceph_armor(char *dst, const char *src, const char *end);
diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
index 8a07939..cbe31fa 100644
--- a/net/ceph/mon_client.c
+++ b/net/ceph/mon_client.c
@@ -759,7 +759,7 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
/* authentication */
monc->auth = ceph_auth_init(cl->options->name,
- cl->options->secret);
+ cl->options->key);
if (IS_ERR(monc->auth))
return PTR_ERR(monc->auth);
monc->auth->want_keys =
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index 02212ed..50af027 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -837,8 +837,7 @@ static void __unregister_request(struct ceph_osd_client *osdc,
dout("moving osd to %p lru\n", req->r_osd);
__move_osd_to_lru(osdc, req->r_osd);
}
- if (list_empty(&req->r_osd_item) &&
- list_empty(&req->r_linger_item))
+ if (list_empty(&req->r_linger_item))
req->r_osd = NULL;
}
@@ -883,7 +882,8 @@ static void __unregister_linger_request(struct ceph_osd_client *osdc,
dout("moving osd to %p lru\n", req->r_osd);
__move_osd_to_lru(osdc, req->r_osd);
}
- req->r_osd = NULL;
+ if (list_empty(&req->r_osd_item))
+ req->r_osd = NULL;
}
}
@@ -917,7 +917,7 @@ EXPORT_SYMBOL(ceph_osdc_set_request_linger);
/*
* Pick an osd (the first 'up' osd in the pg), allocate the osd struct
* (as needed), and set the request r_osd appropriately. If there is
- * no up osd, set r_osd to NULL. Move the request to the appropiate list
+ * no up osd, set r_osd to NULL. Move the request to the appropriate list
* (unsent, homeless) or leave on in-flight lru.
*
* Return 0 if unchanged, 1 if changed, or negative on error.
@@ -1602,11 +1602,11 @@ void handle_watch_notify(struct ceph_osd_client *osdc, struct ceph_msg *msg)
cookie, ver, event);
if (event) {
event_work = kmalloc(sizeof(*event_work), GFP_NOIO);
- INIT_WORK(&event_work->work, do_event_work);
if (!event_work) {
dout("ERROR: could not allocate event_work\n");
goto done_err;
}
+ INIT_WORK(&event_work->work, do_event_work);
event_work->event = event;
event_work->ver = ver;
event_work->notify_id = notify_id;
@@ -1672,7 +1672,7 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
if (req->r_sent == 0) {
rc = __map_request(osdc, req);
if (rc < 0)
- return rc;
+ goto out_unlock;
if (req->r_osd == NULL) {
dout("send_request %p no up osds in pg\n", req);
ceph_monc_request_next_osdmap(&osdc->client->monc);
@@ -1689,6 +1689,8 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
}
}
}
+
+out_unlock:
mutex_unlock(&osdc->request_mutex);
up_read(&osdc->map_sem);
return rc;
diff --git a/net/core/dev.c b/net/core/dev.c
index 3da9fb0..e95dc30 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1315,7 +1315,8 @@ void dev_disable_lro(struct net_device *dev)
return;
__ethtool_set_flags(dev, flags & ~ETH_FLAG_LRO);
- WARN_ON(dev->features & NETIF_F_LRO);
+ if (unlikely(dev->features & NETIF_F_LRO))
+ netdev_WARN(dev, "failed to disable LRO!\n");
}
EXPORT_SYMBOL(dev_disable_lro);
@@ -2091,7 +2092,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
u32 features;
/*
- * If device doesnt need skb->dst, release it right now while
+ * If device doesn't need skb->dst, release it right now while
* its hot in this cpu cache
*/
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
@@ -2151,7 +2152,7 @@ gso:
nskb->next = NULL;
/*
- * If device doesnt need nskb->dst, release it right now while
+ * If device doesn't need nskb->dst, release it right now while
* its hot in this cpu cache
*/
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
@@ -2502,8 +2503,8 @@ static inline void ____napi_schedule(struct softnet_data *sd,
__u32 __skb_get_rxhash(struct sk_buff *skb)
{
int nhoff, hash = 0, poff;
- struct ipv6hdr *ip6;
- struct iphdr *ip;
+ const struct ipv6hdr *ip6;
+ const struct iphdr *ip;
u8 ip_proto;
u32 addr1, addr2, ihl;
union {
@@ -2518,7 +2519,7 @@ __u32 __skb_get_rxhash(struct sk_buff *skb)
if (!pskb_may_pull(skb, sizeof(*ip) + nhoff))
goto done;
- ip = (struct iphdr *) (skb->data + nhoff);
+ ip = (const struct iphdr *) (skb->data + nhoff);
if (ip->frag_off & htons(IP_MF | IP_OFFSET))
ip_proto = 0;
else
@@ -2531,7 +2532,7 @@ __u32 __skb_get_rxhash(struct sk_buff *skb)
if (!pskb_may_pull(skb, sizeof(*ip6) + nhoff))
goto done;
- ip6 = (struct ipv6hdr *) (skb->data + nhoff);
+ ip6 = (const struct ipv6hdr *) (skb->data + nhoff);
ip_proto = ip6->nexthdr;
addr1 = (__force u32) ip6->saddr.s6_addr32[3];
addr2 = (__force u32) ip6->daddr.s6_addr32[3];
@@ -2970,8 +2971,8 @@ EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook);
* when CONFIG_NET_CLS_ACT is? otherwise some useless instructions
* a compare and 2 stores extra right now if we dont have it on
* but have CONFIG_NET_CLS_ACT
- * NOTE: This doesnt stop any functionality; if you dont have
- * the ingress scheduler, you just cant add policies on ingress.
+ * NOTE: This doesn't stop any functionality; if you dont have
+ * the ingress scheduler, you just can't add policies on ingress.
*
*/
static int ing_filter(struct sk_buff *skb, struct netdev_queue *rxq)
@@ -3076,25 +3077,6 @@ void netdev_rx_handler_unregister(struct net_device *dev)
}
EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
-static void vlan_on_bond_hook(struct sk_buff *skb)
-{
- /*
- * Make sure ARP frames received on VLAN interfaces stacked on
- * bonding interfaces still make their way to any base bonding
- * device that may have registered for a specific ptype.
- */
- if (skb->dev->priv_flags & IFF_802_1Q_VLAN &&
- vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING &&
- skb->protocol == htons(ETH_P_ARP)) {
- struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
-
- if (!skb2)
- return;
- skb2->dev = vlan_dev_real_dev(skb->dev);
- netif_rx(skb2);
- }
-}
-
static int __netif_receive_skb(struct sk_buff *skb)
{
struct packet_type *ptype, *pt_prev;
@@ -3130,6 +3112,12 @@ another_round:
__this_cpu_inc(softnet_data.processed);
+ if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
+ skb = vlan_untag(skb);
+ if (unlikely(!skb))
+ goto out;
+ }
+
#ifdef CONFIG_NET_CLS_ACT
if (skb->tc_verd & TC_NCLS) {
skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
@@ -3177,15 +3165,13 @@ ncls:
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = NULL;
}
- if (vlan_hwaccel_do_receive(&skb)) {
+ if (vlan_do_receive(&skb)) {
ret = __netif_receive_skb(skb);
goto out;
} else if (unlikely(!skb))
goto out;
}
- vlan_on_bond_hook(skb);
-
/* deliver only exact match when indicated */
null_or_dev = deliver_exact ? skb->dev : NULL;
@@ -3800,7 +3786,7 @@ static void net_rx_action(struct softirq_action *h)
* with netpoll's poll_napi(). Only the entity which
* obtains the lock and sees NAPI_STATE_SCHED set will
* actually make the ->poll() call. Therefore we avoid
- * accidently calling ->poll() when NAPI is not scheduled.
+ * accidentally calling ->poll() when NAPI is not scheduled.
*/
work = 0;
if (test_bit(NAPI_STATE_SCHED, &n->state)) {
@@ -4510,6 +4496,30 @@ void dev_set_rx_mode(struct net_device *dev)
}
/**
+ * dev_ethtool_get_settings - call device's ethtool_ops::get_settings()
+ * @dev: device
+ * @cmd: memory area for ethtool_ops::get_settings() result
+ *
+ * The cmd arg is initialized properly (cleared and
+ * ethtool_cmd::cmd field set to ETHTOOL_GSET).
+ *
+ * Return device's ethtool_ops::get_settings() result value or
+ * -EOPNOTSUPP when device doesn't expose
+ * ethtool_ops::get_settings() operation.
+ */
+int dev_ethtool_get_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
+ return -EOPNOTSUPP;
+
+ memset(cmd, 0, sizeof(struct ethtool_cmd));
+ cmd->cmd = ETHTOOL_GSET;
+ return dev->ethtool_ops->get_settings(dev, cmd);
+}
+EXPORT_SYMBOL(dev_ethtool_get_settings);
+
+/**
* dev_get_flags - get flags reported to userspace
* @dev: device
*
@@ -5203,11 +5213,15 @@ u32 netdev_fix_features(struct net_device *dev, u32 features)
}
/* TSO requires that SG is present as well. */
- if ((features & NETIF_F_TSO) && !(features & NETIF_F_SG)) {
- netdev_info(dev, "Dropping NETIF_F_TSO since no SG feature.\n");
- features &= ~NETIF_F_TSO;
+ if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG)) {
+ netdev_info(dev, "Dropping TSO features since no SG feature.\n");
+ features &= ~NETIF_F_ALL_TSO;
}
+ /* TSO ECN requires that TSO is present as well. */
+ if ((features & NETIF_F_ALL_TSO) == NETIF_F_TSO_ECN)
+ features &= ~NETIF_F_TSO_ECN;
+
/* Software GSO depends on SG. */
if ((features & NETIF_F_GSO) && !(features & NETIF_F_SG)) {
netdev_info(dev, "Dropping NETIF_F_GSO since no SG feature.\n");
@@ -5236,11 +5250,13 @@ u32 netdev_fix_features(struct net_device *dev, u32 features)
}
EXPORT_SYMBOL(netdev_fix_features);
-void netdev_update_features(struct net_device *dev)
+int __netdev_update_features(struct net_device *dev)
{
u32 features;
int err = 0;
+ ASSERT_RTNL();
+
features = netdev_get_wanted_features(dev);
if (dev->netdev_ops->ndo_fix_features)
@@ -5250,7 +5266,7 @@ void netdev_update_features(struct net_device *dev)
features = netdev_fix_features(dev, features);
if (dev->features == features)
- return;
+ return 0;
netdev_info(dev, "Features changed: 0x%08x -> 0x%08x\n",
dev->features, features);
@@ -5258,12 +5274,23 @@ void netdev_update_features(struct net_device *dev)
if (dev->netdev_ops->ndo_set_features)
err = dev->netdev_ops->ndo_set_features(dev, features);
- if (!err)
- dev->features = features;
- else if (err < 0)
+ if (unlikely(err < 0)) {
netdev_err(dev,
"set_features() failed (%d); wanted 0x%08x, left 0x%08x\n",
err, features, dev->features);
+ return -1;
+ }
+
+ if (!err)
+ dev->features = features;
+
+ return 1;
+}
+
+void netdev_update_features(struct net_device *dev)
+{
+ if (__netdev_update_features(dev))
+ netdev_features_change(dev);
}
EXPORT_SYMBOL(netdev_update_features);
@@ -5414,6 +5441,14 @@ int register_netdevice(struct net_device *dev)
dev->features &= ~NETIF_F_GSO;
}
+ /* Turn on no cache copy if HW is doing checksum */
+ dev->hw_features |= NETIF_F_NOCACHE_COPY;
+ if ((dev->features & NETIF_F_ALL_CSUM) &&
+ !(dev->features & NETIF_F_NO_CSUM)) {
+ dev->wanted_features |= NETIF_F_NOCACHE_COPY;
+ dev->features |= NETIF_F_NOCACHE_COPY;
+ }
+
/* Enable GRO and NETIF_F_HIGHDMA for vlans by default,
* vlan_dev_init() will do the dev->features check, so these features
* are enabled only if supported by underlying device.
@@ -5430,7 +5465,7 @@ int register_netdevice(struct net_device *dev)
goto err_uninit;
dev->reg_state = NETREG_REGISTERED;
- netdev_update_features(dev);
+ __netdev_update_features(dev);
/*
* Default initial state at registry is that the
@@ -6153,29 +6188,20 @@ static int dev_cpu_callback(struct notifier_block *nfb,
*/
u32 netdev_increment_features(u32 all, u32 one, u32 mask)
{
- /* If device needs checksumming, downgrade to it. */
- if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM))
- all ^= NETIF_F_NO_CSUM | (one & NETIF_F_ALL_CSUM);
- else if (mask & NETIF_F_ALL_CSUM) {
- /* If one device supports v4/v6 checksumming, set for all. */
- if (one & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM) &&
- !(all & NETIF_F_GEN_CSUM)) {
- all &= ~NETIF_F_ALL_CSUM;
- all |= one & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
- }
+ if (mask & NETIF_F_GEN_CSUM)
+ mask |= NETIF_F_ALL_CSUM;
+ mask |= NETIF_F_VLAN_CHALLENGED;
- /* If one device supports hw checksumming, set for all. */
- if (one & NETIF_F_GEN_CSUM && !(all & NETIF_F_GEN_CSUM)) {
- all &= ~NETIF_F_ALL_CSUM;
- all |= NETIF_F_HW_CSUM;
- }
- }
+ all |= one & (NETIF_F_ONE_FOR_ALL|NETIF_F_ALL_CSUM) & mask;
+ all &= one | ~NETIF_F_ALL_FOR_ALL;
- one |= NETIF_F_ALL_CSUM;
+ /* If device needs checksumming, downgrade to it. */
+ if (all & (NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM))
+ all &= ~NETIF_F_NO_CSUM;
- one |= all & NETIF_F_ONE_FOR_ALL;
- all &= one | NETIF_F_LLTX | NETIF_F_GSO | NETIF_F_UFO;
- all |= one & mask & NETIF_F_ONE_FOR_ALL;
+ /* If one device supports hw checksumming, set for all. */
+ if (all & NETIF_F_GEN_CSUM)
+ all &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM);
return all;
}
@@ -6336,7 +6362,7 @@ static void __net_exit default_device_exit(struct net *net)
if (dev->rtnl_link_ops)
continue;
- /* Push remaing network devices to init_net */
+ /* Push remaining network devices to init_net */
snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex);
err = dev_change_net_namespace(dev, &init_net, fb_name);
if (err) {
diff --git a/net/core/dst.c b/net/core/dst.c
index 91104d3..30f0093 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -166,7 +166,8 @@ EXPORT_SYMBOL(dst_discard);
const u32 dst_default_metrics[RTAX_MAX];
-void *dst_alloc(struct dst_ops *ops, int initial_ref)
+void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
+ int initial_ref, int initial_obsolete, int flags)
{
struct dst_entry *dst;
@@ -174,15 +175,36 @@ void *dst_alloc(struct dst_ops *ops, int initial_ref)
if (ops->gc(ops))
return NULL;
}
- dst = kmem_cache_zalloc(ops->kmem_cachep, GFP_ATOMIC);
+ dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC);
if (!dst)
return NULL;
- atomic_set(&dst->__refcnt, initial_ref);
+ dst->child = NULL;
+ dst->dev = dev;
+ if (dev)
+ dev_hold(dev);
dst->ops = ops;
- dst->lastuse = jiffies;
- dst->path = dst;
- dst->input = dst->output = dst_discard;
dst_init_metrics(dst, dst_default_metrics, true);
+ dst->expires = 0UL;
+ dst->path = dst;
+ dst->neighbour = NULL;
+ dst->hh = NULL;
+#ifdef CONFIG_XFRM
+ dst->xfrm = NULL;
+#endif
+ dst->input = dst_discard;
+ dst->output = dst_discard;
+ dst->error = 0;
+ dst->obsolete = initial_obsolete;
+ dst->header_len = 0;
+ dst->trailer_len = 0;
+#ifdef CONFIG_IP_ROUTE_CLASSID
+ dst->tclassid = 0;
+#endif
+ atomic_set(&dst->__refcnt, initial_ref);
+ dst->__use = 0;
+ dst->lastuse = jiffies;
+ dst->flags = flags;
+ dst->next = NULL;
#if RT_CACHE_DEBUG >= 2
atomic_inc(&dst_total);
#endif
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 74ead9e..d8b1a8d 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -21,6 +21,8 @@
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
+#include <linux/rtnetlink.h>
+#include <linux/sched.h>
/*
* Some useful ethtool_ops methods that're device independent.
@@ -317,7 +319,7 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
dev->wanted_features &= ~features[0].valid;
dev->wanted_features |= features[0].valid & features[0].requested;
- netdev_update_features(dev);
+ __netdev_update_features(dev);
if ((dev->wanted_features ^ dev->features) & features[0].valid)
ret |= ETHTOOL_F_WISH;
@@ -359,7 +361,7 @@ static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GS
/* NETIF_F_NTUPLE */ "rx-ntuple-filter",
/* NETIF_F_RXHASH */ "rx-hashing",
/* NETIF_F_RXCSUM */ "rx-checksum",
- "",
+ /* NETIF_F_NOCACHE_COPY */ "tx-nocache-copy"
"",
};
@@ -499,7 +501,7 @@ static int ethtool_set_one_feature(struct net_device *dev,
else
dev->wanted_features &= ~mask;
- netdev_update_features(dev);
+ __netdev_update_features(dev);
return 0;
}
@@ -544,14 +546,14 @@ int __ethtool_set_flags(struct net_device *dev, u32 data)
}
/* allow changing only bits set in hw_features */
- changed = (data ^ dev->wanted_features) & flags_dup_features;
+ changed = (data ^ dev->features) & flags_dup_features;
if (changed & ~dev->hw_features)
return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP;
dev->wanted_features =
- (dev->wanted_features & ~changed) | data;
+ (dev->wanted_features & ~changed) | (data & dev->hw_features);
- netdev_update_features(dev);
+ __netdev_update_features(dev);
return 0;
}
@@ -908,6 +910,9 @@ static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev,
struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL;
int ret;
+ if (!ops->set_rx_ntuple)
+ return -EOPNOTSUPP;
+
if (!(dev->features & NETIF_F_NTUPLE))
return -EINVAL;
@@ -1441,6 +1446,35 @@ static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
return dev->ethtool_ops->set_ringparam(dev, &ringparam);
}
+static noinline_for_stack int ethtool_get_channels(struct net_device *dev,
+ void __user *useraddr)
+{
+ struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
+
+ if (!dev->ethtool_ops->get_channels)
+ return -EOPNOTSUPP;
+
+ dev->ethtool_ops->get_channels(dev, &channels);
+
+ if (copy_to_user(useraddr, &channels, sizeof(channels)))
+ return -EFAULT;
+ return 0;
+}
+
+static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
+ void __user *useraddr)
+{
+ struct ethtool_channels channels;
+
+ if (!dev->ethtool_ops->set_channels)
+ return -EOPNOTSUPP;
+
+ if (copy_from_user(&channels, useraddr, sizeof(channels)))
+ return -EFAULT;
+
+ return dev->ethtool_ops->set_channels(dev, &channels);
+}
+
static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr)
{
struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };
@@ -1618,14 +1652,64 @@ out:
static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
{
struct ethtool_value id;
+ static bool busy;
+ int rc;
- if (!dev->ethtool_ops->phys_id)
+ if (!dev->ethtool_ops->set_phys_id && !dev->ethtool_ops->phys_id)
return -EOPNOTSUPP;
+ if (busy)
+ return -EBUSY;
+
if (copy_from_user(&id, useraddr, sizeof(id)))
return -EFAULT;
- return dev->ethtool_ops->phys_id(dev, id.data);
+ if (!dev->ethtool_ops->set_phys_id)
+ /* Do it the old way */
+ return dev->ethtool_ops->phys_id(dev, id.data);
+
+ rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE);
+ if (rc < 0)
+ return rc;
+
+ /* Drop the RTNL lock while waiting, but prevent reentry or
+ * removal of the device.
+ */
+ busy = true;
+ dev_hold(dev);
+ rtnl_unlock();
+
+ if (rc == 0) {
+ /* Driver will handle this itself */
+ schedule_timeout_interruptible(
+ id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT);
+ } else {
+ /* Driver expects to be called at twice the frequency in rc */
+ int n = rc * 2, i, interval = HZ / n;
+
+ /* Count down seconds */
+ do {
+ /* Count down iterations per second */
+ i = n;
+ do {
+ rtnl_lock();
+ rc = dev->ethtool_ops->set_phys_id(dev,
+ (i & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
+ rtnl_unlock();
+ if (rc)
+ break;
+ schedule_timeout_interruptible(interval);
+ } while (!signal_pending(current) && --i != 0);
+ } while (!signal_pending(current) &&
+ (id.data == 0 || --id.data != 0));
+ }
+
+ rtnl_lock();
+ dev_put(dev);
+ busy = false;
+
+ (void)dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE);
+ return rc;
}
static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
@@ -1953,6 +2037,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_SGRO:
rc = ethtool_set_one_feature(dev, useraddr, ethcmd);
break;
+ case ETHTOOL_GCHANNELS:
+ rc = ethtool_get_channels(dev, useraddr);
+ break;
+ case ETHTOOL_SCHANNELS:
+ rc = ethtool_set_channels(dev, useraddr);
+ break;
default:
rc = -EOPNOTSUPP;
}
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 8248ebb..3911586 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -590,7 +590,8 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb,
int idx = 0;
struct fib_rule *rule;
- list_for_each_entry(rule, &ops->rules_list, list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(rule, &ops->rules_list, list) {
if (idx < cb->args[1])
goto skip;
diff --git a/net/core/filter.c b/net/core/filter.c
index 232b187..0eb8c44 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -39,65 +39,6 @@
#include <linux/filter.h>
#include <linux/reciprocal_div.h>
-enum {
- BPF_S_RET_K = 1,
- BPF_S_RET_A,
- BPF_S_ALU_ADD_K,
- BPF_S_ALU_ADD_X,
- BPF_S_ALU_SUB_K,
- BPF_S_ALU_SUB_X,
- BPF_S_ALU_MUL_K,
- BPF_S_ALU_MUL_X,
- BPF_S_ALU_DIV_X,
- BPF_S_ALU_AND_K,
- BPF_S_ALU_AND_X,
- BPF_S_ALU_OR_K,
- BPF_S_ALU_OR_X,
- BPF_S_ALU_LSH_K,
- BPF_S_ALU_LSH_X,
- BPF_S_ALU_RSH_K,
- BPF_S_ALU_RSH_X,
- BPF_S_ALU_NEG,
- BPF_S_LD_W_ABS,
- BPF_S_LD_H_ABS,
- BPF_S_LD_B_ABS,
- BPF_S_LD_W_LEN,
- BPF_S_LD_W_IND,
- BPF_S_LD_H_IND,
- BPF_S_LD_B_IND,
- BPF_S_LD_IMM,
- BPF_S_LDX_W_LEN,
- BPF_S_LDX_B_MSH,
- BPF_S_LDX_IMM,
- BPF_S_MISC_TAX,
- BPF_S_MISC_TXA,
- BPF_S_ALU_DIV_K,
- BPF_S_LD_MEM,
- BPF_S_LDX_MEM,
- BPF_S_ST,
- BPF_S_STX,
- BPF_S_JMP_JA,
- BPF_S_JMP_JEQ_K,
- BPF_S_JMP_JEQ_X,
- BPF_S_JMP_JGE_K,
- BPF_S_JMP_JGE_X,
- BPF_S_JMP_JGT_K,
- BPF_S_JMP_JGT_X,
- BPF_S_JMP_JSET_K,
- BPF_S_JMP_JSET_X,
- /* Ancillary data */
- BPF_S_ANC_PROTOCOL,
- BPF_S_ANC_PKTTYPE,
- BPF_S_ANC_IFINDEX,
- BPF_S_ANC_NLATTR,
- BPF_S_ANC_NLATTR_NEST,
- BPF_S_ANC_MARK,
- BPF_S_ANC_QUEUE,
- BPF_S_ANC_HATYPE,
- BPF_S_ANC_RXHASH,
- BPF_S_ANC_CPU,
-};
-
/* No hurry in this branch */
static void *__load_pointer(const struct sk_buff *skb, int k, unsigned int size)
{
@@ -145,7 +86,7 @@ int sk_filter(struct sock *sk, struct sk_buff *skb)
rcu_read_lock();
filter = rcu_dereference(sk->sk_filter);
if (filter) {
- unsigned int pkt_len = sk_run_filter(skb, filter->insns);
+ unsigned int pkt_len = SK_RUN_FILTER(filter, skb);
err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;
}
@@ -425,7 +366,7 @@ EXPORT_SYMBOL(sk_run_filter);
* As we dont want to clear mem[] array for each packet going through
* sk_run_filter(), we check that filter loaded by user never try to read
* a cell if not previously written, and we check all branches to be sure
- * a malicious user doesnt try to abuse us.
+ * a malicious user doesn't try to abuse us.
*/
static int check_load_and_stores(struct sock_filter *filter, int flen)
{
@@ -638,6 +579,7 @@ void sk_filter_release_rcu(struct rcu_head *rcu)
{
struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
+ bpf_jit_free(fp);
kfree(fp);
}
EXPORT_SYMBOL(sk_filter_release_rcu);
@@ -672,6 +614,7 @@ 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);
if (err) {
@@ -679,6 +622,8 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
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/link_watch.c b/net/core/link_watch.c
index 01a1101..a7b3421 100644
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -129,7 +129,7 @@ static void linkwatch_schedule_work(int urgent)
if (!cancel_delayed_work(&linkwatch_work))
return;
- /* Otherwise we reschedule it again for immediate exection. */
+ /* Otherwise we reschedule it again for immediate execution. */
schedule_delayed_work(&linkwatch_work, 0);
}
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 5ceb257..381813e 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -28,6 +28,7 @@
static const char fmt_hex[] = "%#x\n";
static const char fmt_long_hex[] = "%#lx\n";
static const char fmt_dec[] = "%d\n";
+static const char fmt_udec[] = "%u\n";
static const char fmt_ulong[] = "%lu\n";
static const char fmt_u64[] = "%llu\n";
@@ -145,13 +146,10 @@ static ssize_t show_speed(struct device *dev,
if (!rtnl_trylock())
return restart_syscall();
- if (netif_running(netdev) &&
- netdev->ethtool_ops &&
- netdev->ethtool_ops->get_settings) {
- struct ethtool_cmd cmd = { ETHTOOL_GSET };
-
- if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
- ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd));
+ if (netif_running(netdev)) {
+ struct ethtool_cmd cmd;
+ if (!dev_ethtool_get_settings(netdev, &cmd))
+ ret = sprintf(buf, fmt_udec, ethtool_cmd_speed(&cmd));
}
rtnl_unlock();
return ret;
@@ -166,13 +164,11 @@ static ssize_t show_duplex(struct device *dev,
if (!rtnl_trylock())
return restart_syscall();
- if (netif_running(netdev) &&
- netdev->ethtool_ops &&
- netdev->ethtool_ops->get_settings) {
- struct ethtool_cmd cmd = { ETHTOOL_GSET };
-
- if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
- ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half");
+ if (netif_running(netdev)) {
+ struct ethtool_cmd cmd;
+ if (!dev_ethtool_get_settings(netdev, &cmd))
+ ret = sprintf(buf, "%s\n",
+ cmd.duplex ? "full" : "half");
}
rtnl_unlock();
return ret;
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 3f86026..1abb5084 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -216,11 +216,14 @@ static void net_free(struct net *net)
kmem_cache_free(net_cachep, net);
}
-static struct net *net_create(void)
+struct net *copy_net_ns(unsigned long flags, struct net *old_net)
{
struct net *net;
int rv;
+ if (!(flags & CLONE_NEWNET))
+ return get_net(old_net);
+
net = net_alloc();
if (!net)
return ERR_PTR(-ENOMEM);
@@ -239,13 +242,6 @@ static struct net *net_create(void)
return net;
}
-struct net *copy_net_ns(unsigned long flags, struct net *old_net)
-{
- if (!(flags & CLONE_NEWNET))
- return get_net(old_net);
- return net_create();
-}
-
static DEFINE_SPINLOCK(cleanup_list_lock);
static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 06be243..46d9c3a 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -539,7 +539,7 @@ int __netpoll_rx(struct sk_buff *skb)
{
int proto, len, ulen;
int hits = 0;
- struct iphdr *iph;
+ const struct iphdr *iph;
struct udphdr *uh;
struct netpoll_info *npinfo = skb->dev->npinfo;
struct netpoll *np, *tmp;
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index aeeece7..ff79d94 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2514,7 +2514,6 @@ static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
{
struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
int err = 0;
- struct iphdr *iph;
if (!x)
return 0;
@@ -2524,7 +2523,6 @@ static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
return 0;
spin_lock(&x->lock);
- iph = ip_hdr(skb);
err = x->outer_mode->output(x, skb);
if (err)
@@ -2624,6 +2622,7 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
} else {
int frags = pkt_dev->nfrags;
int i, len;
+ int frag_len;
if (frags > MAX_SKB_FRAGS)
@@ -2635,6 +2634,8 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
}
i = 0;
+ frag_len = (datalen/frags) < PAGE_SIZE ?
+ (datalen/frags) : PAGE_SIZE;
while (datalen > 0) {
if (unlikely(!pkt_dev->page)) {
int node = numa_node_id();
@@ -2648,38 +2649,18 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
skb_shinfo(skb)->frags[i].page = pkt_dev->page;
get_page(pkt_dev->page);
skb_shinfo(skb)->frags[i].page_offset = 0;
- skb_shinfo(skb)->frags[i].size =
- (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+ /*last fragment, fill rest of data*/
+ if (i == (frags - 1))
+ skb_shinfo(skb)->frags[i].size =
+ (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+ else
+ skb_shinfo(skb)->frags[i].size = frag_len;
datalen -= skb_shinfo(skb)->frags[i].size;
skb->len += skb_shinfo(skb)->frags[i].size;
skb->data_len += skb_shinfo(skb)->frags[i].size;
i++;
skb_shinfo(skb)->nr_frags = i;
}
-
- while (i < frags) {
- int rem;
-
- if (i == 0)
- break;
-
- rem = skb_shinfo(skb)->frags[i - 1].size / 2;
- if (rem == 0)
- break;
-
- skb_shinfo(skb)->frags[i - 1].size -= rem;
-
- skb_shinfo(skb)->frags[i] =
- skb_shinfo(skb)->frags[i - 1];
- get_page(skb_shinfo(skb)->frags[i].page);
- skb_shinfo(skb)->frags[i].page =
- skb_shinfo(skb)->frags[i - 1].page;
- skb_shinfo(skb)->frags[i].page_offset +=
- skb_shinfo(skb)->frags[i - 1].size;
- skb_shinfo(skb)->frags[i].size = rem;
- i++;
- skb_shinfo(skb)->nr_frags = i;
- }
}
/* Stamp the time, and sequence number,
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 49f7ea5..29633125 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -196,7 +196,7 @@ EXPORT_SYMBOL_GPL(__rtnl_register);
* as failure of this function is very unlikely, it can only happen due
* to lack of memory when allocating the chain to store all message
* handlers for a protocol. Meant for use in init functions where lack
- * of memory implies no sense in continueing.
+ * of memory implies no sense in continuing.
*/
void rtnl_register(int protocol, int msgtype,
rtnl_doit_func doit, rtnl_dumpit_func dumpit)
@@ -1007,10 +1007,11 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
s_h = cb->args[0];
s_idx = cb->args[1];
+ rcu_read_lock();
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
idx = 0;
head = &net->dev_index_head[h];
- hlist_for_each_entry(dev, node, head, index_hlist) {
+ hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
if (idx < s_idx)
goto cont;
if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
@@ -1023,6 +1024,7 @@ cont:
}
}
out:
+ rcu_read_unlock();
cb->args[1] = idx;
cb->args[0] = h;
@@ -1440,7 +1442,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
errout:
if (err < 0 && modified && net_ratelimit())
printk(KERN_WARNING "A link change request failed with "
- "some changes comitted already. Interface %s may "
+ "some changes committed already. Interface %s may "
"have been left with an inconsistent configuration, "
"please check.\n", dev->name);
@@ -1879,7 +1881,6 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
int min_len;
int family;
int type;
- int err;
type = nlh->nlmsg_type;
if (type > RTM_MAX)
@@ -1906,11 +1907,8 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (dumpit == NULL)
return -EOPNOTSUPP;
- __rtnl_unlock();
rtnl = net->rtnl;
- err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
- rtnl_lock();
- return err;
+ return netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
}
memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *)));
@@ -1980,7 +1978,7 @@ static int __net_init rtnetlink_net_init(struct net *net)
{
struct sock *sk;
sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX,
- rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
+ rtnetlink_rcv, NULL, THIS_MODULE);
if (!sk)
return -ENOMEM;
net->rtnl = sk;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 801dd08..7ebeed0 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2267,7 +2267,7 @@ EXPORT_SYMBOL(skb_prepare_seq_read);
* of bytes already consumed and the next call to
* skb_seq_read() will return the remaining part of the block.
*
- * Note 1: The size of each block of data returned can be arbitary,
+ * Note 1: The size of each block of data returned can be arbitrary,
* this limitation is the cost for zerocopy seqeuental
* reads of potentially non linear data.
*
diff --git a/net/core/sock.c b/net/core/sock.c
index 7dfed79..6e81978 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -215,7 +215,7 @@ __u32 sysctl_rmem_max __read_mostly = SK_RMEM_MAX;
__u32 sysctl_wmem_default __read_mostly = SK_WMEM_MAX;
__u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX;
-/* Maximal space eaten by iovec or ancilliary data plus some space */
+/* Maximal space eaten by iovec or ancillary data plus some space */
int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512);
EXPORT_SYMBOL(sysctl_optmem_max);
@@ -1175,7 +1175,7 @@ static void __sk_free(struct sock *sk)
void sk_free(struct sock *sk)
{
/*
- * We substract one from sk_wmem_alloc and can know if
+ * We subtract one from sk_wmem_alloc and can know if
* some packets are still in some tx queue.
* If not null, sock_wfree() will call __sk_free(sk) later
*/
@@ -1185,10 +1185,10 @@ void sk_free(struct sock *sk)
EXPORT_SYMBOL(sk_free);
/*
- * Last sock_put should drop referrence to sk->sk_net. It has already
- * been dropped in sk_change_net. Taking referrence to stopping namespace
+ * Last sock_put should drop reference to sk->sk_net. It has already
+ * been dropped in sk_change_net. Taking reference to stopping namespace
* is not an option.
- * Take referrence to a socket to remove it from hash _alive_ and after that
+ * Take reference to a socket to remove it from hash _alive_ and after that
* destroy it in the context of init_net.
*/
void sk_release_kernel(struct sock *sk)
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 385b609..a829e3f 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -122,6 +122,15 @@ static struct ctl_table net_core_table[] = {
.mode = 0644,
.proc_handler = proc_dointvec
},
+#ifdef CONFIG_BPF_JIT
+ {
+ .procname = "bpf_jit_enable",
+ .data = &bpf_jit_enable,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+#endif
{
.procname = "netdev_tstamp_prequeue",
.data = &netdev_tstamp_prequeue,
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index ae451c6..36700a46 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -40,13 +40,15 @@
int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
+ const struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
struct inet_sock *inet = inet_sk(sk);
struct dccp_sock *dp = dccp_sk(sk);
- const struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
__be16 orig_sport, orig_dport;
- struct rtable *rt;
__be32 daddr, nexthop;
+ struct flowi4 fl4;
+ struct rtable *rt;
int err;
+ struct ip_options_rcu *inet_opt;
dp->dccps_role = DCCP_ROLE_CLIENT;
@@ -57,15 +59,18 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
return -EAFNOSUPPORT;
nexthop = daddr = usin->sin_addr.s_addr;
- if (inet->opt != NULL && inet->opt->srr) {
+
+ inet_opt = rcu_dereference_protected(inet->inet_opt,
+ sock_owned_by_user(sk));
+ if (inet_opt != NULL && inet_opt->opt.srr) {
if (daddr == 0)
return -EINVAL;
- nexthop = inet->opt->faddr;
+ nexthop = inet_opt->opt.faddr;
}
orig_sport = inet->inet_sport;
orig_dport = usin->sin_port;
- rt = ip_route_connect(nexthop, inet->inet_saddr,
+ rt = ip_route_connect(&fl4, nexthop, inet->inet_saddr,
RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
IPPROTO_DCCP,
orig_sport, orig_dport, sk, true);
@@ -77,19 +82,19 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
return -ENETUNREACH;
}
- if (inet->opt == NULL || !inet->opt->srr)
- daddr = rt->rt_dst;
+ if (inet_opt == NULL || !inet_opt->opt.srr)
+ daddr = fl4.daddr;
if (inet->inet_saddr == 0)
- inet->inet_saddr = rt->rt_src;
+ inet->inet_saddr = fl4.saddr;
inet->inet_rcv_saddr = inet->inet_saddr;
inet->inet_dport = usin->sin_port;
inet->inet_daddr = daddr;
inet_csk(sk)->icsk_ext_hdr_len = 0;
- if (inet->opt != NULL)
- inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen;
+ if (inet_opt)
+ inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
/*
* Socket identity is still unknown (sport may be zero).
* However we set state to DCCP_REQUESTING and not releasing socket
@@ -101,8 +106,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (err != 0)
goto failure;
- rt = ip_route_newports(rt, IPPROTO_DCCP,
- orig_sport, orig_dport,
+ rt = ip_route_newports(&fl4, rt, orig_sport, orig_dport,
inet->inet_sport, inet->inet_dport, sk);
if (IS_ERR(rt)) {
rt = NULL;
@@ -405,7 +409,7 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
newinet->inet_daddr = ireq->rmt_addr;
newinet->inet_rcv_saddr = ireq->loc_addr;
newinet->inet_saddr = ireq->loc_addr;
- newinet->opt = ireq->opt;
+ newinet->inet_opt = ireq->opt;
ireq->opt = NULL;
newinet->mc_index = inet_iif(skb);
newinet->mc_ttl = ip_hdr(skb)->ttl;
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index de1b7e3..8dc4348 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -54,8 +54,8 @@ static void dccp_v6_hash(struct sock *sk)
/* add pseudo-header to DCCP checksum stored in skb->csum */
static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
- struct in6_addr *saddr,
- struct in6_addr *daddr)
+ const struct in6_addr *saddr,
+ const struct in6_addr *daddr)
{
return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
}
@@ -87,7 +87,7 @@ static inline __u32 dccp_v6_init_sequence(struct sk_buff *skb)
static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
u8 type, u8 code, int offset, __be32 info)
{
- struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data;
+ const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
struct dccp_sock *dp;
struct ipv6_pinfo *np;
@@ -296,7 +296,7 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req)
static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
{
- struct ipv6hdr *rxip6h;
+ const struct ipv6hdr *rxip6h;
struct sk_buff *skb;
struct flowi6 fl6;
struct net *net = dev_net(skb_dst(rxskb)->dev);
@@ -573,7 +573,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
First: no IPv4 options.
*/
- newinet->opt = NULL;
+ newinet->inet_opt = NULL;
/* Clone RX bits */
newnp->rxopt.all = np->rxopt.all;
diff --git a/net/dccp/output.c b/net/dccp/output.c
index 784d3021..136d41c 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -143,7 +143,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
}
/**
- * dccp_determine_ccmps - Find out about CCID-specfic packet-size limits
+ * dccp_determine_ccmps - Find out about CCID-specific packet-size limits
* We only consider the HC-sender CCID for setting the CCMPS (RFC 4340, 14.),
* since the RX CCID is restricted to feedback packets (Acks), which are small
* in comparison with the data traffic. A value of 0 means "no current CCMPS".
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 0dcaa90..404fa15 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -752,7 +752,8 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
skip_naddr = cb->args[1];
idx = 0;
- for_each_netdev(&init_net, dev) {
+ rcu_read_lock();
+ for_each_netdev_rcu(&init_net, dev) {
if (idx < skip_ndevs)
goto cont;
else if (idx > skip_ndevs) {
@@ -761,11 +762,11 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
skip_naddr = 0;
}
- if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL)
+ if ((dn_db = rcu_dereference(dev->dn_ptr)) == NULL)
goto cont;
- for (ifa = rtnl_dereference(dn_db->ifa_list), dn_idx = 0; ifa;
- ifa = rtnl_dereference(ifa->ifa_next), dn_idx++) {
+ for (ifa = rcu_dereference(dn_db->ifa_list), dn_idx = 0; ifa;
+ ifa = rcu_dereference(ifa->ifa_next), dn_idx++) {
if (dn_idx < skip_naddr)
continue;
@@ -778,6 +779,7 @@ cont:
idx++;
}
done:
+ rcu_read_unlock();
cb->args[0] = idx;
cb->args[1] = dn_idx;
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 9f09d4f..74544bc 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -1125,13 +1125,11 @@ make_route:
if (dev_out->flags & IFF_LOOPBACK)
flags |= RTCF_LOCAL;
- rt = dst_alloc(&dn_dst_ops, 0);
+ rt = dst_alloc(&dn_dst_ops, dev_out, 1, 0, DST_HOST);
if (rt == NULL)
goto e_nobufs;
- atomic_set(&rt->dst.__refcnt, 1);
- rt->dst.flags = DST_HOST;
-
+ memset(&rt->fld, 0, sizeof(rt->fld));
rt->fld.saddr = oldflp->saddr;
rt->fld.daddr = oldflp->daddr;
rt->fld.flowidn_oif = oldflp->flowidn_oif;
@@ -1146,8 +1144,6 @@ make_route:
rt->rt_dst_map = fld.daddr;
rt->rt_src_map = fld.saddr;
- rt->dst.dev = dev_out;
- dev_hold(dev_out);
rt->dst.neighbour = neigh;
neigh = NULL;
@@ -1399,10 +1395,11 @@ static int dn_route_input_slow(struct sk_buff *skb)
}
make_route:
- rt = dst_alloc(&dn_dst_ops, 0);
+ rt = dst_alloc(&dn_dst_ops, out_dev, 0, 0, DST_HOST);
if (rt == NULL)
goto e_nobufs;
+ memset(&rt->fld, 0, sizeof(rt->fld));
rt->rt_saddr = fld.saddr;
rt->rt_daddr = fld.daddr;
rt->rt_gateway = fld.daddr;
@@ -1419,9 +1416,7 @@ make_route:
rt->fld.flowidn_iif = in_dev->ifindex;
rt->fld.flowidn_mark = fld.flowidn_mark;
- rt->dst.flags = DST_HOST;
rt->dst.neighbour = neigh;
- rt->dst.dev = out_dev;
rt->dst.lastuse = jiffies;
rt->dst.output = dn_rt_bug;
switch(res.type) {
@@ -1440,8 +1435,6 @@ make_route:
rt->dst.input = dst_discard;
}
rt->rt_flags = flags;
- if (rt->dst.dev)
- dev_hold(rt->dst.dev);
err = dn_rt_set_next_hop(rt, &res);
if (err)
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index 99d8d3a..bd0a52d 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -123,11 +123,11 @@ static inline void dn_rebuild_zone(struct dn_zone *dz,
struct dn_fib_node **old_ht,
int old_divisor)
{
- int i;
struct dn_fib_node *f, **fp, *next;
+ int i;
for(i = 0; i < old_divisor; i++) {
- for(f = old_ht[i]; f; f = f->fn_next) {
+ for(f = old_ht[i]; f; f = next) {
next = f->fn_next;
for(fp = dn_chain_p(f->fn_key, dz);
*fp && dn_key_leq((*fp)->fn_key, f->fn_key);
diff --git a/net/dsa/mv88e6131.c b/net/dsa/mv88e6131.c
index bb2b41b..3da4188 100644
--- a/net/dsa/mv88e6131.c
+++ b/net/dsa/mv88e6131.c
@@ -14,6 +14,13 @@
#include "dsa_priv.h"
#include "mv88e6xxx.h"
+/*
+ * Switch product IDs
+ */
+#define ID_6085 0x04a0
+#define ID_6095 0x0950
+#define ID_6131 0x1060
+
static char *mv88e6131_probe(struct mii_bus *bus, int sw_addr)
{
int ret;
@@ -21,9 +28,11 @@ static char *mv88e6131_probe(struct mii_bus *bus, int sw_addr)
ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03);
if (ret >= 0) {
ret &= 0xfff0;
- if (ret == 0x0950)
+ if (ret == ID_6085)
+ return "Marvell 88E6085";
+ if (ret == ID_6095)
return "Marvell 88E6095/88E6095F";
- if (ret == 0x1060)
+ if (ret == ID_6131)
return "Marvell 88E6131";
}
@@ -124,7 +133,7 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
* Ignore removed tag data on doubly tagged packets, disable
* flow control messages, force flow control priority to the
* highest, and send all special multicast frames to the CPU
- * port at the higest priority.
+ * port at the highest priority.
*/
REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
@@ -164,6 +173,7 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
{
+ struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
int addr = REG_PORT(p);
u16 val;
@@ -171,10 +181,13 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
* MAC Forcing register: don't force link, speed, duplex
* or flow control state to any particular values on physical
* ports, but force the CPU port and all DSA ports to 1000 Mb/s
- * full duplex.
+ * (100 Mb/s on 6085) full duplex.
*/
if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
- REG_WRITE(addr, 0x01, 0x003e);
+ if (ps->id == ID_6085)
+ REG_WRITE(addr, 0x01, 0x003d); /* 100 Mb/s */
+ else
+ REG_WRITE(addr, 0x01, 0x003e); /* 1000 Mb/s */
else
REG_WRITE(addr, 0x01, 0x0003);
@@ -286,6 +299,8 @@ static int mv88e6131_setup(struct dsa_switch *ds)
mv88e6xxx_ppu_state_init(ds);
mutex_init(&ps->stats_mutex);
+ ps->id = REG_READ(REG_PORT(0), 0x03) & 0xfff0;
+
ret = mv88e6131_switch_reset(ds);
if (ret < 0)
return ret;
diff --git a/net/dsa/mv88e6xxx.h b/net/dsa/mv88e6xxx.h
index eb0e0aa..61156ca2 100644
--- a/net/dsa/mv88e6xxx.h
+++ b/net/dsa/mv88e6xxx.h
@@ -39,6 +39,8 @@ struct mv88e6xxx_priv_state {
* Hold this mutex over snapshot + dump sequences.
*/
struct mutex stats_mutex;
+
+ int id; /* switch product id */
};
struct mv88e6xxx_hw_stat {
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 64ca2a6..0a47b6c 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -288,7 +288,6 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
.get_drvinfo = dsa_slave_get_drvinfo,
.nway_reset = dsa_slave_nway_reset,
.get_link = dsa_slave_get_link,
- .set_sg = ethtool_op_set_sg,
.get_strings = dsa_slave_get_strings,
.get_ethtool_stats = dsa_slave_get_ethtool_stats,
.get_sset_count = dsa_slave_get_sset_count,
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 116d3fd..a1d9f37 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -935,7 +935,6 @@ static void aun_data_available(struct sock *sk, int slen)
struct sk_buff *skb;
unsigned char *data;
struct aunhdr *ah;
- struct iphdr *ip;
size_t len;
while ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL) {
@@ -949,7 +948,6 @@ static void aun_data_available(struct sock *sk, int slen)
data = skb_transport_header(skb) + sizeof(struct udphdr);
ah = (struct aunhdr *)data;
len = skb->len - sizeof(struct udphdr);
- ip = ip_hdr(skb);
switch (ah->code)
{
@@ -962,12 +960,6 @@ static void aun_data_available(struct sock *sk, int slen)
case 4:
aun_tx_ack(ah->handle, ECTYPE_TRANSMIT_NOT_LISTENING);
break;
-#if 0
- /* This isn't quite right yet. */
- case 5:
- aun_send_response(ip->saddr, ah->handle, 6, ah->cb);
- break;
-#endif
default:
printk(KERN_DEBUG "unknown AUN packet (type %d)\n", data[0]);
}
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
index ce2d335..5761185 100644
--- a/net/ieee802154/Makefile
+++ b/net/ieee802154/Makefile
@@ -1,5 +1,3 @@
obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o
ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
af_802154-y := af_ieee802154.o raw.o dgram.o
-
-ccflags-y += -Wall -DDEBUG
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 807d83c..7b91fa8 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -153,7 +153,7 @@ void inet_sock_destruct(struct sock *sk)
WARN_ON(sk->sk_wmem_queued);
WARN_ON(sk->sk_forward_alloc);
- kfree(inet->opt);
+ kfree(rcu_dereference_protected(inet->inet_opt, 1));
dst_release(rcu_dereference_check(sk->sk_dst_cache, 1));
sk_refcnt_debug_dec(sk);
}
@@ -1103,14 +1103,18 @@ static int inet_sk_reselect_saddr(struct sock *sk)
struct inet_sock *inet = inet_sk(sk);
__be32 old_saddr = inet->inet_saddr;
__be32 daddr = inet->inet_daddr;
+ struct flowi4 fl4;
struct rtable *rt;
__be32 new_saddr;
+ struct ip_options_rcu *inet_opt;
- if (inet->opt && inet->opt->srr)
- daddr = inet->opt->faddr;
+ inet_opt = rcu_dereference_protected(inet->inet_opt,
+ sock_owned_by_user(sk));
+ if (inet_opt && inet_opt->opt.srr)
+ daddr = inet_opt->opt.faddr;
/* Query new route. */
- rt = ip_route_connect(daddr, 0, RT_CONN_FLAGS(sk),
+ rt = ip_route_connect(&fl4, daddr, 0, RT_CONN_FLAGS(sk),
sk->sk_bound_dev_if, sk->sk_protocol,
inet->inet_sport, inet->inet_dport, sk, false);
if (IS_ERR(rt))
@@ -1118,7 +1122,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
sk_setup_caps(sk, &rt->dst);
- new_saddr = rt->rt_src;
+ new_saddr = fl4.saddr;
if (new_saddr == old_saddr)
return 0;
@@ -1147,6 +1151,8 @@ int inet_sk_rebuild_header(struct sock *sk)
struct inet_sock *inet = inet_sk(sk);
struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0);
__be32 daddr;
+ struct ip_options_rcu *inet_opt;
+ struct flowi4 fl4;
int err;
/* Route is OK, nothing to do. */
@@ -1154,10 +1160,13 @@ int inet_sk_rebuild_header(struct sock *sk)
return 0;
/* Reroute. */
+ rcu_read_lock();
+ inet_opt = rcu_dereference(inet->inet_opt);
daddr = inet->inet_daddr;
- if (inet->opt && inet->opt->srr)
- daddr = inet->opt->faddr;
- rt = ip_route_output_ports(sock_net(sk), sk, daddr, inet->inet_saddr,
+ if (inet_opt && inet_opt->opt.srr)
+ daddr = inet_opt->opt.faddr;
+ rcu_read_unlock();
+ rt = ip_route_output_ports(sock_net(sk), &fl4, sk, daddr, inet->inet_saddr,
inet->inet_dport, inet->inet_sport,
sk->sk_protocol, RT_CONN_FLAGS(sk),
sk->sk_bound_dev_if);
@@ -1186,7 +1195,7 @@ EXPORT_SYMBOL(inet_sk_rebuild_header);
static int inet_gso_send_check(struct sk_buff *skb)
{
- struct iphdr *iph;
+ const struct iphdr *iph;
const struct net_protocol *ops;
int proto;
int ihl;
@@ -1293,7 +1302,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
const struct net_protocol *ops;
struct sk_buff **pp = NULL;
struct sk_buff *p;
- struct iphdr *iph;
+ const struct iphdr *iph;
unsigned int hlen;
unsigned int off;
unsigned int id;
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 4286fd3..c1f4154 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -73,7 +73,7 @@ static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash,
* into IP header for icv calculation. Options are already checked
* for validity, so paranoia is not required. */
-static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr)
+static int ip_clear_mutable_options(const struct iphdr *iph, __be32 *daddr)
{
unsigned char * optptr = (unsigned char*)(iph+1);
int l = iph->ihl*4 - sizeof(struct iphdr);
@@ -396,7 +396,7 @@ out:
static void ah4_err(struct sk_buff *skb, u32 info)
{
struct net *net = dev_net(skb->dev);
- struct iphdr *iph = (struct iphdr *)skb->data;
+ const struct iphdr *iph = (const struct iphdr *)skb->data;
struct ip_auth_hdr *ah = (struct ip_auth_hdr *)(skb->data+(iph->ihl<<2));
struct xfrm_state *x;
@@ -404,7 +404,8 @@ static void ah4_err(struct sk_buff *skb, u32 info)
icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
return;
- x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET);
+ x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
+ ah->spi, IPPROTO_AH, AF_INET);
if (!x)
return;
printk(KERN_DEBUG "pmtu discovery on SA AH/%08x/%08x\n",
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 094e150..2b3c23c 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -112,7 +112,7 @@ int cipso_v4_rbm_strictvalid = 1;
/* The maximum number of category ranges permitted in the ranged category tag
* (tag #5). You may note that the IETF draft states that the maximum number
* of category ranges is 7, but if the low end of the last category range is
- * zero then it is possibile to fit 8 category ranges because the zero should
+ * zero then it is possible to fit 8 category ranges because the zero should
* be omitted. */
#define CIPSO_V4_TAG_RNG_CAT_MAX 8
@@ -438,7 +438,7 @@ cache_add_failure:
*
* Description:
* Search the DOI definition list for a DOI definition with a DOI value that
- * matches @doi. The caller is responsibile for calling rcu_read_[un]lock().
+ * matches @doi. The caller is responsible for calling rcu_read_[un]lock().
* Returns a pointer to the DOI definition on success and NULL on failure.
*/
static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
@@ -1293,7 +1293,7 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
return ret_val;
/* This will send packets using the "optimized" format when
- * possibile as specified in section 3.4.2.6 of the
+ * possible as specified in section 3.4.2.6 of the
* CIPSO draft. */
if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10)
tag_len = 14;
@@ -1752,7 +1752,7 @@ validate_return:
}
/**
- * cipso_v4_error - Send the correct reponse for a bad packet
+ * cipso_v4_error - Send the correct response for a bad packet
* @skb: the packet
* @error: the error code
* @gateway: CIPSO gateway flag
@@ -1857,6 +1857,11 @@ static int cipso_v4_genopt(unsigned char *buf, u32 buf_len,
return CIPSO_V4_HDR_LEN + ret_val;
}
+static void opt_kfree_rcu(struct rcu_head *head)
+{
+ kfree(container_of(head, struct ip_options_rcu, rcu));
+}
+
/**
* cipso_v4_sock_setattr - Add a CIPSO option to a socket
* @sk: the socket
@@ -1879,7 +1884,7 @@ int cipso_v4_sock_setattr(struct sock *sk,
unsigned char *buf = NULL;
u32 buf_len;
u32 opt_len;
- struct ip_options *opt = NULL;
+ struct ip_options_rcu *old, *opt = NULL;
struct inet_sock *sk_inet;
struct inet_connection_sock *sk_conn;
@@ -1915,22 +1920,25 @@ int cipso_v4_sock_setattr(struct sock *sk,
ret_val = -ENOMEM;
goto socket_setattr_failure;
}
- memcpy(opt->__data, buf, buf_len);
- opt->optlen = opt_len;
- opt->cipso = sizeof(struct iphdr);
+ memcpy(opt->opt.__data, buf, buf_len);
+ opt->opt.optlen = opt_len;
+ opt->opt.cipso = sizeof(struct iphdr);
kfree(buf);
buf = NULL;
sk_inet = inet_sk(sk);
+
+ old = rcu_dereference_protected(sk_inet->inet_opt, sock_owned_by_user(sk));
if (sk_inet->is_icsk) {
sk_conn = inet_csk(sk);
- if (sk_inet->opt)
- sk_conn->icsk_ext_hdr_len -= sk_inet->opt->optlen;
- sk_conn->icsk_ext_hdr_len += opt->optlen;
+ if (old)
+ sk_conn->icsk_ext_hdr_len -= old->opt.optlen;
+ sk_conn->icsk_ext_hdr_len += opt->opt.optlen;
sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
}
- opt = xchg(&sk_inet->opt, opt);
- kfree(opt);
+ rcu_assign_pointer(sk_inet->inet_opt, opt);
+ if (old)
+ call_rcu(&old->rcu, opt_kfree_rcu);
return 0;
@@ -1960,7 +1968,7 @@ int cipso_v4_req_setattr(struct request_sock *req,
unsigned char *buf = NULL;
u32 buf_len;
u32 opt_len;
- struct ip_options *opt = NULL;
+ struct ip_options_rcu *opt = NULL;
struct inet_request_sock *req_inet;
/* We allocate the maximum CIPSO option size here so we are probably
@@ -1988,15 +1996,16 @@ int cipso_v4_req_setattr(struct request_sock *req,
ret_val = -ENOMEM;
goto req_setattr_failure;
}
- memcpy(opt->__data, buf, buf_len);
- opt->optlen = opt_len;
- opt->cipso = sizeof(struct iphdr);
+ memcpy(opt->opt.__data, buf, buf_len);
+ opt->opt.optlen = opt_len;
+ opt->opt.cipso = sizeof(struct iphdr);
kfree(buf);
buf = NULL;
req_inet = inet_rsk(req);
opt = xchg(&req_inet->opt, opt);
- kfree(opt);
+ if (opt)
+ call_rcu(&opt->rcu, opt_kfree_rcu);
return 0;
@@ -2016,34 +2025,34 @@ req_setattr_failure:
* values on failure.
*
*/
-static int cipso_v4_delopt(struct ip_options **opt_ptr)
+static int cipso_v4_delopt(struct ip_options_rcu **opt_ptr)
{
int hdr_delta = 0;
- struct ip_options *opt = *opt_ptr;
+ struct ip_options_rcu *opt = *opt_ptr;
- if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
+ if (opt->opt.srr || opt->opt.rr || opt->opt.ts || opt->opt.router_alert) {
u8 cipso_len;
u8 cipso_off;
unsigned char *cipso_ptr;
int iter;
int optlen_new;
- cipso_off = opt->cipso - sizeof(struct iphdr);
- cipso_ptr = &opt->__data[cipso_off];
+ cipso_off = opt->opt.cipso - sizeof(struct iphdr);
+ cipso_ptr = &opt->opt.__data[cipso_off];
cipso_len = cipso_ptr[1];
- if (opt->srr > opt->cipso)
- opt->srr -= cipso_len;
- if (opt->rr > opt->cipso)
- opt->rr -= cipso_len;
- if (opt->ts > opt->cipso)
- opt->ts -= cipso_len;
- if (opt->router_alert > opt->cipso)
- opt->router_alert -= cipso_len;
- opt->cipso = 0;
+ if (opt->opt.srr > opt->opt.cipso)
+ opt->opt.srr -= cipso_len;
+ if (opt->opt.rr > opt->opt.cipso)
+ opt->opt.rr -= cipso_len;
+ if (opt->opt.ts > opt->opt.cipso)
+ opt->opt.ts -= cipso_len;
+ if (opt->opt.router_alert > opt->opt.cipso)
+ opt->opt.router_alert -= cipso_len;
+ opt->opt.cipso = 0;
memmove(cipso_ptr, cipso_ptr + cipso_len,
- opt->optlen - cipso_off - cipso_len);
+ opt->opt.optlen - cipso_off - cipso_len);
/* determining the new total option length is tricky because of
* the padding necessary, the only thing i can think to do at
@@ -2052,21 +2061,21 @@ static int cipso_v4_delopt(struct ip_options **opt_ptr)
* from there we can determine the new total option length */
iter = 0;
optlen_new = 0;
- while (iter < opt->optlen)
- if (opt->__data[iter] != IPOPT_NOP) {
- iter += opt->__data[iter + 1];
+ while (iter < opt->opt.optlen)
+ if (opt->opt.__data[iter] != IPOPT_NOP) {
+ iter += opt->opt.__data[iter + 1];
optlen_new = iter;
} else
iter++;
- hdr_delta = opt->optlen;
- opt->optlen = (optlen_new + 3) & ~3;
- hdr_delta -= opt->optlen;
+ hdr_delta = opt->opt.optlen;
+ opt->opt.optlen = (optlen_new + 3) & ~3;
+ hdr_delta -= opt->opt.optlen;
} else {
/* only the cipso option was present on the socket so we can
* remove the entire option struct */
*opt_ptr = NULL;
- hdr_delta = opt->optlen;
- kfree(opt);
+ hdr_delta = opt->opt.optlen;
+ call_rcu(&opt->rcu, opt_kfree_rcu);
}
return hdr_delta;
@@ -2083,15 +2092,15 @@ static int cipso_v4_delopt(struct ip_options **opt_ptr)
void cipso_v4_sock_delattr(struct sock *sk)
{
int hdr_delta;
- struct ip_options *opt;
+ struct ip_options_rcu *opt;
struct inet_sock *sk_inet;
sk_inet = inet_sk(sk);
- opt = sk_inet->opt;
- if (opt == NULL || opt->cipso == 0)
+ opt = rcu_dereference_protected(sk_inet->inet_opt, 1);
+ if (opt == NULL || opt->opt.cipso == 0)
return;
- hdr_delta = cipso_v4_delopt(&sk_inet->opt);
+ hdr_delta = cipso_v4_delopt(&sk_inet->inet_opt);
if (sk_inet->is_icsk && hdr_delta > 0) {
struct inet_connection_sock *sk_conn = inet_csk(sk);
sk_conn->icsk_ext_hdr_len -= hdr_delta;
@@ -2109,12 +2118,12 @@ void cipso_v4_sock_delattr(struct sock *sk)
*/
void cipso_v4_req_delattr(struct request_sock *req)
{
- struct ip_options *opt;
+ struct ip_options_rcu *opt;
struct inet_request_sock *req_inet;
req_inet = inet_rsk(req);
opt = req_inet->opt;
- if (opt == NULL || opt->cipso == 0)
+ if (opt == NULL || opt->opt.cipso == 0)
return;
cipso_v4_delopt(&req_inet->opt);
@@ -2184,14 +2193,18 @@ getattr_return:
*/
int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
{
- struct ip_options *opt;
+ struct ip_options_rcu *opt;
+ int res = -ENOMSG;
- opt = inet_sk(sk)->opt;
- if (opt == NULL || opt->cipso == 0)
- return -ENOMSG;
-
- return cipso_v4_getattr(opt->__data + opt->cipso - sizeof(struct iphdr),
- secattr);
+ rcu_read_lock();
+ opt = rcu_dereference(inet_sk(sk)->inet_opt);
+ if (opt && opt->opt.cipso)
+ res = cipso_v4_getattr(opt->opt.__data +
+ opt->opt.cipso -
+ sizeof(struct iphdr),
+ secattr);
+ rcu_read_unlock();
+ return res;
}
/**
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
index 85bd24c..d5a2e69 100644
--- a/net/ipv4/datagram.c
+++ b/net/ipv4/datagram.c
@@ -24,6 +24,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
struct inet_sock *inet = inet_sk(sk);
struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
+ struct flowi4 fl4;
struct rtable *rt;
__be32 saddr;
int oif;
@@ -46,7 +47,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (!saddr)
saddr = inet->mc_addr;
}
- rt = ip_route_connect(usin->sin_addr.s_addr, saddr,
+ rt = ip_route_connect(&fl4, usin->sin_addr.s_addr, saddr,
RT_CONN_FLAGS(sk), oif,
sk->sk_protocol,
inet->inet_sport, usin->sin_port, sk, true);
@@ -62,13 +63,13 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
return -EACCES;
}
if (!inet->inet_saddr)
- inet->inet_saddr = rt->rt_src; /* Update source address */
+ inet->inet_saddr = fl4.saddr; /* Update source address */
if (!inet->inet_rcv_saddr) {
- inet->inet_rcv_saddr = rt->rt_src;
+ inet->inet_rcv_saddr = fl4.saddr;
if (sk->sk_prot->rehash)
sk->sk_prot->rehash(sk);
}
- inet->inet_daddr = rt->rt_dst;
+ inet->inet_daddr = fl4.daddr;
inet->inet_dport = usin->sin_port;
sk->sk_state = TCP_ESTABLISHED;
inet->inet_id = jiffies;
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 03f994b..a5b4134 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -276,7 +276,7 @@ error:
static int esp_input_done2(struct sk_buff *skb, int err)
{
- struct iphdr *iph;
+ const struct iphdr *iph;
struct xfrm_state *x = xfrm_input_state(skb);
struct esp_data *esp = x->data;
struct crypto_aead *aead = esp->aead;
@@ -484,7 +484,7 @@ static u32 esp4_get_mtu(struct xfrm_state *x, int mtu)
static void esp4_err(struct sk_buff *skb, u32 info)
{
struct net *net = dev_net(skb->dev);
- struct iphdr *iph = (struct iphdr *)skb->data;
+ const struct iphdr *iph = (const struct iphdr *)skb->data;
struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2));
struct xfrm_state *x;
@@ -492,7 +492,8 @@ static void esp4_err(struct sk_buff *skb, u32 info)
icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
return;
- x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET);
+ x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
+ esph->spi, IPPROTO_ESP, AF_INET);
if (!x)
return;
NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n",
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 4510883..2252471 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -44,6 +44,7 @@
#include <net/arp.h>
#include <net/ip_fib.h>
#include <net/rtnetlink.h>
+#include <net/xfrm.h>
#ifndef CONFIG_IP_MULTIPLE_TABLES
@@ -188,9 +189,9 @@ EXPORT_SYMBOL(inet_dev_addr_type);
* - check, that packet arrived from expected physical interface.
* called with rcu_read_lock()
*/
-int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
- struct net_device *dev, __be32 *spec_dst,
- u32 *itag, u32 mark)
+int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos,
+ int oif, struct net_device *dev, __be32 *spec_dst,
+ u32 *itag)
{
struct in_device *in_dev;
struct flowi4 fl4;
@@ -202,7 +203,6 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
fl4.flowi4_oif = 0;
fl4.flowi4_iif = oif;
- fl4.flowi4_mark = mark;
fl4.daddr = src;
fl4.saddr = dst;
fl4.flowi4_tos = tos;
@@ -212,10 +212,12 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
in_dev = __in_dev_get_rcu(dev);
if (in_dev) {
no_addr = in_dev->ifa_list == NULL;
- rpf = IN_DEV_RPFILTER(in_dev);
+
+ /* Ignore rp_filter for packets protected by IPsec. */
+ rpf = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(in_dev);
+
accept_local = IN_DEV_ACCEPT_LOCAL(in_dev);
- if (mark && !IN_DEV_SRC_VMARK(in_dev))
- fl4.flowi4_mark = 0;
+ fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0;
}
if (in_dev == NULL)
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index b92c86f..9ac481a 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -12,7 +12,7 @@
*
* Hans Liss <hans.liss@its.uu.se> Uppsala Universitet
*
- * This work is based on the LPC-trie which is originally descibed in:
+ * This work is based on the LPC-trie which is originally described in:
*
* An experimental study of compression methods for dynamic tries
* Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
@@ -126,7 +126,7 @@ struct tnode {
struct work_struct work;
struct tnode *tnode_free;
};
- struct rt_trie_node *child[0];
+ struct rt_trie_node __rcu *child[0];
};
#ifdef CONFIG_IP_FIB_TRIE_STATS
@@ -151,7 +151,7 @@ struct trie_stat {
};
struct trie {
- struct rt_trie_node *trie;
+ struct rt_trie_node __rcu *trie;
#ifdef CONFIG_IP_FIB_TRIE_STATS
struct trie_use_stats stats;
#endif
@@ -177,16 +177,29 @@ static const int sync_pages = 128;
static struct kmem_cache *fn_alias_kmem __read_mostly;
static struct kmem_cache *trie_leaf_kmem __read_mostly;
-static inline struct tnode *node_parent(struct rt_trie_node *node)
+/*
+ * caller must hold RTNL
+ */
+static inline struct tnode *node_parent(const struct rt_trie_node *node)
{
- return (struct tnode *)(node->parent & ~NODE_TYPE_MASK);
+ unsigned long parent;
+
+ parent = rcu_dereference_index_check(node->parent, lockdep_rtnl_is_held());
+
+ return (struct tnode *)(parent & ~NODE_TYPE_MASK);
}
-static inline struct tnode *node_parent_rcu(struct rt_trie_node *node)
+/*
+ * caller must hold RCU read lock or RTNL
+ */
+static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node)
{
- struct tnode *ret = node_parent(node);
+ unsigned long parent;
+
+ parent = rcu_dereference_index_check(node->parent, rcu_read_lock_held() ||
+ lockdep_rtnl_is_held());
- return rcu_dereference_rtnl(ret);
+ return (struct tnode *)(parent & ~NODE_TYPE_MASK);
}
/* Same as rcu_assign_pointer
@@ -198,18 +211,24 @@ static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr)
node->parent = (unsigned long)ptr | NODE_TYPE(node);
}
-static inline struct rt_trie_node *tnode_get_child(struct tnode *tn, unsigned int i)
+/*
+ * caller must hold RTNL
+ */
+static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i)
{
BUG_ON(i >= 1U << tn->bits);
- return tn->child[i];
+ return rtnl_dereference(tn->child[i]);
}
-static inline struct rt_trie_node *tnode_get_child_rcu(struct tnode *tn, unsigned int i)
+/*
+ * caller must hold RCU read lock or RTNL
+ */
+static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
{
- struct rt_trie_node *ret = tnode_get_child(tn, i);
+ BUG_ON(i >= 1U << tn->bits);
- return rcu_dereference_rtnl(ret);
+ return rcu_dereference_rtnl(tn->child[i]);
}
static inline int tnode_child_length(const struct tnode *tn)
@@ -487,7 +506,7 @@ static inline void put_child(struct trie *t, struct tnode *tn, int i,
static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n,
int wasfull)
{
- struct rt_trie_node *chi = tn->child[i];
+ struct rt_trie_node *chi = rtnl_dereference(tn->child[i]);
int isfull;
BUG_ON(i >= 1<<tn->bits);
@@ -665,7 +684,7 @@ one_child:
for (i = 0; i < tnode_child_length(tn); i++) {
struct rt_trie_node *n;
- n = tn->child[i];
+ n = rtnl_dereference(tn->child[i]);
if (!n)
continue;
@@ -679,6 +698,20 @@ one_child:
return (struct rt_trie_node *) tn;
}
+
+static void tnode_clean_free(struct tnode *tn)
+{
+ int i;
+ struct tnode *tofree;
+
+ for (i = 0; i < tnode_child_length(tn); i++) {
+ tofree = (struct tnode *)rtnl_dereference(tn->child[i]);
+ if (tofree)
+ tnode_free(tofree);
+ }
+ tnode_free(tn);
+}
+
static struct tnode *inflate(struct trie *t, struct tnode *tn)
{
struct tnode *oldtnode = tn;
@@ -755,8 +788,8 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
inode = (struct tnode *) node;
if (inode->bits == 1) {
- put_child(t, tn, 2*i, inode->child[0]);
- put_child(t, tn, 2*i+1, inode->child[1]);
+ put_child(t, tn, 2*i, rtnl_dereference(inode->child[0]));
+ put_child(t, tn, 2*i+1, rtnl_dereference(inode->child[1]));
tnode_free_safe(inode);
continue;
@@ -797,8 +830,8 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
size = tnode_child_length(left);
for (j = 0; j < size; j++) {
- put_child(t, left, j, inode->child[j]);
- put_child(t, right, j, inode->child[j + size]);
+ put_child(t, left, j, rtnl_dereference(inode->child[j]));
+ put_child(t, right, j, rtnl_dereference(inode->child[j + size]));
}
put_child(t, tn, 2*i, resize(t, left));
put_child(t, tn, 2*i+1, resize(t, right));
@@ -808,18 +841,8 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
tnode_free_safe(oldtnode);
return tn;
nomem:
- {
- int size = tnode_child_length(tn);
- int j;
-
- for (j = 0; j < size; j++)
- if (tn->child[j])
- tnode_free((struct tnode *)tn->child[j]);
-
- tnode_free(tn);
-
- return ERR_PTR(-ENOMEM);
- }
+ tnode_clean_free(tn);
+ return ERR_PTR(-ENOMEM);
}
static struct tnode *halve(struct trie *t, struct tnode *tn)
@@ -890,18 +913,8 @@ static struct tnode *halve(struct trie *t, struct tnode *tn)
tnode_free_safe(oldtnode);
return tn;
nomem:
- {
- int size = tnode_child_length(tn);
- int j;
-
- for (j = 0; j < size; j++)
- if (tn->child[j])
- tnode_free((struct tnode *)tn->child[j]);
-
- tnode_free(tn);
-
- return ERR_PTR(-ENOMEM);
- }
+ tnode_clean_free(tn);
+ return ERR_PTR(-ENOMEM);
}
/* readside must use rcu_read_lock currently dump routines
@@ -1033,7 +1046,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
t_key cindex;
pos = 0;
- n = t->trie;
+ n = rtnl_dereference(t->trie);
/* If we point to NULL, stop. Either the tree is empty and we should
* just put a new leaf in if, or we have reached an empty child slot,
@@ -1319,6 +1332,9 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
}
}
+ if (!plen)
+ tb->tb_num_default++;
+
list_add_tail_rcu(&new_fa->fa_list,
(fa ? &fa->fa_list : fa_head));
@@ -1684,6 +1700,9 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
list_del_rcu(&fa->fa_list);
+ if (!plen)
+ tb->tb_num_default--;
+
if (list_empty(fa_head)) {
hlist_del_rcu(&li->hlist);
free_leaf_info(li);
@@ -1756,7 +1775,7 @@ static struct leaf *leaf_walk_rcu(struct tnode *p, struct rt_trie_node *c)
continue;
if (IS_LEAF(c)) {
- prefetch(p->child[idx]);
+ prefetch(rcu_dereference_rtnl(p->child[idx]));
return (struct leaf *) c;
}
@@ -1974,6 +1993,7 @@ struct fib_table *fib_trie_table(u32 id)
tb->tb_id = id;
tb->tb_default = -1;
+ tb->tb_num_default = 0;
t = (struct trie *) tb->tb_data;
memset(t, 0, sizeof(*t));
@@ -2272,7 +2292,7 @@ static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
/* walk rest of this hash chain */
h = tb->tb_id & (FIB_TABLE_HASHSZ - 1);
- while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) {
+ while ((tb_node = rcu_dereference(hlist_next_rcu(&tb->tb_hlist)))) {
tb = hlist_entry(tb_node, struct fib_table, tb_hlist);
n = fib_trie_get_first(iter, (struct trie *) tb->tb_data);
if (n)
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index a91dc16..cfeca3c 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -108,8 +108,7 @@ struct icmp_bxm {
__be32 times[3];
} data;
int head_len;
- struct ip_options replyopts;
- unsigned char optbuf[40];
+ struct ip_options_data replyopts;
};
/* An array of errno for error messages from dest unreach. */
@@ -333,7 +332,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
struct inet_sock *inet;
__be32 daddr;
- if (ip_options_echo(&icmp_param->replyopts, skb))
+ if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb))
return;
sk = icmp_xmit_lock(net);
@@ -347,10 +346,10 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
daddr = ipc.addr = rt->rt_src;
ipc.opt = NULL;
ipc.tx_flags = 0;
- if (icmp_param->replyopts.optlen) {
- ipc.opt = &icmp_param->replyopts;
- if (ipc.opt->srr)
- daddr = icmp_param->replyopts.faddr;
+ if (icmp_param->replyopts.opt.opt.optlen) {
+ ipc.opt = &icmp_param->replyopts.opt;
+ if (ipc.opt->opt.srr)
+ daddr = icmp_param->replyopts.opt.opt.faddr;
}
{
struct flowi4 fl4 = {
@@ -373,14 +372,14 @@ out_unlock:
}
static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in,
- struct iphdr *iph,
+ const struct iphdr *iph,
__be32 saddr, u8 tos,
int type, int code,
struct icmp_bxm *param)
{
struct flowi4 fl4 = {
- .daddr = (param->replyopts.srr ?
- param->replyopts.faddr : iph->saddr),
+ .daddr = (param->replyopts.opt.opt.srr ?
+ param->replyopts.opt.opt.faddr : iph->saddr),
.saddr = saddr,
.flowi4_tos = RT_TOS(tos),
.flowi4_proto = IPPROTO_ICMP,
@@ -581,7 +580,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
IPTOS_PREC_INTERNETCONTROL) :
iph->tos;
- if (ip_options_echo(&icmp_param.replyopts, skb_in))
+ if (ip_options_echo(&icmp_param.replyopts.opt.opt, skb_in))
goto out_unlock;
@@ -597,7 +596,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
icmp_param.offset = skb_network_offset(skb_in);
inet_sk(sk)->tos = tos;
ipc.addr = iph->saddr;
- ipc.opt = &icmp_param.replyopts;
+ ipc.opt = &icmp_param.replyopts.opt;
ipc.tx_flags = 0;
rt = icmp_route_lookup(net, skb_in, iph, saddr, tos,
@@ -613,7 +612,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
room = dst_mtu(&rt->dst);
if (room > 576)
room = 576;
- room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
+ room -= sizeof(struct iphdr) + icmp_param.replyopts.opt.opt.optlen;
room -= sizeof(struct icmphdr);
icmp_param.data_len = skb_in->len - icmp_param.offset;
@@ -637,7 +636,7 @@ EXPORT_SYMBOL(icmp_send);
static void icmp_unreach(struct sk_buff *skb)
{
- struct iphdr *iph;
+ const struct iphdr *iph;
struct icmphdr *icmph;
int hash, protocol;
const struct net_protocol *ipprot;
@@ -656,7 +655,7 @@ static void icmp_unreach(struct sk_buff *skb)
goto out_err;
icmph = icmp_hdr(skb);
- iph = (struct iphdr *)skb->data;
+ iph = (const struct iphdr *)skb->data;
if (iph->ihl < 5) /* Mangled header, drop. */
goto out_err;
@@ -704,7 +703,7 @@ static void icmp_unreach(struct sk_buff *skb)
*/
/*
- * Check the other end isnt violating RFC 1122. Some routers send
+ * Check the other end isn't violating RFC 1122. Some routers send
* bogus responses to broadcast frames. If you see this message
* first check your netmask matches at both ends, if it does then
* get the other vendor to fix their kit.
@@ -729,7 +728,7 @@ static void icmp_unreach(struct sk_buff *skb)
if (!pskb_may_pull(skb, iph->ihl * 4 + 8))
goto out;
- iph = (struct iphdr *)skb->data;
+ iph = (const struct iphdr *)skb->data;
protocol = iph->protocol;
/*
@@ -758,7 +757,7 @@ out_err:
static void icmp_redirect(struct sk_buff *skb)
{
- struct iphdr *iph;
+ const struct iphdr *iph;
if (skb->len < sizeof(struct iphdr))
goto out_err;
@@ -769,7 +768,7 @@ static void icmp_redirect(struct sk_buff *skb)
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto out;
- iph = (struct iphdr *)skb->data;
+ iph = (const struct iphdr *)skb->data;
switch (icmp_hdr(skb)->code & 7) {
case ICMP_REDIR_NET:
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 1fd3d9c..ec03c2f 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -309,6 +309,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
struct iphdr *pip;
struct igmpv3_report *pig;
struct net *net = dev_net(dev);
+ struct flowi4 fl4;
while (1) {
skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev),
@@ -321,18 +322,13 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
}
igmp_skb_size(skb) = size;
- rt = ip_route_output_ports(net, NULL, IGMPV3_ALL_MCR, 0,
+ rt = ip_route_output_ports(net, &fl4, NULL, IGMPV3_ALL_MCR, 0,
0, 0,
IPPROTO_IGMP, 0, dev->ifindex);
if (IS_ERR(rt)) {
kfree_skb(skb);
return NULL;
}
- if (rt->rt_src == 0) {
- kfree_skb(skb);
- ip_rt_put(rt);
- return NULL;
- }
skb_dst_set(skb, &rt->dst);
skb->dev = dev;
@@ -348,8 +344,8 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
pip->tos = 0xc0;
pip->frag_off = htons(IP_DF);
pip->ttl = 1;
- pip->daddr = rt->rt_dst;
- pip->saddr = rt->rt_src;
+ pip->daddr = fl4.daddr;
+ pip->saddr = fl4.saddr;
pip->protocol = IPPROTO_IGMP;
pip->tot_len = 0; /* filled in later */
ip_select_ident(pip, &rt->dst, NULL);
@@ -655,6 +651,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
struct net_device *dev = in_dev->dev;
struct net *net = dev_net(dev);
__be32 group = pmc ? pmc->multiaddr : 0;
+ struct flowi4 fl4;
__be32 dst;
if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
@@ -664,17 +661,12 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
else
dst = group;
- rt = ip_route_output_ports(net, NULL, dst, 0,
+ rt = ip_route_output_ports(net, &fl4, NULL, dst, 0,
0, 0,
IPPROTO_IGMP, 0, dev->ifindex);
if (IS_ERR(rt))
return -1;
- if (rt->rt_src == 0) {
- ip_rt_put(rt);
- return -1;
- }
-
skb = alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
if (skb == NULL) {
ip_rt_put(rt);
@@ -695,7 +687,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
iph->frag_off = htons(IP_DF);
iph->ttl = 1;
iph->daddr = dst;
- iph->saddr = rt->rt_src;
+ iph->saddr = fl4.saddr;
iph->protocol = IPPROTO_IGMP;
ip_select_ident(iph, &rt->dst, NULL);
((u8*)&iph[1])[0] = IPOPT_RA;
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 6c0b7f4..54944da 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -73,7 +73,7 @@ int inet_csk_bind_conflict(const struct sock *sk,
!sk2->sk_bound_dev_if ||
sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
if (!reuse || !sk2->sk_reuse ||
- ((1 << sk2->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))) {
+ sk2->sk_state == TCP_LISTEN) {
const __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2);
if (!sk2_rcv_saddr || !sk_rcv_saddr(sk) ||
sk2_rcv_saddr == sk_rcv_saddr(sk))
@@ -122,8 +122,7 @@ again:
(tb->num_owners < smallest_size || smallest_size == -1)) {
smallest_size = tb->num_owners;
smallest_rover = rover;
- if (atomic_read(&hashinfo->bsockets) > (high - low) + 1 &&
- !inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) {
+ if (atomic_read(&hashinfo->bsockets) > (high - low) + 1) {
spin_unlock(&head->lock);
snum = smallest_rover;
goto have_snum;
@@ -355,26 +354,20 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
{
struct rtable *rt;
const struct inet_request_sock *ireq = inet_rsk(req);
- struct ip_options *opt = inet_rsk(req)->opt;
- struct flowi4 fl4 = {
- .flowi4_oif = sk->sk_bound_dev_if,
- .flowi4_mark = sk->sk_mark,
- .daddr = ((opt && opt->srr) ?
- opt->faddr : ireq->rmt_addr),
- .saddr = ireq->loc_addr,
- .flowi4_tos = RT_CONN_FLAGS(sk),
- .flowi4_proto = sk->sk_protocol,
- .flowi4_flags = inet_sk_flowi_flags(sk),
- .fl4_sport = inet_sk(sk)->inet_sport,
- .fl4_dport = ireq->rmt_port,
- };
+ struct ip_options_rcu *opt = inet_rsk(req)->opt;
struct net *net = sock_net(sk);
+ struct flowi4 fl4;
+ flowi4_init_output(&fl4, sk->sk_bound_dev_if, sk->sk_mark,
+ RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
+ sk->sk_protocol, inet_sk_flowi_flags(sk),
+ (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr,
+ ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport);
security_req_classify_flow(req, flowi4_to_flowi(&fl4));
rt = ip_route_output_flow(net, &fl4, sk);
if (IS_ERR(rt))
goto no_route;
- if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
+ if (opt && opt->opt.is_strictroute && fl4.daddr != rt->rt_gateway)
goto route_err;
return &rt->dst;
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 2ada171..6ffe94c 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -124,7 +124,7 @@ static int inet_csk_diag_fill(struct sock *sk,
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
if (r->idiag_family == AF_INET6) {
- struct ipv6_pinfo *np = inet6_sk(sk);
+ const struct ipv6_pinfo *np = inet6_sk(sk);
ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
&np->rcv_saddr);
diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c
index 47038cb..85a0f75 100644
--- a/net/ipv4/inet_lro.c
+++ b/net/ipv4/inet_lro.c
@@ -51,8 +51,8 @@ MODULE_DESCRIPTION("Large Receive Offload (ipv4 / tcp)");
* Basic tcp checks whether packet is suitable for LRO
*/
-static int lro_tcp_ip_check(struct iphdr *iph, struct tcphdr *tcph,
- int len, struct net_lro_desc *lro_desc)
+static int lro_tcp_ip_check(const struct iphdr *iph, const struct tcphdr *tcph,
+ int len, const struct net_lro_desc *lro_desc)
{
/* check ip header: don't aggregate padded frames */
if (ntohs(iph->tot_len) != len)
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index dd1b20e..9df4e63 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -354,7 +354,8 @@ static void inetpeer_free_rcu(struct rcu_head *head)
}
/* May be called with local BH enabled. */
-static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base)
+static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base,
+ struct inet_peer __rcu **stack[PEER_MAXDEPTH])
{
int do_free;
@@ -368,7 +369,6 @@ static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base)
* We use refcnt=-1 to alert lockless readers this entry is deleted.
*/
if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) {
- struct inet_peer __rcu **stack[PEER_MAXDEPTH];
struct inet_peer __rcu ***stackptr, ***delp;
if (lookup(&p->daddr, stack, base) != p)
BUG();
@@ -422,7 +422,7 @@ static struct inet_peer_base *peer_to_base(struct inet_peer *p)
}
/* May be called with local BH enabled. */
-static int cleanup_once(unsigned long ttl)
+static int cleanup_once(unsigned long ttl, struct inet_peer __rcu **stack[PEER_MAXDEPTH])
{
struct inet_peer *p = NULL;
@@ -454,7 +454,7 @@ static int cleanup_once(unsigned long ttl)
* happen because of entry limits in route cache. */
return -1;
- unlink_from_pool(p, peer_to_base(p));
+ unlink_from_pool(p, peer_to_base(p), stack);
return 0;
}
@@ -524,7 +524,7 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
if (base->total >= inet_peer_threshold)
/* Remove one less-recently-used entry. */
- cleanup_once(0);
+ cleanup_once(0, stack);
return p;
}
@@ -540,6 +540,7 @@ static void peer_check_expire(unsigned long dummy)
{
unsigned long now = jiffies;
int ttl, total;
+ struct inet_peer __rcu **stack[PEER_MAXDEPTH];
total = compute_total();
if (total >= inet_peer_threshold)
@@ -548,7 +549,7 @@ static void peer_check_expire(unsigned long dummy)
ttl = inet_peer_maxttl
- (inet_peer_maxttl - inet_peer_minttl) / HZ *
total / inet_peer_threshold * HZ;
- while (!cleanup_once(ttl)) {
+ while (!cleanup_once(ttl, stack)) {
if (jiffies != now)
break;
}
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index da5941f..10e9b5a 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -462,7 +462,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
by themself???
*/
- struct iphdr *iph = (struct iphdr *)skb->data;
+ const struct iphdr *iph = (const struct iphdr *)skb->data;
__be16 *p = (__be16*)(skb->data+(iph->ihl<<2));
int grehlen = (iph->ihl<<2) + 4;
const int type = icmp_hdr(skb)->type;
@@ -534,7 +534,7 @@ out:
rcu_read_unlock();
}
-static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
+static inline void ipgre_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb)
{
if (INET_ECN_is_ce(iph->tos)) {
if (skb->protocol == htons(ETH_P_IP)) {
@@ -546,19 +546,19 @@ static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
}
static inline u8
-ipgre_ecn_encapsulate(u8 tos, struct iphdr *old_iph, struct sk_buff *skb)
+ipgre_ecn_encapsulate(u8 tos, const struct iphdr *old_iph, struct sk_buff *skb)
{
u8 inner = 0;
if (skb->protocol == htons(ETH_P_IP))
inner = old_iph->tos;
else if (skb->protocol == htons(ETH_P_IPV6))
- inner = ipv6_get_dsfield((struct ipv6hdr *)old_iph);
+ inner = ipv6_get_dsfield((const struct ipv6hdr *)old_iph);
return INET_ECN_encapsulate(tos, inner);
}
static int ipgre_rcv(struct sk_buff *skb)
{
- struct iphdr *iph;
+ const struct iphdr *iph;
u8 *h;
__be16 flags;
__sum16 csum = 0;
@@ -697,8 +697,9 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
{
struct ip_tunnel *tunnel = netdev_priv(dev);
struct pcpu_tstats *tstats;
- struct iphdr *old_iph = ip_hdr(skb);
- struct iphdr *tiph;
+ const struct iphdr *old_iph = ip_hdr(skb);
+ const struct iphdr *tiph;
+ struct flowi4 fl4;
u8 tos;
__be16 df;
struct rtable *rt; /* Route to the other host */
@@ -714,7 +715,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
if (dev->header_ops && dev->type == ARPHRD_IPGRE) {
gre_hlen = 0;
- tiph = (struct iphdr *)skb->data;
+ tiph = (const struct iphdr *)skb->data;
} else {
gre_hlen = tunnel->hlen;
tiph = &tunnel->parms.iph;
@@ -735,14 +736,14 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if (skb->protocol == htons(ETH_P_IPV6)) {
- struct in6_addr *addr6;
+ const struct in6_addr *addr6;
int addr_type;
struct neighbour *neigh = skb_dst(skb)->neighbour;
if (neigh == NULL)
goto tx_error;
- addr6 = (struct in6_addr *)&neigh->primary_key;
+ addr6 = (const struct in6_addr *)&neigh->primary_key;
addr_type = ipv6_addr_type(addr6);
if (addr_type == IPV6_ADDR_ANY) {
@@ -766,10 +767,10 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
if (skb->protocol == htons(ETH_P_IP))
tos = old_iph->tos;
else if (skb->protocol == htons(ETH_P_IPV6))
- tos = ipv6_get_dsfield((struct ipv6hdr *)old_iph);
+ tos = ipv6_get_dsfield((const struct ipv6hdr *)old_iph);
}
- rt = ip_route_output_gre(dev_net(dev), dst, tiph->saddr,
+ rt = ip_route_output_gre(dev_net(dev), &fl4, dst, tiph->saddr,
tunnel->parms.o_key, RT_TOS(tos),
tunnel->parms.link);
if (IS_ERR(rt)) {
@@ -873,15 +874,15 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
iph->frag_off = df;
iph->protocol = IPPROTO_GRE;
iph->tos = ipgre_ecn_encapsulate(tos, old_iph, skb);
- iph->daddr = rt->rt_dst;
- iph->saddr = rt->rt_src;
+ iph->daddr = fl4.daddr;
+ iph->saddr = fl4.saddr;
if ((iph->ttl = tiph->ttl) == 0) {
if (skb->protocol == htons(ETH_P_IP))
iph->ttl = old_iph->ttl;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if (skb->protocol == htons(ETH_P_IPV6))
- iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit;
+ iph->ttl = ((const struct ipv6hdr *)old_iph)->hop_limit;
#endif
else
iph->ttl = ip4_dst_hoplimit(&rt->dst);
@@ -927,7 +928,7 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev)
{
struct net_device *tdev = NULL;
struct ip_tunnel *tunnel;
- struct iphdr *iph;
+ const struct iphdr *iph;
int hlen = LL_MAX_HEADER;
int mtu = ETH_DATA_LEN;
int addend = sizeof(struct iphdr) + 4;
@@ -938,12 +939,14 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev)
/* Guess output device to choose reasonable mtu and needed_headroom */
if (iph->daddr) {
- struct rtable *rt = ip_route_output_gre(dev_net(dev),
- iph->daddr, iph->saddr,
- tunnel->parms.o_key,
- RT_TOS(iph->tos),
- tunnel->parms.link);
-
+ struct flowi4 fl4;
+ struct rtable *rt;
+
+ rt = ip_route_output_gre(dev_net(dev), &fl4,
+ iph->daddr, iph->saddr,
+ tunnel->parms.o_key,
+ RT_TOS(iph->tos),
+ tunnel->parms.link);
if (!IS_ERR(rt)) {
tdev = rt->dst.dev;
ip_rt_put(rt);
@@ -1180,7 +1183,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
- struct iphdr *iph = (struct iphdr *) skb_mac_header(skb);
+ const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
memcpy(haddr, &iph->saddr, 4);
return 4;
}
@@ -1196,13 +1199,15 @@ static int ipgre_open(struct net_device *dev)
struct ip_tunnel *t = netdev_priv(dev);
if (ipv4_is_multicast(t->parms.iph.daddr)) {
- struct rtable *rt = ip_route_output_gre(dev_net(dev),
- t->parms.iph.daddr,
- t->parms.iph.saddr,
- t->parms.o_key,
- RT_TOS(t->parms.iph.tos),
- t->parms.link);
-
+ struct flowi4 fl4;
+ struct rtable *rt;
+
+ rt = ip_route_output_gre(dev_net(dev), &fl4,
+ t->parms.iph.daddr,
+ t->parms.iph.saddr,
+ t->parms.o_key,
+ RT_TOS(t->parms.iph.tos),
+ t->parms.link);
if (IS_ERR(rt))
return -EADDRNOTAVAIL;
dev = rt->dst.dev;
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index d7b2b09..c8f48ef 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -268,7 +268,7 @@ int ip_local_deliver(struct sk_buff *skb)
static inline int ip_rcv_options(struct sk_buff *skb)
{
struct ip_options *opt;
- struct iphdr *iph;
+ const struct iphdr *iph;
struct net_device *dev = skb->dev;
/* It looks as overkill, because not all
@@ -374,7 +374,7 @@ drop:
*/
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
- struct iphdr *iph;
+ const struct iphdr *iph;
u32 len;
/* When the interface is in promisc. mode, drop all the crap
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 28a736f..01fc409 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -36,7 +36,7 @@
* saddr is address of outgoing interface.
*/
-void ip_options_build(struct sk_buff * skb, struct ip_options * opt,
+void ip_options_build(struct sk_buff *skb, struct ip_options *opt,
__be32 daddr, struct rtable *rt, int is_frag)
{
unsigned char *iph = skb_network_header(skb);
@@ -83,9 +83,9 @@ void ip_options_build(struct sk_buff * skb, struct ip_options * opt,
* NOTE: dopt cannot point to skb.
*/
-int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
+int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb)
{
- struct ip_options *sopt;
+ const struct ip_options *sopt;
unsigned char *sptr, *dptr;
int soffset, doffset;
int optlen;
@@ -95,10 +95,8 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
sopt = &(IPCB(skb)->opt);
- if (sopt->optlen == 0) {
- dopt->optlen = 0;
+ if (sopt->optlen == 0)
return 0;
- }
sptr = skb_network_header(skb);
dptr = dopt->__data;
@@ -157,7 +155,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
dopt->optlen += optlen;
}
if (sopt->srr) {
- unsigned char * start = sptr+sopt->srr;
+ unsigned char *start = sptr+sopt->srr;
__be32 faddr;
optlen = start[1];
@@ -329,7 +327,7 @@ int ip_options_compile(struct net *net,
pp_ptr = optptr + 2;
goto error;
}
- if (skb) {
+ if (rt) {
memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
opt->is_changed = 1;
}
@@ -371,7 +369,7 @@ int ip_options_compile(struct net *net,
goto error;
}
opt->ts = optptr - iph;
- if (skb) {
+ if (rt) {
memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
timeptr = (__be32*)&optptr[optptr[2]+3];
}
@@ -499,19 +497,19 @@ void ip_options_undo(struct ip_options * opt)
}
}
-static struct ip_options *ip_options_get_alloc(const int optlen)
+static struct ip_options_rcu *ip_options_get_alloc(const int optlen)
{
- return kzalloc(sizeof(struct ip_options) + ((optlen + 3) & ~3),
+ return kzalloc(sizeof(struct ip_options_rcu) + ((optlen + 3) & ~3),
GFP_KERNEL);
}
-static int ip_options_get_finish(struct net *net, struct ip_options **optp,
- struct ip_options *opt, int optlen)
+static int ip_options_get_finish(struct net *net, struct ip_options_rcu **optp,
+ struct ip_options_rcu *opt, int optlen)
{
while (optlen & 3)
- opt->__data[optlen++] = IPOPT_END;
- opt->optlen = optlen;
- if (optlen && ip_options_compile(net, opt, NULL)) {
+ opt->opt.__data[optlen++] = IPOPT_END;
+ opt->opt.optlen = optlen;
+ if (optlen && ip_options_compile(net, &opt->opt, NULL)) {
kfree(opt);
return -EINVAL;
}
@@ -520,29 +518,29 @@ static int ip_options_get_finish(struct net *net, struct ip_options **optp,
return 0;
}
-int ip_options_get_from_user(struct net *net, struct ip_options **optp,
+int ip_options_get_from_user(struct net *net, struct ip_options_rcu **optp,
unsigned char __user *data, int optlen)
{
- struct ip_options *opt = ip_options_get_alloc(optlen);
+ struct ip_options_rcu *opt = ip_options_get_alloc(optlen);
if (!opt)
return -ENOMEM;
- if (optlen && copy_from_user(opt->__data, data, optlen)) {
+ if (optlen && copy_from_user(opt->opt.__data, data, optlen)) {
kfree(opt);
return -EFAULT;
}
return ip_options_get_finish(net, optp, opt, optlen);
}
-int ip_options_get(struct net *net, struct ip_options **optp,
+int ip_options_get(struct net *net, struct ip_options_rcu **optp,
unsigned char *data, int optlen)
{
- struct ip_options *opt = ip_options_get_alloc(optlen);
+ struct ip_options_rcu *opt = ip_options_get_alloc(optlen);
if (!opt)
return -ENOMEM;
if (optlen)
- memcpy(opt->__data, data, optlen);
+ memcpy(opt->opt.__data, data, optlen);
return ip_options_get_finish(net, optp, opt, optlen);
}
@@ -603,7 +601,7 @@ int ip_options_rcv_srr(struct sk_buff *skb)
unsigned long orefdst;
int err;
- if (!opt->srr)
+ if (!opt->srr || !rt)
return 0;
if (skb->pkt_type != PACKET_HOST)
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 67f241b..db38c18 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -140,14 +140,14 @@ static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst)
*
*/
int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
- __be32 saddr, __be32 daddr, struct ip_options *opt)
+ __be32 saddr, __be32 daddr, struct ip_options_rcu *opt)
{
struct inet_sock *inet = inet_sk(sk);
struct rtable *rt = skb_rtable(skb);
struct iphdr *iph;
/* Build the IP header. */
- skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
+ skb_push(skb, sizeof(struct iphdr) + (opt ? opt->opt.optlen : 0));
skb_reset_network_header(skb);
iph = ip_hdr(skb);
iph->version = 4;
@@ -158,14 +158,14 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
else
iph->frag_off = 0;
iph->ttl = ip_select_ttl(inet, &rt->dst);
- iph->daddr = rt->rt_dst;
- iph->saddr = rt->rt_src;
+ iph->daddr = (opt && opt->opt.srr ? opt->opt.faddr : daddr);
+ iph->saddr = saddr;
iph->protocol = sk->sk_protocol;
ip_select_ident(iph, &rt->dst, sk);
- if (opt && opt->optlen) {
- iph->ihl += opt->optlen>>2;
- ip_options_build(skb, opt, daddr, rt, 0);
+ if (opt && opt->opt.optlen) {
+ iph->ihl += opt->opt.optlen>>2;
+ ip_options_build(skb, &opt->opt, daddr, rt, 0);
}
skb->priority = sk->sk_priority;
@@ -316,7 +316,7 @@ int ip_queue_xmit(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
struct inet_sock *inet = inet_sk(sk);
- struct ip_options *opt = inet->opt;
+ struct ip_options_rcu *inet_opt;
struct rtable *rt;
struct iphdr *iph;
int res;
@@ -325,6 +325,7 @@ int ip_queue_xmit(struct sk_buff *skb)
* f.e. by something like SCTP.
*/
rcu_read_lock();
+ inet_opt = rcu_dereference(inet->inet_opt);
rt = skb_rtable(skb);
if (rt != NULL)
goto packet_routed;
@@ -332,18 +333,19 @@ int ip_queue_xmit(struct sk_buff *skb)
/* Make sure we can route this packet. */
rt = (struct rtable *)__sk_dst_check(sk, 0);
if (rt == NULL) {
+ struct flowi4 fl4;
__be32 daddr;
/* Use correct destination address if we have options. */
daddr = inet->inet_daddr;
- if(opt && opt->srr)
- daddr = opt->faddr;
+ if (inet_opt && inet_opt->opt.srr)
+ daddr = inet_opt->opt.faddr;
/* If this fails, retransmit mechanism of transport layer will
* keep trying until route appears or the connection times
* itself out.
*/
- rt = ip_route_output_ports(sock_net(sk), sk,
+ rt = ip_route_output_ports(sock_net(sk), &fl4, sk,
daddr, inet->inet_saddr,
inet->inet_dport,
inet->inet_sport,
@@ -357,11 +359,11 @@ int ip_queue_xmit(struct sk_buff *skb)
skb_dst_set_noref(skb, &rt->dst);
packet_routed:
- if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
+ if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_dst != rt->rt_gateway)
goto no_route;
/* OK, we know where to send it, allocate and build IP header. */
- skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
+ skb_push(skb, sizeof(struct iphdr) + (inet_opt ? inet_opt->opt.optlen : 0));
skb_reset_network_header(skb);
iph = ip_hdr(skb);
*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
@@ -375,9 +377,9 @@ packet_routed:
iph->daddr = rt->rt_dst;
/* Transport layer set skb->h.foo itself. */
- if (opt && opt->optlen) {
- iph->ihl += opt->optlen >> 2;
- ip_options_build(skb, opt, inet->inet_daddr, rt, 0);
+ if (inet_opt && inet_opt->opt.optlen) {
+ iph->ihl += inet_opt->opt.optlen >> 2;
+ ip_options_build(skb, &inet_opt->opt, inet->inet_daddr, rt, 0);
}
ip_select_ident_more(iph, &rt->dst, sk,
@@ -603,7 +605,7 @@ slow_path:
/* IF: it doesn't fit, use 'mtu' - the data space left */
if (len > mtu)
len = mtu;
- /* IF: we are not sending upto and including the packet end
+ /* IF: we are not sending up to and including the packet end
then align the next start on an eight byte boundary */
if (len < left) {
len &= ~7;
@@ -1033,7 +1035,7 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,
struct ipcm_cookie *ipc, struct rtable **rtp)
{
struct inet_sock *inet = inet_sk(sk);
- struct ip_options *opt;
+ struct ip_options_rcu *opt;
struct rtable *rt;
/*
@@ -1047,7 +1049,7 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,
if (unlikely(cork->opt == NULL))
return -ENOBUFS;
}
- memcpy(cork->opt, opt, sizeof(struct ip_options) + opt->optlen);
+ memcpy(cork->opt, &opt->opt, sizeof(struct ip_options) + opt->opt.optlen);
cork->flags |= IPCORK_OPT;
cork->addr = ipc->addr;
}
@@ -1451,39 +1453,34 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
unsigned int len)
{
struct inet_sock *inet = inet_sk(sk);
- struct {
- struct ip_options opt;
- char data[40];
- } replyopts;
+ struct ip_options_data replyopts;
struct ipcm_cookie ipc;
__be32 daddr;
struct rtable *rt = skb_rtable(skb);
- if (ip_options_echo(&replyopts.opt, skb))
+ if (ip_options_echo(&replyopts.opt.opt, skb))
return;
daddr = ipc.addr = rt->rt_src;
ipc.opt = NULL;
ipc.tx_flags = 0;
- if (replyopts.opt.optlen) {
+ if (replyopts.opt.opt.optlen) {
ipc.opt = &replyopts.opt;
- if (ipc.opt->srr)
- daddr = replyopts.opt.faddr;
+ if (replyopts.opt.opt.srr)
+ daddr = replyopts.opt.opt.faddr;
}
{
- struct flowi4 fl4 = {
- .flowi4_oif = arg->bound_dev_if,
- .daddr = daddr,
- .saddr = rt->rt_spec_dst,
- .flowi4_tos = RT_TOS(ip_hdr(skb)->tos),
- .fl4_sport = tcp_hdr(skb)->dest,
- .fl4_dport = tcp_hdr(skb)->source,
- .flowi4_proto = sk->sk_protocol,
- .flowi4_flags = ip_reply_arg_flowi_flags(arg),
- };
+ struct flowi4 fl4;
+
+ flowi4_init_output(&fl4, arg->bound_dev_if, 0,
+ RT_TOS(ip_hdr(skb)->tos),
+ RT_SCOPE_UNIVERSE, sk->sk_protocol,
+ ip_reply_arg_flowi_flags(arg),
+ daddr, rt->rt_spec_dst,
+ tcp_hdr(skb)->source, tcp_hdr(skb)->dest);
security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
rt = ip_route_output_key(sock_net(sk), &fl4);
if (IS_ERR(rt))
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 3948c86..ab0c9ef 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -131,7 +131,7 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
{
struct sockaddr_in sin;
- struct iphdr *iph = ip_hdr(skb);
+ const struct iphdr *iph = ip_hdr(skb);
__be16 *ports = (__be16 *)skb_transport_header(skb);
if (skb_transport_offset(skb) + 4 > skb->len)
@@ -451,6 +451,11 @@ out:
}
+static void opt_kfree_rcu(struct rcu_head *head)
+{
+ kfree(container_of(head, struct ip_options_rcu, rcu));
+}
+
/*
* Socket option code for IP. This is the end of the line after any
* TCP,UDP etc options on an IP socket.
@@ -497,13 +502,16 @@ static int do_ip_setsockopt(struct sock *sk, int level,
switch (optname) {
case IP_OPTIONS:
{
- struct ip_options *opt = NULL;
+ struct ip_options_rcu *old, *opt = NULL;
+
if (optlen > 40)
goto e_inval;
err = ip_options_get_from_user(sock_net(sk), &opt,
optval, optlen);
if (err)
break;
+ old = rcu_dereference_protected(inet->inet_opt,
+ sock_owned_by_user(sk));
if (inet->is_icsk) {
struct inet_connection_sock *icsk = inet_csk(sk);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -512,17 +520,18 @@ static int do_ip_setsockopt(struct sock *sk, int level,
(TCPF_LISTEN | TCPF_CLOSE)) &&
inet->inet_daddr != LOOPBACK4_IPV6)) {
#endif
- if (inet->opt)
- icsk->icsk_ext_hdr_len -= inet->opt->optlen;
+ if (old)
+ icsk->icsk_ext_hdr_len -= old->opt.optlen;
if (opt)
- icsk->icsk_ext_hdr_len += opt->optlen;
+ icsk->icsk_ext_hdr_len += opt->opt.optlen;
icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
}
#endif
}
- opt = xchg(&inet->opt, opt);
- kfree(opt);
+ rcu_assign_pointer(inet->inet_opt, opt);
+ if (old)
+ call_rcu(&old->rcu, opt_kfree_rcu);
break;
}
case IP_PKTINFO:
@@ -1081,12 +1090,16 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
case IP_OPTIONS:
{
unsigned char optbuf[sizeof(struct ip_options)+40];
- struct ip_options * opt = (struct ip_options *)optbuf;
+ struct ip_options *opt = (struct ip_options *)optbuf;
+ struct ip_options_rcu *inet_opt;
+
+ inet_opt = rcu_dereference_protected(inet->inet_opt,
+ sock_owned_by_user(sk));
opt->optlen = 0;
- if (inet->opt)
- memcpy(optbuf, inet->opt,
- sizeof(struct ip_options)+
- inet->opt->optlen);
+ if (inet_opt)
+ memcpy(optbuf, &inet_opt->opt,
+ sizeof(struct ip_options) +
+ inet_opt->opt.optlen);
release_sock(sk);
if (opt->optlen == 0)
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index 6290675..c857f6f 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -27,7 +27,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
{
struct net *net = dev_net(skb->dev);
__be32 spi;
- struct iphdr *iph = (struct iphdr *)skb->data;
+ const struct iphdr *iph = (const struct iphdr *)skb->data;
struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
struct xfrm_state *x;
@@ -36,7 +36,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
return;
spi = htonl(ntohs(ipch->cpi));
- x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr,
+ x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
spi, IPPROTO_COMP, AF_INET);
if (!x)
return;
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 2b09775..cbff2ec 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -1444,7 +1444,7 @@ static int __init ip_auto_config(void)
root_server_addr = addr;
/*
- * Use defaults whereever applicable.
+ * Use defaults wherever applicable.
*/
if (ic_defaults() < 0)
return -1;
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index bfc17c5..bfa0b98 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -319,7 +319,7 @@ static int ipip_err(struct sk_buff *skb, u32 info)
8 bytes of packet payload. It means, that precise relaying of
ICMP in the real Internet is absolutely infeasible.
*/
- struct iphdr *iph = (struct iphdr *)skb->data;
+ const struct iphdr *iph = (const struct iphdr *)skb->data;
const int type = icmp_hdr(skb)->type;
const int code = icmp_hdr(skb)->code;
struct ip_tunnel *t;
@@ -433,15 +433,16 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
struct pcpu_tstats *tstats;
- struct iphdr *tiph = &tunnel->parms.iph;
+ const struct iphdr *tiph = &tunnel->parms.iph;
u8 tos = tunnel->parms.iph.tos;
__be16 df = tiph->frag_off;
struct rtable *rt; /* Route to the other host */
struct net_device *tdev; /* Device to other host */
- struct iphdr *old_iph = ip_hdr(skb);
+ const struct iphdr *old_iph = ip_hdr(skb);
struct iphdr *iph; /* Our new IP header */
unsigned int max_headroom; /* The extra header space needed */
__be32 dst = tiph->daddr;
+ struct flowi4 fl4;
int mtu;
if (skb->protocol != htons(ETH_P_IP))
@@ -460,7 +461,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_error_icmp;
}
- rt = ip_route_output_ports(dev_net(dev), NULL,
+ rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
dst, tiph->saddr,
0, 0,
IPPROTO_IPIP, RT_TOS(tos),
@@ -549,8 +550,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
iph->frag_off = df;
iph->protocol = IPPROTO_IPIP;
iph->tos = INET_ECN_encapsulate(tos, old_iph->tos);
- iph->daddr = rt->rt_dst;
- iph->saddr = rt->rt_src;
+ iph->daddr = fl4.daddr;
+ iph->saddr = fl4.saddr;
if ((iph->ttl = tiph->ttl) == 0)
iph->ttl = old_iph->ttl;
@@ -572,19 +573,21 @@ static void ipip_tunnel_bind_dev(struct net_device *dev)
{
struct net_device *tdev = NULL;
struct ip_tunnel *tunnel;
- struct iphdr *iph;
+ const struct iphdr *iph;
tunnel = netdev_priv(dev);
iph = &tunnel->parms.iph;
if (iph->daddr) {
- struct rtable *rt = ip_route_output_ports(dev_net(dev), NULL,
- iph->daddr, iph->saddr,
- 0, 0,
- IPPROTO_IPIP,
- RT_TOS(iph->tos),
- tunnel->parms.link);
-
+ struct rtable *rt;
+ struct flowi4 fl4;
+
+ rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
+ iph->daddr, iph->saddr,
+ 0, 0,
+ IPPROTO_IPIP,
+ RT_TOS(iph->tos),
+ tunnel->parms.link);
if (!IS_ERR(rt)) {
tdev = rt->dst.dev;
ip_rt_put(rt);
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 1f62eae..30a7763 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1549,7 +1549,7 @@ static struct notifier_block ip_mr_notifier = {
static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
{
struct iphdr *iph;
- struct iphdr *old_iph = ip_hdr(skb);
+ const struct iphdr *old_iph = ip_hdr(skb);
skb_push(skb, sizeof(struct iphdr));
skb->transport_header = skb->network_header;
@@ -1595,6 +1595,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
struct vif_device *vif = &mrt->vif_table[vifi];
struct net_device *dev;
struct rtable *rt;
+ struct flowi4 fl4;
int encap = 0;
if (vif->dev == NULL)
@@ -1612,7 +1613,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
#endif
if (vif->flags & VIFF_TUNNEL) {
- rt = ip_route_output_ports(net, NULL,
+ rt = ip_route_output_ports(net, &fl4, NULL,
vif->remote, vif->local,
0, 0,
IPPROTO_IPIP,
@@ -1621,7 +1622,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
goto out_free;
encap = sizeof(struct iphdr);
} else {
- rt = ip_route_output_ports(net, NULL, iph->daddr, 0,
+ rt = ip_route_output_ports(net, &fl4, NULL, iph->daddr, 0,
0, 0,
IPPROTO_IPIP,
RT_TOS(iph->tos), vif->link);
@@ -1788,12 +1789,14 @@ dont_forward:
return 0;
}
-static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct rtable *rt)
+static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct sk_buff *skb)
{
+ struct rtable *rt = skb_rtable(skb);
+ struct iphdr *iph = ip_hdr(skb);
struct flowi4 fl4 = {
- .daddr = rt->rt_key_dst,
- .saddr = rt->rt_key_src,
- .flowi4_tos = rt->rt_tos,
+ .daddr = iph->daddr,
+ .saddr = iph->saddr,
+ .flowi4_tos = iph->tos,
.flowi4_oif = rt->rt_oif,
.flowi4_iif = rt->rt_iif,
.flowi4_mark = rt->rt_mark,
@@ -1825,7 +1828,7 @@ int ip_mr_input(struct sk_buff *skb)
if (IPCB(skb)->flags & IPSKB_FORWARDED)
goto dont_forward;
- mrt = ipmr_rt_fib_lookup(net, skb_rtable(skb));
+ mrt = ipmr_rt_fib_lookup(net, skb);
if (IS_ERR(mrt)) {
kfree_skb(skb);
return PTR_ERR(mrt);
@@ -1957,7 +1960,7 @@ int pim_rcv_v1(struct sk_buff *skb)
pim = igmp_hdr(skb);
- mrt = ipmr_rt_fib_lookup(net, skb_rtable(skb));
+ mrt = ipmr_rt_fib_lookup(net, skb);
if (IS_ERR(mrt))
goto drop;
if (!mrt->mroute_do_pim ||
@@ -1989,7 +1992,7 @@ static int pim_rcv(struct sk_buff *skb)
csum_fold(skb_checksum(skb, 0, skb->len, 0))))
goto drop;
- mrt = ipmr_rt_fib_lookup(net, skb_rtable(skb));
+ mrt = ipmr_rt_fib_lookup(net, skb);
if (IS_ERR(mrt))
goto drop;
if (__pim_rcv(mrt, skb, sizeof(*pim))) {
@@ -2038,20 +2041,20 @@ rtattr_failure:
return -EMSGSIZE;
}
-int ipmr_get_route(struct net *net,
- struct sk_buff *skb, struct rtmsg *rtm, int nowait)
+int ipmr_get_route(struct net *net, struct sk_buff *skb,
+ __be32 saddr, __be32 daddr,
+ struct rtmsg *rtm, int nowait)
{
- int err;
- struct mr_table *mrt;
struct mfc_cache *cache;
- struct rtable *rt = skb_rtable(skb);
+ struct mr_table *mrt;
+ int err;
mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
if (mrt == NULL)
return -ENOENT;
rcu_read_lock();
- cache = ipmr_cache_find(mrt, rt->rt_src, rt->rt_dst);
+ cache = ipmr_cache_find(mrt, saddr, daddr);
if (cache == NULL) {
struct sk_buff *skb2;
@@ -2084,8 +2087,8 @@ int ipmr_get_route(struct net *net,
skb_reset_network_header(skb2);
iph = ip_hdr(skb2);
iph->ihl = sizeof(struct iphdr) >> 2;
- iph->saddr = rt->rt_src;
- iph->daddr = rt->rt_dst;
+ iph->saddr = saddr;
+ iph->daddr = daddr;
iph->version = 0;
err = ipmr_cache_unresolved(mrt, vif, skb2);
read_unlock(&mrt_lock);
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index f3c0b54..4614bab 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -221,9 +221,10 @@ static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook,
return csum;
}
-static int nf_ip_route(struct dst_entry **dst, struct flowi *fl)
+static int nf_ip_route(struct net *net, struct dst_entry **dst,
+ struct flowi *fl, bool strict __always_unused)
{
- struct rtable *rt = ip_route_output_key(&init_net, &fl->u.ip4);
+ struct rtable *rt = ip_route_output_key(net, &fl->u.ip4);
if (IS_ERR(rt))
return PTR_ERR(rt);
*dst = &rt->dst;
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 4b5d457..fd7a3f6 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -76,7 +76,7 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
}
/*
- * Unfortunatly, _b and _mask are not aligned to an int (or long int)
+ * Unfortunately, _b and _mask are not aligned to an int (or long int)
* Some arches dont care, unrolling the loop is a win on them.
* For other arches, we only have a 16bit alignement.
*/
@@ -260,6 +260,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
void *table_base;
const struct xt_table_info *private;
struct xt_action_param acpar;
+ unsigned int addend;
if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
return NF_DROP;
@@ -267,7 +268,8 @@ unsigned int arpt_do_table(struct sk_buff *skb,
indev = in ? in->name : nulldevname;
outdev = out ? out->name : nulldevname;
- xt_info_rdlock_bh();
+ local_bh_disable();
+ addend = xt_write_recseq_begin();
private = table->private;
table_base = private->entries[smp_processor_id()];
@@ -338,7 +340,8 @@ unsigned int arpt_do_table(struct sk_buff *skb,
/* Verdict */
break;
} while (!acpar.hotdrop);
- xt_info_rdunlock_bh();
+ xt_write_recseq_end(addend);
+ local_bh_enable();
if (acpar.hotdrop)
return NF_DROP;
@@ -712,7 +715,7 @@ static void get_counters(const struct xt_table_info *t,
unsigned int i;
for_each_possible_cpu(cpu) {
- seqlock_t *lock = &per_cpu(xt_info_locks, cpu).lock;
+ seqcount_t *s = &per_cpu(xt_recseq, cpu);
i = 0;
xt_entry_foreach(iter, t->entries[cpu], t->size) {
@@ -720,10 +723,10 @@ static void get_counters(const struct xt_table_info *t,
unsigned int start;
do {
- start = read_seqbegin(lock);
+ start = read_seqcount_begin(s);
bcnt = iter->counters.bcnt;
pcnt = iter->counters.pcnt;
- } while (read_seqretry(lock, start));
+ } while (read_seqcount_retry(s, start));
ADD_COUNTER(counters[i], bcnt, pcnt);
++i;
@@ -1115,6 +1118,7 @@ static int do_add_counters(struct net *net, const void __user *user,
int ret = 0;
void *loc_cpu_entry;
struct arpt_entry *iter;
+ unsigned int addend;
#ifdef CONFIG_COMPAT
struct compat_xt_counters_info compat_tmp;
@@ -1171,12 +1175,12 @@ static int do_add_counters(struct net *net, const void __user *user,
/* Choose the copy that is on our node */
curcpu = smp_processor_id();
loc_cpu_entry = private->entries[curcpu];
- xt_info_wrlock(curcpu);
+ addend = xt_write_recseq_begin();
xt_entry_foreach(iter, loc_cpu_entry, private->size) {
ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt);
++i;
}
- xt_info_wrunlock(curcpu);
+ xt_write_recseq_end(addend);
unlock_up_free:
local_bh_enable();
xt_table_unlock(t);
@@ -1874,7 +1878,7 @@ static int __init arp_tables_init(void)
if (ret < 0)
goto err1;
- /* Noone else will be downing sem now, so we won't sleep */
+ /* No one else will be downing sem now, so we won't sleep */
ret = xt_register_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
if (ret < 0)
goto err2;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index ffcea0d..7647438 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -68,15 +68,6 @@ void *ipt_alloc_initial_table(const struct xt_table *info)
}
EXPORT_SYMBOL_GPL(ipt_alloc_initial_table);
-/*
- We keep a set of rules for each CPU, so we can avoid write-locking
- them in the softirq when updating the counters and therefore
- only need to read-lock in the softirq; doing a write_lock_bh() in user
- context stops packets coming through and allows user context to read
- the counters or update the rules.
-
- Hence the start of any table is given by get_table() below. */
-
/* Returns whether matches rule or not. */
/* Performance critical - called for every packet */
static inline bool
@@ -311,6 +302,7 @@ ipt_do_table(struct sk_buff *skb,
unsigned int *stackptr, origptr, cpu;
const struct xt_table_info *private;
struct xt_action_param acpar;
+ unsigned int addend;
/* Initialization */
ip = ip_hdr(skb);
@@ -331,7 +323,8 @@ ipt_do_table(struct sk_buff *skb,
acpar.hooknum = hook;
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
- xt_info_rdlock_bh();
+ local_bh_disable();
+ addend = xt_write_recseq_begin();
private = table->private;
cpu = smp_processor_id();
table_base = private->entries[cpu];
@@ -430,7 +423,9 @@ ipt_do_table(struct sk_buff *skb,
pr_debug("Exiting %s; resetting sp from %u to %u\n",
__func__, *stackptr, origptr);
*stackptr = origptr;
- xt_info_rdunlock_bh();
+ xt_write_recseq_end(addend);
+ local_bh_enable();
+
#ifdef DEBUG_ALLOW_ALL
return NF_ACCEPT;
#else
@@ -886,7 +881,7 @@ get_counters(const struct xt_table_info *t,
unsigned int i;
for_each_possible_cpu(cpu) {
- seqlock_t *lock = &per_cpu(xt_info_locks, cpu).lock;
+ seqcount_t *s = &per_cpu(xt_recseq, cpu);
i = 0;
xt_entry_foreach(iter, t->entries[cpu], t->size) {
@@ -894,10 +889,10 @@ get_counters(const struct xt_table_info *t,
unsigned int start;
do {
- start = read_seqbegin(lock);
+ start = read_seqcount_begin(s);
bcnt = iter->counters.bcnt;
pcnt = iter->counters.pcnt;
- } while (read_seqretry(lock, start));
+ } while (read_seqcount_retry(s, start));
ADD_COUNTER(counters[i], bcnt, pcnt);
++i; /* macro does multi eval of i */
@@ -1312,6 +1307,7 @@ do_add_counters(struct net *net, const void __user *user,
int ret = 0;
void *loc_cpu_entry;
struct ipt_entry *iter;
+ unsigned int addend;
#ifdef CONFIG_COMPAT
struct compat_xt_counters_info compat_tmp;
@@ -1368,12 +1364,12 @@ do_add_counters(struct net *net, const void __user *user,
/* Choose the copy that is on our node */
curcpu = smp_processor_id();
loc_cpu_entry = private->entries[curcpu];
- xt_info_wrlock(curcpu);
+ addend = xt_write_recseq_begin();
xt_entry_foreach(iter, loc_cpu_entry, private->size) {
ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt);
++i;
}
- xt_info_wrunlock(curcpu);
+ xt_write_recseq_end(addend);
unlock_up_free:
local_bh_enable();
xt_table_unlock(t);
@@ -2233,7 +2229,7 @@ static int __init ip_tables_init(void)
if (ret < 0)
goto err1;
- /* Noone else will be downing sem now, so we won't sleep */
+ /* No one else will be downing sem now, so we won't sleep */
ret = xt_register_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
if (ret < 0)
goto err2;
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 21bcf47..9c71b27 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -521,7 +521,7 @@ int nf_nat_protocol_register(const struct nf_nat_protocol *proto)
}
EXPORT_SYMBOL(nf_nat_protocol_register);
-/* Noone stores the protocol anywhere; simply delete it. */
+/* No one stores the protocol anywhere; simply delete it. */
void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto)
{
spin_lock_bh(&nf_nat_lock);
@@ -532,7 +532,7 @@ void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto)
}
EXPORT_SYMBOL(nf_nat_protocol_unregister);
-/* Noone using conntrack by the time this called. */
+/* No one using conntrack by the time this called. */
static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
{
struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT);
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index 31427fb..99cfa28 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -153,7 +153,7 @@ void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
}
EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust);
-static void nf_nat_csum(struct sk_buff *skb, struct iphdr *iph, void *data,
+static void nf_nat_csum(struct sk_buff *skb, const struct iphdr *iph, void *data,
int datalen, __sum16 *check, int oldlen)
{
struct rtable *rt = skb_rtable(skb);
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 2d3c72e..a8659e0 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -154,7 +154,7 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
* RFC 1122: SHOULD pass TOS value up to the transport layer.
* -> It does. And not only TOS, but all IP header.
*/
-static int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
+static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
{
struct sock *sk;
struct hlist_head *head;
@@ -247,7 +247,7 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
}
if (inet->recverr) {
- struct iphdr *iph = (struct iphdr *)skb->data;
+ const struct iphdr *iph = (const struct iphdr *)skb->data;
u8 *payload = skb->data + (iph->ihl << 2);
if (inet->hdrincl)
@@ -265,7 +265,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
{
int hash;
struct sock *raw_sk;
- struct iphdr *iph;
+ const struct iphdr *iph;
struct net *net;
hash = protocol & (RAW_HTABLE_SIZE - 1);
@@ -273,7 +273,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
read_lock(&raw_v4_hashinfo.lock);
raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);
if (raw_sk != NULL) {
- iph = (struct iphdr *)skb->data;
+ iph = (const struct iphdr *)skb->data;
net = dev_net(skb->dev);
while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol,
@@ -281,7 +281,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
skb->dev->ifindex)) != NULL) {
raw_err(raw_sk, skb, info);
raw_sk = sk_next(raw_sk);
- iph = (struct iphdr *)skb->data;
+ iph = (const struct iphdr *)skb->data;
}
}
read_unlock(&raw_v4_hashinfo.lock);
@@ -460,6 +460,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
__be32 saddr;
u8 tos;
int err;
+ struct ip_options_data opt_copy;
err = -EMSGSIZE;
if (len > 0xFFFF)
@@ -520,8 +521,18 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
saddr = ipc.addr;
ipc.addr = daddr;
- if (!ipc.opt)
- ipc.opt = inet->opt;
+ if (!ipc.opt) {
+ struct ip_options_rcu *inet_opt;
+
+ rcu_read_lock();
+ inet_opt = rcu_dereference(inet->inet_opt);
+ if (inet_opt) {
+ memcpy(&opt_copy, inet_opt,
+ sizeof(*inet_opt) + inet_opt->opt.optlen);
+ ipc.opt = &opt_copy.opt;
+ }
+ rcu_read_unlock();
+ }
if (ipc.opt) {
err = -EINVAL;
@@ -530,10 +541,10 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
*/
if (inet->hdrincl)
goto done;
- if (ipc.opt->srr) {
+ if (ipc.opt->opt.srr) {
if (!daddr)
goto done;
- daddr = ipc.opt->faddr;
+ daddr = ipc.opt->opt.faddr;
}
}
tos = RT_CONN_FLAGS(sk);
@@ -548,17 +559,13 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
}
{
- struct flowi4 fl4 = {
- .flowi4_oif = ipc.oif,
- .flowi4_mark = sk->sk_mark,
- .daddr = daddr,
- .saddr = saddr,
- .flowi4_tos = tos,
- .flowi4_proto = (inet->hdrincl ?
- IPPROTO_RAW :
- sk->sk_protocol),
- .flowi4_flags = FLOWI_FLAG_CAN_SLEEP,
- };
+ struct flowi4 fl4;
+
+ flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
+ RT_SCOPE_UNIVERSE,
+ inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
+ FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0);
+
if (!inet->hdrincl) {
err = raw_probe_proto_opt(&fl4, msg);
if (err)
@@ -622,7 +629,7 @@ do_confirm:
static void raw_close(struct sock *sk, long timeout)
{
/*
- * Raw sockets may have direct kernel refereneces. Kill them.
+ * Raw sockets may have direct kernel references. Kill them.
*/
ip_ra_control(sk, 0, NULL);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 4b0c811..6a83840 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -424,7 +424,7 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v)
dst_metric(&r->dst, RTAX_WINDOW),
(int)((dst_metric(&r->dst, RTAX_RTT) >> 3) +
dst_metric(&r->dst, RTAX_RTTVAR)),
- r->rt_tos,
+ r->rt_key_tos,
r->dst.hh ? atomic_read(&r->dst.hh->hh_refcnt) : -1,
r->dst.hh ? (r->dst.hh->hh_output ==
dev_queue_xmit) : 0,
@@ -724,7 +724,7 @@ static inline int compare_keys(struct rtable *rt1, struct rtable *rt2)
return (((__force u32)rt1->rt_key_dst ^ (__force u32)rt2->rt_key_dst) |
((__force u32)rt1->rt_key_src ^ (__force u32)rt2->rt_key_src) |
(rt1->rt_mark ^ rt2->rt_mark) |
- (rt1->rt_tos ^ rt2->rt_tos) |
+ (rt1->rt_key_tos ^ rt2->rt_key_tos) |
(rt1->rt_oif ^ rt2->rt_oif) |
(rt1->rt_iif ^ rt2->rt_iif)) == 0;
}
@@ -821,7 +821,7 @@ static int has_noalias(const struct rtable *head, const struct rtable *rth)
}
/*
- * Pertubation of rt_genid by a small quantity [1..256]
+ * Perturbation of rt_genid by a small quantity [1..256]
* Using 8 bits of shuffling ensure we can call rt_cache_invalidate()
* many times (2^24) without giving recent rt_genid.
* Jenkins hash is strong enough that litle changes of rt_genid are OK.
@@ -1191,7 +1191,7 @@ restart:
#endif
/*
* Since lookup is lockfree, we must make sure
- * previous writes to rt are comitted to memory
+ * previous writes to rt are committed to memory
* before making rt visible to other CPUS.
*/
rcu_assign_pointer(rt_hash_table[hash].chain, rt);
@@ -1349,7 +1349,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
rt_genid(dev_net(dst->dev)));
#if RT_CACHE_DEBUG >= 1
printk(KERN_DEBUG "ipv4_negative_advice: redirect to %pI4/%02x dropped\n",
- &rt->rt_dst, rt->rt_tos);
+ &rt->rt_dst, rt->rt_key_tos);
#endif
rt_del(hash, rt);
ret = NULL;
@@ -1507,7 +1507,7 @@ static inline unsigned short guess_mtu(unsigned short old_mtu)
return 68;
}
-unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
+unsigned short ip_rt_frag_needed(struct net *net, const struct iphdr *iph,
unsigned short new_mtu,
struct net_device *dev)
{
@@ -1710,7 +1710,7 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
struct flowi4 fl4 = {
.daddr = rt->rt_key_dst,
.saddr = rt->rt_key_src,
- .flowi4_tos = rt->rt_tos,
+ .flowi4_tos = rt->rt_key_tos,
.flowi4_oif = rt->rt_oif,
.flowi4_iif = rt->rt_iif,
.flowi4_mark = rt->rt_mark,
@@ -1767,7 +1767,7 @@ static unsigned int ipv4_default_mtu(const struct dst_entry *dst)
return mtu;
}
-static void rt_init_metrics(struct rtable *rt, const struct flowi4 *oldflp4,
+static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
struct fib_info *fi)
{
struct inet_peer *peer;
@@ -1776,7 +1776,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *oldflp4,
/* If a peer entry exists for this destination, we must hook
* it up in order to get at cached metrics.
*/
- if (oldflp4 && (oldflp4->flowi4_flags & FLOWI_FLAG_PRECOW_METRICS))
+ if (fl4 && (fl4->flowi4_flags & FLOWI_FLAG_PRECOW_METRICS))
create = 1;
rt->peer = peer = inet_getpeer_v4(rt->rt_dst, create);
@@ -1803,7 +1803,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *oldflp4,
}
}
-static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *oldflp4,
+static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *fl4,
const struct fib_result *res,
struct fib_info *fi, u16 type, u32 itag)
{
@@ -1813,7 +1813,7 @@ static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *oldflp4,
if (FIB_RES_GW(*res) &&
FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
rt->rt_gateway = FIB_RES_GW(*res);
- rt_init_metrics(rt, oldflp4, fi);
+ rt_init_metrics(rt, fl4, fi);
#ifdef CONFIG_IP_ROUTE_CLASSID
dst->tclassid = FIB_RES_NH(*res).nh_tclassid;
#endif
@@ -1830,20 +1830,15 @@ static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *oldflp4,
#endif
set_class_tag(rt, itag);
#endif
- rt->rt_type = type;
}
-static struct rtable *rt_dst_alloc(bool nopolicy, bool noxfrm)
+static struct rtable *rt_dst_alloc(struct net_device *dev,
+ bool nopolicy, bool noxfrm)
{
- struct rtable *rt = dst_alloc(&ipv4_dst_ops, 1);
- if (rt) {
- rt->dst.obsolete = -1;
-
- rt->dst.flags = DST_HOST |
- (nopolicy ? DST_NOPOLICY : 0) |
- (noxfrm ? DST_NOXFRM : 0);
- }
- return rt;
+ return dst_alloc(&ipv4_dst_ops, dev, 1, -1,
+ DST_HOST |
+ (nopolicy ? DST_NOPOLICY : 0) |
+ (noxfrm ? DST_NOXFRM : 0));
}
/* called in rcu_read_lock() section */
@@ -1871,35 +1866,38 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
goto e_inval;
spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
} else {
- err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
- &itag, 0);
+ err = fib_validate_source(skb, saddr, 0, tos, 0, dev, &spec_dst,
+ &itag);
if (err < 0)
goto e_err;
}
- rth = rt_dst_alloc(IN_DEV_CONF_GET(in_dev, NOPOLICY), false);
+ rth = rt_dst_alloc(init_net.loopback_dev,
+ IN_DEV_CONF_GET(in_dev, NOPOLICY), false);
if (!rth)
goto e_nobufs;
+#ifdef CONFIG_IP_ROUTE_CLASSID
+ rth->dst.tclassid = itag;
+#endif
rth->dst.output = ip_rt_bug;
rth->rt_key_dst = daddr;
- rth->rt_dst = daddr;
- rth->rt_tos = tos;
- rth->rt_mark = skb->mark;
rth->rt_key_src = saddr;
+ rth->rt_genid = rt_genid(dev_net(dev));
+ rth->rt_flags = RTCF_MULTICAST;
+ rth->rt_type = RTN_MULTICAST;
+ rth->rt_key_tos = tos;
+ rth->rt_dst = daddr;
rth->rt_src = saddr;
-#ifdef CONFIG_IP_ROUTE_CLASSID
- rth->dst.tclassid = itag;
-#endif
+ rth->rt_route_iif = dev->ifindex;
rth->rt_iif = dev->ifindex;
- rth->dst.dev = init_net.loopback_dev;
- dev_hold(rth->dst.dev);
rth->rt_oif = 0;
+ rth->rt_mark = skb->mark;
rth->rt_gateway = daddr;
rth->rt_spec_dst= spec_dst;
- rth->rt_genid = rt_genid(dev_net(dev));
- rth->rt_flags = RTCF_MULTICAST;
- rth->rt_type = RTN_MULTICAST;
+ rth->rt_peer_genid = 0;
+ rth->peer = NULL;
+ rth->fi = NULL;
if (our) {
rth->dst.input= ip_local_deliver;
rth->rt_flags |= RTCF_LOCAL;
@@ -1980,8 +1978,8 @@ static int __mkroute_input(struct sk_buff *skb,
}
- err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(*res),
- in_dev->dev, &spec_dst, &itag, skb->mark);
+ err = fib_validate_source(skb, saddr, daddr, tos, FIB_RES_OIF(*res),
+ in_dev->dev, &spec_dst, &itag);
if (err < 0) {
ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr,
saddr);
@@ -2012,7 +2010,8 @@ static int __mkroute_input(struct sk_buff *skb,
}
}
- rth = rt_dst_alloc(IN_DEV_CONF_GET(in_dev, NOPOLICY),
+ rth = rt_dst_alloc(out_dev->dev,
+ IN_DEV_CONF_GET(in_dev, NOPOLICY),
IN_DEV_CONF_GET(out_dev, NOXFRM));
if (!rth) {
err = -ENOBUFS;
@@ -2020,26 +2019,28 @@ static int __mkroute_input(struct sk_buff *skb,
}
rth->rt_key_dst = daddr;
- rth->rt_dst = daddr;
- rth->rt_tos = tos;
- rth->rt_mark = skb->mark;
rth->rt_key_src = saddr;
+ rth->rt_genid = rt_genid(dev_net(rth->dst.dev));
+ rth->rt_flags = flags;
+ rth->rt_type = res->type;
+ rth->rt_key_tos = tos;
+ rth->rt_dst = daddr;
rth->rt_src = saddr;
- rth->rt_gateway = daddr;
+ rth->rt_route_iif = in_dev->dev->ifindex;
rth->rt_iif = in_dev->dev->ifindex;
- rth->dst.dev = (out_dev)->dev;
- dev_hold(rth->dst.dev);
rth->rt_oif = 0;
+ rth->rt_mark = skb->mark;
+ rth->rt_gateway = daddr;
rth->rt_spec_dst= spec_dst;
+ rth->rt_peer_genid = 0;
+ rth->peer = NULL;
+ rth->fi = NULL;
rth->dst.input = ip_forward;
rth->dst.output = ip_output;
- rth->rt_genid = rt_genid(dev_net(rth->dst.dev));
rt_set_nexthop(rth, NULL, res, res->fi, res->type, itag);
- rth->rt_flags = flags;
-
*result = rth;
err = 0;
cleanup:
@@ -2148,9 +2149,9 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
goto brd_input;
if (res.type == RTN_LOCAL) {
- err = fib_validate_source(saddr, daddr, tos,
+ err = fib_validate_source(skb, saddr, daddr, tos,
net->loopback_dev->ifindex,
- dev, &spec_dst, &itag, skb->mark);
+ dev, &spec_dst, &itag);
if (err < 0)
goto martian_source_keep_err;
if (err)
@@ -2174,8 +2175,8 @@ brd_input:
if (ipv4_is_zeronet(saddr))
spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
else {
- err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
- &itag, skb->mark);
+ err = fib_validate_source(skb, saddr, 0, tos, 0, dev, &spec_dst,
+ &itag);
if (err < 0)
goto martian_source_keep_err;
if (err)
@@ -2186,35 +2187,42 @@ brd_input:
RT_CACHE_STAT_INC(in_brd);
local_input:
- rth = rt_dst_alloc(IN_DEV_CONF_GET(in_dev, NOPOLICY), false);
+ rth = rt_dst_alloc(net->loopback_dev,
+ IN_DEV_CONF_GET(in_dev, NOPOLICY), false);
if (!rth)
goto e_nobufs;
+ rth->dst.input= ip_local_deliver;
rth->dst.output= ip_rt_bug;
- rth->rt_genid = rt_genid(net);
+#ifdef CONFIG_IP_ROUTE_CLASSID
+ rth->dst.tclassid = itag;
+#endif
rth->rt_key_dst = daddr;
- rth->rt_dst = daddr;
- rth->rt_tos = tos;
- rth->rt_mark = skb->mark;
rth->rt_key_src = saddr;
+ rth->rt_genid = rt_genid(net);
+ rth->rt_flags = flags|RTCF_LOCAL;
+ rth->rt_type = res.type;
+ rth->rt_key_tos = tos;
+ rth->rt_dst = daddr;
rth->rt_src = saddr;
#ifdef CONFIG_IP_ROUTE_CLASSID
rth->dst.tclassid = itag;
#endif
+ rth->rt_route_iif = dev->ifindex;
rth->rt_iif = dev->ifindex;
- rth->dst.dev = net->loopback_dev;
- dev_hold(rth->dst.dev);
+ rth->rt_oif = 0;
+ rth->rt_mark = skb->mark;
rth->rt_gateway = daddr;
rth->rt_spec_dst= spec_dst;
- rth->dst.input= ip_local_deliver;
- rth->rt_flags = flags|RTCF_LOCAL;
+ rth->rt_peer_genid = 0;
+ rth->peer = NULL;
+ rth->fi = NULL;
if (res.type == RTN_UNREACHABLE) {
rth->dst.input= ip_error;
rth->dst.error= -err;
rth->rt_flags &= ~RTCF_LOCAL;
}
- rth->rt_type = res.type;
hash = rt_hash(daddr, saddr, fl4.flowi4_iif, rt_genid(net));
rth = rt_intern_hash(hash, rth, skb, fl4.flowi4_iif);
err = 0;
@@ -2285,7 +2293,7 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
((__force u32)rth->rt_key_src ^ (__force u32)saddr) |
(rth->rt_iif ^ iif) |
rth->rt_oif |
- (rth->rt_tos ^ tos)) == 0 &&
+ (rth->rt_key_tos ^ tos)) == 0 &&
rth->rt_mark == skb->mark &&
net_eq(dev_net(rth->dst.dev), net) &&
!rt_is_expired(rth)) {
@@ -2346,12 +2354,12 @@ EXPORT_SYMBOL(ip_route_input_common);
/* called with rcu_read_lock() */
static struct rtable *__mkroute_output(const struct fib_result *res,
const struct flowi4 *fl4,
- const struct flowi4 *oldflp4,
- struct net_device *dev_out,
+ __be32 orig_daddr, __be32 orig_saddr,
+ int orig_oif, struct net_device *dev_out,
unsigned int flags)
{
struct fib_info *fi = res->fi;
- u32 tos = RT_FL_TOS(oldflp4);
+ u32 tos = RT_FL_TOS(fl4);
struct in_device *in_dev;
u16 type = res->type;
struct rtable *rth;
@@ -2378,8 +2386,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
fi = NULL;
} else if (type == RTN_MULTICAST) {
flags |= RTCF_MULTICAST | RTCF_LOCAL;
- if (!ip_check_mc_rcu(in_dev, oldflp4->daddr, oldflp4->saddr,
- oldflp4->flowi4_proto))
+ if (!ip_check_mc_rcu(in_dev, fl4->daddr, fl4->saddr,
+ fl4->flowi4_proto))
flags &= ~RTCF_LOCAL;
/* If multicast route do not exist use
* default one, but do not gateway in this case.
@@ -2389,28 +2397,31 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
fi = NULL;
}
- rth = rt_dst_alloc(IN_DEV_CONF_GET(in_dev, NOPOLICY),
+ rth = rt_dst_alloc(dev_out,
+ IN_DEV_CONF_GET(in_dev, NOPOLICY),
IN_DEV_CONF_GET(in_dev, NOXFRM));
if (!rth)
return ERR_PTR(-ENOBUFS);
- rth->rt_key_dst = oldflp4->daddr;
- rth->rt_tos = tos;
- rth->rt_key_src = oldflp4->saddr;
- rth->rt_oif = oldflp4->flowi4_oif;
- rth->rt_mark = oldflp4->flowi4_mark;
+ rth->dst.output = ip_output;
+
+ rth->rt_key_dst = orig_daddr;
+ rth->rt_key_src = orig_saddr;
+ rth->rt_genid = rt_genid(dev_net(dev_out));
+ rth->rt_flags = flags;
+ rth->rt_type = type;
+ rth->rt_key_tos = tos;
rth->rt_dst = fl4->daddr;
rth->rt_src = fl4->saddr;
- rth->rt_iif = 0;
- /* get references to the devices that are to be hold by the routing
- cache entry */
- rth->dst.dev = dev_out;
- dev_hold(dev_out);
+ rth->rt_route_iif = 0;
+ rth->rt_iif = orig_oif ? : dev_out->ifindex;
+ rth->rt_oif = orig_oif;
+ rth->rt_mark = fl4->flowi4_mark;
rth->rt_gateway = fl4->daddr;
rth->rt_spec_dst= fl4->saddr;
-
- rth->dst.output=ip_output;
- rth->rt_genid = rt_genid(dev_net(dev_out));
+ rth->rt_peer_genid = 0;
+ rth->peer = NULL;
+ rth->fi = NULL;
RT_CACHE_STAT_INC(out_slow_tot);
@@ -2428,7 +2439,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
#ifdef CONFIG_IP_MROUTE
if (type == RTN_MULTICAST) {
if (IN_DEV_MFORWARD(in_dev) &&
- !ipv4_is_local_multicast(oldflp4->daddr)) {
+ !ipv4_is_local_multicast(fl4->daddr)) {
rth->dst.input = ip_mr_input;
rth->dst.output = ip_mc_output;
}
@@ -2436,9 +2447,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
#endif
}
- rt_set_nexthop(rth, oldflp4, res, fi, type, 0);
+ rt_set_nexthop(rth, fl4, res, fi, type, 0);
- rth->rt_flags = flags;
return rth;
}
@@ -2447,36 +2457,37 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
* called with rcu_read_lock();
*/
-static struct rtable *ip_route_output_slow(struct net *net,
- const struct flowi4 *oldflp4)
+static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4)
{
- u32 tos = RT_FL_TOS(oldflp4);
- struct flowi4 fl4;
- struct fib_result res;
- unsigned int flags = 0;
struct net_device *dev_out = NULL;
+ u32 tos = RT_FL_TOS(fl4);
+ unsigned int flags = 0;
+ struct fib_result res;
struct rtable *rth;
+ __be32 orig_daddr;
+ __be32 orig_saddr;
+ int orig_oif;
res.fi = NULL;
#ifdef CONFIG_IP_MULTIPLE_TABLES
res.r = NULL;
#endif
- fl4.flowi4_oif = oldflp4->flowi4_oif;
- fl4.flowi4_iif = net->loopback_dev->ifindex;
- fl4.flowi4_mark = oldflp4->flowi4_mark;
- fl4.daddr = oldflp4->daddr;
- fl4.saddr = oldflp4->saddr;
- fl4.flowi4_tos = tos & IPTOS_RT_MASK;
- fl4.flowi4_scope = ((tos & RTO_ONLINK) ?
- RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
+ orig_daddr = fl4->daddr;
+ orig_saddr = fl4->saddr;
+ orig_oif = fl4->flowi4_oif;
+
+ fl4->flowi4_iif = net->loopback_dev->ifindex;
+ fl4->flowi4_tos = tos & IPTOS_RT_MASK;
+ fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
+ RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
rcu_read_lock();
- if (oldflp4->saddr) {
+ if (fl4->saddr) {
rth = ERR_PTR(-EINVAL);
- if (ipv4_is_multicast(oldflp4->saddr) ||
- ipv4_is_lbcast(oldflp4->saddr) ||
- ipv4_is_zeronet(oldflp4->saddr))
+ if (ipv4_is_multicast(fl4->saddr) ||
+ ipv4_is_lbcast(fl4->saddr) ||
+ ipv4_is_zeronet(fl4->saddr))
goto out;
/* I removed check for oif == dev_out->oif here.
@@ -2487,11 +2498,11 @@ static struct rtable *ip_route_output_slow(struct net *net,
of another iface. --ANK
*/
- if (oldflp4->flowi4_oif == 0 &&
- (ipv4_is_multicast(oldflp4->daddr) ||
- ipv4_is_lbcast(oldflp4->daddr))) {
+ if (fl4->flowi4_oif == 0 &&
+ (ipv4_is_multicast(fl4->daddr) ||
+ ipv4_is_lbcast(fl4->daddr))) {
/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
- dev_out = __ip_dev_find(net, oldflp4->saddr, false);
+ dev_out = __ip_dev_find(net, fl4->saddr, false);
if (dev_out == NULL)
goto out;
@@ -2510,20 +2521,20 @@ static struct rtable *ip_route_output_slow(struct net *net,
Luckily, this hack is good workaround.
*/
- fl4.flowi4_oif = dev_out->ifindex;
+ fl4->flowi4_oif = dev_out->ifindex;
goto make_route;
}
- if (!(oldflp4->flowi4_flags & FLOWI_FLAG_ANYSRC)) {
+ if (!(fl4->flowi4_flags & FLOWI_FLAG_ANYSRC)) {
/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
- if (!__ip_dev_find(net, oldflp4->saddr, false))
+ if (!__ip_dev_find(net, fl4->saddr, false))
goto out;
}
}
- if (oldflp4->flowi4_oif) {
- dev_out = dev_get_by_index_rcu(net, oldflp4->flowi4_oif);
+ if (fl4->flowi4_oif) {
+ dev_out = dev_get_by_index_rcu(net, fl4->flowi4_oif);
rth = ERR_PTR(-ENODEV);
if (dev_out == NULL)
goto out;
@@ -2533,37 +2544,37 @@ static struct rtable *ip_route_output_slow(struct net *net,
rth = ERR_PTR(-ENETUNREACH);
goto out;
}
- if (ipv4_is_local_multicast(oldflp4->daddr) ||
- ipv4_is_lbcast(oldflp4->daddr)) {
- if (!fl4.saddr)
- fl4.saddr = inet_select_addr(dev_out, 0,
- RT_SCOPE_LINK);
+ if (ipv4_is_local_multicast(fl4->daddr) ||
+ ipv4_is_lbcast(fl4->daddr)) {
+ if (!fl4->saddr)
+ fl4->saddr = inet_select_addr(dev_out, 0,
+ RT_SCOPE_LINK);
goto make_route;
}
- if (!fl4.saddr) {
- if (ipv4_is_multicast(oldflp4->daddr))
- fl4.saddr = inet_select_addr(dev_out, 0,
- fl4.flowi4_scope);
- else if (!oldflp4->daddr)
- fl4.saddr = inet_select_addr(dev_out, 0,
- RT_SCOPE_HOST);
+ if (fl4->saddr) {
+ if (ipv4_is_multicast(fl4->daddr))
+ fl4->saddr = inet_select_addr(dev_out, 0,
+ fl4->flowi4_scope);
+ else if (!fl4->daddr)
+ fl4->saddr = inet_select_addr(dev_out, 0,
+ RT_SCOPE_HOST);
}
}
- if (!fl4.daddr) {
- fl4.daddr = fl4.saddr;
- if (!fl4.daddr)
- fl4.daddr = fl4.saddr = htonl(INADDR_LOOPBACK);
+ if (!fl4->daddr) {
+ fl4->daddr = fl4->saddr;
+ if (!fl4->daddr)
+ fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK);
dev_out = net->loopback_dev;
- fl4.flowi4_oif = net->loopback_dev->ifindex;
+ fl4->flowi4_oif = net->loopback_dev->ifindex;
res.type = RTN_LOCAL;
flags |= RTCF_LOCAL;
goto make_route;
}
- if (fib_lookup(net, &fl4, &res)) {
+ if (fib_lookup(net, fl4, &res)) {
res.fi = NULL;
- if (oldflp4->flowi4_oif) {
+ if (fl4->flowi4_oif) {
/* Apparently, routing tables are wrong. Assume,
that the destination is on link.
@@ -2582,9 +2593,9 @@ static struct rtable *ip_route_output_slow(struct net *net,
likely IPv6, but we do not.
*/
- if (fl4.saddr == 0)
- fl4.saddr = inet_select_addr(dev_out, 0,
- RT_SCOPE_LINK);
+ if (fl4->saddr == 0)
+ fl4->saddr = inet_select_addr(dev_out, 0,
+ RT_SCOPE_LINK);
res.type = RTN_UNICAST;
goto make_route;
}
@@ -2593,42 +2604,45 @@ static struct rtable *ip_route_output_slow(struct net *net,
}
if (res.type == RTN_LOCAL) {
- if (!fl4.saddr) {
+ if (!fl4->saddr) {
if (res.fi->fib_prefsrc)
- fl4.saddr = res.fi->fib_prefsrc;
+ fl4->saddr = res.fi->fib_prefsrc;
else
- fl4.saddr = fl4.daddr;
+ fl4->saddr = fl4->daddr;
}
dev_out = net->loopback_dev;
- fl4.flowi4_oif = dev_out->ifindex;
+ fl4->flowi4_oif = dev_out->ifindex;
res.fi = NULL;
flags |= RTCF_LOCAL;
goto make_route;
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH
- if (res.fi->fib_nhs > 1 && fl4.flowi4_oif == 0)
+ if (res.fi->fib_nhs > 1 && fl4->flowi4_oif == 0)
fib_select_multipath(&res);
else
#endif
- if (!res.prefixlen && res.type == RTN_UNICAST && !fl4.flowi4_oif)
+ if (!res.prefixlen &&
+ res.table->tb_num_default > 1 &&
+ res.type == RTN_UNICAST && !fl4->flowi4_oif)
fib_select_default(&res);
- if (!fl4.saddr)
- fl4.saddr = FIB_RES_PREFSRC(net, res);
+ if (!fl4->saddr)
+ fl4->saddr = FIB_RES_PREFSRC(net, res);
dev_out = FIB_RES_DEV(res);
- fl4.flowi4_oif = dev_out->ifindex;
+ fl4->flowi4_oif = dev_out->ifindex;
make_route:
- rth = __mkroute_output(&res, &fl4, oldflp4, dev_out, flags);
+ rth = __mkroute_output(&res, fl4, orig_daddr, orig_saddr, orig_oif,
+ dev_out, flags);
if (!IS_ERR(rth)) {
unsigned int hash;
- hash = rt_hash(oldflp4->daddr, oldflp4->saddr, oldflp4->flowi4_oif,
+ hash = rt_hash(orig_daddr, orig_saddr, orig_oif,
rt_genid(dev_net(dev_out)));
- rth = rt_intern_hash(hash, rth, NULL, oldflp4->flowi4_oif);
+ rth = rt_intern_hash(hash, rth, NULL, orig_oif);
}
out:
@@ -2636,7 +2650,7 @@ out:
return rth;
}
-struct rtable *__ip_route_output_key(struct net *net, const struct flowi4 *flp4)
+struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *flp4)
{
struct rtable *rth;
unsigned int hash;
@@ -2654,13 +2668,17 @@ struct rtable *__ip_route_output_key(struct net *net, const struct flowi4 *flp4)
rt_is_output_route(rth) &&
rth->rt_oif == flp4->flowi4_oif &&
rth->rt_mark == flp4->flowi4_mark &&
- !((rth->rt_tos ^ flp4->flowi4_tos) &
+ !((rth->rt_key_tos ^ flp4->flowi4_tos) &
(IPTOS_RT_MASK | RTO_ONLINK)) &&
net_eq(dev_net(rth->dst.dev), net) &&
!rt_is_expired(rth)) {
dst_use(&rth->dst, jiffies);
RT_CACHE_STAT_INC(out_hit);
rcu_read_unlock_bh();
+ if (!flp4->saddr)
+ flp4->saddr = rth->rt_src;
+ if (!flp4->daddr)
+ flp4->daddr = rth->rt_dst;
return rth;
}
RT_CACHE_STAT_INC(out_hlist_search);
@@ -2686,6 +2704,12 @@ static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
{
}
+static u32 *ipv4_rt_blackhole_cow_metrics(struct dst_entry *dst,
+ unsigned long old)
+{
+ return NULL;
+}
+
static struct dst_ops ipv4_dst_blackhole_ops = {
.family = AF_INET,
.protocol = cpu_to_be16(ETH_P_IP),
@@ -2694,11 +2718,12 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
.default_mtu = ipv4_blackhole_default_mtu,
.default_advmss = ipv4_default_advmss,
.update_pmtu = ipv4_rt_blackhole_update_pmtu,
+ .cow_metrics = ipv4_rt_blackhole_cow_metrics,
};
struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig)
{
- struct rtable *rt = dst_alloc(&ipv4_dst_blackhole_ops, 1);
+ struct rtable *rt = dst_alloc(&ipv4_dst_blackhole_ops, NULL, 1, 0, 0);
struct rtable *ort = (struct rtable *) dst_orig;
if (rt) {
@@ -2715,7 +2740,8 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
rt->rt_key_dst = ort->rt_key_dst;
rt->rt_key_src = ort->rt_key_src;
- rt->rt_tos = ort->rt_tos;
+ rt->rt_key_tos = ort->rt_key_tos;
+ rt->rt_route_iif = ort->rt_route_iif;
rt->rt_iif = ort->rt_iif;
rt->rt_oif = ort->rt_oif;
rt->rt_mark = ort->rt_mark;
@@ -2725,7 +2751,6 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
rt->rt_type = ort->rt_type;
rt->rt_dst = ort->rt_dst;
rt->rt_src = ort->rt_src;
- rt->rt_iif = ort->rt_iif;
rt->rt_gateway = ort->rt_gateway;
rt->rt_spec_dst = ort->rt_spec_dst;
rt->peer = ort->peer;
@@ -2751,15 +2776,10 @@ struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4,
if (IS_ERR(rt))
return rt;
- if (flp4->flowi4_proto) {
- if (!flp4->saddr)
- flp4->saddr = rt->rt_src;
- if (!flp4->daddr)
- flp4->daddr = rt->rt_dst;
+ if (flp4->flowi4_proto)
rt = (struct rtable *) xfrm_lookup(net, &rt->dst,
flowi4_to_flowi(flp4),
sk, 0);
- }
return rt;
}
@@ -2783,7 +2803,7 @@ static int rt_fill_info(struct net *net,
r->rtm_family = AF_INET;
r->rtm_dst_len = 32;
r->rtm_src_len = 0;
- r->rtm_tos = rt->rt_tos;
+ r->rtm_tos = rt->rt_key_tos;
r->rtm_table = RT_TABLE_MAIN;
NLA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN);
r->rtm_type = rt->rt_type;
@@ -2837,7 +2857,9 @@ static int rt_fill_info(struct net *net,
if (ipv4_is_multicast(dst) && !ipv4_is_local_multicast(dst) &&
IPV4_DEVCONF_ALL(net, MC_FORWARDING)) {
- int err = ipmr_get_route(net, skb, r, nowait);
+ int err = ipmr_get_route(net, skb,
+ rt->rt_src, rt->rt_dst,
+ r, nowait);
if (err <= 0) {
if (!nowait) {
if (err == 0)
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 8b44c6d..2646149 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -321,10 +321,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
* the ACK carries the same options again (see RFC1122 4.2.3.8)
*/
if (opt && opt->optlen) {
- int opt_size = sizeof(struct ip_options) + opt->optlen;
+ int opt_size = sizeof(struct ip_options_rcu) + opt->optlen;
ireq->opt = kmalloc(opt_size, GFP_ATOMIC);
- if (ireq->opt != NULL && ip_options_echo(ireq->opt, skb)) {
+ if (ireq->opt != NULL && ip_options_echo(&ireq->opt->opt, skb)) {
kfree(ireq->opt);
ireq->opt = NULL;
}
@@ -345,17 +345,13 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
* no easy way to do this.
*/
{
- struct flowi4 fl4 = {
- .flowi4_mark = sk->sk_mark,
- .daddr = ((opt && opt->srr) ?
- opt->faddr : ireq->rmt_addr),
- .saddr = ireq->loc_addr,
- .flowi4_tos = RT_CONN_FLAGS(sk),
- .flowi4_proto = IPPROTO_TCP,
- .flowi4_flags = inet_sk_flowi_flags(sk),
- .fl4_sport = th->dest,
- .fl4_dport = th->source,
- };
+ struct flowi4 fl4;
+
+ flowi4_init_output(&fl4, 0, sk->sk_mark, RT_CONN_FLAGS(sk),
+ RT_SCOPE_UNIVERSE, IPPROTO_TCP,
+ inet_sk_flowi_flags(sk),
+ (opt && opt->srr) ? opt->faddr : ireq->rmt_addr,
+ ireq->loc_addr, th->source, th->dest);
security_req_classify_flow(req, flowi4_to_flowi(&fl4));
rt = ip_route_output_key(sock_net(sk), &fl4);
if (IS_ERR(rt)) {
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 1a45665..321e6e8 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -311,7 +311,6 @@ static struct ctl_table ipv4_table[] = {
.mode = 0644,
.proc_handler = proc_do_large_bitmap,
},
-#ifdef CONFIG_IP_MULTICAST
{
.procname = "igmp_max_memberships",
.data = &sysctl_igmp_max_memberships,
@@ -319,8 +318,6 @@ static struct ctl_table ipv4_table[] = {
.mode = 0644,
.proc_handler = proc_dointvec
},
-
-#endif
{
.procname = "igmp_max_msf",
.data = &sysctl_igmp_max_msf,
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index b22d450..054a59d 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -999,7 +999,8 @@ new_segment:
/* We have some space in skb head. Superb! */
if (copy > skb_tailroom(skb))
copy = skb_tailroom(skb);
- if ((err = skb_add_data(skb, from, copy)) != 0)
+ err = skb_add_data_nocache(sk, skb, from, copy);
+ if (err)
goto do_fault;
} else {
int merge = 0;
@@ -1042,8 +1043,8 @@ new_segment:
/* Time to copy data. We are close to
* the end! */
- err = skb_copy_to_page(sk, from, skb, page,
- off, copy);
+ err = skb_copy_to_page_nocache(sk, from, skb,
+ page, off, copy);
if (err) {
/* If this page was new, give it to the
* socket so it does not get leaked.
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index f7e6c2c..f3d16d8 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -146,13 +146,15 @@ EXPORT_SYMBOL_GPL(tcp_twsk_unique);
/* This will initiate an outgoing connection. */
int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
+ struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
struct inet_sock *inet = inet_sk(sk);
struct tcp_sock *tp = tcp_sk(sk);
- struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
__be16 orig_sport, orig_dport;
- struct rtable *rt;
__be32 daddr, nexthop;
+ struct flowi4 fl4;
+ struct rtable *rt;
int err;
+ struct ip_options_rcu *inet_opt;
if (addr_len < sizeof(struct sockaddr_in))
return -EINVAL;
@@ -161,15 +163,17 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
return -EAFNOSUPPORT;
nexthop = daddr = usin->sin_addr.s_addr;
- if (inet->opt && inet->opt->srr) {
+ inet_opt = rcu_dereference_protected(inet->inet_opt,
+ sock_owned_by_user(sk));
+ if (inet_opt && inet_opt->opt.srr) {
if (!daddr)
return -EINVAL;
- nexthop = inet->opt->faddr;
+ nexthop = inet_opt->opt.faddr;
}
orig_sport = inet->inet_sport;
orig_dport = usin->sin_port;
- rt = ip_route_connect(nexthop, inet->inet_saddr,
+ rt = ip_route_connect(&fl4, nexthop, inet->inet_saddr,
RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
IPPROTO_TCP,
orig_sport, orig_dport, sk, true);
@@ -185,11 +189,11 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
return -ENETUNREACH;
}
- if (!inet->opt || !inet->opt->srr)
- daddr = rt->rt_dst;
+ if (!inet_opt || !inet_opt->opt.srr)
+ daddr = fl4.daddr;
if (!inet->inet_saddr)
- inet->inet_saddr = rt->rt_src;
+ inet->inet_saddr = fl4.saddr;
inet->inet_rcv_saddr = inet->inet_saddr;
if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr) {
@@ -200,7 +204,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
}
if (tcp_death_row.sysctl_tw_recycle &&
- !tp->rx_opt.ts_recent_stamp && rt->rt_dst == daddr) {
+ !tp->rx_opt.ts_recent_stamp && fl4.daddr == daddr) {
struct inet_peer *peer = rt_get_peer(rt);
/*
* VJ's idea. We save last timestamp seen from
@@ -221,8 +225,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
inet->inet_daddr = daddr;
inet_csk(sk)->icsk_ext_hdr_len = 0;
- if (inet->opt)
- inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen;
+ if (inet_opt)
+ inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
tp->rx_opt.mss_clamp = TCP_MSS_DEFAULT;
@@ -236,8 +240,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (err)
goto failure;
- rt = ip_route_newports(rt, IPPROTO_TCP,
- orig_sport, orig_dport,
+ rt = ip_route_newports(&fl4, rt, orig_sport, orig_dport,
inet->inet_sport, inet->inet_dport, sk);
if (IS_ERR(rt)) {
err = PTR_ERR(rt);
@@ -279,7 +282,7 @@ EXPORT_SYMBOL(tcp_v4_connect);
/*
* This routine does path mtu discovery as defined in RFC1191.
*/
-static void do_pmtu_discovery(struct sock *sk, struct iphdr *iph, u32 mtu)
+static void do_pmtu_discovery(struct sock *sk, const struct iphdr *iph, u32 mtu)
{
struct dst_entry *dst;
struct inet_sock *inet = inet_sk(sk);
@@ -341,7 +344,7 @@ static void do_pmtu_discovery(struct sock *sk, struct iphdr *iph, u32 mtu)
void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
{
- struct iphdr *iph = (struct iphdr *)icmp_skb->data;
+ const struct iphdr *iph = (const struct iphdr *)icmp_skb->data;
struct tcphdr *th = (struct tcphdr *)(icmp_skb->data + (iph->ihl << 2));
struct inet_connection_sock *icsk;
struct tcp_sock *tp;
@@ -820,17 +823,18 @@ static void syn_flood_warning(const struct sk_buff *skb)
/*
* Save and compile IPv4 options into the request_sock if needed.
*/
-static struct ip_options *tcp_v4_save_options(struct sock *sk,
- struct sk_buff *skb)
+static struct ip_options_rcu *tcp_v4_save_options(struct sock *sk,
+ struct sk_buff *skb)
{
- struct ip_options *opt = &(IPCB(skb)->opt);
- struct ip_options *dopt = NULL;
+ const struct ip_options *opt = &(IPCB(skb)->opt);
+ struct ip_options_rcu *dopt = NULL;
if (opt && opt->optlen) {
- int opt_size = optlength(opt);
+ int opt_size = sizeof(*dopt) + opt->optlen;
+
dopt = kmalloc(opt_size, GFP_ATOMIC);
if (dopt) {
- if (ip_options_echo(dopt, skb)) {
+ if (ip_options_echo(&dopt->opt, skb)) {
kfree(dopt);
dopt = NULL;
}
@@ -1411,6 +1415,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
#ifdef CONFIG_TCP_MD5SIG
struct tcp_md5sig_key *key;
#endif
+ struct ip_options_rcu *inet_opt;
if (sk_acceptq_is_full(sk))
goto exit_overflow;
@@ -1431,13 +1436,14 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newinet->inet_daddr = ireq->rmt_addr;
newinet->inet_rcv_saddr = ireq->loc_addr;
newinet->inet_saddr = ireq->loc_addr;
- newinet->opt = ireq->opt;
+ inet_opt = ireq->opt;
+ rcu_assign_pointer(newinet->inet_opt, inet_opt);
ireq->opt = NULL;
newinet->mc_index = inet_iif(skb);
newinet->mc_ttl = ip_hdr(skb)->ttl;
inet_csk(newsk)->icsk_ext_hdr_len = 0;
- if (newinet->opt)
- inet_csk(newsk)->icsk_ext_hdr_len = newinet->opt->optlen;
+ if (inet_opt)
+ inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
newinet->inet_id = newtp->write_seq ^ jiffies;
tcp_mtup_init(newsk);
@@ -2527,7 +2533,7 @@ void tcp4_proc_exit(void)
struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb)
{
- struct iphdr *iph = skb_gro_network_header(skb);
+ const struct iphdr *iph = skb_gro_network_header(skb);
switch (skb->ip_summed) {
case CHECKSUM_COMPLETE:
@@ -2548,7 +2554,7 @@ struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb)
int tcp4_gro_complete(struct sk_buff *skb)
{
- struct iphdr *iph = ip_hdr(skb);
+ const struct iphdr *iph = ip_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb),
diff --git a/net/ipv4/tcp_lp.c b/net/ipv4/tcp_lp.c
index 656d431..72f7218 100644
--- a/net/ipv4/tcp_lp.c
+++ b/net/ipv4/tcp_lp.c
@@ -12,7 +12,7 @@
* within cong_avoid.
* o Error correcting in remote HZ, therefore remote HZ will be keeped
* on checking and updating.
- * o Handling calculation of One-Way-Delay (OWD) within rtt_sample, sicne
+ * o Handling calculation of One-Way-Delay (OWD) within rtt_sample, since
* OWD have a similar meaning as RTT. Also correct the buggy formular.
* o Handle reaction for Early Congestion Indication (ECI) within
* pkts_acked, as mentioned within pseudo code.
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 8b0d016..17388c7 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -73,7 +73,7 @@ static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb)
tcp_advance_send_head(sk, skb);
tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
- /* Don't override Nagle indefinately with F-RTO */
+ /* Don't override Nagle indefinitely with F-RTO */
if (tp->frto_counter == 2)
tp->frto_counter = 3;
diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c
index dc7f431..05c3b6f 100644
--- a/net/ipv4/tcp_yeah.c
+++ b/net/ipv4/tcp_yeah.c
@@ -20,7 +20,7 @@
#define TCP_YEAH_DELTA 3 //log minimum fraction of cwnd to be removed on loss
#define TCP_YEAH_EPSILON 1 //log maximum fraction to be removed on early decongestion
#define TCP_YEAH_PHY 8 //lin maximum delta from base
-#define TCP_YEAH_RHO 16 //lin minumum number of consecutive rtt to consider competition on loss
+#define TCP_YEAH_RHO 16 //lin minimum number of consecutive rtt to consider competition on loss
#define TCP_YEAH_ZETA 50 //lin minimum number of state switchs to reset reno_count
#define TCP_SCALABLE_AI_CNT 100U
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 588f47a..544f435 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -189,7 +189,7 @@ static int udp_lib_lport_inuse2(struct net *net, __u16 num,
* @sk: socket struct in question
* @snum: port number to look up
* @saddr_comp: AF-dependent comparison of bound local IP addresses
- * @hash2_nulladdr: AF-dependant hash value in secondary hash chains,
+ * @hash2_nulladdr: AF-dependent hash value in secondary hash chains,
* with NULL address
*/
int udp_lib_get_port(struct sock *sk, unsigned short snum,
@@ -578,7 +578,7 @@ found:
void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
{
struct inet_sock *inet;
- struct iphdr *iph = (struct iphdr *)skb->data;
+ const struct iphdr *iph = (const struct iphdr *)skb->data;
struct udphdr *uh = (struct udphdr *)(skb->data+(iph->ihl<<2));
const int type = icmp_hdr(skb)->type;
const int code = icmp_hdr(skb)->code;
@@ -804,6 +804,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
struct sk_buff *skb;
+ struct ip_options_data opt_copy;
if (len > 0xFFFF)
return -EMSGSIZE;
@@ -877,22 +878,32 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
free = 1;
connected = 0;
}
- if (!ipc.opt)
- ipc.opt = inet->opt;
+ if (!ipc.opt) {
+ struct ip_options_rcu *inet_opt;
+
+ rcu_read_lock();
+ inet_opt = rcu_dereference(inet->inet_opt);
+ if (inet_opt) {
+ memcpy(&opt_copy, inet_opt,
+ sizeof(*inet_opt) + inet_opt->opt.optlen);
+ ipc.opt = &opt_copy.opt;
+ }
+ rcu_read_unlock();
+ }
saddr = ipc.addr;
ipc.addr = faddr = daddr;
- if (ipc.opt && ipc.opt->srr) {
+ if (ipc.opt && ipc.opt->opt.srr) {
if (!daddr)
return -EINVAL;
- faddr = ipc.opt->faddr;
+ faddr = ipc.opt->opt.faddr;
connected = 0;
}
tos = RT_TOS(inet->tos);
if (sock_flag(sk, SOCK_LOCALROUTE) ||
(msg->msg_flags & MSG_DONTROUTE) ||
- (ipc.opt && ipc.opt->is_strictroute)) {
+ (ipc.opt && ipc.opt->opt.is_strictroute)) {
tos |= RTO_ONLINK;
connected = 0;
}
@@ -909,20 +920,14 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
rt = (struct rtable *)sk_dst_check(sk, 0);
if (rt == NULL) {
- struct flowi4 fl4 = {
- .flowi4_oif = ipc.oif,
- .flowi4_mark = sk->sk_mark,
- .daddr = faddr,
- .saddr = saddr,
- .flowi4_tos = tos,
- .flowi4_proto = sk->sk_protocol,
- .flowi4_flags = (inet_sk_flowi_flags(sk) |
- FLOWI_FLAG_CAN_SLEEP),
- .fl4_sport = inet->inet_sport,
- .fl4_dport = dport,
- };
+ struct flowi4 fl4;
struct net *net = sock_net(sk);
+ flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
+ RT_SCOPE_UNIVERSE, sk->sk_protocol,
+ inet_sk_flowi_flags(sk)|FLOWI_FLAG_CAN_SLEEP,
+ faddr, saddr, dport, inet->inet_sport);
+
security_sk_classify_flow(sk, flowi4_to_flowi(&fl4));
rt = ip_route_output_flow(net, &fl4, sk);
if (IS_ERR(rt)) {
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 13e0e7f..7ff973b 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -73,7 +73,8 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
rt->rt_key_dst = fl4->daddr;
rt->rt_key_src = fl4->saddr;
- rt->rt_tos = fl4->flowi4_tos;
+ rt->rt_key_tos = fl4->flowi4_tos;
+ rt->rt_route_iif = fl4->flowi4_iif;
rt->rt_iif = fl4->flowi4_iif;
rt->rt_oif = fl4->flowi4_oif;
rt->rt_mark = fl4->flowi4_mark;
@@ -101,7 +102,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
static void
_decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
{
- struct iphdr *iph = ip_hdr(skb);
+ const struct iphdr *iph = ip_hdr(skb);
u8 *xprth = skb_network_header(skb) + iph->ihl * 4;
struct flowi4 *fl4 = &fl->u.ip4;
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 1717c64..ea983ae 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -55,7 +55,7 @@ xfrm4_init_temprop(struct xfrm_state *x, const struct xfrm_tmpl *tmpl,
int xfrm4_extract_header(struct sk_buff *skb)
{
- struct iphdr *iph = ip_hdr(skb);
+ const struct iphdr *iph = ip_hdr(skb);
XFRM_MODE_SKB_CB(skb)->ihl = sizeof(*iph);
XFRM_MODE_SKB_CB(skb)->id = iph->id;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 3daaf3c..c663a3b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -825,6 +825,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
dst_release(&rt->dst);
}
+ /* clean up prefsrc entries */
+ rt6_remove_prefsrc(ifp);
out:
in6_ifa_put(ifp);
}
@@ -1084,7 +1086,7 @@ static int ipv6_get_saddr_eval(struct net *net,
case IPV6_SADDR_RULE_PRIVACY:
{
/* Rule 7: Prefer public address
- * Note: prefer temprary address if use_tempaddr >= 2
+ * Note: prefer temporary address if use_tempaddr >= 2
*/
int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ?
!!(dst->prefs & IPV6_PREFER_SRC_TMP) :
@@ -1281,7 +1283,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev)
return cnt;
}
-int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
+int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
struct net_device *dev, int strict)
{
struct inet6_ifaddr *ifp;
@@ -1324,7 +1326,7 @@ static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
return false;
}
-int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev)
+int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev)
{
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
@@ -1455,7 +1457,7 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
/* Join to solicited addr multicast group. */
-void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr)
+void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr)
{
struct in6_addr maddr;
@@ -1466,7 +1468,7 @@ void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr)
ipv6_dev_mc_inc(dev, &maddr);
}
-void addrconf_leave_solict(struct inet6_dev *idev, struct in6_addr *addr)
+void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr)
{
struct in6_addr maddr;
@@ -1968,7 +1970,7 @@ ok:
* to the stored lifetime since we'll
* be updating the timestamp below,
* else we'll set it back to the
- * minumum.
+ * minimum.
*/
if (prefered_lft != ifp->prefered_lft) {
valid_lft = stored_lft;
@@ -2111,7 +2113,7 @@ err_exit:
/*
* Manual configuration of address on an interface
*/
-static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx,
+static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx,
unsigned int plen, __u8 ifa_flags, __u32 prefered_lft,
__u32 valid_lft)
{
@@ -2185,7 +2187,7 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx,
return PTR_ERR(ifp);
}
-static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx,
+static int inet6_addr_del(struct net *net, int ifindex, const struct in6_addr *pfx,
unsigned int plen)
{
struct inet6_ifaddr *ifp;
@@ -2348,7 +2350,7 @@ static void init_loopback(struct net_device *dev)
add_addr(idev, &in6addr_loopback, 128, IFA_HOST);
}
-static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr)
+static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr)
{
struct inet6_ifaddr * ifp;
u32 addr_flags = IFA_F_PERMANENT;
@@ -3119,7 +3121,7 @@ void if6_proc_exit(void)
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
/* Check if address is a home address configured on any interface. */
-int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
+int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr)
{
int ret = 0;
struct inet6_ifaddr *ifp = NULL;
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 4b13d5d..b7919f9 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -740,7 +740,7 @@ static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
static int ipv6_gso_send_check(struct sk_buff *skb)
{
- struct ipv6hdr *ipv6h;
+ const struct ipv6hdr *ipv6h;
const struct inet6_protocol *ops;
int err = -EINVAL;
@@ -1113,7 +1113,7 @@ static int __init inet6_init(void)
/*
* ipngwg API draft makes clear that the correct semantics
* for TCP and UDP is to consider one TCP and UDP instance
- * in a host availiable by both INET and INET6 APIs and
+ * in a host available by both INET and INET6 APIs and
* able to communicate via both network protocols.
*/
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 0e5e943..674255f 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -44,7 +44,7 @@
#include <net/checksum.h>
-static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr);
+static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr);
/* Big ac list lock for all the sockets */
static DEFINE_RWLOCK(ipv6_sk_ac_lock);
@@ -54,7 +54,7 @@ static DEFINE_RWLOCK(ipv6_sk_ac_lock);
* socket join an anycast group
*/
-int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
+int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct net_device *dev = NULL;
@@ -145,7 +145,7 @@ error:
/*
* socket leave an anycast group
*/
-int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
+int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct net_device *dev;
@@ -252,7 +252,7 @@ static void aca_put(struct ifacaddr6 *ac)
/*
* device anycast group inc (add if not found)
*/
-int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
+int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr)
{
struct ifacaddr6 *aca;
struct inet6_dev *idev;
@@ -324,7 +324,7 @@ out:
/*
* device anycast group decrement
*/
-int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr)
+int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr)
{
struct ifacaddr6 *aca, *prev_aca;
@@ -358,7 +358,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr)
}
/* called with rcu_read_lock() */
-static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
+static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr)
{
struct inet6_dev *idev = __in6_dev_get(dev);
@@ -371,7 +371,7 @@ static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
* check if the interface has this anycast address
* called with rcu_read_lock()
*/
-static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr)
+static int ipv6_chk_acast_dev(struct net_device *dev, const struct in6_addr *addr)
{
struct inet6_dev *idev;
struct ifacaddr6 *aca;
@@ -392,7 +392,7 @@ static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr)
* check if given interface (or any, if dev==0) has this anycast address
*/
int ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
- struct in6_addr *addr)
+ const struct in6_addr *addr)
{
int found = 0;
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 5aa8ec8..e97b4b7 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -430,7 +430,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
u8 type, u8 code, int offset, __be32 info)
{
struct net *net = dev_net(skb->dev);
- struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
+ const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data;
struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset);
struct xfrm_state *x;
@@ -438,7 +438,8 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
type != ICMPV6_PKT_TOOBIG)
return;
- x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6);
+ x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
+ esph->spi, IPPROTO_ESP, AF_INET6);
if (!x)
return;
printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6\n",
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 83cb4f9..1190041 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -372,7 +372,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
struct ipv6hdr *hdr = ipv6_hdr(skb);
struct sock *sk;
struct ipv6_pinfo *np;
- struct in6_addr *saddr = NULL;
+ const struct in6_addr *saddr = NULL;
struct dst_entry *dst;
struct icmp6hdr tmp_hdr;
struct flowi6 fl6;
@@ -521,7 +521,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
struct sock *sk;
struct inet6_dev *idev;
struct ipv6_pinfo *np;
- struct in6_addr *saddr = NULL;
+ const struct in6_addr *saddr = NULL;
struct icmp6hdr *icmph = icmp6_hdr(skb);
struct icmp6hdr tmp_hdr;
struct flowi6 fl6;
@@ -645,8 +645,8 @@ static int icmpv6_rcv(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
struct inet6_dev *idev = __in6_dev_get(dev);
- struct in6_addr *saddr, *daddr;
- struct ipv6hdr *orig_hdr;
+ const struct in6_addr *saddr, *daddr;
+ const struct ipv6hdr *orig_hdr;
struct icmp6hdr *hdr;
u8 type;
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 1660546..f2c5b0f 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -44,7 +44,7 @@ int inet6_csk_bind_conflict(const struct sock *sk,
!sk2->sk_bound_dev_if ||
sk->sk_bound_dev_if == sk2->sk_bound_dev_if) &&
(!sk->sk_reuse || !sk2->sk_reuse ||
- ((1 << sk2->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))) &&
+ sk2->sk_state == TCP_LISTEN) &&
ipv6_rcv_saddr_equal(sk, sk2))
break;
}
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 7548905..4076a0b 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -134,9 +134,9 @@ static __inline__ u32 fib6_new_sernum(void)
# define BITOP_BE32_SWIZZLE 0
#endif
-static __inline__ __be32 addr_bit_set(void *token, int fn_bit)
+static __inline__ __be32 addr_bit_set(const void *token, int fn_bit)
{
- __be32 *addr = token;
+ const __be32 *addr = token;
/*
* Here,
* 1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)
@@ -394,10 +394,11 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
arg.net = net;
w->args = &arg;
+ rcu_read_lock();
for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) {
e = 0;
head = &net->ipv6.fib_table_hash[h];
- hlist_for_each_entry(tb, node, head, tb6_hlist) {
+ hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) {
if (e < s_e)
goto next;
res = fib6_dump_table(tb, skb, cb);
@@ -408,6 +409,7 @@ next:
}
}
out:
+ rcu_read_unlock();
cb->args[1] = e;
cb->args[0] = h;
@@ -822,7 +824,7 @@ st_failure:
struct lookup_args {
int offset; /* key offset on rt6_info */
- struct in6_addr *addr; /* search key */
+ const struct in6_addr *addr; /* search key */
};
static struct fib6_node * fib6_lookup_1(struct fib6_node *root,
@@ -881,8 +883,8 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root,
return NULL;
}
-struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr,
- struct in6_addr *saddr)
+struct fib6_node * fib6_lookup(struct fib6_node *root, const struct in6_addr *daddr,
+ const struct in6_addr *saddr)
{
struct fib6_node *fn;
struct lookup_args args[] = {
@@ -916,7 +918,7 @@ struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr,
static struct fib6_node * fib6_locate_1(struct fib6_node *root,
- struct in6_addr *addr,
+ const struct in6_addr *addr,
int plen, int offset)
{
struct fib6_node *fn;
@@ -946,8 +948,8 @@ static struct fib6_node * fib6_locate_1(struct fib6_node *root,
}
struct fib6_node * fib6_locate(struct fib6_node *root,
- struct in6_addr *daddr, int dst_len,
- struct in6_addr *saddr, int src_len)
+ const struct in6_addr *daddr, int dst_len,
+ const struct in6_addr *saddr, int src_len)
{
struct fib6_node *fn;
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index a83e920..027c7ff 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -57,7 +57,7 @@ inline int ip6_rcv_finish( struct sk_buff *skb)
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
- struct ipv6hdr *hdr;
+ const struct ipv6hdr *hdr;
u32 pkt_len;
struct inet6_dev *idev;
struct net *net = dev_net(skb->dev);
@@ -186,7 +186,7 @@ resubmit:
int ret;
if (ipprot->flags & INET6_PROTO_FINAL) {
- struct ipv6hdr *hdr;
+ const struct ipv6hdr *hdr;
/* Free reference early: we don't need it any more,
and it may hold ip_conntrack module loaded
@@ -242,7 +242,7 @@ int ip6_input(struct sk_buff *skb)
int ip6_mc_input(struct sk_buff *skb)
{
- struct ipv6hdr *hdr;
+ const struct ipv6hdr *hdr;
int deliver;
IP6_UPD_PO_STATS_BH(dev_net(skb_dst(skb)->dev),
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 1820887..4cfbb24 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -779,7 +779,7 @@ slow_path:
/* IF: it doesn't fit, use 'mtu' - the data space left */
if (len > mtu)
len = mtu;
- /* IF: we are not sending upto and including the packet end
+ /* IF: we are not sending up to and including the packet end
then align the next start on an eight byte boundary */
if (len < left) {
len &= ~7;
@@ -869,9 +869,9 @@ fail:
return err;
}
-static inline int ip6_rt_check(struct rt6key *rt_key,
- struct in6_addr *fl_addr,
- struct in6_addr *addr_cache)
+static inline int ip6_rt_check(const struct rt6key *rt_key,
+ const struct in6_addr *fl_addr,
+ const struct in6_addr *addr_cache)
{
return (rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) &&
(addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache));
@@ -879,7 +879,7 @@ static inline int ip6_rt_check(struct rt6key *rt_key,
static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
struct dst_entry *dst,
- struct flowi6 *fl6)
+ const struct flowi6 *fl6)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct rt6_info *rt = (struct rt6_info *)dst;
@@ -930,10 +930,10 @@ static int ip6_dst_lookup_tail(struct sock *sk,
goto out_err_release;
if (ipv6_addr_any(&fl6->saddr)) {
- err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev,
- &fl6->daddr,
- sk ? inet6_sk(sk)->srcprefs : 0,
- &fl6->saddr);
+ struct rt6_info *rt = (struct rt6_info *) *dst;
+ err = ip6_route_get_saddr(net, rt, &fl6->daddr,
+ sk ? inet6_sk(sk)->srcprefs : 0,
+ &fl6->saddr);
if (err)
goto out_err_release;
}
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index c1b1bd3..3dff27c 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -162,7 +162,7 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
static struct ip6_tnl *
-ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local)
+ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
{
unsigned int h0 = HASH(remote);
unsigned int h1 = HASH(local);
@@ -194,10 +194,10 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local)
**/
static struct ip6_tnl __rcu **
-ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p)
+ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct ip6_tnl_parm *p)
{
- struct in6_addr *remote = &p->raddr;
- struct in6_addr *local = &p->laddr;
+ const struct in6_addr *remote = &p->raddr;
+ const struct in6_addr *local = &p->laddr;
unsigned h = 0;
int prio = 0;
@@ -321,8 +321,8 @@ failed:
static struct ip6_tnl *ip6_tnl_locate(struct net *net,
struct ip6_tnl_parm *p, int create)
{
- struct in6_addr *remote = &p->raddr;
- struct in6_addr *local = &p->laddr;
+ const struct in6_addr *remote = &p->raddr;
+ const struct in6_addr *local = &p->laddr;
struct ip6_tnl __rcu **tp;
struct ip6_tnl *t;
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
@@ -374,7 +374,7 @@ ip6_tnl_dev_uninit(struct net_device *dev)
static __u16
parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
{
- struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw;
+ const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
__u8 nexthdr = ipv6h->nexthdr;
__u16 off = sizeof (*ipv6h);
@@ -435,7 +435,7 @@ static int
ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
u8 *type, u8 *code, int *msg, __u32 *info, int offset)
{
- struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
+ const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) skb->data;
struct ip6_tnl *t;
int rel_msg = 0;
u8 rel_type = ICMPV6_DEST_UNREACH;
@@ -535,8 +535,9 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
__u32 rel_info = ntohl(info);
int err;
struct sk_buff *skb2;
- struct iphdr *eiph;
+ const struct iphdr *eiph;
struct rtable *rt;
+ struct flowi4 fl4;
err = ip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code,
&rel_msg, &rel_info, offset);
@@ -577,7 +578,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
eiph = ip_hdr(skb2);
/* Try to guess incoming interface */
- rt = ip_route_output_ports(dev_net(skb->dev), NULL,
+ rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL,
eiph->saddr, 0,
0, 0,
IPPROTO_IPIP, RT_TOS(eiph->tos), 0);
@@ -590,7 +591,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (rt->rt_flags & RTCF_LOCAL) {
ip_rt_put(rt);
rt = NULL;
- rt = ip_route_output_ports(dev_net(skb->dev), NULL,
+ rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL,
eiph->daddr, eiph->saddr,
0, 0,
IPPROTO_IPIP,
@@ -669,8 +670,8 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
return 0;
}
-static void ip4ip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
- struct ipv6hdr *ipv6h,
+static void ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
+ const struct ipv6hdr *ipv6h,
struct sk_buff *skb)
{
__u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK;
@@ -682,8 +683,8 @@ static void ip4ip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
IP_ECN_set_ce(ip_hdr(skb));
}
-static void ip6ip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
- struct ipv6hdr *ipv6h,
+static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
+ const struct ipv6hdr *ipv6h,
struct sk_buff *skb)
{
if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
@@ -726,12 +727,12 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t)
static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
__u8 ipproto,
- void (*dscp_ecn_decapsulate)(struct ip6_tnl *t,
- struct ipv6hdr *ipv6h,
+ void (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
+ const struct ipv6hdr *ipv6h,
struct sk_buff *skb))
{
struct ip6_tnl *t;
- struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+ const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
rcu_read_lock();
@@ -828,7 +829,7 @@ static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit)
**/
static inline int
-ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
+ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
{
return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
}
@@ -1005,7 +1006,7 @@ static inline int
ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
- struct iphdr *iph = ip_hdr(skb);
+ const struct iphdr *iph = ip_hdr(skb);
int encap_limit = -1;
struct flowi6 fl6;
__u8 dsfield;
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 29e4859..82a8099 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -989,8 +989,8 @@ static int mif6_add(struct net *net, struct mr6_table *mrt,
}
static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt,
- struct in6_addr *origin,
- struct in6_addr *mcastgrp)
+ const struct in6_addr *origin,
+ const struct in6_addr *mcastgrp)
{
int line = MFC6_HASH(mcastgrp, origin);
struct mfc6_cache *c;
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 85cccd6..bba658d 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -55,7 +55,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
{
struct net *net = dev_net(skb->dev);
__be32 spi;
- struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
+ const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data;
struct ip_comp_hdr *ipcomph =
(struct ip_comp_hdr *)(skb->data + offset);
struct xfrm_state *x;
@@ -64,7 +64,8 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
return;
spi = htonl(ntohs(ipcomph->cpi));
- x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6);
+ x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
+ spi, IPPROTO_COMP, AF_INET6);
if (!x)
return;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 76b8937..ff62e33 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -92,16 +92,16 @@ static void mld_gq_timer_expire(unsigned long data);
static void mld_ifc_timer_expire(unsigned long data);
static void mld_ifc_event(struct inet6_dev *idev);
static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc);
-static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *addr);
+static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *addr);
static void mld_clear_delrec(struct inet6_dev *idev);
static int sf_setstate(struct ifmcaddr6 *pmc);
static void sf_markstate(struct ifmcaddr6 *pmc);
static void ip6_mc_clear_src(struct ifmcaddr6 *pmc);
-static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca,
- int sfmode, int sfcount, struct in6_addr *psfsrc,
+static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+ int sfmode, int sfcount, const struct in6_addr *psfsrc,
int delta);
-static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca,
- int sfmode, int sfcount, struct in6_addr *psfsrc,
+static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+ int sfmode, int sfcount, const struct in6_addr *psfsrc,
int delta);
static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
struct inet6_dev *idev);
@@ -250,7 +250,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
/* called with rcu_read_lock() */
static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
- struct in6_addr *group,
+ const struct in6_addr *group,
int ifindex)
{
struct net_device *dev = NULL;
@@ -451,7 +451,7 @@ done:
int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
{
- struct in6_addr *group;
+ const struct in6_addr *group;
struct ipv6_mc_socklist *pmc;
struct inet6_dev *idev;
struct ipv6_pinfo *inet6 = inet6_sk(sk);
@@ -542,7 +542,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
struct group_filter __user *optval, int __user *optlen)
{
int err, i, count, copycount;
- struct in6_addr *group;
+ const struct in6_addr *group;
struct ipv6_mc_socklist *pmc;
struct inet6_dev *idev;
struct ipv6_pinfo *inet6 = inet6_sk(sk);
@@ -752,7 +752,7 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
spin_unlock_bh(&idev->mc_lock);
}
-static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca)
+static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca)
{
struct ifmcaddr6 *pmc, *pmc_prev;
struct ip6_sf_list *psf, *psf_next;
@@ -1052,7 +1052,7 @@ static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime)
/* mark EXCLUDE-mode sources */
static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,
- struct in6_addr *srcs)
+ const struct in6_addr *srcs)
{
struct ip6_sf_list *psf;
int i, scount;
@@ -1080,7 +1080,7 @@ static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,
}
static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
- struct in6_addr *srcs)
+ const struct in6_addr *srcs)
{
struct ip6_sf_list *psf;
int i, scount;
@@ -1115,7 +1115,7 @@ int igmp6_event_query(struct sk_buff *skb)
{
struct mld2_query *mlh2 = NULL;
struct ifmcaddr6 *ma;
- struct in6_addr *group;
+ const struct in6_addr *group;
unsigned long max_delay;
struct inet6_dev *idev;
struct mld_msg *mld;
@@ -1821,7 +1821,7 @@ err_out:
}
static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
- struct in6_addr *psfsrc)
+ const struct in6_addr *psfsrc)
{
struct ip6_sf_list *psf, *psf_prev;
int rv = 0;
@@ -1857,8 +1857,8 @@ static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
return rv;
}
-static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca,
- int sfmode, int sfcount, struct in6_addr *psfsrc,
+static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+ int sfmode, int sfcount, const struct in6_addr *psfsrc,
int delta)
{
struct ifmcaddr6 *pmc;
@@ -1918,7 +1918,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca,
* Add multicast single-source filter to the interface list
*/
static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,
- struct in6_addr *psfsrc, int delta)
+ const struct in6_addr *psfsrc, int delta)
{
struct ip6_sf_list *psf, *psf_prev;
@@ -2021,8 +2021,8 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
/*
* Add multicast source filter list to the interface list
*/
-static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca,
- int sfmode, int sfcount, struct in6_addr *psfsrc,
+static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+ int sfmode, int sfcount, const struct in6_addr *psfsrc,
int delta)
{
struct ifmcaddr6 *pmc;
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index 9b21048..43242e6 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -126,7 +126,7 @@ static struct mip6_report_rate_limiter mip6_report_rl = {
static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb)
{
- struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data;
int err = destopt->nexthdr;
@@ -181,8 +181,8 @@ static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb)
}
static inline int mip6_report_rl_allow(struct timeval *stamp,
- struct in6_addr *dst,
- struct in6_addr *src, int iif)
+ const struct in6_addr *dst,
+ const struct in6_addr *src, int iif)
{
int allow = 0;
@@ -349,7 +349,7 @@ static const struct xfrm_type mip6_destopt_type =
static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
{
- struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data;
int err = rt2->rt_hdr.nexthdr;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 92f952d..7596f07 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -324,7 +324,7 @@ static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p,
return lladdr + prepad;
}
-int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
+int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
{
switch (dev->type) {
case ARPHRD_ETHER:
@@ -611,6 +611,29 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
}
+static void ndisc_send_unsol_na(struct net_device *dev)
+{
+ struct inet6_dev *idev;
+ struct inet6_ifaddr *ifa;
+ struct in6_addr mcaddr;
+
+ idev = in6_dev_get(dev);
+ if (!idev)
+ return;
+
+ read_lock_bh(&idev->lock);
+ list_for_each_entry(ifa, &idev->addr_list, if_list) {
+ addrconf_addr_solict_mult(&ifa->addr, &mcaddr);
+ ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr,
+ /*router=*/ !!idev->cnf.forwarding,
+ /*solicited=*/ false, /*override=*/ true,
+ /*inc_opt=*/ true);
+ }
+ read_unlock_bh(&idev->lock);
+
+ in6_dev_put(idev);
+}
+
void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
const struct in6_addr *solicit,
const struct in6_addr *daddr, const struct in6_addr *saddr)
@@ -725,8 +748,8 @@ static int pndisc_is_router(const void *pkey,
static void ndisc_recv_ns(struct sk_buff *skb)
{
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
- struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
- struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
+ const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
+ const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
u8 *lladdr = NULL;
u32 ndoptlen = skb->tail - (skb->transport_header +
offsetof(struct nd_msg, opt));
@@ -901,8 +924,8 @@ out:
static void ndisc_recv_na(struct sk_buff *skb)
{
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
- struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
- struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
+ const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
+ const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
u8 *lladdr = NULL;
u32 ndoptlen = skb->tail - (skb->transport_header +
offsetof(struct nd_msg, opt));
@@ -945,9 +968,10 @@ static void ndisc_recv_na(struct sk_buff *skb)
}
ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
if (ifp) {
- if (ifp->flags & IFA_F_TENTATIVE) {
- addrconf_dad_failure(ifp);
- return;
+ if (skb->pkt_type != PACKET_LOOPBACK
+ && (ifp->flags & IFA_F_TENTATIVE)) {
+ addrconf_dad_failure(ifp);
+ return;
}
/* What should we make now? The advertisement
is invalid, but ndisc specs say nothing
@@ -1014,7 +1038,7 @@ static void ndisc_recv_rs(struct sk_buff *skb)
unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
struct neighbour *neigh;
struct inet6_dev *idev;
- struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
+ const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
struct ndisc_options ndopts;
u8 *lladdr = NULL;
@@ -1411,8 +1435,8 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
{
struct inet6_dev *in6_dev;
struct icmp6hdr *icmph;
- struct in6_addr *dest;
- struct in6_addr *target; /* new first hop to destination */
+ const struct in6_addr *dest;
+ const struct in6_addr *target; /* new first hop to destination */
struct neighbour *neigh;
int on_link = 0;
struct ndisc_options ndopts;
@@ -1445,7 +1469,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
}
icmph = icmp6_hdr(skb);
- target = (struct in6_addr *) (icmph + 1);
+ target = (const struct in6_addr *) (icmph + 1);
dest = target + 1;
if (ipv6_addr_is_multicast(dest)) {
@@ -1722,6 +1746,9 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
neigh_ifdown(&nd_tbl, dev);
fib6_run_gc(~0UL, net);
break;
+ case NETDEV_NOTIFY_PEERS:
+ ndisc_send_unsol_na(dev);
+ break;
default:
break;
}
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index 39aaca2..30fcee4 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -13,7 +13,7 @@
int ip6_route_me_harder(struct sk_buff *skb)
{
struct net *net = dev_net(skb_dst(skb)->dev);
- struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
struct dst_entry *dst;
struct flowi6 fl6 = {
.flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0,
@@ -67,7 +67,7 @@ static void nf_ip6_saveroute(const struct sk_buff *skb,
struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry);
if (entry->hook == NF_INET_LOCAL_OUT) {
- struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
rt_info->daddr = iph->daddr;
rt_info->saddr = iph->saddr;
@@ -81,7 +81,7 @@ static int nf_ip6_reroute(struct sk_buff *skb,
struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry);
if (entry->hook == NF_INET_LOCAL_OUT) {
- struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||
!ipv6_addr_equal(&iph->saddr, &rt_info->saddr) ||
skb->mark != rt_info->mark)
@@ -90,16 +90,25 @@ static int nf_ip6_reroute(struct sk_buff *skb,
return 0;
}
-static int nf_ip6_route(struct dst_entry **dst, struct flowi *fl)
+static int nf_ip6_route(struct net *net, struct dst_entry **dst,
+ struct flowi *fl, bool strict)
{
- *dst = ip6_route_output(&init_net, NULL, &fl->u.ip6);
+ static const struct ipv6_pinfo fake_pinfo;
+ static const struct inet_sock fake_sk = {
+ /* makes ip6_route_output set RT6_LOOKUP_F_IFACE: */
+ .sk.sk_bound_dev_if = 1,
+ .pinet6 = (struct ipv6_pinfo *) &fake_pinfo,
+ };
+ const void *sk = strict ? &fake_sk : NULL;
+
+ *dst = ip6_route_output(net, sk, &fl->u.ip6);
return (*dst)->error;
}
__sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, u_int8_t protocol)
{
- struct ipv6hdr *ip6h = ipv6_hdr(skb);
+ const struct ipv6hdr *ip6h = ipv6_hdr(skb);
__sum16 csum = 0;
switch (skb->ip_summed) {
@@ -133,7 +142,7 @@ static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, unsigned int len,
u_int8_t protocol)
{
- struct ipv6hdr *ip6h = ipv6_hdr(skb);
+ const struct ipv6hdr *ip6h = ipv6_hdr(skb);
__wsum hsum;
__sum16 csum = 0;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 0b2af9b..94874b0 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -340,6 +340,7 @@ ip6t_do_table(struct sk_buff *skb,
unsigned int *stackptr, origptr, cpu;
const struct xt_table_info *private;
struct xt_action_param acpar;
+ unsigned int addend;
/* Initialization */
indev = in ? in->name : nulldevname;
@@ -358,7 +359,8 @@ ip6t_do_table(struct sk_buff *skb,
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
- xt_info_rdlock_bh();
+ local_bh_disable();
+ addend = xt_write_recseq_begin();
private = table->private;
cpu = smp_processor_id();
table_base = private->entries[cpu];
@@ -442,7 +444,9 @@ ip6t_do_table(struct sk_buff *skb,
} while (!acpar.hotdrop);
*stackptr = origptr;
- xt_info_rdunlock_bh();
+
+ xt_write_recseq_end(addend);
+ local_bh_enable();
#ifdef DEBUG_ALLOW_ALL
return NF_ACCEPT;
@@ -899,7 +903,7 @@ get_counters(const struct xt_table_info *t,
unsigned int i;
for_each_possible_cpu(cpu) {
- seqlock_t *lock = &per_cpu(xt_info_locks, cpu).lock;
+ seqcount_t *s = &per_cpu(xt_recseq, cpu);
i = 0;
xt_entry_foreach(iter, t->entries[cpu], t->size) {
@@ -907,10 +911,10 @@ get_counters(const struct xt_table_info *t,
unsigned int start;
do {
- start = read_seqbegin(lock);
+ start = read_seqcount_begin(s);
bcnt = iter->counters.bcnt;
pcnt = iter->counters.pcnt;
- } while (read_seqretry(lock, start));
+ } while (read_seqcount_retry(s, start));
ADD_COUNTER(counters[i], bcnt, pcnt);
++i;
@@ -1325,6 +1329,7 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len,
int ret = 0;
const void *loc_cpu_entry;
struct ip6t_entry *iter;
+ unsigned int addend;
#ifdef CONFIG_COMPAT
struct compat_xt_counters_info compat_tmp;
@@ -1381,13 +1386,13 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len,
i = 0;
/* Choose the copy that is on our node */
curcpu = smp_processor_id();
- xt_info_wrlock(curcpu);
+ addend = xt_write_recseq_begin();
loc_cpu_entry = private->entries[curcpu];
xt_entry_foreach(iter, loc_cpu_entry, private->size) {
ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt);
++i;
}
- xt_info_wrunlock(curcpu);
+ xt_write_recseq_end(addend);
unlock_up_free:
local_bh_enable();
@@ -1578,7 +1583,6 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
struct xt_table_info *newinfo, unsigned char *base)
{
struct xt_entry_target *t;
- struct xt_target *target;
struct ip6t_entry *de;
unsigned int origsize;
int ret, h;
@@ -1600,7 +1604,6 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
}
de->target_offset = e->target_offset - (origsize - *size);
t = compat_ip6t_get_target(e);
- target = t->u.kernel.target;
xt_compat_target_from_user(t, dstptr, size);
de->next_offset = e->next_offset - (origsize - *size);
@@ -2248,7 +2251,7 @@ static int __init ip6_tables_init(void)
if (ret < 0)
goto err1;
- /* Noone else will be downing sem now, so we won't sleep */
+ /* No one else will be downing sem now, so we won't sleep */
ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
if (ret < 0)
goto err2;
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index 679a0a3..00d1917 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -64,7 +64,8 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
(memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) ||
memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) ||
skb->mark != mark ||
- ipv6_hdr(skb)->hop_limit != hop_limit))
+ ipv6_hdr(skb)->hop_limit != hop_limit ||
+ flowlabel != *((u_int32_t *)ipv6_hdr(skb))))
return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP;
return ret;
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
index 97c5b21..cdd6d04 100644
--- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
+++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
@@ -71,7 +71,7 @@ static unsigned int ipv6_defrag(unsigned int hooknum,
if (reasm == NULL)
return NF_STOLEN;
- /* error occured or not fragmented */
+ /* error occurred or not fragmented */
if (reasm == skb)
return NF_ACCEPT;
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 4a1c3b4..e5e5425 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -67,8 +67,8 @@ static struct raw_hashinfo raw_v6_hashinfo = {
};
static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk,
- unsigned short num, struct in6_addr *loc_addr,
- struct in6_addr *rmt_addr, int dif)
+ unsigned short num, const struct in6_addr *loc_addr,
+ const struct in6_addr *rmt_addr, int dif)
{
struct hlist_node *node;
int is_multicast = ipv6_addr_is_multicast(loc_addr);
@@ -154,8 +154,8 @@ EXPORT_SYMBOL(rawv6_mh_filter_unregister);
*/
static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
{
- struct in6_addr *saddr;
- struct in6_addr *daddr;
+ const struct in6_addr *saddr;
+ const struct in6_addr *daddr;
struct sock *sk;
int delivered = 0;
__u8 hash;
@@ -348,7 +348,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
{
struct sock *sk;
int hash;
- struct in6_addr *saddr, *daddr;
+ const struct in6_addr *saddr, *daddr;
struct net *net;
hash = nexthdr & (RAW_HTABLE_SIZE - 1);
@@ -357,7 +357,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
sk = sk_head(&raw_v6_hashinfo.ht[hash]);
if (sk != NULL) {
/* Note: ipv6_hdr(skb) != skb->data */
- struct ipv6hdr *ip6h = (struct ipv6hdr *)skb->data;
+ const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data;
saddr = &ip6h->saddr;
daddr = &ip6h->daddr;
net = dev_net(skb->dev);
@@ -1231,7 +1231,7 @@ struct proto rawv6_prot = {
static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
{
struct ipv6_pinfo *np = inet6_sk(sp);
- struct in6_addr *dest, *src;
+ const struct in6_addr *dest, *src;
__u16 destp, srcp;
dest = &np->daddr;
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 07beeb0..7b954e2 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -224,7 +224,7 @@ out:
}
static __inline__ struct frag_queue *
-fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst)
+fq_find(struct net *net, __be32 id, const struct in6_addr *src, const struct in6_addr *dst)
{
struct inet_frag_queue *q;
struct ip6_create_arg arg;
@@ -535,7 +535,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
{
struct frag_hdr *fhdr;
struct frag_queue *fq;
- struct ipv6hdr *hdr = ipv6_hdr(skb);
+ const struct ipv6hdr *hdr = ipv6_hdr(skb);
struct net *net = dev_net(skb_dst(skb)->dev);
IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 843406f..f1be5c5 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -89,12 +89,12 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
#ifdef CONFIG_IPV6_ROUTE_INFO
static struct rt6_info *rt6_add_route_info(struct net *net,
- struct in6_addr *prefix, int prefixlen,
- struct in6_addr *gwaddr, int ifindex,
+ const struct in6_addr *prefix, int prefixlen,
+ const struct in6_addr *gwaddr, int ifindex,
unsigned pref);
static struct rt6_info *rt6_get_route_info(struct net *net,
- struct in6_addr *prefix, int prefixlen,
- struct in6_addr *gwaddr, int ifindex);
+ const struct in6_addr *prefix, int prefixlen,
+ const struct in6_addr *gwaddr, int ifindex);
#endif
static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
@@ -153,6 +153,12 @@ static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
{
}
+static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
+ unsigned long old)
+{
+ return NULL;
+}
+
static struct dst_ops ip6_dst_blackhole_ops = {
.family = AF_INET6,
.protocol = cpu_to_be16(ETH_P_IPV6),
@@ -161,6 +167,7 @@ static struct dst_ops ip6_dst_blackhole_ops = {
.default_mtu = ip6_blackhole_default_mtu,
.default_advmss = ip6_default_advmss,
.update_pmtu = ip6_rt_blackhole_update_pmtu,
+ .cow_metrics = ip6_rt_blackhole_cow_metrics,
};
static const u32 ip6_template_metrics[RTAX_MAX] = {
@@ -220,9 +227,14 @@ static struct rt6_info ip6_blk_hole_entry_template = {
#endif
/* allocate dst with ip6_dst_ops */
-static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops)
+static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops,
+ struct net_device *dev)
{
- return (struct rt6_info *)dst_alloc(ops, 0);
+ struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, 0);
+
+ memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry));
+
+ return rt;
}
static void ip6_dst_destroy(struct dst_entry *dst)
@@ -283,7 +295,7 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt)
time_after(jiffies, rt->rt6i_expires);
}
-static inline int rt6_need_strict(struct in6_addr *daddr)
+static inline int rt6_need_strict(const struct in6_addr *daddr)
{
return ipv6_addr_type(daddr) &
(IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK);
@@ -295,7 +307,7 @@ static inline int rt6_need_strict(struct in6_addr *daddr)
static inline struct rt6_info *rt6_device_match(struct net *net,
struct rt6_info *rt,
- struct in6_addr *saddr,
+ const struct in6_addr *saddr,
int oif,
int flags)
{
@@ -507,7 +519,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
#ifdef CONFIG_IPV6_ROUTE_INFO
int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
- struct in6_addr *gwaddr)
+ const struct in6_addr *gwaddr)
{
struct net *net = dev_net(dev);
struct route_info *rinfo = (struct route_info *) opt;
@@ -670,8 +682,8 @@ int ip6_ins_rt(struct rt6_info *rt)
return __ip6_ins_rt(rt, &info);
}
-static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr,
- struct in6_addr *saddr)
+static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_addr *daddr,
+ const struct in6_addr *saddr)
{
struct rt6_info *rt;
@@ -739,7 +751,7 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *dad
return rt;
}
-static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr)
+static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, const struct in6_addr *daddr)
{
struct rt6_info *rt = ip6_rt_copy(ort);
if (rt) {
@@ -830,7 +842,7 @@ static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *
void ip6_route_input(struct sk_buff *skb)
{
- struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
struct net *net = dev_net(skb->dev);
int flags = RT6_LOOKUP_F_HAS_SADDR;
struct flowi6 fl6 = {
@@ -874,11 +886,13 @@ EXPORT_SYMBOL(ip6_route_output);
struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
{
- struct rt6_info *rt = dst_alloc(&ip6_dst_blackhole_ops, 1);
- struct rt6_info *ort = (struct rt6_info *) dst_orig;
+ struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
struct dst_entry *new = NULL;
+ rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, 0, 0);
if (rt) {
+ memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry));
+
new = &rt->dst;
new->__use = 1;
@@ -886,9 +900,6 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
new->output = dst_discard;
dst_copy_metrics(new, &ort->dst);
- new->dev = ort->dst.dev;
- if (new->dev)
- dev_hold(new->dev);
rt->rt6i_idev = ort->rt6i_idev;
if (rt->rt6i_idev)
in6_dev_hold(rt->rt6i_idev);
@@ -1031,13 +1042,12 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
if (unlikely(idev == NULL))
return NULL;
- rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops);
+ rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev);
if (unlikely(rt == NULL)) {
in6_dev_put(idev);
goto out;
}
- dev_hold(dev);
if (neigh)
neigh_hold(neigh);
else {
@@ -1046,7 +1056,6 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
neigh = NULL;
}
- rt->rt6i_dev = dev;
rt->rt6i_idev = idev;
rt->rt6i_nexthop = neigh;
atomic_set(&rt->dst.__refcnt, 1);
@@ -1205,7 +1214,7 @@ int ip6_route_add(struct fib6_config *cfg)
goto out;
}
- rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops);
+ rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, NULL);
if (rt == NULL) {
err = -ENOMEM;
@@ -1272,7 +1281,7 @@ int ip6_route_add(struct fib6_config *cfg)
}
if (cfg->fc_flags & RTF_GATEWAY) {
- struct in6_addr *gw_addr;
+ const struct in6_addr *gw_addr;
int gwa_type;
gw_addr = &cfg->fc_gateway;
@@ -1325,6 +1334,16 @@ int ip6_route_add(struct fib6_config *cfg)
if (dev == NULL)
goto out;
+ if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
+ if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
+ err = -EINVAL;
+ goto out;
+ }
+ ipv6_addr_copy(&rt->rt6i_prefsrc.addr, &cfg->fc_prefsrc);
+ rt->rt6i_prefsrc.plen = 128;
+ } else
+ rt->rt6i_prefsrc.plen = 0;
+
if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev);
if (IS_ERR(rt->rt6i_nexthop)) {
@@ -1502,9 +1521,9 @@ out:
return rt;
};
-static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
- struct in6_addr *src,
- struct in6_addr *gateway,
+static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest,
+ const struct in6_addr *src,
+ const struct in6_addr *gateway,
struct net_device *dev)
{
int flags = RT6_LOOKUP_F_HAS_SADDR;
@@ -1526,8 +1545,8 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
flags, __ip6_route_redirect);
}
-void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
- struct in6_addr *saddr,
+void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,
+ const struct in6_addr *saddr,
struct neighbour *neigh, u8 *lladdr, int on_link)
{
struct rt6_info *rt, *nrt = NULL;
@@ -1601,7 +1620,7 @@ out:
* i.e. Path MTU discovery
*/
-static void rt6_do_pmtu_disc(struct in6_addr *daddr, struct in6_addr *saddr,
+static void rt6_do_pmtu_disc(const struct in6_addr *daddr, const struct in6_addr *saddr,
struct net *net, u32 pmtu, int ifindex)
{
struct rt6_info *rt, *nrt;
@@ -1686,7 +1705,7 @@ out:
dst_release(&rt->dst);
}
-void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
+void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *saddr,
struct net_device *dev, u32 pmtu)
{
struct net *net = dev_net(dev);
@@ -1714,7 +1733,8 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
{
struct net *net = dev_net(ort->rt6i_dev);
- struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops);
+ struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops,
+ ort->dst.dev);
if (rt) {
rt->dst.input = ort->dst.input;
@@ -1722,9 +1742,6 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
dst_copy_metrics(&rt->dst, &ort->dst);
rt->dst.error = ort->dst.error;
- rt->dst.dev = ort->dst.dev;
- if (rt->dst.dev)
- dev_hold(rt->dst.dev);
rt->rt6i_idev = ort->rt6i_idev;
if (rt->rt6i_idev)
in6_dev_hold(rt->rt6i_idev);
@@ -1746,8 +1763,8 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
#ifdef CONFIG_IPV6_ROUTE_INFO
static struct rt6_info *rt6_get_route_info(struct net *net,
- struct in6_addr *prefix, int prefixlen,
- struct in6_addr *gwaddr, int ifindex)
+ const struct in6_addr *prefix, int prefixlen,
+ const struct in6_addr *gwaddr, int ifindex)
{
struct fib6_node *fn;
struct rt6_info *rt = NULL;
@@ -1778,8 +1795,8 @@ out:
}
static struct rt6_info *rt6_add_route_info(struct net *net,
- struct in6_addr *prefix, int prefixlen,
- struct in6_addr *gwaddr, int ifindex,
+ const struct in6_addr *prefix, int prefixlen,
+ const struct in6_addr *gwaddr, int ifindex,
unsigned pref)
{
struct fib6_config cfg = {
@@ -1807,7 +1824,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net,
}
#endif
-struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev)
+struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
{
struct rt6_info *rt;
struct fib6_table *table;
@@ -1829,7 +1846,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
return rt;
}
-struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
+struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
struct net_device *dev,
unsigned int pref)
{
@@ -1994,7 +2011,8 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
int anycast)
{
struct net *net = dev_net(idev->dev);
- struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops);
+ struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops,
+ net->loopback_dev);
struct neighbour *neigh;
if (rt == NULL) {
@@ -2004,15 +2022,12 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
return ERR_PTR(-ENOMEM);
}
- dev_hold(net->loopback_dev);
in6_dev_hold(idev);
rt->dst.flags = DST_HOST;
rt->dst.input = ip6_input;
rt->dst.output = ip6_output;
- rt->rt6i_dev = net->loopback_dev;
rt->rt6i_idev = idev;
- dst_metric_set(&rt->dst, RTAX_HOPLIMIT, -1);
rt->dst.obsolete = -1;
rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
@@ -2037,6 +2052,55 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
return rt;
}
+int ip6_route_get_saddr(struct net *net,
+ struct rt6_info *rt,
+ const struct in6_addr *daddr,
+ unsigned int prefs,
+ struct in6_addr *saddr)
+{
+ struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
+ int err = 0;
+ if (rt->rt6i_prefsrc.plen)
+ ipv6_addr_copy(saddr, &rt->rt6i_prefsrc.addr);
+ else
+ err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
+ daddr, prefs, saddr);
+ return err;
+}
+
+/* remove deleted ip from prefsrc entries */
+struct arg_dev_net_ip {
+ struct net_device *dev;
+ struct net *net;
+ struct in6_addr *addr;
+};
+
+static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
+{
+ struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
+ struct net *net = ((struct arg_dev_net_ip *)arg)->net;
+ struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
+
+ if (((void *)rt->rt6i_dev == dev || dev == NULL) &&
+ rt != net->ipv6.ip6_null_entry &&
+ ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
+ /* remove prefsrc entry */
+ rt->rt6i_prefsrc.plen = 0;
+ }
+ return 0;
+}
+
+void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
+{
+ struct net *net = dev_net(ifp->idev->dev);
+ struct arg_dev_net_ip adni = {
+ .dev = ifp->idev->dev,
+ .net = net,
+ .addr = &ifp->addr,
+ };
+ fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni);
+}
+
struct arg_dev_net {
struct net_device *dev;
struct net *net;
@@ -2183,6 +2247,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
}
+ if (tb[RTA_PREFSRC])
+ nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
+
if (tb[RTA_OIF])
cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
@@ -2325,13 +2392,17 @@ static int rt6_fill_node(struct net *net,
#endif
NLA_PUT_U32(skb, RTA_IIF, iif);
} else if (dst) {
- struct inet6_dev *idev = ip6_dst_idev(&rt->dst);
struct in6_addr saddr_buf;
- if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
- dst, 0, &saddr_buf) == 0)
+ if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0)
NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
}
+ if (rt->rt6i_prefsrc.plen) {
+ struct in6_addr saddr_buf;
+ ipv6_addr_copy(&saddr_buf, &rt->rt6i_prefsrc.addr);
+ NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
+ }
+
if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
goto nla_put_failure;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 43b3337..c53abcf 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -452,7 +452,7 @@ out:
}
static int
-isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
+isatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t)
{
struct ip_tunnel_prl_entry *p;
int ok = 1;
@@ -465,7 +465,8 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
else
skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT;
} else {
- struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr;
+ const struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr;
+
if (ipv6_addr_is_isatap(addr6) &&
(addr6->s6_addr32[3] == iph->saddr) &&
ipv6_chk_prefix(addr6, t->dev))
@@ -499,7 +500,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
8 bytes of packet payload. It means, that precise relaying of
ICMP in the real Internet is absolutely infeasible.
*/
- struct iphdr *iph = (struct iphdr*)skb->data;
+ const struct iphdr *iph = (const struct iphdr *)skb->data;
const int type = icmp_hdr(skb)->type;
const int code = icmp_hdr(skb)->code;
struct ip_tunnel *t;
@@ -557,7 +558,7 @@ out:
return err;
}
-static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
+static inline void ipip6_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb)
{
if (INET_ECN_is_ce(iph->tos))
IP6_ECN_set_ce(ipv6_hdr(skb));
@@ -565,7 +566,7 @@ static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
static int ipip6_rcv(struct sk_buff *skb)
{
- struct iphdr *iph;
+ const struct iphdr *iph;
struct ip_tunnel *tunnel;
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
@@ -621,7 +622,7 @@ out:
* comes from 6rd / 6to4 (RFC 3056) addr space.
*/
static inline
-__be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel)
+__be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel)
{
__be32 dst = 0;
@@ -664,8 +665,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
{
struct ip_tunnel *tunnel = netdev_priv(dev);
struct pcpu_tstats *tstats;
- struct iphdr *tiph = &tunnel->parms.iph;
- struct ipv6hdr *iph6 = ipv6_hdr(skb);
+ const struct iphdr *tiph = &tunnel->parms.iph;
+ const struct ipv6hdr *iph6 = ipv6_hdr(skb);
u8 tos = tunnel->parms.iph.tos;
__be16 df = tiph->frag_off;
struct rtable *rt; /* Route to the other host */
@@ -673,8 +674,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
struct iphdr *iph; /* Our new IP header */
unsigned int max_headroom; /* The extra header space needed */
__be32 dst = tiph->daddr;
+ struct flowi4 fl4;
int mtu;
- struct in6_addr *addr6;
+ const struct in6_addr *addr6;
int addr_type;
if (skb->protocol != htons(ETH_P_IPV6))
@@ -693,7 +695,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
goto tx_error;
}
- addr6 = (struct in6_addr*)&neigh->primary_key;
+ addr6 = (const struct in6_addr*)&neigh->primary_key;
addr_type = ipv6_addr_type(addr6);
if ((addr_type & IPV6_ADDR_UNICAST) &&
@@ -718,7 +720,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
goto tx_error;
}
- addr6 = (struct in6_addr*)&neigh->primary_key;
+ addr6 = (const struct in6_addr*)&neigh->primary_key;
addr_type = ipv6_addr_type(addr6);
if (addr_type == IPV6_ADDR_ANY) {
@@ -732,7 +734,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
dst = addr6->s6_addr32[3];
}
- rt = ip_route_output_ports(dev_net(dev), NULL,
+ rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
dst, tiph->saddr,
0, 0,
IPPROTO_IPV6, RT_TOS(tos),
@@ -826,8 +828,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
iph->frag_off = df;
iph->protocol = IPPROTO_IPV6;
iph->tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6));
- iph->daddr = rt->rt_dst;
- iph->saddr = rt->rt_src;
+ iph->daddr = fl4.daddr;
+ iph->saddr = fl4.saddr;
if ((iph->ttl = tiph->ttl) == 0)
iph->ttl = iph6->hop_limit;
@@ -849,13 +851,14 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev)
{
struct net_device *tdev = NULL;
struct ip_tunnel *tunnel;
- struct iphdr *iph;
+ const struct iphdr *iph;
+ struct flowi4 fl4;
tunnel = netdev_priv(dev);
iph = &tunnel->parms.iph;
if (iph->daddr) {
- struct rtable *rt = ip_route_output_ports(dev_net(dev), NULL,
+ struct rtable *rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
iph->daddr, iph->saddr,
0, 0,
IPPROTO_IPV6,
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 352c260..8b9644a 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -66,7 +66,7 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS],
ipv6_cookie_scratch);
-static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr,
+static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *daddr,
__be16 sport, __be16 dport, u32 count, int c)
{
__u32 *tmp = __get_cpu_var(ipv6_cookie_scratch);
@@ -86,7 +86,8 @@ static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr,
return tmp[17];
}
-static __u32 secure_tcp_syn_cookie(struct in6_addr *saddr, struct in6_addr *daddr,
+static __u32 secure_tcp_syn_cookie(const struct in6_addr *saddr,
+ const struct in6_addr *daddr,
__be16 sport, __be16 dport, __u32 sseq,
__u32 count, __u32 data)
{
@@ -96,8 +97,8 @@ static __u32 secure_tcp_syn_cookie(struct in6_addr *saddr, struct in6_addr *dadd
& COOKIEMASK));
}
-static __u32 check_tcp_syn_cookie(__u32 cookie, struct in6_addr *saddr,
- struct in6_addr *daddr, __be16 sport,
+static __u32 check_tcp_syn_cookie(__u32 cookie, const struct in6_addr *saddr,
+ const struct in6_addr *daddr, __be16 sport,
__be16 dport, __u32 sseq, __u32 count,
__u32 maxdiff)
{
@@ -116,7 +117,7 @@ static __u32 check_tcp_syn_cookie(__u32 cookie, struct in6_addr *saddr,
__u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
{
- struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
const struct tcphdr *th = tcp_hdr(skb);
int mssind;
const __u16 mss = *mssp;
@@ -138,7 +139,7 @@ __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
{
- struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
const struct tcphdr *th = tcp_hdr(skb);
__u32 seq = ntohl(th->seq) - 1;
__u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr,
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 2b0c186..8683664 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -76,8 +76,8 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
static void __tcp_v6_send_check(struct sk_buff *skb,
- struct in6_addr *saddr,
- struct in6_addr *daddr);
+ const struct in6_addr *saddr,
+ const struct in6_addr *daddr);
static const struct inet_connection_sock_af_ops ipv6_mapped;
static const struct inet_connection_sock_af_ops ipv6_specific;
@@ -86,7 +86,7 @@ static const struct tcp_sock_af_ops tcp_sock_ipv6_specific;
static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
#else
static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
- struct in6_addr *addr)
+ const struct in6_addr *addr)
{
return NULL;
}
@@ -106,8 +106,8 @@ static void tcp_v6_hash(struct sock *sk)
}
static __inline__ __sum16 tcp_v6_check(int len,
- struct in6_addr *saddr,
- struct in6_addr *daddr,
+ const struct in6_addr *saddr,
+ const struct in6_addr *daddr,
__wsum base)
{
return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
@@ -331,7 +331,7 @@ failure:
static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
u8 type, u8 code, int offset, __be32 info)
{
- struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
+ const struct ipv6hdr *hdr = (const struct ipv6hdr*)skb->data;
const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
struct ipv6_pinfo *np;
struct sock *sk;
@@ -503,6 +503,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
+ dst = NULL;
goto done;
}
skb = tcp_make_synack(sk, dst, req, rvp);
@@ -550,7 +551,7 @@ static void tcp_v6_reqsk_destructor(struct request_sock *req)
#ifdef CONFIG_TCP_MD5SIG
static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
- struct in6_addr *addr)
+ const struct in6_addr *addr)
{
struct tcp_sock *tp = tcp_sk(sk);
int i;
@@ -579,7 +580,7 @@ static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
}
-static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer,
+static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer,
char *newkey, u8 newkeylen)
{
/* Add key to the list */
@@ -644,7 +645,7 @@ static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk,
newkey, newkeylen);
}
-static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer)
+static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer)
{
struct tcp_sock *tp = tcp_sk(sk);
int i;
@@ -752,8 +753,8 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
}
static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
- struct in6_addr *daddr,
- struct in6_addr *saddr, int nbytes)
+ const struct in6_addr *daddr,
+ const struct in6_addr *saddr, int nbytes)
{
struct tcp6_pseudohdr *bp;
struct scatterlist sg;
@@ -770,7 +771,7 @@ static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
}
static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
- struct in6_addr *daddr, struct in6_addr *saddr,
+ const struct in6_addr *daddr, struct in6_addr *saddr,
struct tcphdr *th)
{
struct tcp_md5sig_pool *hp;
@@ -806,7 +807,7 @@ static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
struct sock *sk, struct request_sock *req,
struct sk_buff *skb)
{
- struct in6_addr *saddr, *daddr;
+ const struct in6_addr *saddr, *daddr;
struct tcp_md5sig_pool *hp;
struct hash_desc *desc;
struct tcphdr *th = tcp_hdr(skb);
@@ -818,7 +819,7 @@ static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
saddr = &inet6_rsk(req)->loc_addr;
daddr = &inet6_rsk(req)->rmt_addr;
} else {
- struct ipv6hdr *ip6h = ipv6_hdr(skb);
+ const struct ipv6hdr *ip6h = ipv6_hdr(skb);
saddr = &ip6h->saddr;
daddr = &ip6h->daddr;
}
@@ -856,7 +857,7 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
{
__u8 *hash_location = NULL;
struct tcp_md5sig_key *hash_expected;
- struct ipv6hdr *ip6h = ipv6_hdr(skb);
+ const struct ipv6hdr *ip6h = ipv6_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
int genhash;
u8 newhash[16];
@@ -914,7 +915,7 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
#endif
static void __tcp_v6_send_check(struct sk_buff *skb,
- struct in6_addr *saddr, struct in6_addr *daddr)
+ const struct in6_addr *saddr, const struct in6_addr *daddr)
{
struct tcphdr *th = tcp_hdr(skb);
@@ -938,7 +939,7 @@ static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
static int tcp_v6_gso_send_check(struct sk_buff *skb)
{
- struct ipv6hdr *ipv6h;
+ const struct ipv6hdr *ipv6h;
struct tcphdr *th;
if (!pskb_may_pull(skb, sizeof(*th)))
@@ -956,7 +957,7 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb)
static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
struct sk_buff *skb)
{
- struct ipv6hdr *iph = skb_gro_network_header(skb);
+ const struct ipv6hdr *iph = skb_gro_network_header(skb);
switch (skb->ip_summed) {
case CHECKSUM_COMPLETE:
@@ -977,7 +978,7 @@ static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
static int tcp6_gro_complete(struct sk_buff *skb)
{
- struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
@@ -1468,7 +1469,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
First: no IPv4 options.
*/
- newinet->opt = NULL;
+ newinet->inet_opt = NULL;
newnp->ipv6_fl_list = NULL;
/* Clone RX bits */
@@ -1621,6 +1622,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
opt_skb = skb_clone(skb, GFP_ATOMIC);
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
+ sock_rps_save_rxhash(sk, skb->rxhash);
if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
goto reset;
if (opt_skb)
@@ -1648,7 +1650,8 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
__kfree_skb(opt_skb);
return 0;
}
- }
+ } else
+ sock_rps_save_rxhash(sk, skb->rxhash);
if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
goto reset;
@@ -1699,7 +1702,7 @@ ipv6_pktoptions:
static int tcp_v6_rcv(struct sk_buff *skb)
{
struct tcphdr *th;
- struct ipv6hdr *hdr;
+ const struct ipv6hdr *hdr;
struct sock *sk;
int ret;
struct net *net = dev_net(skb->dev);
@@ -2025,8 +2028,8 @@ static void get_openreq6(struct seq_file *seq,
struct sock *sk, struct request_sock *req, int i, int uid)
{
int ttd = req->expires - jiffies;
- struct in6_addr *src = &inet6_rsk(req)->loc_addr;
- struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
+ const struct in6_addr *src = &inet6_rsk(req)->loc_addr;
+ const struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
if (ttd < 0)
ttd = 0;
@@ -2054,7 +2057,7 @@ static void get_openreq6(struct seq_file *seq,
static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
{
- struct in6_addr *dest, *src;
+ const struct in6_addr *dest, *src;
__u16 destp, srcp;
int timer_active;
unsigned long timer_expires;
@@ -2111,7 +2114,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
static void get_timewait6_sock(struct seq_file *seq,
struct inet_timewait_sock *tw, int i)
{
- struct in6_addr *dest, *src;
+ const struct in6_addr *dest, *src;
__u16 destp, srcp;
struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
int ttd = tw->tw_ttd - jiffies;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index d7037c0..fc0c42a 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -311,7 +311,7 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb,
struct udp_table *udptable)
{
struct sock *sk;
- struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
if (unlikely(sk = skb_steal_sock(skb)))
return sk;
@@ -463,9 +463,9 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
struct udp_table *udptable)
{
struct ipv6_pinfo *np;
- struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
- struct in6_addr *saddr = &hdr->saddr;
- struct in6_addr *daddr = &hdr->daddr;
+ const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
+ const struct in6_addr *saddr = &hdr->saddr;
+ const struct in6_addr *daddr = &hdr->daddr;
struct udphdr *uh = (struct udphdr*)(skb->data+offset);
struct sock *sk;
int err;
@@ -505,6 +505,9 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
int rc;
int is_udplite = IS_UDPLITE(sk);
+ if (!ipv6_addr_any(&inet6_sk(sk)->daddr))
+ sock_rps_save_rxhash(sk, skb->rxhash);
+
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
goto drop;
@@ -550,8 +553,8 @@ drop_no_sk_drops_inc:
}
static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk,
- __be16 loc_port, struct in6_addr *loc_addr,
- __be16 rmt_port, struct in6_addr *rmt_addr,
+ __be16 loc_port, const struct in6_addr *loc_addr,
+ __be16 rmt_port, const struct in6_addr *rmt_addr,
int dif)
{
struct hlist_nulls_node *node;
@@ -630,7 +633,7 @@ drop:
* so we don't need to lock the hashes.
*/
static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
- struct in6_addr *saddr, struct in6_addr *daddr,
+ const struct in6_addr *saddr, const struct in6_addr *daddr,
struct udp_table *udptable)
{
struct sock *sk, *stack[256 / sizeof(struct sock *)];
@@ -713,7 +716,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
struct net *net = dev_net(skb->dev);
struct sock *sk;
struct udphdr *uh;
- struct in6_addr *saddr, *daddr;
+ const struct in6_addr *saddr, *daddr;
u32 ulen = 0;
if (!pskb_may_pull(skb, sizeof(struct udphdr)))
@@ -1275,7 +1278,7 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
static int udp6_ufo_send_check(struct sk_buff *skb)
{
- struct ipv6hdr *ipv6h;
+ const struct ipv6hdr *ipv6h;
struct udphdr *uh;
if (!pskb_may_pull(skb, sizeof(*uh)))
@@ -1325,14 +1328,14 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features)
/* Do software UFO. Complete and fill in the UDP checksum as HW cannot
* do checksum of UDP packets sent as multiple IP fragments.
*/
- offset = skb->csum_start - skb_headroom(skb);
+ offset = skb_checksum_start_offset(skb);
csum = skb_checksum(skb, offset, skb->len- offset, 0);
offset += skb->csum_offset;
*(__sum16 *)(skb->data + offset) = csum_fold(csum);
skb->ip_summed = CHECKSUM_NONE;
/* Check if there is enough headroom to insert fragment header. */
- if ((skb_headroom(skb) < frag_hdr_sz) &&
+ if ((skb_mac_header(skb) < skb->head + frag_hdr_sz) &&
pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC))
goto out;
@@ -1379,7 +1382,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket
{
struct inet_sock *inet = inet_sk(sp);
struct ipv6_pinfo *np = inet6_sk(sp);
- struct in6_addr *dest, *src;
+ const struct in6_addr *dest, *src;
__u16 destp, srcp;
dest = &np->daddr;
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
index bbd48b1..3437d7d 100644
--- a/net/ipv6/xfrm6_mode_beet.c
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -41,10 +41,8 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
{
struct ipv6hdr *top_iph;
struct ip_beet_phdr *ph;
- struct iphdr *iphv4;
int optlen, hdr_len;
- iphv4 = ip_hdr(skb);
hdr_len = 0;
optlen = XFRM_MODE_SKB_CB(skb)->optlen;
if (unlikely(optlen))
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 645cb96..4d6edff 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -20,7 +20,7 @@
static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
{
- struct ipv6hdr *outer_iph = ipv6_hdr(skb);
+ const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
struct ipv6hdr *inner_iph = ipipv6_hdr(skb);
if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph)))
@@ -55,8 +55,8 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
dsfield &= ~INET_ECN_MASK;
ipv6_change_dsfield(top_iph, 0, dsfield);
top_iph->hop_limit = ip6_dst_hoplimit(dst->child);
- ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
- ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
+ ipv6_addr_copy(&top_iph->saddr, (const struct in6_addr *)&x->props.saddr);
+ ipv6_addr_copy(&top_iph->daddr, (const struct in6_addr *)&x->id.daddr);
return 0;
}
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 05e34c8..d879f7e 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -124,7 +124,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
struct flowi6 *fl6 = &fl->u.ip6;
int onlyproto = 0;
u16 offset = skb_network_header_len(skb);
- struct ipv6hdr *hdr = ipv6_hdr(skb);
+ const struct ipv6hdr *hdr = ipv6_hdr(skb);
struct ipv6_opt_hdr *exthdr;
const unsigned char *nh = skb_network_header(skb);
u8 nexthdr = nh[IP6CB(skb)->nhoff];
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 2969cad..a6770a0 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -68,7 +68,7 @@ static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock);
static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly;
-static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr)
+static inline unsigned xfrm6_tunnel_spi_hash_byaddr(const xfrm_address_t *addr)
{
unsigned h;
@@ -85,7 +85,7 @@ static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi)
return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE;
}
-static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr)
+static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr)
{
struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
struct xfrm6_tunnel_spi *x6spi;
@@ -101,7 +101,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_
return NULL;
}
-__be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr)
+__be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr)
{
struct xfrm6_tunnel_spi *x6spi;
u32 spi;
@@ -237,10 +237,10 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
static int xfrm6_tunnel_rcv(struct sk_buff *skb)
{
struct net *net = dev_net(skb->dev);
- struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
__be32 spi;
- spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&iph->saddr);
+ spi = xfrm6_tunnel_spi_lookup(net, (const xfrm_address_t *)&iph->saddr);
return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0;
}
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index c9890e2..cc61697 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -1297,8 +1297,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
/* Note : socket.c set MSG_EOR on SEQPACKET sockets */
if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT |
MSG_NOSIGNAL)) {
- err = -EINVAL;
- goto out;
+ return -EINVAL;
}
lock_sock(sk);
diff --git a/net/irda/irlap.c b/net/irda/irlap.c
index 783c5f3..005b424 100644
--- a/net/irda/irlap.c
+++ b/net/irda/irlap.c
@@ -165,7 +165,7 @@ struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos,
irlap_apply_default_connection_parameters(self);
- self->N3 = 3; /* # connections attemts to try before giving up */
+ self->N3 = 3; /* # connections attempts to try before giving up */
self->state = LAP_NDM;
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c
index d434c88..ccd214f 100644
--- a/net/irda/irlap_event.c
+++ b/net/irda/irlap_event.c
@@ -708,7 +708,7 @@ static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event,
self->frame_sent = TRUE;
}
- /* Readjust our timer to accomodate devices
+ /* Readjust our timer to accommodate devices
* doing faster or slower discovery than us...
* Jean II */
irlap_start_query_timer(self, info->S, info->s);
@@ -931,7 +931,7 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
irlap_send_rr_frame(self, CMD_FRAME);
/* The timer is set to half the normal timer to quickly
- * detect a failure to negociate the new connection
+ * detect a failure to negotiate the new connection
* parameters. IrLAP 6.11.3.2, note 3.
* Note that currently we don't process this failure
* properly, as we should do a quick disconnect.
@@ -1052,7 +1052,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
return -EPROTO;
}
- /* Substract space used by this skb */
+ /* Subtract space used by this skb */
self->bytes_left -= skb->len;
#else /* CONFIG_IRDA_DYNAMIC_WINDOW */
/* Window has been adjusted for the max packet
@@ -1808,7 +1808,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
return -EPROTO; /* Try again later */
}
- /* Substract space used by this skb */
+ /* Subtract space used by this skb */
self->bytes_left -= skb->len;
#else /* CONFIG_IRDA_DYNAMIC_WINDOW */
/* Window has been adjusted for the max packet
@@ -2227,8 +2227,6 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event,
struct sk_buff *skb, struct irlap_info *info)
{
- int ret = 0;
-
IRDA_DEBUG(1, "%s()\n", __func__);
IRDA_ASSERT(self != NULL, return -ENODEV;);
@@ -2289,7 +2287,6 @@ static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event,
IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__,
event, irlap_event[event]);
- ret = -EINVAL;
break;
}
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index 688222c..8c00416 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -848,7 +848,7 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
* though IrLAP is currently sending the *last* frame of the
* tx-window, the driver most likely has only just started
* sending the *first* frame of the same tx-window.
- * I.e. we are always at the very begining of or Tx window.
+ * I.e. we are always at the very beginning of or Tx window.
* Now, we are supposed to set the final timer from the end
* of our tx-window to let the other peer reply. So, we need
* to add extra time to compensate for the fact that we
diff --git a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c
index c1fb5db..9505a7d 100644
--- a/net/irda/irlmp_event.c
+++ b/net/irda/irlmp_event.c
@@ -498,7 +498,7 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
switch (event) {
#ifdef CONFIG_IRDA_ULTRA
case LM_UDATA_INDICATION:
- /* This is most bizzare. Those packets are aka unreliable
+ /* This is most bizarre. Those packets are aka unreliable
* connected, aka IrLPT or SOCK_DGRAM/IRDAPROTO_UNITDATA.
* Why do we pass them as Ultra ??? Jean II */
irlmp_connless_data_indication(self, skb);
diff --git a/net/irda/irnet/irnet.h b/net/irda/irnet/irnet.h
index 0d82ff5..979ecb2 100644
--- a/net/irda/irnet/irnet.h
+++ b/net/irda/irnet/irnet.h
@@ -73,7 +73,7 @@
* Infinite thanks to those brave souls for providing the infrastructure
* upon which IrNET is built.
*
- * Thanks to all my collegues in HP for helping me. In particular,
+ * Thanks to all my colleagues in HP for helping me. In particular,
* thanks to Salil Pradhan and Bill Serra for W2k testing...
* Thanks to Luiz Magalhaes for irnetd and much testing...
*
diff --git a/net/irda/irproc.c b/net/irda/irproc.c
index 318766e..b9ac598 100644
--- a/net/irda/irproc.c
+++ b/net/irda/irproc.c
@@ -65,15 +65,14 @@ static const struct irda_entry irda_dirs[] = {
void __init irda_proc_register(void)
{
int i;
- struct proc_dir_entry *d;
proc_irda = proc_mkdir("irda", init_net.proc_net);
if (proc_irda == NULL)
return;
for (i = 0; i < ARRAY_SIZE(irda_dirs); i++)
- d = proc_create(irda_dirs[i].name, 0, proc_irda,
- irda_dirs[i].fops);
+ (void) proc_create(irda_dirs[i].name, 0, proc_irda,
+ irda_dirs[i].fops);
}
/*
diff --git a/net/irda/irqueue.c b/net/irda/irqueue.c
index 849aaf0..9715e6e 100644
--- a/net/irda/irqueue.c
+++ b/net/irda/irqueue.c
@@ -40,7 +40,7 @@
* o the hash function for ints is pathetic (but could be changed)
* o locking is sometime suspicious (especially during enumeration)
* o most users have only a few elements (== overhead)
- * o most users never use seach, so don't benefit from hashing
+ * o most users never use search, so don't benefit from hashing
* Problem already fixed :
* o not 64 bit compliant (most users do hashv = (int) self)
* o hashbin_remove() is broken => use hashbin_remove_this()
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index f6054f9..9d9af46 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -1193,7 +1193,7 @@ EXPORT_SYMBOL(irttp_connect_request);
/*
* Function irttp_connect_confirm (handle, qos, skb)
*
- * Sevice user confirms TSAP connection with peer.
+ * Service user confirms TSAP connection with peer.
*
*/
static void irttp_connect_confirm(void *instance, void *sap,
diff --git a/net/irda/qos.c b/net/irda/qos.c
index 2b00974..1b51bcf 100644
--- a/net/irda/qos.c
+++ b/net/irda/qos.c
@@ -39,16 +39,16 @@
#include <net/irda/irlap_frame.h>
/*
- * Maximum values of the baud rate we negociate with the other end.
+ * Maximum values of the baud rate we negotiate with the other end.
* Most often, you don't have to change that, because Linux-IrDA will
* use the maximum offered by the link layer, which usually works fine.
* In some very rare cases, you may want to limit it to lower speeds...
*/
int sysctl_max_baud_rate = 16000000;
/*
- * Maximum value of the lap disconnect timer we negociate with the other end.
+ * Maximum value of the lap disconnect timer we negotiate with the other end.
* Most often, the value below represent the best compromise, but some user
- * may want to keep the LAP alive longuer or shorter in case of link failure.
+ * may want to keep the LAP alive longer or shorter in case of link failure.
* Remember that the threshold time (early warning) is fixed to 3s...
*/
int sysctl_max_noreply_time = 12;
@@ -411,7 +411,7 @@ static void irlap_adjust_qos_settings(struct qos_info *qos)
* Fix tx data size according to user limits - Jean II
*/
if (qos->data_size.value > sysctl_max_tx_data_size)
- /* Allow non discrete adjustement to avoid loosing capacity */
+ /* Allow non discrete adjustement to avoid losing capacity */
qos->data_size.value = sysctl_max_tx_data_size;
/*
* Override Tx window if user request it. - Jean II
diff --git a/net/irda/timer.c b/net/irda/timer.c
index 0335ba0..f418cb2 100644
--- a/net/irda/timer.c
+++ b/net/irda/timer.c
@@ -59,7 +59,7 @@ void irlap_start_query_timer(struct irlap_cb *self, int S, int s)
* slot time, plus add some extra time to properly receive the last
* discovery packet (which is longer due to extra discovery info),
* to avoid messing with for incomming connections requests and
- * to accomodate devices that perform discovery slower than us.
+ * to accommodate devices that perform discovery slower than us.
* Jean II */
timeout = ((sysctl_slot_timeout * HZ / 1000) * (S - s)
+ XIDEXTRA_TIMEOUT + SMALLBUSY_TIMEOUT);
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index 9637e45..986b2a5 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -250,7 +250,7 @@ static struct device *af_iucv_dev;
* PRMDATA[0..6] socket data (max 7 bytes);
* PRMDATA[7] socket data length value (len is 0xff - PRMDATA[7])
*
- * The socket data length is computed by substracting the socket data length
+ * The socket data length is computed by subtracting the socket data length
* value from 0xFF.
* If the socket data len is greater 7, then PRMDATA can be used for special
* notifications (see iucv_sock_shutdown); and further,
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index 1ee5dab..8f156bd 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -735,7 +735,7 @@ static void iucv_cleanup_queue(void)
struct iucv_irq_list *p, *n;
/*
- * When a path is severed, the pathid can be reused immediatly
+ * When a path is severed, the pathid can be reused immediately
* on a iucv connect or a connection pending interrupt. Remove
* all entries from the task queue that refer to a stale pathid
* (iucv_path_table[ix] == NULL). Only then do the iucv connect
@@ -807,7 +807,7 @@ void iucv_unregister(struct iucv_handler *handler, int smp)
spin_lock_bh(&iucv_table_lock);
/* Remove handler from the iucv_handler_list. */
list_del_init(&handler->list);
- /* Sever all pathids still refering to the handler. */
+ /* Sever all pathids still referring to the handler. */
list_for_each_entry_safe(p, n, &handler->paths, list) {
iucv_sever_pathid(p->pathid, NULL);
iucv_path_table[p->pathid] = NULL;
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 7db86ff..d62401c 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -712,7 +712,7 @@ static unsigned int pfkey_sockaddr_fill(const xfrm_address_t *xaddr, __be16 port
sin6->sin6_family = AF_INET6;
sin6->sin6_port = port;
sin6->sin6_flowinfo = 0;
- ipv6_addr_copy(&sin6->sin6_addr, (struct in6_addr *)xaddr->a6);
+ ipv6_addr_copy(&sin6->sin6_addr, (const struct in6_addr *)xaddr->a6);
sin6->sin6_scope_id = 0;
return 128;
}
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index fce9bd3..8189960 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -296,12 +296,12 @@ out_in_use:
static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
- int rc;
- struct inet_sock *inet = inet_sk(sk);
struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr;
+ struct inet_sock *inet = inet_sk(sk);
+ struct flowi4 fl4;
struct rtable *rt;
__be32 saddr;
- int oif;
+ int oif, rc;
rc = -EINVAL;
if (addr_len < sizeof(*lsa))
@@ -320,7 +320,7 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
if (ipv4_is_multicast(lsa->l2tp_addr.s_addr))
goto out;
- rt = ip_route_connect(lsa->l2tp_addr.s_addr, saddr,
+ rt = ip_route_connect(&fl4, lsa->l2tp_addr.s_addr, saddr,
RT_CONN_FLAGS(sk), oif,
IPPROTO_L2TP,
0, 0, sk, true);
@@ -340,10 +340,10 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
if (!inet->inet_saddr)
- inet->inet_saddr = rt->rt_src;
+ inet->inet_saddr = fl4.saddr;
if (!inet->inet_rcv_saddr)
- inet->inet_rcv_saddr = rt->rt_src;
- inet->inet_daddr = rt->rt_dst;
+ inet->inet_rcv_saddr = fl4.saddr;
+ inet->inet_daddr = fl4.daddr;
sk->sk_state = TCP_ESTABLISHED;
inet->inet_id = jiffies;
@@ -416,7 +416,6 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
int rc;
struct l2tp_ip_sock *lsa = l2tp_ip_sk(sk);
struct inet_sock *inet = inet_sk(sk);
- struct ip_options *opt = inet->opt;
struct rtable *rt = NULL;
int connected = 0;
__be32 daddr;
@@ -471,15 +470,23 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
rt = (struct rtable *) __sk_dst_check(sk, 0);
if (rt == NULL) {
+ struct ip_options_rcu *inet_opt;
+ struct flowi4 fl4;
+
+ rcu_read_lock();
+ inet_opt = rcu_dereference(inet->inet_opt);
+
/* Use correct destination address if we have options. */
- if (opt && opt->srr)
- daddr = opt->faddr;
+ if (inet_opt && inet_opt->opt.srr)
+ daddr = inet_opt->opt.faddr;
+
+ rcu_read_unlock();
/* If this fails, retransmit mechanism of transport layer will
* keep trying until route appears or the connection times
* itself out.
*/
- rt = ip_route_output_ports(sock_net(sk), sk,
+ rt = ip_route_output_ports(sock_net(sk), &fl4, sk,
daddr, inet->inet_saddr,
inet->inet_dport, inet->inet_sport,
sk->sk_protocol, RT_CONN_FLAGS(sk),
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index 4c1e540..93a41a0 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -795,11 +795,12 @@ int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops
goto out;
l2tp_nl_cmd_ops[pw_type] = ops;
+ ret = 0;
out:
genl_unlock();
err:
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(l2tp_nl_register_ops);
diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c
index 058f1e9..9032421 100644
--- a/net/llc/llc_input.c
+++ b/net/llc/llc_input.c
@@ -121,8 +121,7 @@ static inline int llc_fixup_skb(struct sk_buff *skb)
s32 data_size = ntohs(pdulen) - llc_len;
if (data_size < 0 ||
- ((skb_tail_pointer(skb) -
- (u8 *)pdu) - llc_len) < data_size)
+ !pskb_may_pull(skb, data_size))
return 0;
if (unlikely(pskb_trim_rcsum(skb, data_size)))
return 0;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9e3b4f0..027c046 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -97,7 +97,7 @@ struct ieee80211_bss {
size_t supp_rates_len;
/*
- * During assocation, we save an ERP value from a probe response so
+ * During association, we save an ERP value from a probe response so
* that we can feed ERP info to the driver when handling the
* association completes. these fields probably won't be up-to-date
* otherwise, you probably don't want to use them.
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 7776ae5..35c715a 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -629,7 +629,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
*
* @mpath: mesh path whose queue has to be freed
*
- * Locking: the function must me called withing a rcu_read_lock region
+ * Locking: the function must me called within a rcu_read_lock region
*/
void mesh_path_flush_pending(struct mesh_path *mpath)
{
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index dbdebeda..c06aa3a 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -259,7 +259,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
}
}
- /* try to sample up to half of the availble rates during each interval */
+ /* try to sample up to half of the available rates during each interval */
mi->sample_count *= 4;
cur_prob = 0;
diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h
index 6510f8e..19111c7 100644
--- a/net/mac80211/rc80211_pid.h
+++ b/net/mac80211/rc80211_pid.h
@@ -77,7 +77,7 @@ union rc_pid_event_data {
};
struct rc_pid_event {
- /* The time when the event occured */
+ /* The time when the event occurred */
unsigned long timestamp;
/* Event ID number */
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 81241e1..13a6697 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -382,7 +382,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
* specs were sane enough this time around to require padding each A-MSDU
* subframe to a length that is a multiple of four.
*
- * Padding like Atheros hardware adds which is inbetween the 802.11 header and
+ * Padding like Atheros hardware adds which is between the 802.11 header and
* the payload is not supported, the driver is required to move the 802.11
* header to be directly in front of the payload in that case.
*/
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index f05244d..d9e6e81 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -47,9 +47,9 @@
* Station entries are added by mac80211 when you establish a link with a
* peer. This means different things for the different type of interfaces
* we support. For a regular station this mean we add the AP sta when we
- * receive an assocation response from the AP. For IBSS this occurs when
+ * receive an association response from the AP. For IBSS this occurs when
* get to know about a peer on the same IBSS. For WDS we add the sta for
- * the peer imediately upon device open. When using AP mode we add stations
+ * the peer immediately upon device open. When using AP mode we add stations
* for each respective station upon request from userspace through nl80211.
*
* In order to remove a STA info structure, various sta_info_destroy_*()
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index af1a7f8..aa0adcb 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -176,7 +176,7 @@ struct sta_ampdu_mlme {
/**
* enum plink_state - state of a mesh peer link finite state machine
*
- * @PLINK_LISTEN: initial state, considered the implicit state of non existant
+ * @PLINK_LISTEN: initial state, considered the implicit state of non existent
* mesh peer links
* @PLINK_OPN_SNT: mesh plink open frame has been sent to this mesh peer
* @PLINK_OPN_RCVD: mesh plink open frame has been received from this mesh peer
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index c3f988a..32bff6d 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -652,7 +652,6 @@ comment "Xtables matches"
config NETFILTER_XT_MATCH_ADDRTYPE
tristate '"addrtype" address type match support'
depends on NETFILTER_ADVANCED
- depends on (IPV6 || IPV6=n)
---help---
This option allows you to match what routing thinks of an address,
eg. UNICAST, LOCAL, BROADCAST, ...
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c
index bca9699..a113ff0 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ip.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ip.c
@@ -338,8 +338,7 @@ bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
if (map->netmask != 32)
NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
- NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
- htonl(atomic_read(&set->ref) - 1));
+ NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
htonl(sizeof(*map) + map->memsize));
if (with_timeout(map->timeout))
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
index 5e79017..a274300 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
@@ -343,6 +343,10 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
ipset_adtfn adtfn = set->variant->adt[adt];
struct ipmac data;
+ /* MAC can be src only */
+ if (!(flags & IPSET_DIM_TWO_SRC))
+ return 0;
+
data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
if (data.id < map->first_ip || data.id > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
@@ -434,8 +438,7 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb)
goto nla_put_failure;
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip));
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
- NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
- htonl(atomic_read(&set->ref) - 1));
+ NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
htonl(sizeof(*map)
+ (map->last_ip - map->first_ip + 1) * map->dsize));
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c
index 165f09b..6b38eb8 100644
--- a/net/netfilter/ipset/ip_set_bitmap_port.c
+++ b/net/netfilter/ipset/ip_set_bitmap_port.c
@@ -320,8 +320,7 @@ bitmap_port_head(struct ip_set *set, struct sk_buff *skb)
goto nla_put_failure;
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port));
NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
- NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
- htonl(atomic_read(&set->ref) - 1));
+ NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
htonl(sizeof(*map) + map->memsize));
if (with_timeout(map->timeout))
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index d6b4823..72d1ac6 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -26,6 +26,7 @@
static LIST_HEAD(ip_set_type_list); /* all registered set types */
static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */
+static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */
static struct ip_set **ip_set_list; /* all individual sets */
static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */
@@ -301,13 +302,18 @@ EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6);
static inline void
__ip_set_get(ip_set_id_t index)
{
- atomic_inc(&ip_set_list[index]->ref);
+ write_lock_bh(&ip_set_ref_lock);
+ ip_set_list[index]->ref++;
+ write_unlock_bh(&ip_set_ref_lock);
}
static inline void
__ip_set_put(ip_set_id_t index)
{
- atomic_dec(&ip_set_list[index]->ref);
+ write_lock_bh(&ip_set_ref_lock);
+ BUG_ON(ip_set_list[index]->ref == 0);
+ ip_set_list[index]->ref--;
+ write_unlock_bh(&ip_set_ref_lock);
}
/*
@@ -324,7 +330,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
struct ip_set *set = ip_set_list[index];
int ret = 0;
- BUG_ON(set == NULL || atomic_read(&set->ref) == 0);
+ BUG_ON(set == NULL);
pr_debug("set %s, index %u\n", set->name, index);
if (dim < set->type->dimension ||
@@ -356,7 +362,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
struct ip_set *set = ip_set_list[index];
int ret;
- BUG_ON(set == NULL || atomic_read(&set->ref) == 0);
+ BUG_ON(set == NULL);
pr_debug("set %s, index %u\n", set->name, index);
if (dim < set->type->dimension ||
@@ -378,7 +384,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
struct ip_set *set = ip_set_list[index];
int ret = 0;
- BUG_ON(set == NULL || atomic_read(&set->ref) == 0);
+ BUG_ON(set == NULL);
pr_debug("set %s, index %u\n", set->name, index);
if (dim < set->type->dimension ||
@@ -397,7 +403,6 @@ EXPORT_SYMBOL_GPL(ip_set_del);
* Find set by name, reference it once. The reference makes sure the
* thing pointed to, does not go away under our feet.
*
- * The nfnl mutex must already be activated.
*/
ip_set_id_t
ip_set_get_byname(const char *name, struct ip_set **set)
@@ -423,15 +428,12 @@ EXPORT_SYMBOL_GPL(ip_set_get_byname);
* reference count by 1. The caller shall not assume the index
* to be valid, after calling this function.
*
- * The nfnl mutex must already be activated.
*/
void
ip_set_put_byindex(ip_set_id_t index)
{
- if (ip_set_list[index] != NULL) {
- BUG_ON(atomic_read(&ip_set_list[index]->ref) == 0);
+ if (ip_set_list[index] != NULL)
__ip_set_put(index);
- }
}
EXPORT_SYMBOL_GPL(ip_set_put_byindex);
@@ -441,7 +443,6 @@ EXPORT_SYMBOL_GPL(ip_set_put_byindex);
* can't be destroyed. The set cannot be renamed due to
* the referencing either.
*
- * The nfnl mutex must already be activated.
*/
const char *
ip_set_name_byindex(ip_set_id_t index)
@@ -449,7 +450,7 @@ ip_set_name_byindex(ip_set_id_t index)
const struct ip_set *set = ip_set_list[index];
BUG_ON(set == NULL);
- BUG_ON(atomic_read(&set->ref) == 0);
+ BUG_ON(set->ref == 0);
/* Referenced, so it's safe */
return set->name;
@@ -515,10 +516,7 @@ void
ip_set_nfnl_put(ip_set_id_t index)
{
nfnl_lock();
- if (ip_set_list[index] != NULL) {
- BUG_ON(atomic_read(&ip_set_list[index]->ref) == 0);
- __ip_set_put(index);
- }
+ ip_set_put_byindex(index);
nfnl_unlock();
}
EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
@@ -526,7 +524,7 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
/*
* Communication protocol with userspace over netlink.
*
- * We already locked by nfnl_lock.
+ * The commands are serialized by the nfnl mutex.
*/
static inline bool
@@ -657,7 +655,6 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
return -ENOMEM;
rwlock_init(&set->lock);
strlcpy(set->name, name, IPSET_MAXNAMELEN);
- atomic_set(&set->ref, 0);
set->family = family;
/*
@@ -690,8 +687,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
/*
* Here, we have a valid, constructed set and we are protected
- * by nfnl_lock. Find the first free index in ip_set_list and
- * check clashing.
+ * by the nfnl mutex. Find the first free index in ip_set_list
+ * and check clashing.
*/
if ((ret = find_free_id(set->name, &index, &clash)) != 0) {
/* If this is the same set and requested, ignore error */
@@ -751,31 +748,51 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
const struct nlattr * const attr[])
{
ip_set_id_t i;
+ int ret = 0;
if (unlikely(protocol_failed(attr)))
return -IPSET_ERR_PROTOCOL;
- /* References are protected by the nfnl mutex */
+ /* Commands are serialized and references are
+ * protected by the ip_set_ref_lock.
+ * External systems (i.e. xt_set) must call
+ * ip_set_put|get_nfnl_* functions, that way we
+ * can safely check references here.
+ *
+ * list:set timer can only decrement the reference
+ * counter, so if it's already zero, we can proceed
+ * without holding the lock.
+ */
+ read_lock_bh(&ip_set_ref_lock);
if (!attr[IPSET_ATTR_SETNAME]) {
for (i = 0; i < ip_set_max; i++) {
- if (ip_set_list[i] != NULL &&
- (atomic_read(&ip_set_list[i]->ref)))
- return -IPSET_ERR_BUSY;
+ if (ip_set_list[i] != NULL && ip_set_list[i]->ref) {
+ ret = IPSET_ERR_BUSY;
+ goto out;
+ }
}
+ read_unlock_bh(&ip_set_ref_lock);
for (i = 0; i < ip_set_max; i++) {
if (ip_set_list[i] != NULL)
ip_set_destroy_set(i);
}
} else {
i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
- if (i == IPSET_INVALID_ID)
- return -ENOENT;
- else if (atomic_read(&ip_set_list[i]->ref))
- return -IPSET_ERR_BUSY;
+ if (i == IPSET_INVALID_ID) {
+ ret = -ENOENT;
+ goto out;
+ } else if (ip_set_list[i]->ref) {
+ ret = -IPSET_ERR_BUSY;
+ goto out;
+ }
+ read_unlock_bh(&ip_set_ref_lock);
ip_set_destroy_set(i);
}
return 0;
+out:
+ read_unlock_bh(&ip_set_ref_lock);
+ return ret;
}
/* Flush sets */
@@ -834,6 +851,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
struct ip_set *set;
const char *name2;
ip_set_id_t i;
+ int ret = 0;
if (unlikely(protocol_failed(attr) ||
attr[IPSET_ATTR_SETNAME] == NULL ||
@@ -843,25 +861,33 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL)
return -ENOENT;
- if (atomic_read(&set->ref) != 0)
- return -IPSET_ERR_REFERENCED;
+
+ read_lock_bh(&ip_set_ref_lock);
+ if (set->ref != 0) {
+ ret = -IPSET_ERR_REFERENCED;
+ goto out;
+ }
name2 = nla_data(attr[IPSET_ATTR_SETNAME2]);
for (i = 0; i < ip_set_max; i++) {
if (ip_set_list[i] != NULL &&
- STREQ(ip_set_list[i]->name, name2))
- return -IPSET_ERR_EXIST_SETNAME2;
+ STREQ(ip_set_list[i]->name, name2)) {
+ ret = -IPSET_ERR_EXIST_SETNAME2;
+ goto out;
+ }
}
strncpy(set->name, name2, IPSET_MAXNAMELEN);
- return 0;
+out:
+ read_unlock_bh(&ip_set_ref_lock);
+ return ret;
}
/* Swap two sets so that name/index points to the other.
* References and set names are also swapped.
*
- * We are protected by the nfnl mutex and references are
- * manipulated only by holding the mutex. The kernel interfaces
+ * The commands are serialized by the nfnl mutex and references are
+ * protected by the ip_set_ref_lock. The kernel interfaces
* do not hold the mutex but the pointer settings are atomic
* so the ip_set_list always contains valid pointers to the sets.
*/
@@ -874,7 +900,6 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
struct ip_set *from, *to;
ip_set_id_t from_id, to_id;
char from_name[IPSET_MAXNAMELEN];
- u32 from_ref;
if (unlikely(protocol_failed(attr) ||
attr[IPSET_ATTR_SETNAME] == NULL ||
@@ -893,23 +918,21 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
to = ip_set_list[to_id];
/* Features must not change.
- * Not an artifical restriction anymore, as we must prevent
+ * Not an artificial restriction anymore, as we must prevent
* possible loops created by swapping in setlist type of sets. */
if (!(from->type->features == to->type->features &&
from->type->family == to->type->family))
return -IPSET_ERR_TYPE_MISMATCH;
- /* No magic here: ref munging protected by the nfnl_lock */
strncpy(from_name, from->name, IPSET_MAXNAMELEN);
- from_ref = atomic_read(&from->ref);
-
strncpy(from->name, to->name, IPSET_MAXNAMELEN);
- atomic_set(&from->ref, atomic_read(&to->ref));
strncpy(to->name, from_name, IPSET_MAXNAMELEN);
- atomic_set(&to->ref, from_ref);
+ write_lock_bh(&ip_set_ref_lock);
+ swap(from->ref, to->ref);
ip_set_list[from_id] = to;
ip_set_list[to_id] = from;
+ write_unlock_bh(&ip_set_ref_lock);
return 0;
}
@@ -926,7 +949,7 @@ ip_set_dump_done(struct netlink_callback *cb)
{
if (cb->args[2]) {
pr_debug("release set %s\n", ip_set_list[cb->args[1]]->name);
- __ip_set_put((ip_set_id_t) cb->args[1]);
+ ip_set_put_byindex((ip_set_id_t) cb->args[1]);
}
return 0;
}
@@ -999,8 +1022,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
if (cb->args[1] >= ip_set_max)
goto out;
- pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]);
max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
+dump_last:
+ pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]);
for (; cb->args[1] < max; cb->args[1]++) {
index = (ip_set_id_t) cb->args[1];
set = ip_set_list[index];
@@ -1015,8 +1039,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
* so that lists (unions of sets) are dumped last.
*/
if (cb->args[0] != DUMP_ONE &&
- !((cb->args[0] == DUMP_ALL) ^
- (set->type->features & IPSET_DUMP_LAST)))
+ ((cb->args[0] == DUMP_ALL) ==
+ !!(set->type->features & IPSET_DUMP_LAST)))
continue;
pr_debug("List set: %s\n", set->name);
if (!cb->args[2]) {
@@ -1060,6 +1084,12 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
goto release_refcount;
}
}
+ /* If we dump all sets, continue with dumping last ones */
+ if (cb->args[0] == DUMP_ALL) {
+ cb->args[0] = DUMP_LAST;
+ cb->args[1] = 0;
+ goto dump_last;
+ }
goto out;
nla_put_failure:
@@ -1068,13 +1098,8 @@ release_refcount:
/* If there was an error or set is done, release set */
if (ret || !cb->args[2]) {
pr_debug("release set %s\n", ip_set_list[index]->name);
- __ip_set_put(index);
+ ip_set_put_byindex(index);
}
-
- /* If we dump all sets, continue with dumping last ones */
- if (cb->args[0] == DUMP_ALL && cb->args[1] >= max && !cb->args[2])
- cb->args[0] = DUMP_LAST;
-
out:
if (nlh) {
nlmsg_end(skb, nlh);
diff --git a/net/netfilter/ipset/ip_set_getport.c b/net/netfilter/ipset/ip_set_getport.c
index 8d52272..757143b 100644
--- a/net/netfilter/ipset/ip_set_getport.c
+++ b/net/netfilter/ipset/ip_set_getport.c
@@ -11,6 +11,7 @@
#include <linux/skbuff.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
+#include <linux/sctp.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <net/ip.h>
#include <net/ipv6.h>
@@ -35,7 +36,20 @@ get_port(const struct sk_buff *skb, int protocol, unsigned int protooff,
*port = src ? th->source : th->dest;
break;
}
- case IPPROTO_UDP: {
+ case IPPROTO_SCTP: {
+ sctp_sctphdr_t _sh;
+ const sctp_sctphdr_t *sh;
+
+ sh = skb_header_pointer(skb, protooff, sizeof(_sh), &_sh);
+ if (sh == NULL)
+ /* No choice either */
+ return false;
+
+ *port = src ? sh->source : sh->dest;
+ break;
+ }
+ case IPPROTO_UDP:
+ case IPPROTO_UDPLITE: {
struct udphdr _udph;
const struct udphdr *uh;
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c
index b921414..14281b6 100644
--- a/net/netfilter/ipset/ip_set_hash_ipport.c
+++ b/net/netfilter/ipset/ip_set_hash_ipport.c
@@ -491,7 +491,7 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
.dimension = IPSET_DIM_TWO,
.family = AF_UNSPEC,
- .revision = 0,
+ .revision = 1,
.create = hash_ipport_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c
index 4642872..401c8a2 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportip.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportip.c
@@ -509,7 +509,7 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
.dimension = IPSET_DIM_THREE,
.family = AF_UNSPEC,
- .revision = 0,
+ .revision = 1,
.create = hash_ipportip_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c
index 2cb84a5..4743e54 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -574,7 +574,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
.dimension = IPSET_DIM_THREE,
.family = AF_UNSPEC,
- .revision = 0,
+ .revision = 1,
.create = hash_ipportnet_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c
index 8598676..d2a4036 100644
--- a/net/netfilter/ipset/ip_set_hash_netport.c
+++ b/net/netfilter/ipset/ip_set_hash_netport.c
@@ -526,7 +526,7 @@ static struct ip_set_type hash_netport_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
.dimension = IPSET_DIM_TWO,
.family = AF_UNSPEC,
- .revision = 0,
+ .revision = 1,
.create = hash_netport_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index a47c329..e9159e9 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/net/netfilter/ipset/ip_set_list_set.c
@@ -43,14 +43,19 @@ struct list_set {
static inline struct set_elem *
list_set_elem(const struct list_set *map, u32 id)
{
- return (struct set_elem *)((char *)map->members + id * map->dsize);
+ return (struct set_elem *)((void *)map->members + id * map->dsize);
+}
+
+static inline struct set_telem *
+list_set_telem(const struct list_set *map, u32 id)
+{
+ return (struct set_telem *)((void *)map->members + id * map->dsize);
}
static inline bool
list_set_timeout(const struct list_set *map, u32 id)
{
- const struct set_telem *elem =
- (const struct set_telem *) list_set_elem(map, id);
+ const struct set_telem *elem = list_set_telem(map, id);
return ip_set_timeout_test(elem->timeout);
}
@@ -58,19 +63,11 @@ list_set_timeout(const struct list_set *map, u32 id)
static inline bool
list_set_expired(const struct list_set *map, u32 id)
{
- const struct set_telem *elem =
- (const struct set_telem *) list_set_elem(map, id);
+ const struct set_telem *elem = list_set_telem(map, id);
return ip_set_timeout_expired(elem->timeout);
}
-static inline int
-list_set_exist(const struct set_telem *elem)
-{
- return elem->id != IPSET_INVALID_ID &&
- !ip_set_timeout_expired(elem->timeout);
-}
-
/* Set list without and with timeout */
static int
@@ -146,11 +143,11 @@ list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id,
struct set_telem *e;
for (; i < map->size; i++) {
- e = (struct set_telem *)list_set_elem(map, i);
+ e = list_set_telem(map, i);
swap(e->id, id);
+ swap(e->timeout, timeout);
if (e->id == IPSET_INVALID_ID)
break;
- swap(e->timeout, timeout);
}
}
@@ -164,7 +161,7 @@ list_set_add(struct list_set *map, u32 i, ip_set_id_t id,
/* Last element replaced: e.g. add new,before,last */
ip_set_put_byindex(e->id);
if (with_timeout(map->timeout))
- list_elem_tadd(map, i, id, timeout);
+ list_elem_tadd(map, i, id, ip_set_timeout_set(timeout));
else
list_elem_add(map, i, id);
@@ -172,11 +169,11 @@ list_set_add(struct list_set *map, u32 i, ip_set_id_t id,
}
static int
-list_set_del(struct list_set *map, ip_set_id_t id, u32 i)
+list_set_del(struct list_set *map, u32 i)
{
struct set_elem *a = list_set_elem(map, i), *b;
- ip_set_put_byindex(id);
+ ip_set_put_byindex(a->id);
for (; i < map->size - 1; i++) {
b = list_set_elem(map, i + 1);
@@ -308,11 +305,11 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
(before == 0 ||
(before > 0 &&
next_id_eq(map, i, refid))))
- ret = list_set_del(map, id, i);
+ ret = list_set_del(map, i);
else if (before < 0 &&
elem->id == refid &&
next_id_eq(map, i, id))
- ret = list_set_del(map, id, i + 1);
+ ret = list_set_del(map, i + 1);
}
break;
default:
@@ -369,8 +366,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
NLA_PUT_NET32(skb, IPSET_ATTR_SIZE, htonl(map->size));
if (with_timeout(map->timeout))
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
- NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
- htonl(atomic_read(&set->ref) - 1));
+ NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
htonl(sizeof(*map) + map->size * map->dsize));
ipset_nest_end(skb, nested);
@@ -461,16 +457,13 @@ list_set_gc(unsigned long ul_set)
struct set_telem *e;
u32 i;
- /* We run parallel with other readers (test element)
- * but adding/deleting new entries is locked out */
- read_lock_bh(&set->lock);
- for (i = map->size - 1; i >= 0; i--) {
- e = (struct set_telem *) list_set_elem(map, i);
- if (e->id != IPSET_INVALID_ID &&
- list_set_expired(map, i))
- list_set_del(map, e->id, i);
+ write_lock_bh(&set->lock);
+ for (i = 0; i < map->size; i++) {
+ e = list_set_telem(map, i);
+ if (e->id != IPSET_INVALID_ID && list_set_expired(map, i))
+ list_set_del(map, i);
}
- read_unlock_bh(&set->lock);
+ write_unlock_bh(&set->lock);
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
add_timer(&map->gc);
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index f289306..c97bd45 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -595,7 +595,7 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
atomic_inc(&dest->inactconns);
} else {
/* It is a persistent connection/template, so increase
- the peristent connection counter */
+ the persistent connection counter */
atomic_inc(&dest->persistconns);
}
@@ -657,7 +657,7 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
}
} else {
/* It is a persistent connection/template, so decrease
- the peristent connection counter */
+ the persistent connection counter */
atomic_dec(&dest->persistconns);
}
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 33733c8..9930f34 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -1984,9 +1984,6 @@ static const struct file_operations ip_vs_info_fops = {
.release = seq_release_private,
};
-#endif
-
-#ifdef CONFIG_PROC_FS
static int ip_vs_stats_show(struct seq_file *seq, void *v)
{
struct net *net = seq_file_single_net(seq);
@@ -3120,7 +3117,7 @@ nla_put_failure:
static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
struct netlink_callback *cb)
{
- struct net *net = skb_net(skb);
+ struct net *net = skb_sknet(skb);
struct netns_ipvs *ipvs = net_ipvs(net);
mutex_lock(&__ip_vs_mutex);
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index f276df9..87e40ea 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -131,7 +131,7 @@ static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en)
{
list_del(&en->list);
/*
- * We don't kfree dest because it is refered either by its service
+ * We don't kfree dest because it is referred either by its service
* or the trash dest list.
*/
atomic_dec(&en->dest->refcnt);
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index cb1c991..90f618a 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -152,7 +152,7 @@ static void ip_vs_dest_set_eraseall(struct ip_vs_dest_set *set)
write_lock(&set->lock);
list_for_each_entry_safe(e, ep, &set->list, list) {
/*
- * We don't kfree dest because it is refered either
+ * We don't kfree dest because it is referred either
* by its service or by the trash dest list.
*/
atomic_dec(&e->dest->refcnt);
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
index b027ccc..d12ed53 100644
--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -566,7 +566,7 @@ static struct ipvs_sctp_nextstate
* SHUTDOWN sent from the client, waitinf for SHUT ACK from the server
*/
/*
- * We recieved the data chuck, keep the state unchanged. I assume
+ * We received the data chuck, keep the state unchanged. I assume
* that still data chuncks can be received by both the peers in
* SHUDOWN state
*/
@@ -633,7 +633,7 @@ static struct ipvs_sctp_nextstate
* SHUTDOWN sent from the server, waitinf for SHUTDOWN ACK from client
*/
/*
- * We recieved the data chuck, keep the state unchanged. I assume
+ * We received the data chuck, keep the state unchanged. I assume
* that still data chuncks can be received by both the peers in
* SHUDOWN state
*/
@@ -701,7 +701,7 @@ static struct ipvs_sctp_nextstate
* SHUTDOWN ACK from the client, awaiting for SHUTDOWN COM from server
*/
/*
- * We recieved the data chuck, keep the state unchanged. I assume
+ * We received the data chuck, keep the state unchanged. I assume
* that still data chuncks can be received by both the peers in
* SHUDOWN state
*/
@@ -771,7 +771,7 @@ static struct ipvs_sctp_nextstate
* SHUTDOWN ACK from the server, awaiting for SHUTDOWN COM from client
*/
/*
- * We recieved the data chuck, keep the state unchanged. I assume
+ * We received the data chuck, keep the state unchanged. I assume
* that still data chuncks can be received by both the peers in
* SHUDOWN state
*/
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 941286c..2e1c11f 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -453,7 +453,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
REJECT will give spurious warnings here. */
/* NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
- /* No external references means noone else could have
+ /* No external references means no one else could have
confirmed us. */
NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
pr_debug("Confirming conntrack %p\n", ct);
@@ -901,7 +901,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
ret = l3proto->get_l4proto(skb, skb_network_offset(skb),
&dataoff, &protonum);
if (ret <= 0) {
- pr_debug("not prepared to track yet or error occured\n");
+ pr_debug("not prepared to track yet or error occurred\n");
NF_CT_STAT_INC_ATOMIC(net, error);
NF_CT_STAT_INC_ATOMIC(net, invalid);
ret = -ret;
diff --git a/net/netfilter/nf_conntrack_h323_asn1.c b/net/netfilter/nf_conntrack_h323_asn1.c
index 8678823..bcd5ed6 100644
--- a/net/netfilter/nf_conntrack_h323_asn1.c
+++ b/net/netfilter/nf_conntrack_h323_asn1.c
@@ -631,7 +631,7 @@ static int decode_seqof(bitstr_t *bs, const struct field_t *f,
CHECK_BOUND(bs, 2);
count = *bs->cur++;
count <<= 8;
- count = *bs->cur++;
+ count += *bs->cur++;
break;
case SEMI:
BYTE_ALIGN(bs);
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 533a183..18b2ce5 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -731,10 +731,10 @@ static int callforward_do_filter(const union nf_inet_addr *src,
memset(&fl2, 0, sizeof(fl2));
fl2.daddr = dst->ip;
- if (!afinfo->route((struct dst_entry **)&rt1,
- flowi4_to_flowi(&fl1))) {
- if (!afinfo->route((struct dst_entry **)&rt2,
- flowi4_to_flowi(&fl2))) {
+ if (!afinfo->route(&init_net, (struct dst_entry **)&rt1,
+ flowi4_to_flowi(&fl1), false)) {
+ if (!afinfo->route(&init_net, (struct dst_entry **)&rt2,
+ flowi4_to_flowi(&fl2), false)) {
if (rt1->rt_gateway == rt2->rt_gateway &&
rt1->dst.dev == rt2->dst.dev)
ret = 1;
@@ -755,10 +755,10 @@ static int callforward_do_filter(const union nf_inet_addr *src,
memset(&fl2, 0, sizeof(fl2));
ipv6_addr_copy(&fl2.daddr, &dst->in6);
- if (!afinfo->route((struct dst_entry **)&rt1,
- flowi6_to_flowi(&fl1))) {
- if (!afinfo->route((struct dst_entry **)&rt2,
- flowi6_to_flowi(&fl2))) {
+ if (!afinfo->route(&init_net, (struct dst_entry **)&rt1,
+ flowi6_to_flowi(&fl1), false)) {
+ if (!afinfo->route(&init_net, (struct dst_entry **)&rt2,
+ flowi6_to_flowi(&fl2), false)) {
if (!memcmp(&rt1->rt6i_gateway, &rt2->rt6i_gateway,
sizeof(rt1->rt6i_gateway)) &&
rt1->dst.dev == rt2->dst.dev)
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index 9ae57c5..2e664a6 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -98,7 +98,7 @@ static const char * const dccp_state_names[] = {
#define sIV CT_DCCP_INVALID
/*
- * DCCP state transistion table
+ * DCCP state transition table
*
* The assumption is the same as for TCP tracking:
*
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index 6f4ee70..6772b11 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -107,9 +107,9 @@ static const u8 sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = {
/* abort */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
/* shutdown */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA},
/* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA},
-/* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant have Stale cookie*/
+/* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Can't have Stale cookie*/
/* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA},/* 5.2.4 - Big TODO */
-/* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in orig dir */
+/* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Can't come in orig dir */
/* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL}
},
{
@@ -121,7 +121,7 @@ static const u8 sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = {
/* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA},
/* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA},
/* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA},
-/* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in reply dir */
+/* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Can't come in reply dir */
/* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA},
/* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL}
}
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index bcf47eb..237cc19 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -707,7 +707,7 @@ static const char *ct_sdp_header_search(const char *dptr, const char *limit,
}
/* Locate a SDP header (optionally a substring within the header value),
- * optionally stopping at the first occurence of the term header, parse
+ * optionally stopping at the first occurrence of the term header, parse
* it and return the offset and length of the data we're interested in.
*/
int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 0ae1428..05e9feb 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -245,7 +245,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
ret = 0;
release:
nf_ct_put(ct);
- return 0;
+ return ret;
}
static const struct seq_operations ct_seq_ops = {
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 5ab22e2..5b466cd 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -134,7 +134,7 @@ static int __nf_queue(struct sk_buff *skb,
const struct nf_afinfo *afinfo;
const struct nf_queue_handler *qh;
- /* QUEUE == DROP if noone is waiting, to be safe. */
+ /* QUEUE == DROP if no one is waiting, to be safe. */
rcu_read_lock();
qh = rcu_dereference(queue_handler[pf]);
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 985e9b7..e0ee010 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -381,7 +381,6 @@ __build_packet_message(struct nfulnl_instance *inst,
struct nfulnl_msg_packet_hdr pmsg;
struct nlmsghdr *nlh;
struct nfgenmsg *nfmsg;
- __be32 tmp_uint;
sk_buff_data_t old_tail = inst->skb->tail;
nlh = NLMSG_PUT(inst->skb, 0, 0,
@@ -428,7 +427,6 @@ __build_packet_message(struct nfulnl_instance *inst,
}
if (outdev) {
- tmp_uint = htonl(outdev->ifindex);
#ifndef CONFIG_BRIDGE_NETFILTER
NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV,
htonl(outdev->ifindex));
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index a9adf4c..52959ef 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -762,8 +762,8 @@ void xt_compat_unlock(u_int8_t af)
EXPORT_SYMBOL_GPL(xt_compat_unlock);
#endif
-DEFINE_PER_CPU(struct xt_info_lock, xt_info_locks);
-EXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks);
+DEFINE_PER_CPU(seqcount_t, xt_recseq);
+EXPORT_PER_CPU_SYMBOL_GPL(xt_recseq);
static int xt_jumpstack_alloc(struct xt_table_info *i)
{
@@ -1362,10 +1362,7 @@ static int __init xt_init(void)
int rv;
for_each_possible_cpu(i) {
- struct xt_info_lock *lock = &per_cpu(xt_info_locks, i);
-
- seqlock_init(&lock->lock);
- lock->readers = 0;
+ seqcount_init(&per_cpu(xt_recseq, i));
}
xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL);
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
index 6e6b46c..9e63b43 100644
--- a/net/netfilter/xt_TCPMSS.c
+++ b/net/netfilter/xt_TCPMSS.c
@@ -166,7 +166,7 @@ static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb,
rcu_read_lock();
ai = nf_get_afinfo(family);
if (ai != NULL)
- ai->route((struct dst_entry **)&rt, &fl);
+ ai->route(&init_net, (struct dst_entry **)&rt, &fl, false);
rcu_read_unlock();
if (rt != NULL) {
diff --git a/net/netfilter/xt_addrtype.c b/net/netfilter/xt_addrtype.c
index 2220b85..b77d383 100644
--- a/net/netfilter/xt_addrtype.c
+++ b/net/netfilter/xt_addrtype.c
@@ -32,11 +32,32 @@ MODULE_ALIAS("ipt_addrtype");
MODULE_ALIAS("ip6t_addrtype");
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
-static u32 xt_addrtype_rt6_to_type(const struct rt6_info *rt)
+static u32 match_lookup_rt6(struct net *net, const struct net_device *dev,
+ const struct in6_addr *addr)
{
+ const struct nf_afinfo *afinfo;
+ struct flowi6 flow;
+ struct rt6_info *rt;
u32 ret;
+ int route_err;
- if (!rt)
+ memset(&flow, 0, sizeof(flow));
+ ipv6_addr_copy(&flow.daddr, addr);
+ if (dev)
+ flow.flowi6_oif = dev->ifindex;
+
+ rcu_read_lock();
+
+ afinfo = nf_get_afinfo(NFPROTO_IPV6);
+ if (afinfo != NULL)
+ route_err = afinfo->route(net, (struct dst_entry **)&rt,
+ flowi6_to_flowi(&flow), !!dev);
+ else
+ route_err = 1;
+
+ rcu_read_unlock();
+
+ if (route_err)
return XT_ADDRTYPE_UNREACHABLE;
if (rt->rt6i_flags & RTF_REJECT)
@@ -48,6 +69,9 @@ static u32 xt_addrtype_rt6_to_type(const struct rt6_info *rt)
ret |= XT_ADDRTYPE_LOCAL;
if (rt->rt6i_flags & RTF_ANYCAST)
ret |= XT_ADDRTYPE_ANYCAST;
+
+
+ dst_release(&rt->dst);
return ret;
}
@@ -65,18 +89,8 @@ static bool match_type6(struct net *net, const struct net_device *dev,
return false;
if ((XT_ADDRTYPE_LOCAL | XT_ADDRTYPE_ANYCAST |
- XT_ADDRTYPE_UNREACHABLE) & mask) {
- struct rt6_info *rt;
- u32 type;
- int ifindex = dev ? dev->ifindex : 0;
-
- rt = rt6_lookup(net, addr, NULL, ifindex, !!dev);
-
- type = xt_addrtype_rt6_to_type(rt);
-
- dst_release(&rt->dst);
- return !!(mask & type);
- }
+ XT_ADDRTYPE_UNREACHABLE) & mask)
+ return !!(mask & match_lookup_rt6(net, dev, addr));
return true;
}
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index 2c0086a..481a86f 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -195,7 +195,7 @@ conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par,
return info->match_flags & XT_CONNTRACK_STATE;
if ((info->match_flags & XT_CONNTRACK_DIRECTION) &&
(CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^
- !!(info->invert_flags & XT_CONNTRACK_DIRECTION))
+ !(info->invert_flags & XT_CONNTRACK_DIRECTION))
return false;
if (info->match_flags & XT_CONNTRACK_ORIGSRC)
diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c
index 061d48c..b3babae 100644
--- a/net/netfilter/xt_set.c
+++ b/net/netfilter/xt_set.c
@@ -81,6 +81,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
pr_warning("Protocol error: set match dimension "
"is over the limit!\n");
+ ip_set_nfnl_put(info->match_set.index);
return -ERANGE;
}
@@ -135,6 +136,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find del_set index %u as target\n",
info->del_set.index);
+ if (info->add_set.index != IPSET_INVALID_ID)
+ ip_set_nfnl_put(info->add_set.index);
return -ENOENT;
}
}
@@ -142,6 +145,10 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
pr_warning("Protocol error: SET target dimension "
"is over the limit!\n");
+ if (info->add_set.index != IPSET_INVALID_ID)
+ ip_set_nfnl_put(info->add_set.index);
+ if (info->del_set.index != IPSET_INVALID_ID)
+ ip_set_nfnl_put(info->del_set.index);
return -ERANGE;
}
@@ -192,6 +199,7 @@ set_match_checkentry(const struct xt_mtchk_param *par)
if (info->match_set.dim > IPSET_DIM_MAX) {
pr_warning("Protocol error: set match dimension "
"is over the limit!\n");
+ ip_set_nfnl_put(info->match_set.index);
return -ERANGE;
}
@@ -219,7 +227,7 @@ set_target(struct sk_buff *skb, const struct xt_action_param *par)
if (info->del_set.index != IPSET_INVALID_ID)
ip_set_del(info->del_set.index,
skb, par->family,
- info->add_set.dim,
+ info->del_set.dim,
info->del_set.flags);
return XT_CONTINUE;
@@ -245,13 +253,19 @@ set_target_checkentry(const struct xt_tgchk_param *par)
if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find del_set index %u as target\n",
info->del_set.index);
+ if (info->add_set.index != IPSET_INVALID_ID)
+ ip_set_nfnl_put(info->add_set.index);
return -ENOENT;
}
}
if (info->add_set.dim > IPSET_DIM_MAX ||
- info->del_set.flags > IPSET_DIM_MAX) {
+ info->del_set.dim > IPSET_DIM_MAX) {
pr_warning("Protocol error: SET target dimension "
"is over the limit!\n");
+ if (info->add_set.index != IPSET_INVALID_ID)
+ ip_set_nfnl_put(info->add_set.index);
+ if (info->del_set.index != IPSET_INVALID_ID)
+ ip_set_nfnl_put(info->del_set.index);
return -ERANGE;
}
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index 5f14c84..bae5756 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -422,7 +422,6 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
{
int ret_val = -EINVAL;
- const char *type_str = "(unknown)";
struct netlbl_audit audit_info;
if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
@@ -432,15 +431,12 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
netlbl_netlink_auditinfo(skb, &audit_info);
switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
case CIPSO_V4_MAP_TRANS:
- type_str = "trans";
ret_val = netlbl_cipsov4_add_std(info, &audit_info);
break;
case CIPSO_V4_MAP_PASS:
- type_str = "pass";
ret_val = netlbl_cipsov4_add_pass(info, &audit_info);
break;
case CIPSO_V4_MAP_LOCAL:
- type_str = "local";
ret_val = netlbl_cipsov4_add_local(info, &audit_info);
break;
}
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
index d37b7f8..de0d8e4 100644
--- a/net/netlabel/netlabel_domainhash.c
+++ b/net/netlabel/netlabel_domainhash.c
@@ -109,7 +109,7 @@ static void netlbl_domhsh_free_entry(struct rcu_head *entry)
*
* Description:
* This is the hashing function for the domain hash table, it returns the
- * correct bucket number for the domain. The caller is responsibile for
+ * correct bucket number for the domain. The caller is responsible for
* ensuring that the hash table is protected with either a RCU read lock or the
* hash table lock.
*
@@ -134,7 +134,7 @@ static u32 netlbl_domhsh_hash(const char *key)
*
* Description:
* Searches the domain hash table and returns a pointer to the hash table
- * entry if found, otherwise NULL is returned. The caller is responsibile for
+ * entry if found, otherwise NULL is returned. The caller is responsible for
* ensuring that the hash table is protected with either a RCU read lock or the
* hash table lock.
*
@@ -165,7 +165,7 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
* Searches the domain hash table and returns a pointer to the hash table
* entry if an exact match is found, if an exact match is not present in the
* hash table then the default entry is returned if valid otherwise NULL is
- * returned. The caller is responsibile ensuring that the hash table is
+ * returned. The caller is responsible ensuring that the hash table is
* protected with either a RCU read lock or the hash table lock.
*
*/
@@ -193,7 +193,7 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
*
* Description:
* Generate an audit record for adding a new NetLabel/LSM mapping entry with
- * the given information. Caller is responsibile for holding the necessary
+ * the given information. Caller is responsible for holding the necessary
* locks.
*
*/
@@ -605,7 +605,7 @@ int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info)
*
* Description:
* Look through the domain hash table searching for an entry to match @domain,
- * return a pointer to a copy of the entry or NULL. The caller is responsibile
+ * return a pointer to a copy of the entry or NULL. The caller is responsible
* for ensuring that rcu_read_[un]lock() is called.
*
*/
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index 998e85e..4f251b1 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -259,7 +259,7 @@ add_failure:
*
* Description:
* This function is a helper function used by the LISTALL and LISTDEF command
- * handlers. The caller is responsibile for ensuring that the RCU read lock
+ * handlers. The caller is responsible for ensuring that the RCU read lock
* is held. Returns zero on success, negative values on failure.
*
*/
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 06cb027..732152f 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -591,7 +591,6 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
return -EINVAL;
}
if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) {
- SOCK_DEBUG(sk, "NET/ROM: bind failed: invalid node callsign\n");
release_sock(sk);
return -EADDRNOTAVAIL;
}
@@ -632,7 +631,7 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
sock_reset_flag(sk, SOCK_ZAPPED);
dev_put(dev);
release_sock(sk);
- SOCK_DEBUG(sk, "NET/ROM: socket is bound\n");
+
return 0;
}
@@ -1082,8 +1081,6 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
sax.sax25_call = nr->dest_addr;
}
- SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n");
-
/* Build a packet - the conventional user limit is 236 bytes. We can
do ludicrously large NetROM frames but must not overflow */
if (len > 65536) {
@@ -1091,7 +1088,6 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
goto out;
}
- SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n");
size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
@@ -1105,7 +1101,6 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
*/
asmptr = skb_push(skb, NR_TRANSPORT_LEN);
- SOCK_DEBUG(sk, "Building NET/ROM Header.\n");
/* Build a NET/ROM Transport header */
@@ -1114,15 +1109,12 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
*asmptr++ = 0; /* To be filled in later */
*asmptr++ = 0; /* Ditto */
*asmptr++ = NR_INFO;
- SOCK_DEBUG(sk, "Built header.\n");
/*
* Put the data on the end
*/
skb_put(skb, len);
- SOCK_DEBUG(sk, "NET/ROM: Appending user data\n");
-
/* User data follows immediately after the NET/ROM transport header */
if (memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len)) {
kfree_skb(skb);
@@ -1130,8 +1122,6 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
goto out;
}
- SOCK_DEBUG(sk, "NET/ROM: Transmitting buffer\n");
-
if (sk->sk_state != TCP_ESTABLISHED) {
kfree_skb(skb);
err = -ENOTCONN;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index b5362e9..549527b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -538,7 +538,7 @@ static inline unsigned int run_filter(const struct sk_buff *skb,
rcu_read_lock();
filter = rcu_dereference(sk->sk_filter);
if (filter != NULL)
- res = sk_run_filter(skb, filter->insns);
+ res = SK_RUN_FILTER(filter, skb);
rcu_read_unlock();
return res;
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 947038d..47b3452 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -426,18 +426,14 @@ int phonet_route_del(struct net_device *dev, u8 daddr)
return 0;
}
-struct net_device *phonet_route_get(struct net *net, u8 daddr)
+struct net_device *phonet_route_get_rcu(struct net *net, u8 daddr)
{
struct phonet_net *pnn = phonet_pernet(net);
struct phonet_routes *routes = &pnn->routes;
struct net_device *dev;
- ASSERT_RTNL(); /* no need to hold the device */
-
daddr >>= 2;
- rcu_read_lock();
dev = rcu_dereference(routes->table[daddr]);
- rcu_read_unlock();
return dev;
}
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
index 58b3b1f..438accb 100644
--- a/net/phonet/pn_netlink.c
+++ b/net/phonet/pn_netlink.c
@@ -264,10 +264,11 @@ static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
struct net *net = sock_net(skb->sk);
u8 addr, addr_idx = 0, addr_start_idx = cb->args[0];
+ rcu_read_lock();
for (addr = 0; addr < 64; addr++) {
struct net_device *dev;
- dev = phonet_route_get(net, addr << 2);
+ dev = phonet_route_get_rcu(net, addr << 2);
if (!dev)
continue;
@@ -279,6 +280,7 @@ static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
}
out:
+ rcu_read_unlock();
cb->args[0] = addr_idx;
cb->args[1] = 0;
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index b1adafa..8c5bfce 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -52,7 +52,7 @@ static int pn_socket_release(struct socket *sock)
static struct {
struct hlist_head hlist[PN_HASHSIZE];
- spinlock_t lock;
+ struct mutex lock;
} pnsocks;
void __init pn_sock_init(void)
@@ -61,7 +61,7 @@ void __init pn_sock_init(void)
for (i = 0; i < PN_HASHSIZE; i++)
INIT_HLIST_HEAD(pnsocks.hlist + i);
- spin_lock_init(&pnsocks.lock);
+ mutex_init(&pnsocks.lock);
}
static struct hlist_head *pn_hash_list(u16 obj)
@@ -82,9 +82,8 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
u8 res = spn->spn_resource;
struct hlist_head *hlist = pn_hash_list(obj);
- spin_lock_bh(&pnsocks.lock);
-
- sk_for_each(sknode, node, hlist) {
+ rcu_read_lock();
+ sk_for_each_rcu(sknode, node, hlist) {
struct pn_sock *pn = pn_sk(sknode);
BUG_ON(!pn->sobject); /* unbound socket */
@@ -107,8 +106,7 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
sock_hold(sknode);
break;
}
-
- spin_unlock_bh(&pnsocks.lock);
+ rcu_read_unlock();
return rval;
}
@@ -119,7 +117,7 @@ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
struct hlist_head *hlist = pnsocks.hlist;
unsigned h;
- spin_lock(&pnsocks.lock);
+ rcu_read_lock();
for (h = 0; h < PN_HASHSIZE; h++) {
struct hlist_node *node;
struct sock *sknode;
@@ -140,25 +138,26 @@ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
}
hlist++;
}
- spin_unlock(&pnsocks.lock);
+ rcu_read_unlock();
}
void pn_sock_hash(struct sock *sk)
{
struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject);
- spin_lock_bh(&pnsocks.lock);
- sk_add_node(sk, hlist);
- spin_unlock_bh(&pnsocks.lock);
+ mutex_lock(&pnsocks.lock);
+ sk_add_node_rcu(sk, hlist);
+ mutex_unlock(&pnsocks.lock);
}
EXPORT_SYMBOL(pn_sock_hash);
void pn_sock_unhash(struct sock *sk)
{
- spin_lock_bh(&pnsocks.lock);
- sk_del_node_init(sk);
- spin_unlock_bh(&pnsocks.lock);
+ mutex_lock(&pnsocks.lock);
+ sk_del_node_init_rcu(sk);
+ mutex_unlock(&pnsocks.lock);
pn_sock_unbind_all_res(sk);
+ synchronize_rcu();
}
EXPORT_SYMBOL(pn_sock_unhash);
@@ -548,7 +547,7 @@ static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
unsigned h;
for (h = 0; h < PN_HASHSIZE; h++) {
- sk_for_each(sknode, node, hlist) {
+ sk_for_each_rcu(sknode, node, hlist) {
if (!net_eq(net, sock_net(sknode)))
continue;
if (!pos)
@@ -572,9 +571,9 @@ static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
}
static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(pnsocks.lock)
+ __acquires(rcu)
{
- spin_lock_bh(&pnsocks.lock);
+ rcu_read_lock();
return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
}
@@ -591,9 +590,9 @@ static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
}
static void pn_sock_seq_stop(struct seq_file *seq, void *v)
- __releases(pnsocks.lock)
+ __releases(rcu)
{
- spin_unlock_bh(&pnsocks.lock);
+ rcu_read_unlock();
}
static int pn_sock_seq_show(struct seq_file *seq, void *v)
@@ -721,13 +720,11 @@ void pn_sock_unbind_all_res(struct sock *sk)
}
mutex_unlock(&resource_mutex);
- if (match == 0)
- return;
- synchronize_rcu();
while (match > 0) {
- sock_put(sk);
+ __sock_put(sk);
match--;
}
+ /* Caller is responsible for RCU sync before final sock_put() */
}
#ifdef CONFIG_PROC_FS
diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c
index c47a511..7c4dce8 100644
--- a/net/rds/ib_send.c
+++ b/net/rds/ib_send.c
@@ -355,7 +355,7 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
*
* Conceptually, we have two counters:
* - send credits: this tells us how many WRs we're allowed
- * to submit without overruning the reciever's queue. For
+ * to submit without overruning the receiver's queue. For
* each SEND WR we post, we decrement this by one.
*
* - posted credits: this tells us how many WRs we recently
diff --git a/net/rds/iw_cm.c b/net/rds/iw_cm.c
index 712cf2d..3a60a15 100644
--- a/net/rds/iw_cm.c
+++ b/net/rds/iw_cm.c
@@ -181,7 +181,7 @@ static int rds_iw_init_qp_attrs(struct ib_qp_init_attr *attr,
unsigned int send_size, recv_size;
int ret;
- /* The offset of 1 is to accomodate the additional ACK WR. */
+ /* The offset of 1 is to accommodate the additional ACK WR. */
send_size = min_t(unsigned int, rds_iwdev->max_wrs, rds_iw_sysctl_max_send_wr + 1);
recv_size = min_t(unsigned int, rds_iwdev->max_wrs, rds_iw_sysctl_max_recv_wr + 1);
rds_iw_ring_resize(send_ring, send_size - 1);
diff --git a/net/rds/iw_rdma.c b/net/rds/iw_rdma.c
index 59509e9..6deaa77 100644
--- a/net/rds/iw_rdma.c
+++ b/net/rds/iw_rdma.c
@@ -122,7 +122,7 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd
#else
/* FIXME - needs to compare the local and remote
* ipaddr/port tuple, but the ipaddr is the only
- * available infomation in the rds_sock (as the rest are
+ * available information in the rds_sock (as the rest are
* zero'ed. It doesn't appear to be properly populated
* during connection setup...
*/
diff --git a/net/rds/iw_send.c b/net/rds/iw_send.c
index 6280ea0..545d8ee 100644
--- a/net/rds/iw_send.c
+++ b/net/rds/iw_send.c
@@ -307,7 +307,7 @@ void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context)
*
* Conceptually, we have two counters:
* - send credits: this tells us how many WRs we're allowed
- * to submit without overruning the reciever's queue. For
+ * to submit without overruning the receiver's queue. For
* each SEND WR we post, we decrement this by one.
*
* - posted credits: this tells us how many WRs we recently
diff --git a/net/rds/send.c b/net/rds/send.c
index 35b9c2e..d58ae5f 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -116,7 +116,7 @@ static void release_in_xmit(struct rds_connection *conn)
}
/*
- * We're making the concious trade-off here to only send one message
+ * We're making the conscious trade-off here to only send one message
* down the connection at a time.
* Pro:
* - tx queueing is a simple fifo list
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index a80aef6..f9ea925 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -682,10 +682,8 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS)
return -EINVAL;
- if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) {
- SOCK_DEBUG(sk, "ROSE: bind failed: invalid address\n");
+ if ((dev = rose_dev_get(&addr->srose_addr)) == NULL)
return -EADDRNOTAVAIL;
- }
source = &addr->srose_call;
@@ -716,7 +714,7 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
rose_insert_socket(sk);
sock_reset_flag(sk, SOCK_ZAPPED);
- SOCK_DEBUG(sk, "ROSE: socket is bound\n");
+
return 0;
}
@@ -1109,10 +1107,7 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
srose.srose_digis[n] = rose->dest_digis[n];
}
- SOCK_DEBUG(sk, "ROSE: sendto: Addresses built.\n");
-
/* Build a packet */
- SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n");
/* Sanity check the packet size */
if (len > 65535)
return -EMSGSIZE;
@@ -1127,7 +1122,6 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
/*
* Put the data on the end
*/
- SOCK_DEBUG(sk, "ROSE: Appending user data\n");
skb_reset_transport_header(skb);
skb_put(skb, len);
@@ -1152,8 +1146,6 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
*/
asmptr = skb_push(skb, ROSE_MIN_LEN);
- SOCK_DEBUG(sk, "ROSE: Building Network Header.\n");
-
/* Build a ROSE Network header */
asmptr[0] = ((rose->lci >> 8) & 0x0F) | ROSE_GFI;
asmptr[1] = (rose->lci >> 0) & 0xFF;
@@ -1162,10 +1154,6 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
if (qbit)
asmptr[0] |= ROSE_Q_BIT;
- SOCK_DEBUG(sk, "ROSE: Built header.\n");
-
- SOCK_DEBUG(sk, "ROSE: Transmitting buffer\n");
-
if (sk->sk_state != TCP_ESTABLISHED) {
kfree_skb(skb);
return -ENOTCONN;
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index 08dcd2f..479cae5 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -587,7 +587,7 @@ static int rose_clear_routes(void)
/*
* Check that the device given is a valid AX.25 interface that is "up".
- * called whith RTNL
+ * called with RTNL
*/
static struct net_device *rose_ax25_dev_find(char *devname)
{
diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c
index 55b93dc..b6ff063 100644
--- a/net/rxrpc/ar-peer.c
+++ b/net/rxrpc/ar-peer.c
@@ -36,10 +36,11 @@ static void rxrpc_destroy_peer(struct work_struct *work);
static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer)
{
struct rtable *rt;
+ struct flowi4 fl4;
peer->if_mtu = 1500;
- rt = ip_route_output_ports(&init_net, NULL,
+ rt = ip_route_output_ports(&init_net, &fl4, NULL,
peer->srx.transport.sin.sin_addr.s_addr, 0,
htons(7000), htons(7001),
IPPROTO_UDP, 0, 0);
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index a7a5583d..aeaa211 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -239,6 +239,17 @@ config NET_SCH_CHOKE
To compile this code as a module, choose M here: the
module will be called sch_choke.
+config NET_SCH_QFQ
+ tristate "Quick Fair Queueing scheduler (QFQ)"
+ help
+ Say Y here if you want to use the Quick Fair Queueing Scheduler (QFQ)
+ packet scheduling algorithm.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sch_qfq.
+
+ If unsure, say N.
+
config NET_SCH_INGRESS
tristate "Ingress Qdisc"
depends on NET_CLS_ACT
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 2e77b8d..dc5889c 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_NET_SCH_NETEM) += sch_netem.o
obj-$(CONFIG_NET_SCH_DRR) += sch_drr.o
obj-$(CONFIG_NET_SCH_MQPRIO) += sch_mqprio.o
obj-$(CONFIG_NET_SCH_CHOKE) += sch_choke.o
+obj-$(CONFIG_NET_SCH_QFQ) += sch_qfq.o
obj-$(CONFIG_NET_CLS_U32) += cls_u32.o
obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 15873e1..14b42f4 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -999,7 +999,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
switch (n->nlmsg_type) {
case RTM_NEWACTION:
/* we are going to assume all other flags
- * imply create only if it doesnt exist
+ * imply create only if it doesn't exist
* Note that CREATE | EXCL implies that
* but since we want avoid ambiguity (eg when flags
* is zero) then just set this
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index 50c7c06..7affe9a 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -161,7 +161,7 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a,
}
if (offset > 0 && offset > skb->len) {
pr_info("tc filter pedit"
- " offset %d cant exceed pkt length %d\n",
+ " offset %d can't exceed pkt length %d\n",
offset, skb->len);
goto bad;
}
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
index a4de67e..49130e8 100644
--- a/net/sched/em_meta.c
+++ b/net/sched/em_meta.c
@@ -47,7 +47,7 @@
* on the meta type. Obviously, the length of the data must also
* be provided for non-numeric types.
*
- * Additionaly, type dependant modifiers such as shift operators
+ * Additionally, type dependent modifiers such as shift operators
* or mask may be applied to extend the functionaliy. As of now,
* the variable length type supports shifting the byte string to
* the right, eating up any number of octets and thus supporting
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index e1429a8..29b942c 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -183,7 +183,7 @@ static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch)
* filters in qdisc and in inner nodes (if higher filter points to the inner
* node). If we end up with classid MAJOR:0 we enqueue the skb into special
* internal fifo (direct). These packets then go directly thru. If we still
- * have no valid leaf we try to use MAJOR:default leaf. It still unsuccessfull
+ * have no valid leaf we try to use MAJOR:default leaf. It still unsuccessful
* then finish and return direct queue.
*/
#define HTB_DIRECT ((struct htb_class *)-1L)
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index edbbf7a..69c35f6 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -160,7 +160,7 @@ static bool loss_4state(struct netem_sched_data *q)
u32 rnd = net_random();
/*
- * Makes a comparision between rnd and the transition
+ * Makes a comparison between rnd and the transition
* probabilities outgoing from the current state, then decides the
* next state and if the next packet has to be transmitted or lost.
* The four states correspond to:
@@ -212,9 +212,9 @@ static bool loss_4state(struct netem_sched_data *q)
* Generates losses according to the Gilbert-Elliot loss model or
* its special cases (Gilbert or Simple Gilbert)
*
- * Makes a comparision between random number and the transition
+ * Makes a comparison between random number and the transition
* probabilities outgoing from the current state, then decides the
- * next state. A second random number is extracted and the comparision
+ * next state. A second random number is extracted and the comparison
* with the loss probability of the current state decides if the next
* packet will be transmitted or lost.
*/
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
new file mode 100644
index 0000000..1033434
--- /dev/null
+++ b/net/sched/sch_qfq.c
@@ -0,0 +1,1137 @@
+/*
+ * net/sched/sch_qfq.c Quick Fair Queueing Scheduler.
+ *
+ * Copyright (c) 2009 Fabio Checconi, Luigi Rizzo, and Paolo Valente.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/pkt_sched.h>
+#include <net/sch_generic.h>
+#include <net/pkt_sched.h>
+#include <net/pkt_cls.h>
+
+
+/* Quick Fair Queueing
+ ===================
+
+ Sources:
+
+ Fabio Checconi, Luigi Rizzo, and Paolo Valente: "QFQ: Efficient
+ Packet Scheduling with Tight Bandwidth Distribution Guarantees."
+
+ See also:
+ http://retis.sssup.it/~fabio/linux/qfq/
+ */
+
+/*
+
+ Virtual time computations.
+
+ S, F and V are all computed in fixed point arithmetic with
+ FRAC_BITS decimal bits.
+
+ QFQ_MAX_INDEX is the maximum index allowed for a group. We need
+ one bit per index.
+ QFQ_MAX_WSHIFT is the maximum power of two supported as a weight.
+
+ The layout of the bits is as below:
+
+ [ MTU_SHIFT ][ FRAC_BITS ]
+ [ MAX_INDEX ][ MIN_SLOT_SHIFT ]
+ ^.__grp->index = 0
+ *.__grp->slot_shift
+
+ where MIN_SLOT_SHIFT is derived by difference from the others.
+
+ The max group index corresponds to Lmax/w_min, where
+ Lmax=1<<MTU_SHIFT, w_min = 1 .
+ From this, and knowing how many groups (MAX_INDEX) we want,
+ we can derive the shift corresponding to each group.
+
+ Because we often need to compute
+ F = S + len/w_i and V = V + len/wsum
+ instead of storing w_i store the value
+ inv_w = (1<<FRAC_BITS)/w_i
+ so we can do F = S + len * inv_w * wsum.
+ We use W_TOT in the formulas so we can easily move between
+ static and adaptive weight sum.
+
+ The per-scheduler-instance data contain all the data structures
+ for the scheduler: bitmaps and bucket lists.
+
+ */
+
+/*
+ * Maximum number of consecutive slots occupied by backlogged classes
+ * inside a group.
+ */
+#define QFQ_MAX_SLOTS 32
+
+/*
+ * Shifts used for class<->group mapping. We allow class weights that are
+ * in the range [1, 2^MAX_WSHIFT], and we try to map each class i to the
+ * group with the smallest index that can support the L_i / r_i configured
+ * for the class.
+ *
+ * grp->index is the index of the group; and grp->slot_shift
+ * is the shift for the corresponding (scaled) sigma_i.
+ */
+#define QFQ_MAX_INDEX 19
+#define QFQ_MAX_WSHIFT 16
+
+#define QFQ_MAX_WEIGHT (1<<QFQ_MAX_WSHIFT)
+#define QFQ_MAX_WSUM (2*QFQ_MAX_WEIGHT)
+
+#define FRAC_BITS 30 /* fixed point arithmetic */
+#define ONE_FP (1UL << FRAC_BITS)
+#define IWSUM (ONE_FP/QFQ_MAX_WSUM)
+
+#define QFQ_MTU_SHIFT 11
+#define QFQ_MIN_SLOT_SHIFT (FRAC_BITS + QFQ_MTU_SHIFT - QFQ_MAX_INDEX)
+
+/*
+ * Possible group states. These values are used as indexes for the bitmaps
+ * array of struct qfq_queue.
+ */
+enum qfq_state { ER, IR, EB, IB, QFQ_MAX_STATE };
+
+struct qfq_group;
+
+struct qfq_class {
+ struct Qdisc_class_common common;
+
+ unsigned int refcnt;
+ unsigned int filter_cnt;
+
+ struct gnet_stats_basic_packed bstats;
+ struct gnet_stats_queue qstats;
+ struct gnet_stats_rate_est rate_est;
+ struct Qdisc *qdisc;
+
+ struct hlist_node next; /* Link for the slot list. */
+ u64 S, F; /* flow timestamps (exact) */
+
+ /* group we belong to. In principle we would need the index,
+ * which is log_2(lmax/weight), but we never reference it
+ * directly, only the group.
+ */
+ struct qfq_group *grp;
+
+ /* these are copied from the flowset. */
+ u32 inv_w; /* ONE_FP/weight */
+ u32 lmax; /* Max packet size for this flow. */
+};
+
+struct qfq_group {
+ u64 S, F; /* group timestamps (approx). */
+ unsigned int slot_shift; /* Slot shift. */
+ unsigned int index; /* Group index. */
+ unsigned int front; /* Index of the front slot. */
+ unsigned long full_slots; /* non-empty slots */
+
+ /* Array of RR lists of active classes. */
+ struct hlist_head slots[QFQ_MAX_SLOTS];
+};
+
+struct qfq_sched {
+ struct tcf_proto *filter_list;
+ struct Qdisc_class_hash clhash;
+
+ u64 V; /* Precise virtual time. */
+ u32 wsum; /* weight sum */
+
+ unsigned long bitmaps[QFQ_MAX_STATE]; /* Group bitmaps. */
+ struct qfq_group groups[QFQ_MAX_INDEX + 1]; /* The groups. */
+};
+
+static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct Qdisc_class_common *clc;
+
+ clc = qdisc_class_find(&q->clhash, classid);
+ if (clc == NULL)
+ return NULL;
+ return container_of(clc, struct qfq_class, common);
+}
+
+static void qfq_purge_queue(struct qfq_class *cl)
+{
+ unsigned int len = cl->qdisc->q.qlen;
+
+ qdisc_reset(cl->qdisc);
+ qdisc_tree_decrease_qlen(cl->qdisc, len);
+}
+
+static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = {
+ [TCA_QFQ_WEIGHT] = { .type = NLA_U32 },
+ [TCA_QFQ_LMAX] = { .type = NLA_U32 },
+};
+
+/*
+ * Calculate a flow index, given its weight and maximum packet length.
+ * index = log_2(maxlen/weight) but we need to apply the scaling.
+ * This is used only once at flow creation.
+ */
+static int qfq_calc_index(u32 inv_w, unsigned int maxlen)
+{
+ u64 slot_size = (u64)maxlen * inv_w;
+ unsigned long size_map;
+ int index = 0;
+
+ size_map = slot_size >> QFQ_MIN_SLOT_SHIFT;
+ if (!size_map)
+ goto out;
+
+ index = __fls(size_map) + 1; /* basically a log_2 */
+ index -= !(slot_size - (1ULL << (index + QFQ_MIN_SLOT_SHIFT - 1)));
+
+ if (index < 0)
+ index = 0;
+out:
+ pr_debug("qfq calc_index: W = %lu, L = %u, I = %d\n",
+ (unsigned long) ONE_FP/inv_w, maxlen, index);
+
+ return index;
+}
+
+static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
+ struct nlattr **tca, unsigned long *arg)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_class *cl = (struct qfq_class *)*arg;
+ struct nlattr *tb[TCA_QFQ_MAX + 1];
+ u32 weight, lmax, inv_w;
+ int i, err;
+
+ if (tca[TCA_OPTIONS] == NULL) {
+ pr_notice("qfq: no options\n");
+ return -EINVAL;
+ }
+
+ err = nla_parse_nested(tb, TCA_QFQ_MAX, tca[TCA_OPTIONS], qfq_policy);
+ if (err < 0)
+ return err;
+
+ if (tb[TCA_QFQ_WEIGHT]) {
+ weight = nla_get_u32(tb[TCA_QFQ_WEIGHT]);
+ if (!weight || weight > (1UL << QFQ_MAX_WSHIFT)) {
+ pr_notice("qfq: invalid weight %u\n", weight);
+ return -EINVAL;
+ }
+ } else
+ weight = 1;
+
+ inv_w = ONE_FP / weight;
+ weight = ONE_FP / inv_w;
+ if (q->wsum + weight > QFQ_MAX_WSUM) {
+ pr_notice("qfq: total weight out of range (%u + %u)\n",
+ weight, q->wsum);
+ return -EINVAL;
+ }
+
+ if (tb[TCA_QFQ_LMAX]) {
+ lmax = nla_get_u32(tb[TCA_QFQ_LMAX]);
+ if (!lmax || lmax > (1UL << QFQ_MTU_SHIFT)) {
+ pr_notice("qfq: invalid max length %u\n", lmax);
+ return -EINVAL;
+ }
+ } else
+ lmax = 1UL << QFQ_MTU_SHIFT;
+
+ if (cl != NULL) {
+ if (tca[TCA_RATE]) {
+ err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+ qdisc_root_sleeping_lock(sch),
+ tca[TCA_RATE]);
+ if (err)
+ return err;
+ }
+
+ sch_tree_lock(sch);
+ if (tb[TCA_QFQ_WEIGHT]) {
+ q->wsum = weight - ONE_FP / cl->inv_w;
+ cl->inv_w = inv_w;
+ }
+ sch_tree_unlock(sch);
+
+ return 0;
+ }
+
+ cl = kzalloc(sizeof(struct qfq_class), GFP_KERNEL);
+ if (cl == NULL)
+ return -ENOBUFS;
+
+ cl->refcnt = 1;
+ cl->common.classid = classid;
+ cl->lmax = lmax;
+ cl->inv_w = inv_w;
+ i = qfq_calc_index(cl->inv_w, cl->lmax);
+
+ cl->grp = &q->groups[i];
+ q->wsum += weight;
+
+ cl->qdisc = qdisc_create_dflt(sch->dev_queue,
+ &pfifo_qdisc_ops, classid);
+ if (cl->qdisc == NULL)
+ cl->qdisc = &noop_qdisc;
+
+ if (tca[TCA_RATE]) {
+ err = gen_new_estimator(&cl->bstats, &cl->rate_est,
+ qdisc_root_sleeping_lock(sch),
+ tca[TCA_RATE]);
+ if (err) {
+ qdisc_destroy(cl->qdisc);
+ kfree(cl);
+ return err;
+ }
+ }
+
+ sch_tree_lock(sch);
+ qdisc_class_hash_insert(&q->clhash, &cl->common);
+ sch_tree_unlock(sch);
+
+ qdisc_class_hash_grow(sch, &q->clhash);
+
+ *arg = (unsigned long)cl;
+ return 0;
+}
+
+static void qfq_destroy_class(struct Qdisc *sch, struct qfq_class *cl)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+
+ if (cl->inv_w) {
+ q->wsum -= ONE_FP / cl->inv_w;
+ cl->inv_w = 0;
+ }
+
+ gen_kill_estimator(&cl->bstats, &cl->rate_est);
+ qdisc_destroy(cl->qdisc);
+ kfree(cl);
+}
+
+static int qfq_delete_class(struct Qdisc *sch, unsigned long arg)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_class *cl = (struct qfq_class *)arg;
+
+ if (cl->filter_cnt > 0)
+ return -EBUSY;
+
+ sch_tree_lock(sch);
+
+ qfq_purge_queue(cl);
+ qdisc_class_hash_remove(&q->clhash, &cl->common);
+
+ BUG_ON(--cl->refcnt == 0);
+ /*
+ * This shouldn't happen: we "hold" one cops->get() when called
+ * from tc_ctl_tclass; the destroy method is done from cops->put().
+ */
+
+ sch_tree_unlock(sch);
+ return 0;
+}
+
+static unsigned long qfq_get_class(struct Qdisc *sch, u32 classid)
+{
+ struct qfq_class *cl = qfq_find_class(sch, classid);
+
+ if (cl != NULL)
+ cl->refcnt++;
+
+ return (unsigned long)cl;
+}
+
+static void qfq_put_class(struct Qdisc *sch, unsigned long arg)
+{
+ struct qfq_class *cl = (struct qfq_class *)arg;
+
+ if (--cl->refcnt == 0)
+ qfq_destroy_class(sch, cl);
+}
+
+static struct tcf_proto **qfq_tcf_chain(struct Qdisc *sch, unsigned long cl)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+
+ if (cl)
+ return NULL;
+
+ return &q->filter_list;
+}
+
+static unsigned long qfq_bind_tcf(struct Qdisc *sch, unsigned long parent,
+ u32 classid)
+{
+ struct qfq_class *cl = qfq_find_class(sch, classid);
+
+ if (cl != NULL)
+ cl->filter_cnt++;
+
+ return (unsigned long)cl;
+}
+
+static void qfq_unbind_tcf(struct Qdisc *sch, unsigned long arg)
+{
+ struct qfq_class *cl = (struct qfq_class *)arg;
+
+ cl->filter_cnt--;
+}
+
+static int qfq_graft_class(struct Qdisc *sch, unsigned long arg,
+ struct Qdisc *new, struct Qdisc **old)
+{
+ struct qfq_class *cl = (struct qfq_class *)arg;
+
+ if (new == NULL) {
+ new = qdisc_create_dflt(sch->dev_queue,
+ &pfifo_qdisc_ops, cl->common.classid);
+ if (new == NULL)
+ new = &noop_qdisc;
+ }
+
+ sch_tree_lock(sch);
+ qfq_purge_queue(cl);
+ *old = cl->qdisc;
+ cl->qdisc = new;
+ sch_tree_unlock(sch);
+ return 0;
+}
+
+static struct Qdisc *qfq_class_leaf(struct Qdisc *sch, unsigned long arg)
+{
+ struct qfq_class *cl = (struct qfq_class *)arg;
+
+ return cl->qdisc;
+}
+
+static int qfq_dump_class(struct Qdisc *sch, unsigned long arg,
+ struct sk_buff *skb, struct tcmsg *tcm)
+{
+ struct qfq_class *cl = (struct qfq_class *)arg;
+ struct nlattr *nest;
+
+ tcm->tcm_parent = TC_H_ROOT;
+ tcm->tcm_handle = cl->common.classid;
+ tcm->tcm_info = cl->qdisc->handle;
+
+ nest = nla_nest_start(skb, TCA_OPTIONS);
+ if (nest == NULL)
+ goto nla_put_failure;
+ NLA_PUT_U32(skb, TCA_QFQ_WEIGHT, ONE_FP/cl->inv_w);
+ NLA_PUT_U32(skb, TCA_QFQ_LMAX, cl->lmax);
+ return nla_nest_end(skb, nest);
+
+nla_put_failure:
+ nla_nest_cancel(skb, nest);
+ return -EMSGSIZE;
+}
+
+static int qfq_dump_class_stats(struct Qdisc *sch, unsigned long arg,
+ struct gnet_dump *d)
+{
+ struct qfq_class *cl = (struct qfq_class *)arg;
+ struct tc_qfq_stats xstats;
+
+ memset(&xstats, 0, sizeof(xstats));
+ cl->qdisc->qstats.qlen = cl->qdisc->q.qlen;
+
+ xstats.weight = ONE_FP/cl->inv_w;
+ xstats.lmax = cl->lmax;
+
+ if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
+ gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 ||
+ gnet_stats_copy_queue(d, &cl->qdisc->qstats) < 0)
+ return -1;
+
+ return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
+}
+
+static void qfq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_class *cl;
+ struct hlist_node *n;
+ unsigned int i;
+
+ if (arg->stop)
+ return;
+
+ for (i = 0; i < q->clhash.hashsize; i++) {
+ hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) {
+ if (arg->count < arg->skip) {
+ arg->count++;
+ continue;
+ }
+ if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
+ arg->stop = 1;
+ return;
+ }
+ arg->count++;
+ }
+ }
+}
+
+static struct qfq_class *qfq_classify(struct sk_buff *skb, struct Qdisc *sch,
+ int *qerr)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_class *cl;
+ struct tcf_result res;
+ int result;
+
+ if (TC_H_MAJ(skb->priority ^ sch->handle) == 0) {
+ pr_debug("qfq_classify: found %d\n", skb->priority);
+ cl = qfq_find_class(sch, skb->priority);
+ if (cl != NULL)
+ return cl;
+ }
+
+ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
+ result = tc_classify(skb, q->filter_list, &res);
+ if (result >= 0) {
+#ifdef CONFIG_NET_CLS_ACT
+ switch (result) {
+ case TC_ACT_QUEUED:
+ case TC_ACT_STOLEN:
+ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
+ case TC_ACT_SHOT:
+ return NULL;
+ }
+#endif
+ cl = (struct qfq_class *)res.class;
+ if (cl == NULL)
+ cl = qfq_find_class(sch, res.classid);
+ return cl;
+ }
+
+ return NULL;
+}
+
+/* Generic comparison function, handling wraparound. */
+static inline int qfq_gt(u64 a, u64 b)
+{
+ return (s64)(a - b) > 0;
+}
+
+/* Round a precise timestamp to its slotted value. */
+static inline u64 qfq_round_down(u64 ts, unsigned int shift)
+{
+ return ts & ~((1ULL << shift) - 1);
+}
+
+/* return the pointer to the group with lowest index in the bitmap */
+static inline struct qfq_group *qfq_ffs(struct qfq_sched *q,
+ unsigned long bitmap)
+{
+ int index = __ffs(bitmap);
+ return &q->groups[index];
+}
+/* Calculate a mask to mimic what would be ffs_from(). */
+static inline unsigned long mask_from(unsigned long bitmap, int from)
+{
+ return bitmap & ~((1UL << from) - 1);
+}
+
+/*
+ * The state computation relies on ER=0, IR=1, EB=2, IB=3
+ * First compute eligibility comparing grp->S, q->V,
+ * then check if someone is blocking us and possibly add EB
+ */
+static int qfq_calc_state(struct qfq_sched *q, const struct qfq_group *grp)
+{
+ /* if S > V we are not eligible */
+ unsigned int state = qfq_gt(grp->S, q->V);
+ unsigned long mask = mask_from(q->bitmaps[ER], grp->index);
+ struct qfq_group *next;
+
+ if (mask) {
+ next = qfq_ffs(q, mask);
+ if (qfq_gt(grp->F, next->F))
+ state |= EB;
+ }
+
+ return state;
+}
+
+
+/*
+ * In principle
+ * q->bitmaps[dst] |= q->bitmaps[src] & mask;
+ * q->bitmaps[src] &= ~mask;
+ * but we should make sure that src != dst
+ */
+static inline void qfq_move_groups(struct qfq_sched *q, unsigned long mask,
+ int src, int dst)
+{
+ q->bitmaps[dst] |= q->bitmaps[src] & mask;
+ q->bitmaps[src] &= ~mask;
+}
+
+static void qfq_unblock_groups(struct qfq_sched *q, int index, u64 old_F)
+{
+ unsigned long mask = mask_from(q->bitmaps[ER], index + 1);
+ struct qfq_group *next;
+
+ if (mask) {
+ next = qfq_ffs(q, mask);
+ if (!qfq_gt(next->F, old_F))
+ return;
+ }
+
+ mask = (1UL << index) - 1;
+ qfq_move_groups(q, mask, EB, ER);
+ qfq_move_groups(q, mask, IB, IR);
+}
+
+/*
+ * perhaps
+ *
+ old_V ^= q->V;
+ old_V >>= QFQ_MIN_SLOT_SHIFT;
+ if (old_V) {
+ ...
+ }
+ *
+ */
+static void qfq_make_eligible(struct qfq_sched *q, u64 old_V)
+{
+ unsigned long vslot = q->V >> QFQ_MIN_SLOT_SHIFT;
+ unsigned long old_vslot = old_V >> QFQ_MIN_SLOT_SHIFT;
+
+ if (vslot != old_vslot) {
+ unsigned long mask = (1UL << fls(vslot ^ old_vslot)) - 1;
+ qfq_move_groups(q, mask, IR, ER);
+ qfq_move_groups(q, mask, IB, EB);
+ }
+}
+
+
+/*
+ * XXX we should make sure that slot becomes less than 32.
+ * This is guaranteed by the input values.
+ * roundedS is always cl->S rounded on grp->slot_shift bits.
+ */
+static void qfq_slot_insert(struct qfq_group *grp, struct qfq_class *cl,
+ u64 roundedS)
+{
+ u64 slot = (roundedS - grp->S) >> grp->slot_shift;
+ unsigned int i = (grp->front + slot) % QFQ_MAX_SLOTS;
+
+ hlist_add_head(&cl->next, &grp->slots[i]);
+ __set_bit(slot, &grp->full_slots);
+}
+
+/* Maybe introduce hlist_first_entry?? */
+static struct qfq_class *qfq_slot_head(struct qfq_group *grp)
+{
+ return hlist_entry(grp->slots[grp->front].first,
+ struct qfq_class, next);
+}
+
+/*
+ * remove the entry from the slot
+ */
+static void qfq_front_slot_remove(struct qfq_group *grp)
+{
+ struct qfq_class *cl = qfq_slot_head(grp);
+
+ BUG_ON(!cl);
+ hlist_del(&cl->next);
+ if (hlist_empty(&grp->slots[grp->front]))
+ __clear_bit(0, &grp->full_slots);
+}
+
+/*
+ * Returns the first full queue in a group. As a side effect,
+ * adjust the bucket list so the first non-empty bucket is at
+ * position 0 in full_slots.
+ */
+static struct qfq_class *qfq_slot_scan(struct qfq_group *grp)
+{
+ unsigned int i;
+
+ pr_debug("qfq slot_scan: grp %u full %#lx\n",
+ grp->index, grp->full_slots);
+
+ if (grp->full_slots == 0)
+ return NULL;
+
+ i = __ffs(grp->full_slots); /* zero based */
+ if (i > 0) {
+ grp->front = (grp->front + i) % QFQ_MAX_SLOTS;
+ grp->full_slots >>= i;
+ }
+
+ return qfq_slot_head(grp);
+}
+
+/*
+ * adjust the bucket list. When the start time of a group decreases,
+ * we move the index down (modulo QFQ_MAX_SLOTS) so we don't need to
+ * move the objects. The mask of occupied slots must be shifted
+ * because we use ffs() to find the first non-empty slot.
+ * This covers decreases in the group's start time, but what about
+ * increases of the start time ?
+ * Here too we should make sure that i is less than 32
+ */
+static void qfq_slot_rotate(struct qfq_group *grp, u64 roundedS)
+{
+ unsigned int i = (grp->S - roundedS) >> grp->slot_shift;
+
+ grp->full_slots <<= i;
+ grp->front = (grp->front - i) % QFQ_MAX_SLOTS;
+}
+
+static void qfq_update_eligible(struct qfq_sched *q, u64 old_V)
+{
+ struct qfq_group *grp;
+ unsigned long ineligible;
+
+ ineligible = q->bitmaps[IR] | q->bitmaps[IB];
+ if (ineligible) {
+ if (!q->bitmaps[ER]) {
+ grp = qfq_ffs(q, ineligible);
+ if (qfq_gt(grp->S, q->V))
+ q->V = grp->S;
+ }
+ qfq_make_eligible(q, old_V);
+ }
+}
+
+/* What is length of next packet in queue (0 if queue is empty) */
+static unsigned int qdisc_peek_len(struct Qdisc *sch)
+{
+ struct sk_buff *skb;
+
+ skb = sch->ops->peek(sch);
+ return skb ? qdisc_pkt_len(skb) : 0;
+}
+
+/*
+ * Updates the class, returns true if also the group needs to be updated.
+ */
+static bool qfq_update_class(struct qfq_group *grp, struct qfq_class *cl)
+{
+ unsigned int len = qdisc_peek_len(cl->qdisc);
+
+ cl->S = cl->F;
+ if (!len)
+ qfq_front_slot_remove(grp); /* queue is empty */
+ else {
+ u64 roundedS;
+
+ cl->F = cl->S + (u64)len * cl->inv_w;
+ roundedS = qfq_round_down(cl->S, grp->slot_shift);
+ if (roundedS == grp->S)
+ return false;
+
+ qfq_front_slot_remove(grp);
+ qfq_slot_insert(grp, cl, roundedS);
+ }
+
+ return true;
+}
+
+static struct sk_buff *qfq_dequeue(struct Qdisc *sch)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_group *grp;
+ struct qfq_class *cl;
+ struct sk_buff *skb;
+ unsigned int len;
+ u64 old_V;
+
+ if (!q->bitmaps[ER])
+ return NULL;
+
+ grp = qfq_ffs(q, q->bitmaps[ER]);
+
+ cl = qfq_slot_head(grp);
+ skb = qdisc_dequeue_peeked(cl->qdisc);
+ if (!skb) {
+ WARN_ONCE(1, "qfq_dequeue: non-workconserving leaf\n");
+ return NULL;
+ }
+
+ sch->q.qlen--;
+ qdisc_bstats_update(sch, skb);
+
+ old_V = q->V;
+ len = qdisc_pkt_len(skb);
+ q->V += (u64)len * IWSUM;
+ pr_debug("qfq dequeue: len %u F %lld now %lld\n",
+ len, (unsigned long long) cl->F, (unsigned long long) q->V);
+
+ if (qfq_update_class(grp, cl)) {
+ u64 old_F = grp->F;
+
+ cl = qfq_slot_scan(grp);
+ if (!cl)
+ __clear_bit(grp->index, &q->bitmaps[ER]);
+ else {
+ u64 roundedS = qfq_round_down(cl->S, grp->slot_shift);
+ unsigned int s;
+
+ if (grp->S == roundedS)
+ goto skip_unblock;
+ grp->S = roundedS;
+ grp->F = roundedS + (2ULL << grp->slot_shift);
+ __clear_bit(grp->index, &q->bitmaps[ER]);
+ s = qfq_calc_state(q, grp);
+ __set_bit(grp->index, &q->bitmaps[s]);
+ }
+
+ qfq_unblock_groups(q, grp->index, old_F);
+ }
+
+skip_unblock:
+ qfq_update_eligible(q, old_V);
+
+ return skb;
+}
+
+/*
+ * Assign a reasonable start time for a new flow k in group i.
+ * Admissible values for \hat(F) are multiples of \sigma_i
+ * no greater than V+\sigma_i . Larger values mean that
+ * we had a wraparound so we consider the timestamp to be stale.
+ *
+ * If F is not stale and F >= V then we set S = F.
+ * Otherwise we should assign S = V, but this may violate
+ * the ordering in ER. So, if we have groups in ER, set S to
+ * the F_j of the first group j which would be blocking us.
+ * We are guaranteed not to move S backward because
+ * otherwise our group i would still be blocked.
+ */
+static void qfq_update_start(struct qfq_sched *q, struct qfq_class *cl)
+{
+ unsigned long mask;
+ uint32_t limit, roundedF;
+ int slot_shift = cl->grp->slot_shift;
+
+ roundedF = qfq_round_down(cl->F, slot_shift);
+ limit = qfq_round_down(q->V, slot_shift) + (1UL << slot_shift);
+
+ if (!qfq_gt(cl->F, q->V) || qfq_gt(roundedF, limit)) {
+ /* timestamp was stale */
+ mask = mask_from(q->bitmaps[ER], cl->grp->index);
+ if (mask) {
+ struct qfq_group *next = qfq_ffs(q, mask);
+ if (qfq_gt(roundedF, next->F)) {
+ cl->S = next->F;
+ return;
+ }
+ }
+ cl->S = q->V;
+ } else /* timestamp is not stale */
+ cl->S = cl->F;
+}
+
+static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_group *grp;
+ struct qfq_class *cl;
+ int err;
+ u64 roundedS;
+ int s;
+
+ cl = qfq_classify(skb, sch, &err);
+ if (cl == NULL) {
+ if (err & __NET_XMIT_BYPASS)
+ sch->qstats.drops++;
+ kfree_skb(skb);
+ return err;
+ }
+ pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid);
+
+ err = qdisc_enqueue(skb, cl->qdisc);
+ if (unlikely(err != NET_XMIT_SUCCESS)) {
+ pr_debug("qfq_enqueue: enqueue failed %d\n", err);
+ if (net_xmit_drop_count(err)) {
+ cl->qstats.drops++;
+ sch->qstats.drops++;
+ }
+ return err;
+ }
+
+ bstats_update(&cl->bstats, skb);
+ ++sch->q.qlen;
+
+ /* If the new skb is not the head of queue, then done here. */
+ if (cl->qdisc->q.qlen != 1)
+ return err;
+
+ /* If reach this point, queue q was idle */
+ grp = cl->grp;
+ qfq_update_start(q, cl);
+
+ /* compute new finish time and rounded start. */
+ cl->F = cl->S + (u64)qdisc_pkt_len(skb) * cl->inv_w;
+ roundedS = qfq_round_down(cl->S, grp->slot_shift);
+
+ /*
+ * insert cl in the correct bucket.
+ * If cl->S >= grp->S we don't need to adjust the
+ * bucket list and simply go to the insertion phase.
+ * Otherwise grp->S is decreasing, we must make room
+ * in the bucket list, and also recompute the group state.
+ * Finally, if there were no flows in this group and nobody
+ * was in ER make sure to adjust V.
+ */
+ if (grp->full_slots) {
+ if (!qfq_gt(grp->S, cl->S))
+ goto skip_update;
+
+ /* create a slot for this cl->S */
+ qfq_slot_rotate(grp, roundedS);
+ /* group was surely ineligible, remove */
+ __clear_bit(grp->index, &q->bitmaps[IR]);
+ __clear_bit(grp->index, &q->bitmaps[IB]);
+ } else if (!q->bitmaps[ER] && qfq_gt(roundedS, q->V))
+ q->V = roundedS;
+
+ grp->S = roundedS;
+ grp->F = roundedS + (2ULL << grp->slot_shift);
+ s = qfq_calc_state(q, grp);
+ __set_bit(grp->index, &q->bitmaps[s]);
+
+ pr_debug("qfq enqueue: new state %d %#lx S %lld F %lld V %lld\n",
+ s, q->bitmaps[s],
+ (unsigned long long) cl->S,
+ (unsigned long long) cl->F,
+ (unsigned long long) q->V);
+
+skip_update:
+ qfq_slot_insert(grp, cl, roundedS);
+
+ return err;
+}
+
+
+static void qfq_slot_remove(struct qfq_sched *q, struct qfq_group *grp,
+ struct qfq_class *cl)
+{
+ unsigned int i, offset;
+ u64 roundedS;
+
+ roundedS = qfq_round_down(cl->S, grp->slot_shift);
+ offset = (roundedS - grp->S) >> grp->slot_shift;
+ i = (grp->front + offset) % QFQ_MAX_SLOTS;
+
+ hlist_del(&cl->next);
+ if (hlist_empty(&grp->slots[i]))
+ __clear_bit(offset, &grp->full_slots);
+}
+
+/*
+ * called to forcibly destroy a queue.
+ * If the queue is not in the front bucket, or if it has
+ * other queues in the front bucket, we can simply remove
+ * the queue with no other side effects.
+ * Otherwise we must propagate the event up.
+ */
+static void qfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl)
+{
+ struct qfq_group *grp = cl->grp;
+ unsigned long mask;
+ u64 roundedS;
+ int s;
+
+ cl->F = cl->S;
+ qfq_slot_remove(q, grp, cl);
+
+ if (!grp->full_slots) {
+ __clear_bit(grp->index, &q->bitmaps[IR]);
+ __clear_bit(grp->index, &q->bitmaps[EB]);
+ __clear_bit(grp->index, &q->bitmaps[IB]);
+
+ if (test_bit(grp->index, &q->bitmaps[ER]) &&
+ !(q->bitmaps[ER] & ~((1UL << grp->index) - 1))) {
+ mask = q->bitmaps[ER] & ((1UL << grp->index) - 1);
+ if (mask)
+ mask = ~((1UL << __fls(mask)) - 1);
+ else
+ mask = ~0UL;
+ qfq_move_groups(q, mask, EB, ER);
+ qfq_move_groups(q, mask, IB, IR);
+ }
+ __clear_bit(grp->index, &q->bitmaps[ER]);
+ } else if (hlist_empty(&grp->slots[grp->front])) {
+ cl = qfq_slot_scan(grp);
+ roundedS = qfq_round_down(cl->S, grp->slot_shift);
+ if (grp->S != roundedS) {
+ __clear_bit(grp->index, &q->bitmaps[ER]);
+ __clear_bit(grp->index, &q->bitmaps[IR]);
+ __clear_bit(grp->index, &q->bitmaps[EB]);
+ __clear_bit(grp->index, &q->bitmaps[IB]);
+ grp->S = roundedS;
+ grp->F = roundedS + (2ULL << grp->slot_shift);
+ s = qfq_calc_state(q, grp);
+ __set_bit(grp->index, &q->bitmaps[s]);
+ }
+ }
+
+ qfq_update_eligible(q, q->V);
+}
+
+static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_class *cl = (struct qfq_class *)arg;
+
+ if (cl->qdisc->q.qlen == 0)
+ qfq_deactivate_class(q, cl);
+}
+
+static unsigned int qfq_drop(struct Qdisc *sch)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_group *grp;
+ unsigned int i, j, len;
+
+ for (i = 0; i <= QFQ_MAX_INDEX; i++) {
+ grp = &q->groups[i];
+ for (j = 0; j < QFQ_MAX_SLOTS; j++) {
+ struct qfq_class *cl;
+ struct hlist_node *n;
+
+ hlist_for_each_entry(cl, n, &grp->slots[j], next) {
+
+ if (!cl->qdisc->ops->drop)
+ continue;
+
+ len = cl->qdisc->ops->drop(cl->qdisc);
+ if (len > 0) {
+ sch->q.qlen--;
+ if (!cl->qdisc->q.qlen)
+ qfq_deactivate_class(q, cl);
+
+ return len;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int qfq_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_group *grp;
+ int i, j, err;
+
+ err = qdisc_class_hash_init(&q->clhash);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i <= QFQ_MAX_INDEX; i++) {
+ grp = &q->groups[i];
+ grp->index = i;
+ grp->slot_shift = QFQ_MTU_SHIFT + FRAC_BITS
+ - (QFQ_MAX_INDEX - i);
+ for (j = 0; j < QFQ_MAX_SLOTS; j++)
+ INIT_HLIST_HEAD(&grp->slots[j]);
+ }
+
+ return 0;
+}
+
+static void qfq_reset_qdisc(struct Qdisc *sch)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_group *grp;
+ struct qfq_class *cl;
+ struct hlist_node *n, *tmp;
+ unsigned int i, j;
+
+ for (i = 0; i <= QFQ_MAX_INDEX; i++) {
+ grp = &q->groups[i];
+ for (j = 0; j < QFQ_MAX_SLOTS; j++) {
+ hlist_for_each_entry_safe(cl, n, tmp,
+ &grp->slots[j], next) {
+ qfq_deactivate_class(q, cl);
+ }
+ }
+ }
+
+ for (i = 0; i < q->clhash.hashsize; i++) {
+ hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode)
+ qdisc_reset(cl->qdisc);
+ }
+ sch->q.qlen = 0;
+}
+
+static void qfq_destroy_qdisc(struct Qdisc *sch)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_class *cl;
+ struct hlist_node *n, *next;
+ unsigned int i;
+
+ tcf_destroy_chain(&q->filter_list);
+
+ for (i = 0; i < q->clhash.hashsize; i++) {
+ hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i],
+ common.hnode) {
+ qfq_destroy_class(sch, cl);
+ }
+ }
+ qdisc_class_hash_destroy(&q->clhash);
+}
+
+static const struct Qdisc_class_ops qfq_class_ops = {
+ .change = qfq_change_class,
+ .delete = qfq_delete_class,
+ .get = qfq_get_class,
+ .put = qfq_put_class,
+ .tcf_chain = qfq_tcf_chain,
+ .bind_tcf = qfq_bind_tcf,
+ .unbind_tcf = qfq_unbind_tcf,
+ .graft = qfq_graft_class,
+ .leaf = qfq_class_leaf,
+ .qlen_notify = qfq_qlen_notify,
+ .dump = qfq_dump_class,
+ .dump_stats = qfq_dump_class_stats,
+ .walk = qfq_walk,
+};
+
+static struct Qdisc_ops qfq_qdisc_ops __read_mostly = {
+ .cl_ops = &qfq_class_ops,
+ .id = "qfq",
+ .priv_size = sizeof(struct qfq_sched),
+ .enqueue = qfq_enqueue,
+ .dequeue = qfq_dequeue,
+ .peek = qdisc_peek_dequeued,
+ .drop = qfq_drop,
+ .init = qfq_init_qdisc,
+ .reset = qfq_reset_qdisc,
+ .destroy = qfq_destroy_qdisc,
+ .owner = THIS_MODULE,
+};
+
+static int __init qfq_init(void)
+{
+ return register_qdisc(&qfq_qdisc_ops);
+}
+
+static void __exit qfq_exit(void)
+{
+ unregister_qdisc(&qfq_qdisc_ops);
+}
+
+module_init(qfq_init);
+module_exit(qfq_exit);
+MODULE_LICENSE("GPL");
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index c2e628d..7ef87f9 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -169,7 +169,7 @@ static unsigned int sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
}
case htons(ETH_P_IPV6):
{
- struct ipv6hdr *iph;
+ const struct ipv6hdr *iph;
int poff;
if (!pskb_network_may_pull(skb, sizeof(*iph)))
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 6b04287..1a21c57 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -569,6 +569,8 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
sctp_assoc_set_primary(asoc, transport);
if (asoc->peer.active_path == peer)
asoc->peer.active_path = transport;
+ if (asoc->peer.retran_path == peer)
+ asoc->peer.retran_path = transport;
if (asoc->peer.last_data_from == peer)
asoc->peer.last_data_from = transport;
@@ -1323,6 +1325,8 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
if (t)
asoc->peer.retran_path = t;
+ else
+ t = asoc->peer.retran_path;
SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association"
" %p addr: ",
@@ -1593,7 +1597,7 @@ void sctp_assoc_clean_asconf_ack_cache(const struct sctp_association *asoc)
struct sctp_chunk *ack;
struct sctp_chunk *tmp;
- /* We can remove all the entries from the queue upto
+ /* We can remove all the entries from the queue up to
* the "Peer-Sequence-Number".
*/
list_for_each_entry_safe(ack, tmp, &asoc->asconf_ack_list,
diff --git a/net/sctp/auth.c b/net/sctp/auth.c
index ddbbf7c..865e68f 100644
--- a/net/sctp/auth.c
+++ b/net/sctp/auth.c
@@ -113,7 +113,7 @@ struct sctp_shared_key *sctp_auth_shkey_create(__u16 key_id, gfp_t gfp)
return new;
}
-/* Free the shared key stucture */
+/* Free the shared key structure */
static void sctp_auth_shkey_free(struct sctp_shared_key *sh_key)
{
BUG_ON(!list_empty(&sh_key->key_list));
@@ -122,7 +122,7 @@ static void sctp_auth_shkey_free(struct sctp_shared_key *sh_key)
kfree(sh_key);
}
-/* Destory the entire key list. This is done during the
+/* Destroy the entire key list. This is done during the
* associon and endpoint free process.
*/
void sctp_auth_destroy_keys(struct list_head *keys)
@@ -324,7 +324,7 @@ static struct sctp_auth_bytes *sctp_auth_asoc_create_secret(
if (!peer_key_vector || !local_key_vector)
goto out;
- /* Figure out the order in wich the key_vectors will be
+ /* Figure out the order in which the key_vectors will be
* added to the endpoint shared key.
* SCTP-AUTH, Section 6.1:
* This is performed by selecting the numerically smaller key
diff --git a/net/sctp/debug.c b/net/sctp/debug.c
index bf24fa6..ec997cf 100644
--- a/net/sctp/debug.c
+++ b/net/sctp/debug.c
@@ -98,7 +98,6 @@ const char *sctp_cname(const sctp_subtype_t cid)
/* These are printable forms of the states. */
const char *const sctp_state_tbl[SCTP_STATE_NUM_STATES] = {
- "STATE_EMPTY",
"STATE_CLOSED",
"STATE_COOKIE_WAIT",
"STATE_COOKIE_ECHOED",
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index e10acc0..c8cc24e 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -325,6 +325,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
struct sctp_transport **transport)
{
struct sctp_association *asoc = NULL;
+ struct sctp_association *tmp;
struct sctp_transport *t = NULL;
struct sctp_hashbucket *head;
struct sctp_ep_common *epb;
@@ -333,25 +334,32 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
int rport;
*transport = NULL;
+
+ /* If the local port is not set, there can't be any associations
+ * on this endpoint.
+ */
+ if (!ep->base.bind_addr.port)
+ goto out;
+
rport = ntohs(paddr->v4.sin_port);
hash = sctp_assoc_hashfn(ep->base.bind_addr.port, rport);
head = &sctp_assoc_hashtable[hash];
read_lock(&head->lock);
sctp_for_each_hentry(epb, node, &head->chain) {
- asoc = sctp_assoc(epb);
- if (asoc->ep != ep || rport != asoc->peer.port)
- goto next;
+ tmp = sctp_assoc(epb);
+ if (tmp->ep != ep || rport != tmp->peer.port)
+ continue;
- t = sctp_assoc_lookup_paddr(asoc, paddr);
+ t = sctp_assoc_lookup_paddr(tmp, paddr);
if (t) {
+ asoc = tmp;
*transport = t;
break;
}
-next:
- asoc = NULL;
}
read_unlock(&head->lock);
+out:
return asoc;
}
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 826661b..741ed16 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -565,7 +565,7 @@ void sctp_err_finish(struct sock *sk, struct sctp_association *asoc)
*/
void sctp_v4_err(struct sk_buff *skb, __u32 info)
{
- struct iphdr *iph = (struct iphdr *)skb->data;
+ const struct iphdr *iph = (const struct iphdr *)skb->data;
const int ihlen = iph->ihl * 4;
const int type = icmp_hdr(skb)->type;
const int code = icmp_hdr(skb)->code;
@@ -661,7 +661,6 @@ static int sctp_rcv_ootb(struct sk_buff *skb)
{
sctp_chunkhdr_t *ch;
__u8 *ch_end;
- sctp_errhdr_t *err;
ch = (sctp_chunkhdr_t *) skb->data;
@@ -697,20 +696,6 @@ static int sctp_rcv_ootb(struct sk_buff *skb)
if (SCTP_CID_INIT == ch->type && (void *)ch != skb->data)
goto discard;
- /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR
- * or a COOKIE ACK the SCTP Packet should be silently
- * discarded.
- */
- if (SCTP_CID_COOKIE_ACK == ch->type)
- goto discard;
-
- if (SCTP_CID_ERROR == ch->type) {
- sctp_walk_errors(err, ch) {
- if (SCTP_ERROR_STALE_COOKIE == err->cause)
- goto discard;
- }
- }
-
ch = (sctp_chunkhdr_t *) ch_end;
} while (ch_end < skb_tail_pointer(skb));
@@ -1017,7 +1002,7 @@ static struct sctp_association *__sctp_rcv_asconf_lookup(
/* Skip over the ADDIP header and find the Address parameter */
param = (union sctp_addr_param *)(asconf + 1);
- af = sctp_get_af_specific(param_type2af(param->v4.param_hdr.type));
+ af = sctp_get_af_specific(param_type2af(param->p.type));
if (unlikely(!af))
return NULL;
@@ -1034,7 +1019,7 @@ static struct sctp_association *__sctp_rcv_asconf_lookup(
* association.
*
* This means that any chunks that can help us identify the association need
-* to be looked at to find this assocation.
+* to be looked at to find this association.
*/
static struct sctp_association *__sctp_rcv_walk_lookup(struct sk_buff *skb,
const union sctp_addr *laddr,
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 865ce7b..500875f 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -80,6 +80,13 @@
#include <asm/uaccess.h>
+static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
+ union sctp_addr *s2);
+static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
+ __be16 port);
+static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
+ const union sctp_addr *addr2);
+
/* Event handler for inet6 address addition/deletion events.
* The sctp_local_addr_list needs to be protocted by a spin lock since
* multiple notifiers (say IPv4 and IPv6) may be running at the same
@@ -240,37 +247,107 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
/* Returns the dst cache entry for the given source and destination ip
* addresses.
*/
-static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
- union sctp_addr *daddr,
- union sctp_addr *saddr)
+static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+ struct flowi *fl, struct sock *sk)
{
- struct dst_entry *dst;
- struct flowi6 fl6;
+ struct sctp_association *asoc = t->asoc;
+ struct dst_entry *dst = NULL;
+ struct flowi6 *fl6 = &fl->u.ip6;
+ struct sctp_bind_addr *bp;
+ struct sctp_sockaddr_entry *laddr;
+ union sctp_addr *baddr = NULL;
+ union sctp_addr *daddr = &t->ipaddr;
+ union sctp_addr dst_saddr;
+ __u8 matchlen = 0;
+ __u8 bmatchlen;
+ sctp_scope_t scope;
- memset(&fl6, 0, sizeof(fl6));
- ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr);
+ memset(fl6, 0, sizeof(struct flowi6));
+ ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr);
+ fl6->fl6_dport = daddr->v6.sin6_port;
+ fl6->flowi6_proto = IPPROTO_SCTP;
if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
- fl6.flowi6_oif = daddr->v6.sin6_scope_id;
+ fl6->flowi6_oif = daddr->v6.sin6_scope_id;
+ SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr);
- SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6.daddr);
+ if (asoc)
+ fl6->fl6_sport = htons(asoc->base.bind_addr.port);
if (saddr) {
- ipv6_addr_copy(&fl6.saddr, &saddr->v6.sin6_addr);
- SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6.saddr);
+ ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr);
+ fl6->fl6_sport = saddr->v6.sin6_port;
+ SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr);
+ }
+
+ dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
+ if (!asoc || saddr)
+ goto out;
+
+ bp = &asoc->base.bind_addr;
+ scope = sctp_scope(daddr);
+ /* ip6_dst_lookup has filled in the fl6->saddr for us. Check
+ * to see if we can use it.
+ */
+ if (!IS_ERR(dst)) {
+ /* Walk through the bind address list and look for a bind
+ * address that matches the source address of the returned dst.
+ */
+ sctp_v6_to_addr(&dst_saddr, &fl6->saddr, htons(bp->port));
+ rcu_read_lock();
+ list_for_each_entry_rcu(laddr, &bp->address_list, list) {
+ if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
+ continue;
+
+ /* Do not compare against v4 addrs */
+ if ((laddr->a.sa.sa_family == AF_INET6) &&
+ (sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) {
+ rcu_read_unlock();
+ goto out;
+ }
+ }
+ rcu_read_unlock();
+ /* None of the bound addresses match the source address of the
+ * dst. So release it.
+ */
+ dst_release(dst);
+ dst = NULL;
}
- dst = ip6_route_output(&init_net, NULL, &fl6);
- if (!dst->error) {
+ /* Walk through the bind address list and try to get the
+ * best source address for a given destination.
+ */
+ rcu_read_lock();
+ list_for_each_entry_rcu(laddr, &bp->address_list, list) {
+ if (!laddr->valid && laddr->state != SCTP_ADDR_SRC)
+ continue;
+ if ((laddr->a.sa.sa_family == AF_INET6) &&
+ (scope <= sctp_scope(&laddr->a))) {
+ bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
+ if (!baddr || (matchlen < bmatchlen)) {
+ baddr = &laddr->a;
+ matchlen = bmatchlen;
+ }
+ }
+ }
+ rcu_read_unlock();
+ if (baddr) {
+ ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr);
+ fl6->fl6_sport = baddr->v6.sin6_port;
+ dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
+ }
+
+out:
+ if (!IS_ERR(dst)) {
struct rt6_info *rt;
rt = (struct rt6_info *)dst;
+ t->dst = dst;
SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n",
- &rt->rt6i_dst.addr, &rt->rt6i_src.addr);
- return dst;
+ &rt->rt6i_dst.addr, &fl6->saddr);
+ } else {
+ t->dst = NULL;
+ SCTP_DEBUG_PRINTK("NO ROUTE\n");
}
- SCTP_DEBUG_PRINTK("NO ROUTE\n");
- dst_release(dst);
- return NULL;
}
/* Returns the number of consecutive initial bits that match in the 2 ipv6
@@ -286,64 +363,18 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
* and asoc's bind address list.
*/
static void sctp_v6_get_saddr(struct sctp_sock *sk,
- struct sctp_association *asoc,
- struct dst_entry *dst,
- union sctp_addr *daddr,
- union sctp_addr *saddr)
+ struct sctp_transport *t,
+ struct flowi *fl)
{
- struct sctp_bind_addr *bp;
- struct sctp_sockaddr_entry *laddr;
- sctp_scope_t scope;
- union sctp_addr *baddr = NULL;
- __u8 matchlen = 0;
- __u8 bmatchlen;
+ struct flowi6 *fl6 = &fl->u.ip6;
+ union sctp_addr *saddr = &t->saddr;
- SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ",
- __func__, asoc, dst, &daddr->v6.sin6_addr);
-
- if (!asoc) {
- ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)),
- dst ? ip6_dst_idev(dst)->dev : NULL,
- &daddr->v6.sin6_addr,
- inet6_sk(&sk->inet.sk)->srcprefs,
- &saddr->v6.sin6_addr);
- SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n",
- &saddr->v6.sin6_addr);
- return;
- }
-
- scope = sctp_scope(daddr);
-
- bp = &asoc->base.bind_addr;
+ SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p\n", __func__, t->asoc, t->dst);
- /* Go through the bind address list and find the best source address
- * that matches the scope of the destination address.
- */
- rcu_read_lock();
- list_for_each_entry_rcu(laddr, &bp->address_list, list) {
- if (!laddr->valid)
- continue;
- if ((laddr->state == SCTP_ADDR_SRC) &&
- (laddr->a.sa.sa_family == AF_INET6) &&
- (scope <= sctp_scope(&laddr->a))) {
- bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
- if (!baddr || (matchlen < bmatchlen)) {
- baddr = &laddr->a;
- matchlen = bmatchlen;
- }
- }
- }
-
- if (baddr) {
- memcpy(saddr, baddr, sizeof(union sctp_addr));
- SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
- } else {
- pr_err("%s: asoc:%p Could not find a valid source "
- "address for the dest:%pI6\n",
- __func__, asoc, &daddr->v6.sin6_addr);
+ if (t->dst) {
+ saddr->v6.sin6_family = AF_INET6;
+ ipv6_addr_copy(&saddr->v6.sin6_addr, &fl6->saddr);
}
-
- rcu_read_unlock();
}
/* Make a copy of all potential local addresses. */
@@ -465,14 +496,13 @@ static int sctp_v6_to_addr_param(const union sctp_addr *addr,
return length;
}
-/* Initialize a sctp_addr from a dst_entry. */
-static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
+/* Initialize a sctp_addr from struct in6_addr. */
+static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
__be16 port)
{
- struct rt6_info *rt = (struct rt6_info *)dst;
addr->sa.sa_family = AF_INET6;
addr->v6.sin6_port = port;
- ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr);
+ ipv6_addr_copy(&addr->v6.sin6_addr, saddr);
}
/* Compare addresses exactly.
@@ -531,7 +561,7 @@ static int sctp_v6_is_any(const union sctp_addr *addr)
static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
{
int type;
- struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr;
+ const struct in6_addr *in6 = (const struct in6_addr *)&addr->v6.sin6_addr;
type = ipv6_addr_type(in6);
if (IPV6_ADDR_ANY == type)
@@ -959,7 +989,6 @@ static struct sctp_af sctp_af_inet6 = {
.to_sk_daddr = sctp_v6_to_sk_daddr,
.from_addr_param = sctp_v6_from_addr_param,
.to_addr_param = sctp_v6_to_addr_param,
- .dst_saddr = sctp_v6_dst_saddr,
.cmp_addr = sctp_v6_cmp_addr,
.scope = sctp_v6_scope,
.addr_valid = sctp_v6_addr_valid,
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 60600d3..b4f3cf0 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -510,7 +510,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
sh->checksum = sctp_end_cksum(crc32);
} else {
if (dst->dev->features & NETIF_F_SCTP_CSUM) {
- /* no need to seed psuedo checksum for SCTP */
+ /* no need to seed pseudo checksum for SCTP */
nskb->ip_summed = CHECKSUM_PARTIAL;
nskb->csum_start = (skb_transport_header(nskb) -
nskb->head);
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 26dc005..1c88c89 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -131,7 +131,8 @@ static inline int sctp_cacc_skip_3_1_d(struct sctp_transport *primary,
static inline int sctp_cacc_skip_3_1_f(struct sctp_transport *transport,
int count_of_newacks)
{
- if (count_of_newacks < 2 && !transport->cacc.cacc_saw_newack)
+ if (count_of_newacks < 2 &&
+ (transport && !transport->cacc.cacc_saw_newack))
return 1;
return 0;
}
@@ -177,13 +178,13 @@ static inline int sctp_cacc_skip_3_2(struct sctp_transport *primary, __u32 tsn)
* 3) If the missing report count for TSN t is to be
* incremented according to [RFC2960] and
* [SCTP_STEWART-2002], and CHANGEOVER_ACTIVE is set,
- * then the sender MUST futher execute steps 3.1 and
+ * then the sender MUST further execute steps 3.1 and
* 3.2 to determine if the missing report count for
* TSN t SHOULD NOT be incremented.
*
* 3.3) If 3.1 and 3.2 do not dictate that the missing
* report count for t should not be incremented, then
- * the sender SOULD increment missing report count for
+ * the sender SHOULD increment missing report count for
* t (according to [RFC2960] and [SCTP_STEWART_2002]).
*/
static inline int sctp_cacc_skip(struct sctp_transport *primary,
@@ -319,7 +320,6 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
* chunk.
*/
switch (q->asoc->state) {
- case SCTP_STATE_EMPTY:
case SCTP_STATE_CLOSED:
case SCTP_STATE_SHUTDOWN_PENDING:
case SCTP_STATE_SHUTDOWN_SENT:
@@ -577,6 +577,13 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
* try to send as much as possible.
*/
list_for_each_entry_safe(chunk, chunk1, lqueue, transmitted_list) {
+ /* If the chunk is abandoned, move it to abandoned list. */
+ if (sctp_chunk_abandoned(chunk)) {
+ list_del_init(&chunk->transmitted_list);
+ sctp_insert_list(&q->abandoned,
+ &chunk->transmitted_list);
+ continue;
+ }
/* Make sure that Gap Acked TSNs are not retransmitted. A
* simple approach is just to move such TSNs out of the
@@ -618,9 +625,12 @@ redo:
/* If we are retransmitting, we should only
* send a single packet.
+ * Otherwise, try appending this chunk again.
*/
if (rtx_timeout || fast_rtx)
done = 1;
+ else
+ goto redo;
/* Bundle next chunk in the next round. */
break;
@@ -843,7 +853,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
case SCTP_CID_ECN_CWR:
case SCTP_CID_ASCONF_ACK:
one_packet = 1;
- /* Fall throught */
+ /* Fall through */
case SCTP_CID_SACK:
case SCTP_CID_HEARTBEAT:
@@ -1683,8 +1693,9 @@ static void sctp_mark_missing(struct sctp_outq *q,
/* SFR-CACC may require us to skip marking
* this chunk as missing.
*/
- if (!transport || !sctp_cacc_skip(primary, transport,
- count_of_newacks, tsn)) {
+ if (!transport || !sctp_cacc_skip(primary,
+ chunk->transport,
+ count_of_newacks, tsn)) {
chunk->tsn_missing_report++;
SCTP_DEBUG_PRINTK(
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index d5bf91d..69fbc55 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -339,13 +339,12 @@ static int sctp_v4_to_addr_param(const union sctp_addr *addr,
}
/* Initialize a sctp_addr from a dst_entry. */
-static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst,
+static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct flowi4 *fl4,
__be16 port)
{
- struct rtable *rt = (struct rtable *)dst;
saddr->v4.sin_family = AF_INET;
saddr->v4.sin_port = port;
- saddr->v4.sin_addr.s_addr = rt->rt_src;
+ saddr->v4.sin_addr.s_addr = fl4->saddr;
}
/* Compare two addresses exactly. */
@@ -463,35 +462,36 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
* addresses. If an association is passed, trys to get a dst entry with a
* source address that matches an address in the bind address list.
*/
-static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
- union sctp_addr *daddr,
- union sctp_addr *saddr)
+static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+ struct flowi *fl, struct sock *sk)
{
+ struct sctp_association *asoc = t->asoc;
struct rtable *rt;
- struct flowi4 fl4;
+ struct flowi4 *fl4 = &fl->u.ip4;
struct sctp_bind_addr *bp;
struct sctp_sockaddr_entry *laddr;
struct dst_entry *dst = NULL;
+ union sctp_addr *daddr = &t->ipaddr;
union sctp_addr dst_saddr;
- memset(&fl4, 0x0, sizeof(struct flowi4));
- fl4.daddr = daddr->v4.sin_addr.s_addr;
- fl4.fl4_dport = daddr->v4.sin_port;
- fl4.flowi4_proto = IPPROTO_SCTP;
+ memset(fl4, 0x0, sizeof(struct flowi4));
+ fl4->daddr = daddr->v4.sin_addr.s_addr;
+ fl4->fl4_dport = daddr->v4.sin_port;
+ fl4->flowi4_proto = IPPROTO_SCTP;
if (asoc) {
- fl4.flowi4_tos = RT_CONN_FLAGS(asoc->base.sk);
- fl4.flowi4_oif = asoc->base.sk->sk_bound_dev_if;
- fl4.fl4_sport = htons(asoc->base.bind_addr.port);
+ fl4->flowi4_tos = RT_CONN_FLAGS(asoc->base.sk);
+ fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if;
+ fl4->fl4_sport = htons(asoc->base.bind_addr.port);
}
if (saddr) {
- fl4.saddr = saddr->v4.sin_addr.s_addr;
- fl4.fl4_sport = saddr->v4.sin_port;
+ fl4->saddr = saddr->v4.sin_addr.s_addr;
+ fl4->fl4_sport = saddr->v4.sin_port;
}
SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ",
- __func__, &fl4.daddr, &fl4.saddr);
+ __func__, &fl4->daddr, &fl4->saddr);
- rt = ip_route_output_key(&init_net, &fl4);
+ rt = ip_route_output_key(&init_net, fl4);
if (!IS_ERR(rt))
dst = &rt->dst;
@@ -507,7 +507,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
/* Walk through the bind address list and look for a bind
* address that matches the source address of the returned dst.
*/
- sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
+ sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port));
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
@@ -533,9 +533,9 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
continue;
if ((laddr->state == SCTP_ADDR_SRC) &&
(AF_INET == laddr->a.sa.sa_family)) {
- fl4.saddr = laddr->a.v4.sin_addr.s_addr;
- fl4.fl4_sport = laddr->a.v4.sin_port;
- rt = ip_route_output_key(&init_net, &fl4);
+ fl4->saddr = laddr->a.v4.sin_addr.s_addr;
+ fl4->fl4_sport = laddr->a.v4.sin_port;
+ rt = ip_route_output_key(&init_net, fl4);
if (!IS_ERR(rt)) {
dst = &rt->dst;
goto out_unlock;
@@ -546,32 +546,26 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
out_unlock:
rcu_read_unlock();
out:
+ t->dst = dst;
if (dst)
SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n",
- &rt->rt_dst, &rt->rt_src);
+ &fl4->daddr, &fl4->saddr);
else
SCTP_DEBUG_PRINTK("NO ROUTE\n");
-
- return dst;
}
/* For v4, the source address is cached in the route entry(dst). So no need
* to cache it separately and hence this is an empty routine.
*/
static void sctp_v4_get_saddr(struct sctp_sock *sk,
- struct sctp_association *asoc,
- struct dst_entry *dst,
- union sctp_addr *daddr,
- union sctp_addr *saddr)
+ struct sctp_transport *t,
+ struct flowi *fl)
{
- struct rtable *rt = (struct rtable *)dst;
-
- if (!asoc)
- return;
+ union sctp_addr *saddr = &t->saddr;
+ struct rtable *rt = (struct rtable *)t->dst;
if (rt) {
saddr->v4.sin_family = AF_INET;
- saddr->v4.sin_port = htons(asoc->base.bind_addr.port);
saddr->v4.sin_addr.s_addr = rt->rt_src;
}
}
@@ -950,7 +944,6 @@ static struct sctp_af sctp_af_inet = {
.to_sk_daddr = sctp_v4_to_sk_daddr,
.from_addr_param = sctp_v4_from_addr_param,
.to_addr_param = sctp_v4_to_addr_param,
- .dst_saddr = sctp_v4_dst_saddr,
.cmp_addr = sctp_v4_cmp_addr,
.addr_valid = sctp_v4_addr_valid,
.inaddr_any = sctp_v4_inaddr_any,
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index b3434cc..58eb27f 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1075,20 +1075,28 @@ nodata:
/* Make a HEARTBEAT chunk. */
struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
- const struct sctp_transport *transport,
- const void *payload, const size_t paylen)
+ const struct sctp_transport *transport)
{
- struct sctp_chunk *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT,
- 0, paylen);
+ struct sctp_chunk *retval;
+ sctp_sender_hb_info_t hbinfo;
+
+ retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo));
if (!retval)
goto nodata;
+ hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO;
+ hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t));
+ hbinfo.daddr = transport->ipaddr;
+ hbinfo.sent_at = jiffies;
+ hbinfo.hb_nonce = transport->hb_nonce;
+
/* Cast away the 'const', as this is just telling the chunk
* what transport it belongs to.
*/
retval->transport = (struct sctp_transport *) transport;
- retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload);
+ retval->subh.hbs_hdr = sctp_addto_chunk(retval, sizeof(hbinfo),
+ &hbinfo);
nodata:
return retval;
@@ -2242,14 +2250,17 @@ int sctp_verify_init(const struct sctp_association *asoc,
* Returns 0 on failure, else success.
* FIXME: This is an association method.
*/
-int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
+int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
const union sctp_addr *peer_addr,
sctp_init_chunk_t *peer_init, gfp_t gfp)
{
union sctp_params param;
struct sctp_transport *transport;
struct list_head *pos, *temp;
+ struct sctp_af *af;
+ union sctp_addr addr;
char *cookie;
+ int src_match = 0;
/* We must include the address that the INIT packet came from.
* This is the only address that matters for an INIT packet.
@@ -2261,18 +2272,31 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
* added as the primary transport. The source address seems to
* be a a better choice than any of the embedded addresses.
*/
- if (peer_addr) {
- if(!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE))
- goto nomem;
- }
+ if(!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE))
+ goto nomem;
+
+ if (sctp_cmp_addr_exact(sctp_source(chunk), peer_addr))
+ src_match = 1;
/* Process the initialization parameters. */
sctp_walk_params(param, peer_init, init_hdr.params) {
+ if (!src_match && (param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
+ param.p->type == SCTP_PARAM_IPV6_ADDRESS)) {
+ af = sctp_get_af_specific(param_type2af(param.p->type));
+ af->from_addr_param(&addr, param.addr,
+ chunk->sctp_hdr->source, 0);
+ if (sctp_cmp_addr_exact(sctp_source(chunk), &addr))
+ src_match = 1;
+ }
if (!sctp_process_param(asoc, param, peer_addr, gfp))
goto clean_up;
}
+ /* source address of chunk may not match any valid address */
+ if (!src_match)
+ goto clean_up;
+
/* AUTH: After processing the parameters, make sure that we
* have all the required info to potentially do authentications.
*/
@@ -2923,7 +2947,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY)
return SCTP_ERROR_UNKNOWN_PARAM;
- switch (addr_param->v4.param_hdr.type) {
+ switch (addr_param->p.type) {
case SCTP_PARAM_IPV6_ADDRESS:
if (!asoc->peer.ipv6_address)
return SCTP_ERROR_DNS_FAILED;
@@ -2936,7 +2960,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
return SCTP_ERROR_DNS_FAILED;
}
- af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type));
+ af = sctp_get_af_specific(param_type2af(addr_param->p.type));
if (unlikely(!af))
return SCTP_ERROR_DNS_FAILED;
@@ -3100,7 +3124,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
/* Skip the address parameter and store a pointer to the first
* asconf parameter.
*/
- length = ntohs(addr_param->v4.param_hdr.length);
+ length = ntohs(addr_param->p.length);
asconf_param = (sctp_addip_param_t *)((void *)addr_param + length);
chunk_len -= length;
@@ -3177,7 +3201,7 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
((void *)asconf_param + sizeof(sctp_addip_param_t));
/* We have checked the packet before, so we do not check again. */
- af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type));
+ af = sctp_get_af_specific(param_type2af(addr_param->p.type));
af->from_addr_param(&addr, addr_param, htons(bp->port), 0);
switch (asconf_param->param_hdr.type) {
@@ -3193,11 +3217,8 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
local_bh_enable();
list_for_each_entry(transport, &asoc->peer.transport_addr_list,
transports) {
- if (transport->state == SCTP_ACTIVE)
- continue;
dst_release(transport->dst);
- sctp_transport_route(transport, NULL,
- sctp_sk(asoc->base.sk));
+ transport->dst = NULL;
}
break;
case SCTP_PARAM_DEL_IP:
@@ -3207,8 +3228,7 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
list_for_each_entry(transport, &asoc->peer.transport_addr_list,
transports) {
dst_release(transport->dst);
- sctp_transport_route(transport, NULL,
- sctp_sk(asoc->base.sk));
+ transport->dst = NULL;
}
break;
default:
@@ -3304,7 +3324,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
/* Skip the address parameter in the last asconf sent and store a
* pointer to the first asconf parameter.
*/
- length = ntohs(addr_param->v4.param_hdr.length);
+ length = ntohs(addr_param->p.length);
asconf_param = (sctp_addip_param_t *)((void *)addr_param + length);
asconf_len -= length;
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index b21b218..d612ca1 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -482,7 +482,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
* If the timer was a heartbeat, we only increment error counts
* when we already have an outstanding HEARTBEAT that has not
* been acknowledged.
- * Additionaly, some tranport states inhibit error increments.
+ * Additionally, some tranport states inhibit error increments.
*/
if (!is_hb) {
asoc->overall_error_count++;
@@ -595,8 +595,7 @@ static int sctp_cmd_process_init(sctp_cmd_seq_t *commands,
* fail during INIT processing (due to malloc problems),
* just return the error and stop processing the stack.
*/
- if (!sctp_process_init(asoc, chunk->chunk_hdr->type,
- sctp_source(chunk), peer_init, gfp))
+ if (!sctp_process_init(asoc, chunk, sctp_source(chunk), peer_init, gfp))
error = -ENOMEM;
else
error = 0;
@@ -1415,12 +1414,6 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
SCTP_RTXR_T3_RTX);
break;
- case SCTP_CMD_TRANSMIT:
- /* Kick start transmission. */
- error = sctp_outq_uncork(&asoc->outqueue);
- local_cork = 0;
- break;
-
case SCTP_CMD_ECN_CE:
/* Do delayed CE processing. */
sctp_do_ecn_ce_work(asoc, cmd->obj.u32);
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 4b4eb7c..7f4a4f8 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -393,8 +393,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
goto nomem_init;
/* The call, sctp_process_init(), can fail on memory allocation. */
- if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
- sctp_source(chunk),
+ if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk),
(sctp_init_chunk_t *)chunk->chunk_hdr,
GFP_ATOMIC))
goto nomem_init;
@@ -551,7 +550,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
*
* This means that if we only want to abort associations
* in an authenticated way (i.e AUTH+ABORT), then we
- * can't destroy this association just becuase the packet
+ * can't destroy this association just because the packet
* was malformed.
*/
if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
@@ -725,7 +724,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
*/
peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
- if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
+ if (!sctp_process_init(new_asoc, chunk,
&chunk->subh.cookie_hdr->c.peer_addr,
peer_init, GFP_ATOMIC))
goto nomem_init;
@@ -942,18 +941,9 @@ static sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
{
struct sctp_transport *transport = (struct sctp_transport *) arg;
struct sctp_chunk *reply;
- sctp_sender_hb_info_t hbinfo;
- size_t paylen = 0;
-
- hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO;
- hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t));
- hbinfo.daddr = transport->ipaddr;
- hbinfo.sent_at = jiffies;
- hbinfo.hb_nonce = transport->hb_nonce;
/* Send a heartbeat to our peer. */
- paylen = sizeof(sctp_sender_hb_info_t);
- reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen);
+ reply = sctp_make_heartbeat(asoc, transport);
if (!reply)
return SCTP_DISPOSITION_NOMEM;
@@ -1464,8 +1454,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
* Verification Tag and Peers Verification tag into a reserved
* place (local tie-tag and per tie-tag) within the state cookie.
*/
- if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
- sctp_source(chunk),
+ if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk),
(sctp_init_chunk_t *)chunk->chunk_hdr,
GFP_ATOMIC))
goto nomem;
@@ -1546,7 +1535,7 @@ cleanup:
}
/*
- * Handle simultanous INIT.
+ * Handle simultaneous INIT.
* This means we started an INIT and then we got an INIT request from
* our peer.
*
@@ -1694,8 +1683,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep,
*/
peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
- if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
- sctp_source(chunk), peer_init,
+ if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), peer_init,
GFP_ATOMIC))
goto nomem;
@@ -1780,8 +1768,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
* side effects--it is safe to run them here.
*/
peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
- if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
- sctp_source(chunk), peer_init,
+ if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), peer_init,
GFP_ATOMIC))
goto nomem;
@@ -2079,7 +2066,7 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(
* RFC 2960, Section 3.3.7
* If an endpoint receives an ABORT with a format error or for an
* association that doesn't exist, it MUST silently discard it.
- * Becasue the length is "invalid", we can't really discard just
+ * Because the length is "invalid", we can't really discard just
* as we do not know its true length. So, to be safe, discard the
* packet.
*/
@@ -2120,7 +2107,7 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
* RFC 2960, Section 3.3.7
* If an endpoint receives an ABORT with a format error or for an
* association that doesn't exist, it MUST silently discard it.
- * Becasue the length is "invalid", we can't really discard just
+ * Because the length is "invalid", we can't really discard just
* as we do not know its true length. So, to be safe, discard the
* packet.
*/
@@ -2381,7 +2368,7 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
* RFC 2960, Section 3.3.7
* If an endpoint receives an ABORT with a format error or for an
* association that doesn't exist, it MUST silently discard it.
- * Becasue the length is "invalid", we can't really discard just
+ * Because the length is "invalid", we can't really discard just
* as we do not know its true length. So, to be safe, discard the
* packet.
*/
@@ -2412,8 +2399,15 @@ static sctp_disposition_t __sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
/* See if we have an error cause code in the chunk. */
len = ntohs(chunk->chunk_hdr->length);
- if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
+ if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) {
+
+ sctp_errhdr_t *err;
+ sctp_walk_errors(err, chunk->chunk_hdr);
+ if ((void *)err != (void *)chunk->chunk_end)
+ return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
+ }
sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNRESET));
/* ASSOC_FAILED will DELETE_TCB. */
@@ -2448,7 +2442,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
* RFC 2960, Section 3.3.7
* If an endpoint receives an ABORT with a format error or for an
* association that doesn't exist, it MUST silently discard it.
- * Becasue the length is "invalid", we can't really discard just
+ * Because the length is "invalid", we can't really discard just
* as we do not know its true length. So, to be safe, discard the
* packet.
*/
@@ -3204,6 +3198,7 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
sctp_cmd_seq_t *commands)
{
struct sctp_chunk *chunk = arg;
+ sctp_errhdr_t *err;
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
@@ -3212,6 +3207,10 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
+ sctp_walk_errors(err, chunk->chunk_hdr);
+ if ((void *)err != (void *)chunk->chunk_end)
+ return sctp_sf_violation_paramlen(ep, asoc, type, arg,
+ (void *)err, commands);
sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR,
SCTP_CHUNK(chunk));
@@ -3320,8 +3319,10 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
struct sctp_chunk *chunk = arg;
struct sk_buff *skb = chunk->skb;
sctp_chunkhdr_t *ch;
+ sctp_errhdr_t *err;
__u8 *ch_end;
int ootb_shut_ack = 0;
+ int ootb_cookie_ack = 0;
SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES);
@@ -3346,6 +3347,23 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
if (SCTP_CID_ABORT == ch->type)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+ /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR
+ * or a COOKIE ACK the SCTP Packet should be silently
+ * discarded.
+ */
+
+ if (SCTP_CID_COOKIE_ACK == ch->type)
+ ootb_cookie_ack = 1;
+
+ if (SCTP_CID_ERROR == ch->type) {
+ sctp_walk_errors(err, ch) {
+ if (SCTP_ERROR_STALE_COOKIE == err->cause) {
+ ootb_cookie_ack = 1;
+ break;
+ }
+ }
+ }
+
/* Report violation if chunk len overflows */
ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
if (ch_end > skb_tail_pointer(skb))
@@ -3357,6 +3375,8 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
if (ootb_shut_ack)
return sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands);
+ else if (ootb_cookie_ack)
+ return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
else
return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
}
@@ -3855,7 +3875,7 @@ gen_shutdown:
}
/*
- * SCTP-AUTH Section 6.3 Receving authenticated chukns
+ * SCTP-AUTH Section 6.3 Receiving authenticated chukns
*
* The receiver MUST use the HMAC algorithm indicated in the HMAC
* Identifier field. If this algorithm was not specified by the
@@ -4231,7 +4251,7 @@ static sctp_disposition_t sctp_sf_abort_violation(
*
* This means that if we only want to abort associations
* in an authenticated way (i.e AUTH+ABORT), then we
- * can't destroy this association just becuase the packet
+ * can't destroy this association just because the packet
* was malformed.
*/
if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
@@ -4343,8 +4363,9 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
/*
* Handle a protocol violation when the parameter length is invalid.
- * "Invalid" length is identified as smaller than the minimal length a
- * given parameter can be.
+ * If the length is smaller than the minimum length of a given parameter,
+ * or accumulated length in multi parameters exceeds the end of the chunk,
+ * the length is considered as invalid.
*/
static sctp_disposition_t sctp_sf_violation_paramlen(
const struct sctp_endpoint *ep,
@@ -4402,9 +4423,9 @@ static sctp_disposition_t sctp_sf_violation_ctsn(
}
/* Handle protocol violation of an invalid chunk bundling. For example,
- * when we have an association and we recieve bundled INIT-ACK, or
+ * when we have an association and we receive bundled INIT-ACK, or
* SHUDOWN-COMPLETE, our peer is clearly violationg the "MUST NOT bundle"
- * statement from the specs. Additinally, there might be an attacker
+ * statement from the specs. Additionally, there might be an attacker
* on the path and we may not want to continue this communication.
*/
static sctp_disposition_t sctp_sf_violation_chunk(
@@ -5056,6 +5077,30 @@ sctp_disposition_t sctp_sf_ignore_primitive(
***************************************************************************/
/*
+ * When the SCTP stack has no more user data to send or retransmit, this
+ * notification is given to the user. Also, at the time when a user app
+ * subscribes to this event, if there is no data to be sent or
+ * retransmit, the stack will immediately send up this notification.
+ */
+sctp_disposition_t sctp_sf_do_no_pending_tsn(
+ const struct sctp_endpoint *ep,
+ const struct sctp_association *asoc,
+ const sctp_subtype_t type,
+ void *arg,
+ sctp_cmd_seq_t *commands)
+{
+ struct sctp_ulpevent *event;
+
+ event = sctp_ulpevent_make_sender_dry_event(asoc, GFP_ATOMIC);
+ if (!event)
+ return SCTP_DISPOSITION_NOMEM;
+
+ sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(event));
+
+ return SCTP_DISPOSITION_CONSUME;
+}
+
+/*
* Start the shutdown negotiation.
*
* From Section 9.2:
diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c
index 546d4387..0338dc6 100644
--- a/net/sctp/sm_statetable.c
+++ b/net/sctp/sm_statetable.c
@@ -107,8 +107,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
#define TYPE_SCTP_FUNC(func) {.fn = func, .name = #func}
#define TYPE_SCTP_DATA { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -128,8 +126,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_DATA */
#define TYPE_SCTP_INIT { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_do_5_1B_init), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -149,8 +145,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_INIT */
#define TYPE_SCTP_INIT_ACK { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_do_5_2_3_initack), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -170,8 +164,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_INIT_ACK */
#define TYPE_SCTP_SACK { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -191,8 +183,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_SACK */
#define TYPE_SCTP_HEARTBEAT { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -213,8 +203,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_HEARTBEAT */
#define TYPE_SCTP_HEARTBEAT_ACK { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -234,8 +222,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_HEARTBEAT_ACK */
#define TYPE_SCTP_ABORT { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_pdiscard), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -255,8 +241,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_ABORT */
#define TYPE_SCTP_SHUTDOWN { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -276,8 +260,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_SHUTDOWN */
#define TYPE_SCTP_SHUTDOWN_ACK { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -297,8 +279,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_SHUTDOWN_ACK */
#define TYPE_SCTP_ERROR { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -318,8 +298,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_ERROR */
#define TYPE_SCTP_COOKIE_ECHO { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_do_5_1D_ce), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -339,8 +317,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_COOKIE_ECHO */
#define TYPE_SCTP_COOKIE_ACK { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -360,8 +336,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_COOKIE_ACK */
#define TYPE_SCTP_ECN_ECNE { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -381,8 +355,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_ECN_ECNE */
#define TYPE_SCTP_ECN_CWR { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -402,8 +374,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
} /* TYPE_SCTP_ECN_CWR */
#define TYPE_SCTP_SHUTDOWN_COMPLETE { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -446,8 +416,6 @@ static const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][
}; /* state_fn_t chunk_event_table[][] */
#define TYPE_SCTP_ASCONF { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -467,8 +435,6 @@ static const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][
} /* TYPE_SCTP_ASCONF */
#define TYPE_SCTP_ASCONF_ACK { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -496,8 +462,6 @@ static const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_
}; /*state_fn_t addip_chunk_event_table[][] */
#define TYPE_SCTP_FWD_TSN { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -524,8 +488,6 @@ static const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUN
}; /*state_fn_t prsctp_chunk_event_table[][] */
#define TYPE_SCTP_AUTH { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -553,8 +515,6 @@ static const sctp_sm_table_entry_t auth_chunk_event_table[SCTP_NUM_AUTH_CHUNK_TY
static const sctp_sm_table_entry_t
chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
- /* SCTP_STATE_EMPTY */
- TYPE_SCTP_FUNC(sctp_sf_ootb),
/* SCTP_STATE_CLOSED */
TYPE_SCTP_FUNC(sctp_sf_ootb),
/* SCTP_STATE_COOKIE_WAIT */
@@ -575,8 +535,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
#define TYPE_SCTP_PRIMITIVE_ASSOCIATE { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_do_prm_asoc), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -596,8 +554,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
} /* TYPE_SCTP_PRIMITIVE_ASSOCIATE */
#define TYPE_SCTP_PRIMITIVE_SHUTDOWN { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_error_closed), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -617,8 +573,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
} /* TYPE_SCTP_PRIMITIVE_SHUTDOWN */
#define TYPE_SCTP_PRIMITIVE_ABORT { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_error_closed), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -638,8 +592,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
} /* TYPE_SCTP_PRIMITIVE_ABORT */
#define TYPE_SCTP_PRIMITIVE_SEND { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_error_closed), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -659,8 +611,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
} /* TYPE_SCTP_PRIMITIVE_SEND */
#define TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_error_closed), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -680,8 +630,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
} /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */
#define TYPE_SCTP_PRIMITIVE_ASCONF { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_error_closed), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -713,8 +661,6 @@ static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPE
};
#define TYPE_SCTP_OTHER_NO_PENDING_TSN { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_ignore_other), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -722,7 +668,7 @@ static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPE
/* SCTP_STATE_COOKIE_ECHOED */ \
TYPE_SCTP_FUNC(sctp_sf_ignore_other), \
/* SCTP_STATE_ESTABLISHED */ \
- TYPE_SCTP_FUNC(sctp_sf_ignore_other), \
+ TYPE_SCTP_FUNC(sctp_sf_do_no_pending_tsn), \
/* SCTP_STATE_SHUTDOWN_PENDING */ \
TYPE_SCTP_FUNC(sctp_sf_do_9_2_start_shutdown), \
/* SCTP_STATE_SHUTDOWN_SENT */ \
@@ -734,8 +680,6 @@ static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPE
}
#define TYPE_SCTP_OTHER_ICMP_PROTO_UNREACH { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_ignore_other), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -760,8 +704,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
};
#define TYPE_SCTP_EVENT_TIMEOUT_NONE { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -781,8 +723,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
}
#define TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -802,8 +742,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
}
#define TYPE_SCTP_EVENT_TIMEOUT_T1_INIT { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -823,8 +761,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
}
#define TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -844,8 +780,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
}
#define TYPE_SCTP_EVENT_TIMEOUT_T3_RTX { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -865,8 +799,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
}
#define TYPE_SCTP_EVENT_TIMEOUT_T4_RTO { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -886,8 +818,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
}
#define TYPE_SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -907,8 +837,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
}
#define TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -928,8 +856,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
}
#define TYPE_SCTP_EVENT_TIMEOUT_SACK { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_bug), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
/* SCTP_STATE_COOKIE_WAIT */ \
@@ -949,8 +875,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
}
#define TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE { \
- /* SCTP_STATE_EMPTY */ \
- TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
/* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
/* SCTP_STATE_COOKIE_WAIT */ \
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 3951a10..33d9ee6 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -658,11 +658,15 @@ static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
goto err_bindx_rem;
}
- if (sa_addr->v4.sin_port != htons(bp->port)) {
+ if (sa_addr->v4.sin_port &&
+ sa_addr->v4.sin_port != htons(bp->port)) {
retval = -EINVAL;
goto err_bindx_rem;
}
+ if (!sa_addr->v4.sin_port)
+ sa_addr->v4.sin_port = htons(bp->port);
+
/* FIXME - There is probably a need to check if sk->sk_saddr and
* sk->sk_rcv_addr are currently set to one of the addresses to
* be removed. This is something which needs to be looked into
@@ -1193,7 +1197,7 @@ out_free:
* an endpoint that is multi-homed. Much like sctp_bindx() this call
* allows a caller to specify multiple addresses at which a peer can be
* reached. The way the SCTP stack uses the list of addresses to set up
- * the association is implementation dependant. This function only
+ * the association is implementation dependent. This function only
* specifies that the stack will try to make use of all the addresses in
* the list when needed.
*
@@ -2283,7 +2287,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
trans->param_flags =
(trans->param_flags & ~SPP_PMTUD) | pmtud_change;
if (update) {
- sctp_transport_pmtu(trans);
+ sctp_transport_pmtu(trans, sctp_opt2sk(sp));
sctp_assoc_sync_pmtu(asoc);
}
} else if (asoc) {
@@ -3215,14 +3219,9 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,
if (optlen < sizeof(struct sctp_hmacalgo))
return -EINVAL;
- hmacs = kmalloc(optlen, GFP_KERNEL);
- if (!hmacs)
- return -ENOMEM;
-
- if (copy_from_user(hmacs, optval, optlen)) {
- err = -EFAULT;
- goto out;
- }
+ hmacs= memdup_user(optval, optlen);
+ if (IS_ERR(hmacs))
+ return PTR_ERR(hmacs);
idents = hmacs->shmac_num_idents;
if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS ||
@@ -3257,14 +3256,9 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
if (optlen <= sizeof(struct sctp_authkey))
return -EINVAL;
- authkey = kmalloc(optlen, GFP_KERNEL);
- if (!authkey)
- return -ENOMEM;
-
- if (copy_from_user(authkey, optval, optlen)) {
- ret = -EFAULT;
- goto out;
- }
+ authkey= memdup_user(optval, optlen);
+ if (IS_ERR(authkey))
+ return PTR_ERR(authkey);
if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) {
ret = -EINVAL;
@@ -5283,6 +5277,55 @@ static int sctp_getsockopt_assoc_number(struct sock *sk, int len,
return 0;
}
+/*
+ * 8.2.6. Get the Current Identifiers of Associations
+ * (SCTP_GET_ASSOC_ID_LIST)
+ *
+ * This option gets the current list of SCTP association identifiers of
+ * the SCTP associations handled by a one-to-many style socket.
+ */
+static int sctp_getsockopt_assoc_ids(struct sock *sk, int len,
+ char __user *optval, int __user *optlen)
+{
+ struct sctp_sock *sp = sctp_sk(sk);
+ struct sctp_association *asoc;
+ struct sctp_assoc_ids *ids;
+ u32 num = 0;
+
+ if (sctp_style(sk, TCP))
+ return -EOPNOTSUPP;
+
+ if (len < sizeof(struct sctp_assoc_ids))
+ return -EINVAL;
+
+ list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
+ num++;
+ }
+
+ if (len < sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num)
+ return -EINVAL;
+
+ len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num;
+
+ ids = kmalloc(len, GFP_KERNEL);
+ if (unlikely(!ids))
+ return -ENOMEM;
+
+ ids->gaids_number_of_ids = num;
+ num = 0;
+ list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
+ ids->gaids_assoc_id[num++] = asoc->assoc_id;
+ }
+
+ if (put_user(len, optlen) || copy_to_user(optval, ids, len)) {
+ kfree(ids);
+ return -EFAULT;
+ }
+
+ kfree(ids);
+ return 0;
+}
+
SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
@@ -5415,6 +5458,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
case SCTP_GET_ASSOC_NUMBER:
retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen);
break;
+ case SCTP_GET_ASSOC_ID_LIST:
+ retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen);
+ break;
default:
retval = -ENOPROTOOPT;
break;
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index d3ae493..d8595dd 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -211,15 +211,19 @@ void sctp_transport_set_owner(struct sctp_transport *transport,
}
/* Initialize the pmtu of a transport. */
-void sctp_transport_pmtu(struct sctp_transport *transport)
+void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk)
{
- struct dst_entry *dst;
+ struct flowi fl;
- dst = transport->af_specific->get_dst(NULL, &transport->ipaddr, NULL);
+ /* If we don't have a fresh route, look one up */
+ if (!transport->dst || transport->dst->obsolete > 1) {
+ dst_release(transport->dst);
+ transport->af_specific->get_dst(transport, &transport->saddr,
+ &fl, sk);
+ }
- if (dst) {
- transport->pathmtu = dst_mtu(dst);
- dst_release(dst);
+ if (transport->dst) {
+ transport->pathmtu = dst_mtu(transport->dst);
} else
transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
}
@@ -270,22 +274,20 @@ void sctp_transport_route(struct sctp_transport *transport,
{
struct sctp_association *asoc = transport->asoc;
struct sctp_af *af = transport->af_specific;
- union sctp_addr *daddr = &transport->ipaddr;
- struct dst_entry *dst;
+ struct flowi fl;
- dst = af->get_dst(asoc, daddr, saddr);
+ af->get_dst(transport, saddr, &fl, sctp_opt2sk(opt));
if (saddr)
memcpy(&transport->saddr, saddr, sizeof(union sctp_addr));
else
- af->get_saddr(opt, asoc, dst, daddr, &transport->saddr);
+ af->get_saddr(opt, transport, &fl);
- transport->dst = dst;
if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) {
return;
}
- if (dst) {
- transport->pathmtu = dst_mtu(dst);
+ if (transport->dst) {
+ transport->pathmtu = dst_mtu(transport->dst);
/* Initialize sk->sk_rcv_saddr, if the transport is the
* association's active path for getsockname().
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index aa72e89..c962c60 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -554,7 +554,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));
/* Per TSVWG discussion with Randy. Allow the application to
- * ressemble a fragmented message.
+ * resemble a fragmented message.
*/
ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags;
@@ -843,7 +843,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_authkey(
ak = (struct sctp_authkey_event *)
skb_put(skb, sizeof(struct sctp_authkey_event));
- ak->auth_type = SCTP_AUTHENTICATION_INDICATION;
+ ak->auth_type = SCTP_AUTHENTICATION_EVENT;
ak->auth_flags = 0;
ak->auth_length = sizeof(struct sctp_authkey_event);
@@ -862,6 +862,34 @@ fail:
return NULL;
}
+/*
+ * Socket Extensions for SCTP
+ * 6.3.10. SCTP_SENDER_DRY_EVENT
+ */
+struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event(
+ const struct sctp_association *asoc, gfp_t gfp)
+{
+ struct sctp_ulpevent *event;
+ struct sctp_sender_dry_event *sdry;
+ struct sk_buff *skb;
+
+ event = sctp_ulpevent_new(sizeof(struct sctp_sender_dry_event),
+ MSG_NOTIFICATION, gfp);
+ if (!event)
+ return NULL;
+
+ skb = sctp_event2skb(event);
+ sdry = (struct sctp_sender_dry_event *)
+ skb_put(skb, sizeof(struct sctp_sender_dry_event));
+
+ sdry->sender_dry_type = SCTP_SENDER_DRY_EVENT;
+ sdry->sender_dry_flags = 0;
+ sdry->sender_dry_length = sizeof(struct sctp_sender_dry_event);
+ sctp_ulpevent_set_owner(event, asoc);
+ sdry->sender_dry_assoc_id = sctp_assoc2id(asoc);
+
+ return event;
+}
/* Return the notification type, assuming this is a notification
* event.
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index 1767818..f2d1de7 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -240,7 +240,7 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
} else {
/*
* If fragment interleave is enabled, we
- * can queue this to the recieve queue instead
+ * can queue this to the receive queue instead
* of the lobby.
*/
if (sctp_sk(sk)->frag_interleave)
diff --git a/net/socket.c b/net/socket.c
index 5212447..d25f5a9 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2643,13 +2643,13 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
return -EFAULT;
if (convert_in) {
- /* We expect there to be holes between fs.m_u and
+ /* We expect there to be holes between fs.m_ext and
* fs.ring_cookie and at the end of fs, but nowhere else.
*/
- BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_u) +
- sizeof(compat_rxnfc->fs.m_u) !=
- offsetof(struct ethtool_rxnfc, fs.m_u) +
- sizeof(rxnfc->fs.m_u));
+ BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) +
+ sizeof(compat_rxnfc->fs.m_ext) !=
+ offsetof(struct ethtool_rxnfc, fs.m_ext) +
+ sizeof(rxnfc->fs.m_ext));
BUILD_BUG_ON(
offsetof(struct compat_ethtool_rxnfc, fs.location) -
offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) !=
@@ -2657,7 +2657,7 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
offsetof(struct ethtool_rxnfc, fs.ring_cookie));
if (copy_in_user(rxnfc, compat_rxnfc,
- (void *)(&rxnfc->fs.m_u + 1) -
+ (void *)(&rxnfc->fs.m_ext + 1) -
(void *)rxnfc) ||
copy_in_user(&rxnfc->fs.ring_cookie,
&compat_rxnfc->fs.ring_cookie,
@@ -2674,7 +2674,7 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
if (convert_out) {
if (copy_in_user(compat_rxnfc, rxnfc,
- (const void *)(&rxnfc->fs.m_u + 1) -
+ (const void *)(&rxnfc->fs.m_ext + 1) -
(const void *)rxnfc) ||
copy_in_user(&compat_rxnfc->fs.ring_cookie,
&rxnfc->fs.ring_cookie,
@@ -2986,7 +2986,7 @@ out:
/* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
* for some operations; this forces use of the newer bridge-utils that
- * use compatiable ioctls
+ * use compatible ioctls
*/
static int old_bridge_ioctl(compat_ulong_t __user *argp)
{
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 9022f0a..0a9a2ec 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -427,7 +427,7 @@ static int
context_derive_keys_rc4(struct krb5_ctx *ctx)
{
struct crypto_hash *hmac;
- static const char sigkeyconstant[] = "signaturekey";
+ char sigkeyconstant[] = "signaturekey";
int slen = strlen(sigkeyconstant) + 1; /* include null terminator */
struct hash_desc desc;
struct scatterlist sg[1];
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index bcdae78..8d0f7d3 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -1101,7 +1101,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
/* credential is:
* version(==1), proc(0,1,2,3), seq, service (1,2,3), handle
- * at least 5 u32s, and is preceeded by length, so that makes 6.
+ * at least 5 u32s, and is preceded by length, so that makes 6.
*/
if (argv->iov_len < 5 * 4)
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 1e336a0..bf005d3 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -504,7 +504,7 @@ static int xs_nospace(struct rpc_task *task)
* EAGAIN: The socket was blocked, please call again later to
* complete the request
* ENOTCONN: Caller needs to invoke connect logic then call again
- * other: Some other error occured, the request was not sent
+ * other: Some other error occurred, the request was not sent
*/
static int xs_udp_send_request(struct rpc_task *task)
{
@@ -590,7 +590,7 @@ static inline void xs_encode_tcp_record_marker(struct xdr_buf *buf)
* EAGAIN: The socket was blocked, please call again later to
* complete the request
* ENOTCONN: Caller needs to invoke connect logic then call again
- * other: Some other error occured, the request was not sent
+ * other: Some other error occurred, the request was not sent
*
* XXX: In the case of soft timeouts, should we eventually give up
* if sendmsg is not able to make progress?
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 43639ff..ebf338f 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -2471,7 +2471,7 @@ exit:
* A pending message being re-assembled must store certain values
* to handle subsequent fragments correctly. The following functions
* help storing these values in unused, available fields in the
- * pending message. This makes dynamic memory allocation unecessary.
+ * pending message. This makes dynamic memory allocation unnecessary.
*/
static void set_long_msg_seqno(struct sk_buff *buf, u32 seqno)
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index c9fa6df..80025a1 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -160,7 +160,7 @@ void tipc_named_withdraw(struct publication *publ)
buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0);
if (!buf) {
- warn("Withdrawl distribution failure\n");
+ warn("Withdrawal distribution failure\n");
return;
}
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 1663e1a..3a43a83 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -207,7 +207,7 @@ static int unix_mkname(struct sockaddr_un *sunaddr, int len, unsigned *hashp)
/*
* This may look like an off by one error but it is a bit more
* subtle. 108 is the longest valid AF_UNIX path for a binding.
- * sun_path[108] doesnt as such exist. However in kernel space
+ * sun_path[108] doesn't as such exist. However in kernel space
* we are guaranteed that it is a valid memory location in our
* kernel address buffer.
*/
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
index 11f25c7..f346395 100644
--- a/net/wanrouter/wanproc.c
+++ b/net/wanrouter/wanproc.c
@@ -51,7 +51,7 @@
/*
* Structures for interfacing with the /proc filesystem.
- * Router creates its own directory /proc/net/router with the folowing
+ * Router creates its own directory /proc/net/router with the following
* entries:
* config device configuration
* status global device statistics
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 8982053..1613080 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -812,7 +812,7 @@ static void handle_channel(struct wiphy *wiphy,
if (r) {
/*
* We will disable all channels that do not match our
- * recieved regulatory rule unless the hint is coming
+ * received regulatory rule unless the hint is coming
* from a Country IE and the Country IE had no information
* about a band. The IEEE 802.11 spec allows for an AP
* to send only a subset of the regulatory rules allowed,
@@ -841,7 +841,7 @@ static void handle_channel(struct wiphy *wiphy,
request_wiphy && request_wiphy == wiphy &&
request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
/*
- * This gaurantees the driver's requested regulatory domain
+ * This guarantees the driver's requested regulatory domain
* will always be used as a base for further regulatory
* settings
*/
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
index 4062075..f77e4e7 100644
--- a/net/x25/x25_facilities.c
+++ b/net/x25/x25_facilities.c
@@ -31,7 +31,7 @@
* x25_parse_facilities - Parse facilities from skb into the facilities structs
*
* @skb: sk_buff to parse
- * @facilities: Regular facilites, updated as facilities are found
+ * @facilities: Regular facilities, updated as facilities are found
* @dte_facs: ITU DTE facilities, updated as DTE facilities are found
* @vc_fac_mask: mask is updated with all facilities found
*
diff --git a/net/x25/x25_forward.c b/net/x25/x25_forward.c
index 25a8107..c541b62 100644
--- a/net/x25/x25_forward.c
+++ b/net/x25/x25_forward.c
@@ -31,7 +31,7 @@ int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from,
goto out_no_route;
if ((neigh_new = x25_get_neigh(rt->dev)) == NULL) {
- /* This shouldnt happen, if it occurs somehow
+ /* This shouldn't happen, if it occurs somehow
* do something sensible
*/
goto out_put_route;
@@ -45,7 +45,7 @@ int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from,
}
/* Remote end sending a call request on an already
- * established LCI? It shouldnt happen, just in case..
+ * established LCI? It shouldn't happen, just in case..
*/
read_lock_bh(&x25_forward_list_lock);
list_for_each(entry, &x25_forward_list) {
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 15792d8..00bcb88 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1348,7 +1348,8 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
default:
BUG();
}
- xdst = dst_alloc(dst_ops, 0);
+ xdst = dst_alloc(dst_ops, NULL, 0, 0, 0);
+ memset(&xdst->u.rt6.rt6i_table, 0, sizeof(*xdst) - sizeof(struct dst_entry));
xfrm_policy_put_afinfo(afinfo);
if (likely(xdst))
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index dd78536..d70f85e 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1036,15 +1036,15 @@ static struct xfrm_state *__find_acq_core(struct net *net, struct xfrm_mark *m,
case AF_INET6:
ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
- (struct in6_addr *)daddr);
+ (const struct in6_addr *)daddr);
ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
- (struct in6_addr *)saddr);
+ (const struct in6_addr *)saddr);
x->sel.prefixlen_d = 128;
x->sel.prefixlen_s = 128;
ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
- (struct in6_addr *)saddr);
+ (const struct in6_addr *)saddr);
ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
- (struct in6_addr *)daddr);
+ (const struct in6_addr *)daddr);
break;
}
@@ -2092,8 +2092,8 @@ static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
struct audit_buffer *audit_buf)
{
- struct iphdr *iph4;
- struct ipv6hdr *iph6;
+ const struct iphdr *iph4;
+ const struct ipv6hdr *iph6;
switch (family) {
case AF_INET:
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 3d15d3e..5d1d60d 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -894,7 +894,7 @@ static int build_spdinfo(struct sk_buff *skb, struct net *net,
u32 *f;
nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);
- if (nlh == NULL) /* shouldnt really happen ... */
+ if (nlh == NULL) /* shouldn't really happen ... */
return -EMSGSIZE;
f = nlmsg_data(nlh);
@@ -954,7 +954,7 @@ static int build_sadinfo(struct sk_buff *skb, struct net *net,
u32 *f;
nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSADINFO, sizeof(u32), 0);
- if (nlh == NULL) /* shouldnt really happen ... */
+ if (nlh == NULL) /* shouldn't really happen ... */
return -EMSGSIZE;
f = nlmsg_data(nlh);
@@ -1361,7 +1361,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!xp)
return err;
- /* shouldnt excl be based on nlh flags??
+ /* shouldn't excl be based on nlh flags??
* Aha! this is anti-netlink really i.e more pfkey derived
* in netlink excl is a flag and you wouldnt need
* a type XFRM_MSG_UPDPOLICY - JHS */