diff options
Diffstat (limited to 'net')
235 files changed, 4424 insertions, 2072 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index e47600b4e2e3..969e7004cf86 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) @@ -504,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: @@ -684,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; @@ -705,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 5687c9b95f33..c3408def8a19 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 ce8e3ab3e7a5..41495dc2a4c9 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 b84a46b30c0c..d174c312b7f1 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) { diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index d1314cf18adf..d940c49d168a 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 2ccbf04d37df..0ce959218607 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 9172ab78fcb0..d47880e971dd 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 b84619b5ba22..da6af81e59d9 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/appletalk/ddp.c b/net/appletalk/ddp.c index 206e771e82d1..956a5302002a 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1051,16 +1051,17 @@ static int atalk_release(struct socket *sock) { struct sock *sk = sock->sk; - sock_hold(sk); - lock_sock(sk); if (sk) { + sock_hold(sk); + lock_sock(sk); + sock_orphan(sk); sock->sk = NULL; atalk_destroy_socket(sk); - } - release_sock(sk); - sock_put(sk); + release_sock(sk); + sock_put(sk); + } return 0; } diff --git a/net/atm/br2684.c b/net/atm/br2684.c index fce2eae8d476..2252c2085dac 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 38754fdb88ba..25073b6ef474 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 9d14d196cc1d..dfc071966463 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 6da5daeebab7..e7c69f4619ec 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 5a0dda8df492..60b545e2822a 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/gateway_client.c b/net/batman-adv/gateway_client.c index 3cc43558cf9c..2acd7a666bda 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; + curr_gw_orig = gw_get_selected_orig(bat_priv); + if (!curr_gw_orig) + goto deselect; - if (!curr_gateway_tmp->orig_node) - goto deselect_rcu; - - 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,11 @@ 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; + + curr_gw = gw_get_selected_gw_node(bat_priv); + if (!curr_gw) + goto out; rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { @@ -312,22 +333,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(); +out: + 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 +362,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 +378,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; } @@ -422,10 +465,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset) 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(); @@ -442,6 +485,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 +550,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 2aa439124ee3..1ce8c6066da1 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/icmp_socket.c b/net/batman-adv/icmp_socket.c index 34ce56c358e5..49079c254476 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -218,23 +218,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; @@ -252,8 +242,6 @@ 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); diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 0b9133022d2d..5b8fe32043da 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; @@ -390,7 +406,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) struct hlist_node *node, *node_tmp; struct hlist_head *head; 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; @@ -421,37 +437,41 @@ 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; diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 5cc011057da1..e1d641f27aa9 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 c172f5d0e05a..f6c642246972 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); } @@ -869,7 +905,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, struct sk_buff *skb, size_t icmp_len) { 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; @@ -886,23 +922,13 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, /* 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) @@ -916,15 +942,12 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, 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 (router) + neigh_node_free_ref(router); if (orig_node) orig_node_free_ref(orig_node); return ret; @@ -934,7 +957,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, struct sk_buff *skb) { 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; @@ -952,23 +975,13 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, 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) @@ -982,15 +995,12 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, 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 (router) + neigh_node_free_ref(router); if (orig_node) orig_node_free_ref(orig_node); return ret; @@ -1003,7 +1013,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 +1060,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 +1078,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 +1198,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 +1215,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 +1248,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; diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index d49e54d932af..e78670c3c4b7 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -308,6 +308,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 +317,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 +327,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); diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 9ed26140a269..1f6f756bc584 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -90,10 +90,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 +146,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, @@ -171,6 +216,7 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) struct bat_priv *bat_priv = netdev_priv(net_dev); struct softif_neigh *softif_neigh; struct hlist_node *node; + struct softif_neigh *curr_softif_neigh; if (!bat_priv->primary_if) { return seq_printf(seq, "BATMAN mesh %s disabled - " @@ -180,14 +226,17 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) 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; } @@ -198,7 +247,8 @@ 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; + struct softif_neigh *curr_softif_neigh = NULL; if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) batman_packet = (struct batman_packet *) @@ -223,7 +273,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, if (!softif_neigh) goto err; - if (bat_priv->softif_neigh == softif_neigh) + curr_softif_neigh = softif_neigh_get_selected(bat_priv); + if (curr_softif_neigh == softif_neigh) goto out; /* we got a neighbor but its mac is 'bigger' than ours */ @@ -232,38 +283,39 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, 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)) { 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 (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); + return; } @@ -321,6 +373,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) struct bat_priv *bat_priv = netdev_priv(soft_iface); 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 +401,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 */ @@ -410,6 +464,8 @@ dropped: dropped_freed: bat_priv->stats.tx_dropped++; end: + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); return NETDEV_TX_OK; } @@ -421,6 +477,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 +507,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 +519,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 +532,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 +544,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 +584,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 diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 83445cf0cc9f..75123b1ae0de 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,7 +147,7 @@ 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; diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c index 19f84bd443af..d46acc815138 100644 --- a/net/batman-adv/unicast.c +++ b/net/batman-adv/unicast.c @@ -289,7 +289,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 f90212f42082..d4cc4f5399f4 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c @@ -558,6 +558,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 +572,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 +610,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 +638,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 +732,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 +753,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,45 +787,29 @@ 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; + goto out; - neigh_node = orig_node->router; - - 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); - - goto out; + send_skb_packet(skb, router->if_incoming, router->addr); -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() */ diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h index 70672544db86..8e6c06158f8e 100644 --- a/net/bluetooth/bnep/bnep.h +++ b/net/bluetooth/bnep/bnep.h @@ -23,88 +23,88 @@ #include <linux/crc32.h> #include <net/bluetooth/bluetooth.h> -// Limits -#define BNEP_MAX_PROTO_FILTERS 5 -#define BNEP_MAX_MULTICAST_FILTERS 20 - -// UUIDs -#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB -#define BNEP_UUID16 0x02 -#define BNEP_UUID32 0x04 -#define BNEP_UUID128 0x16 - -#define BNEP_SVC_PANU 0x1115 -#define BNEP_SVC_NAP 0x1116 -#define BNEP_SVC_GN 0x1117 - -// Packet types -#define BNEP_GENERAL 0x00 -#define BNEP_CONTROL 0x01 -#define BNEP_COMPRESSED 0x02 -#define BNEP_COMPRESSED_SRC_ONLY 0x03 -#define BNEP_COMPRESSED_DST_ONLY 0x04 - -// Control types -#define BNEP_CMD_NOT_UNDERSTOOD 0x00 -#define BNEP_SETUP_CONN_REQ 0x01 -#define BNEP_SETUP_CONN_RSP 0x02 -#define BNEP_FILTER_NET_TYPE_SET 0x03 -#define BNEP_FILTER_NET_TYPE_RSP 0x04 -#define BNEP_FILTER_MULTI_ADDR_SET 0x05 -#define BNEP_FILTER_MULTI_ADDR_RSP 0x06 - -// Extension types -#define BNEP_EXT_CONTROL 0x00 - -// Response messages -#define BNEP_SUCCESS 0x00 - -#define BNEP_CONN_INVALID_DST 0x01 -#define BNEP_CONN_INVALID_SRC 0x02 -#define BNEP_CONN_INVALID_SVC 0x03 -#define BNEP_CONN_NOT_ALLOWED 0x04 - -#define BNEP_FILTER_UNSUPPORTED_REQ 0x01 -#define BNEP_FILTER_INVALID_RANGE 0x02 -#define BNEP_FILTER_INVALID_MCADDR 0x02 -#define BNEP_FILTER_LIMIT_REACHED 0x03 -#define BNEP_FILTER_DENIED_SECURITY 0x04 - -// L2CAP settings -#define BNEP_MTU 1691 -#define BNEP_PSM 0x0f -#define BNEP_FLUSH_TO 0xffff -#define BNEP_CONNECT_TO 15 -#define BNEP_FILTER_TO 15 - -// Headers -#define BNEP_TYPE_MASK 0x7f -#define BNEP_EXT_HEADER 0x80 +/* Limits */ +#define BNEP_MAX_PROTO_FILTERS 5 +#define BNEP_MAX_MULTICAST_FILTERS 20 + +/* UUIDs */ +#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB +#define BNEP_UUID16 0x02 +#define BNEP_UUID32 0x04 +#define BNEP_UUID128 0x16 + +#define BNEP_SVC_PANU 0x1115 +#define BNEP_SVC_NAP 0x1116 +#define BNEP_SVC_GN 0x1117 + +/* Packet types */ +#define BNEP_GENERAL 0x00 +#define BNEP_CONTROL 0x01 +#define BNEP_COMPRESSED 0x02 +#define BNEP_COMPRESSED_SRC_ONLY 0x03 +#define BNEP_COMPRESSED_DST_ONLY 0x04 + +/* Control types */ +#define BNEP_CMD_NOT_UNDERSTOOD 0x00 +#define BNEP_SETUP_CONN_REQ 0x01 +#define BNEP_SETUP_CONN_RSP 0x02 +#define BNEP_FILTER_NET_TYPE_SET 0x03 +#define BNEP_FILTER_NET_TYPE_RSP 0x04 +#define BNEP_FILTER_MULTI_ADDR_SET 0x05 +#define BNEP_FILTER_MULTI_ADDR_RSP 0x06 + +/* Extension types */ +#define BNEP_EXT_CONTROL 0x00 + +/* Response messages */ +#define BNEP_SUCCESS 0x00 + +#define BNEP_CONN_INVALID_DST 0x01 +#define BNEP_CONN_INVALID_SRC 0x02 +#define BNEP_CONN_INVALID_SVC 0x03 +#define BNEP_CONN_NOT_ALLOWED 0x04 + +#define BNEP_FILTER_UNSUPPORTED_REQ 0x01 +#define BNEP_FILTER_INVALID_RANGE 0x02 +#define BNEP_FILTER_INVALID_MCADDR 0x02 +#define BNEP_FILTER_LIMIT_REACHED 0x03 +#define BNEP_FILTER_DENIED_SECURITY 0x04 + +/* L2CAP settings */ +#define BNEP_MTU 1691 +#define BNEP_PSM 0x0f +#define BNEP_FLUSH_TO 0xffff +#define BNEP_CONNECT_TO 15 +#define BNEP_FILTER_TO 15 + +/* Headers */ +#define BNEP_TYPE_MASK 0x7f +#define BNEP_EXT_HEADER 0x80 struct bnep_setup_conn_req { - __u8 type; - __u8 ctrl; - __u8 uuid_size; - __u8 service[0]; + __u8 type; + __u8 ctrl; + __u8 uuid_size; + __u8 service[0]; } __packed; struct bnep_set_filter_req { - __u8 type; - __u8 ctrl; + __u8 type; + __u8 ctrl; __be16 len; - __u8 list[0]; + __u8 list[0]; } __packed; struct bnep_control_rsp { - __u8 type; - __u8 ctrl; + __u8 type; + __u8 ctrl; __be16 resp; } __packed; struct bnep_ext_hdr { - __u8 type; - __u8 len; - __u8 data[0]; + __u8 type; + __u8 len; + __u8 data[0]; } __packed; /* BNEP ioctl defines */ @@ -114,10 +114,10 @@ struct bnep_ext_hdr { #define BNEPGETCONNINFO _IOR('B', 211, int) struct bnep_connadd_req { - int sock; // Connected socket + int sock; /* Connected socket */ __u32 flags; __u16 role; - char device[16]; // Name of the Ethernet device + char device[16]; /* Name of the Ethernet device */ }; struct bnep_conndel_req { @@ -148,14 +148,14 @@ int bnep_del_connection(struct bnep_conndel_req *req); int bnep_get_connlist(struct bnep_connlist_req *req); int bnep_get_conninfo(struct bnep_conninfo *ci); -// BNEP sessions +/* BNEP sessions */ struct bnep_session { struct list_head list; unsigned int role; unsigned long state; unsigned long flags; - atomic_t killed; + struct task_struct *task; struct ethhdr eh; struct msghdr msg; @@ -173,7 +173,7 @@ void bnep_sock_cleanup(void); static inline int bnep_mc_hash(__u8 *addr) { - return (crc32_be(~0, addr, ETH_ALEN) >> 26); + return crc32_be(~0, addr, ETH_ALEN) >> 26; } #endif diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 03d4d1245d58..ca39fcf010ce 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -36,6 +36,7 @@ #include <linux/errno.h> #include <linux/net.h> #include <linux/slab.h> +#include <linux/kthread.h> #include <net/sock.h> #include <linux/socket.h> @@ -131,7 +132,8 @@ static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len return -EILSEQ; n = get_unaligned_be16(data); - data++; len -= 2; + data++; + len -= 2; if (len < n) return -EILSEQ; @@ -176,7 +178,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) return -EILSEQ; n = get_unaligned_be16(data); - data += 2; len -= 2; + data += 2; + len -= 2; if (len < n) return -EILSEQ; @@ -187,6 +190,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) n /= (ETH_ALEN * 2); if (n > 0) { + int i; + s->mc_filter = 0; /* Always send broadcast */ @@ -196,18 +201,22 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) for (; n > 0; n--) { u8 a1[6], *a2; - memcpy(a1, data, ETH_ALEN); data += ETH_ALEN; - a2 = data; data += ETH_ALEN; + memcpy(a1, data, ETH_ALEN); + data += ETH_ALEN; + a2 = data; + data += ETH_ALEN; BT_DBG("mc filter %s -> %s", batostr((void *) a1), batostr((void *) a2)); - #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); } - /* Iterate from a1 to a2 */ set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter); while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) { - INCA(a1); + /* Increment a1 */ + i = 5; + while (i >= 0 && ++a1[i--] == 0) + ; + set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter); } } @@ -227,7 +236,8 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) u8 cmd = *(u8 *)data; int err = 0; - data++; len--; + data++; + len--; switch (cmd) { case BNEP_CMD_NOT_UNDERSTOOD: @@ -302,7 +312,6 @@ static u8 __bnep_rx_hlen[] = { ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */ ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */ }; -#define BNEP_RX_TYPES (sizeof(__bnep_rx_hlen) - 1) static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) { @@ -312,9 +321,10 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) dev->stats.rx_bytes += skb->len; - type = *(u8 *) skb->data; skb_pull(skb, 1); + type = *(u8 *) skb->data; + skb_pull(skb, 1); - if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES) + if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) goto badframe; if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { @@ -367,14 +377,14 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) case BNEP_COMPRESSED_DST_ONLY: memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), - ETH_ALEN); + ETH_ALEN); memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, - ETH_ALEN + 2); + ETH_ALEN + 2); break; case BNEP_GENERAL: memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb), - ETH_ALEN * 2); + ETH_ALEN * 2); put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2)); break; } @@ -470,15 +480,14 @@ static int bnep_session(void *arg) BT_DBG(""); - daemonize("kbnepd %s", dev->name); set_user_nice(current, -15); init_waitqueue_entry(&wait, current); add_wait_queue(sk_sleep(sk), &wait); - while (!atomic_read(&s->killed)) { + while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); - // RX + /* RX */ while ((skb = skb_dequeue(&sk->sk_receive_queue))) { skb_orphan(skb); bnep_rx_frame(s, skb); @@ -487,7 +496,7 @@ static int bnep_session(void *arg) if (sk->sk_state != BT_CONNECTED) break; - // TX + /* TX */ while ((skb = skb_dequeue(&sk->sk_write_queue))) if (bnep_tx_frame(s, skb)) break; @@ -555,8 +564,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) /* session struct allocated as private part of net_device */ dev = alloc_netdev(sizeof(struct bnep_session), - (*req->device) ? req->device : "bnep%d", - bnep_net_setup); + (*req->device) ? req->device : "bnep%d", + bnep_net_setup); if (!dev) return -ENOMEM; @@ -571,7 +580,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) s = netdev_priv(dev); /* This is rx header therefore addresses are swapped. - * ie eh.h_dest is our local address. */ + * ie. eh.h_dest is our local address. */ memcpy(s->eh.h_dest, &src, ETH_ALEN); memcpy(s->eh.h_source, &dst, ETH_ALEN); memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN); @@ -597,17 +606,17 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) SET_NETDEV_DEVTYPE(dev, &bnep_type); err = register_netdev(dev); - if (err) { + if (err) goto failed; - } __bnep_link_session(s); - err = kernel_thread(bnep_session, s, CLONE_KERNEL); - if (err < 0) { + s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name); + if (IS_ERR(s->task)) { /* Session thread start failed, gotta cleanup. */ unregister_netdev(dev); __bnep_unlink_session(s); + err = PTR_ERR(s->task); goto failed; } @@ -631,15 +640,9 @@ int bnep_del_connection(struct bnep_conndel_req *req) down_read(&bnep_session_sem); s = __bnep_get_session(req->dst); - if (s) { - /* Wakeup user-space which is polling for socket errors. - * This is temporary hack until we have shutdown in L2CAP */ - s->sock->sk->sk_err = EUNATCH; - - /* Kill session thread */ - atomic_inc(&s->killed); - wake_up_interruptible(sk_sleep(s->sock->sk)); - } else + if (s) + kthread_stop(s->task); + else err = -ENOENT; up_read(&bnep_session_sem); diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index d935da71ab3b..17800b1d28ea 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -39,10 +39,10 @@ #include <linux/init.h> #include <linux/compat.h> #include <linux/gfp.h> +#include <linux/uaccess.h> #include <net/sock.h> #include <asm/system.h> -#include <asm/uaccess.h> #include "bnep.h" diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 67cff810c77d..744233cba244 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -35,6 +35,7 @@ #include <linux/ioctl.h> #include <linux/file.h> #include <linux/wait.h> +#include <linux/kthread.h> #include <net/sock.h> #include <linux/isdn/capilli.h> @@ -143,7 +144,7 @@ static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb) skb_queue_tail(&session->transmit, skb); - cmtp_schedule(session); + wake_up_interruptible(sk_sleep(session->sock->sk)); } static void cmtp_send_interopmsg(struct cmtp_session *session, @@ -386,8 +387,7 @@ static void cmtp_reset_ctr(struct capi_ctr *ctrl) capi_ctr_down(ctrl); - atomic_inc(&session->terminate); - cmtp_schedule(session); + kthread_stop(session->task); } static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) diff --git a/net/bluetooth/cmtp/cmtp.h b/net/bluetooth/cmtp/cmtp.h index 785e79e953c5..db43b54ac9af 100644 --- a/net/bluetooth/cmtp/cmtp.h +++ b/net/bluetooth/cmtp/cmtp.h @@ -37,7 +37,7 @@ #define CMTP_LOOPBACK 0 struct cmtp_connadd_req { - int sock; // Connected socket + int sock; /* Connected socket */ __u32 flags; }; @@ -81,7 +81,7 @@ struct cmtp_session { char name[BTNAMSIZ]; - atomic_t terminate; + struct task_struct *task; wait_queue_head_t wait; @@ -121,13 +121,6 @@ void cmtp_detach_device(struct cmtp_session *session); void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb); -static inline void cmtp_schedule(struct cmtp_session *session) -{ - struct sock *sk = session->sock->sk; - - wake_up_interruptible(sk_sleep(sk)); -} - /* CMTP init defines */ int cmtp_init_sockets(void); void cmtp_cleanup_sockets(void); diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 964ea9126f9f..cce99b0919f5 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -35,6 +35,7 @@ #include <linux/ioctl.h> #include <linux/file.h> #include <linux/init.h> +#include <linux/kthread.h> #include <net/sock.h> #include <linux/isdn/capilli.h> @@ -235,9 +236,12 @@ static void cmtp_process_transmit(struct cmtp_session *session) size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len); - if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) { - skb_queue_head(&session->transmit, skb); - break; + if (scb->id < 0) { + scb->id = cmtp_alloc_block_id(session); + if (scb->id < 0) { + skb_queue_head(&session->transmit, skb); + break; + } } if (size < 256) { @@ -284,12 +288,11 @@ static int cmtp_session(void *arg) BT_DBG("session %p", session); - daemonize("kcmtpd_ctr_%d", session->num); set_user_nice(current, -15); init_waitqueue_entry(&wait, current); add_wait_queue(sk_sleep(sk), &wait); - while (!atomic_read(&session->terminate)) { + while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); if (sk->sk_state != BT_CONNECTED) @@ -367,9 +370,12 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) __cmtp_link_session(session); - err = kernel_thread(cmtp_session, session, CLONE_KERNEL); - if (err < 0) + session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d", + session->num); + if (IS_ERR(session->task)) { + err = PTR_ERR(session->task); goto unlink; + } if (!(session->flags & (1 << CMTP_LOOPBACK))) { err = cmtp_attach_device(session); @@ -406,9 +412,8 @@ int cmtp_del_connection(struct cmtp_conndel_req *req) /* Flush the transmit queue */ skb_queue_purge(&session->transmit); - /* Kill session thread */ - atomic_inc(&session->terminate); - cmtp_schedule(session); + /* Stop session thread */ + kthread_stop(session->task); } else err = -ENOENT; diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 7ea1979a8e4f..3f2dd5c25ae5 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -34,12 +34,12 @@ #include <linux/file.h> #include <linux/compat.h> #include <linux/gfp.h> +#include <linux/uaccess.h> #include <net/sock.h> #include <linux/isdn/capilli.h> #include <asm/system.h> -#include <asm/uaccess.h> #include "cmtp.h" diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b372fb8bcdcf..1ad4907766c7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -56,7 +56,6 @@ static void hci_cmd_task(unsigned long arg); static void hci_rx_task(unsigned long arg); static void hci_tx_task(unsigned long arg); -static void hci_notify(struct hci_dev *hdev, int event); static DEFINE_RWLOCK(hci_task_lock); @@ -186,6 +185,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) BT_DBG("%s %ld", hdev->name, opt); /* Reset device */ + set_bit(HCI_RESET, &hdev->flags); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); } @@ -213,8 +213,10 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) /* Mandatory initialization */ /* Reset */ - if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) + if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) { + set_bit(HCI_RESET, &hdev->flags); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); + } /* Read Local Supported Features */ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL); @@ -584,6 +586,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) hci_req_cancel(hdev, ENODEV); hci_req_lock(hdev); + /* Stop timer, it might be running */ + del_timer_sync(&hdev->cmd_timer); + if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { hci_req_unlock(hdev); return 0; @@ -623,7 +628,6 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Drop last sent command */ if (hdev->sent_cmd) { - del_timer_sync(&hdev->cmd_timer); kfree_skb(hdev->sent_cmd); hdev->sent_cmd = NULL; } @@ -1074,9 +1078,74 @@ static void hci_cmd_timer(unsigned long arg) BT_ERR("%s command tx timeout", hdev->name); atomic_set(&hdev->cmd_cnt, 1); + clear_bit(HCI_RESET, &hdev->flags); tasklet_schedule(&hdev->cmd_task); } +struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, + bdaddr_t *bdaddr) +{ + struct oob_data *data; + + list_for_each_entry(data, &hdev->remote_oob_data, list) + if (bacmp(bdaddr, &data->bdaddr) == 0) + return data; + + return NULL; +} + +int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr) +{ + struct oob_data *data; + + data = hci_find_remote_oob_data(hdev, bdaddr); + if (!data) + return -ENOENT; + + BT_DBG("%s removing %s", hdev->name, batostr(bdaddr)); + + list_del(&data->list); + kfree(data); + + return 0; +} + +int hci_remote_oob_data_clear(struct hci_dev *hdev) +{ + struct oob_data *data, *n; + + list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) { + list_del(&data->list); + kfree(data); + } + + return 0; +} + +int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, + u8 *randomizer) +{ + struct oob_data *data; + + data = hci_find_remote_oob_data(hdev, bdaddr); + + if (!data) { + data = kmalloc(sizeof(*data), GFP_ATOMIC); + if (!data) + return -ENOMEM; + + bacpy(&data->bdaddr, bdaddr); + list_add(&data->list, &hdev->remote_oob_data); + } + + memcpy(data->hash, hash, sizeof(data->hash)); + memcpy(data->randomizer, randomizer, sizeof(data->randomizer)); + + BT_DBG("%s for %s", hdev->name, batostr(bdaddr)); + + return 0; +} + /* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { @@ -1141,6 +1210,8 @@ int hci_register_dev(struct hci_dev *hdev) INIT_LIST_HEAD(&hdev->link_keys); + INIT_LIST_HEAD(&hdev->remote_oob_data); + INIT_WORK(&hdev->power_on, hci_power_on); INIT_WORK(&hdev->power_off, hci_power_off); setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev); @@ -1220,6 +1291,7 @@ int hci_unregister_dev(struct hci_dev *hdev) hci_blacklist_clear(hdev); hci_uuids_clear(hdev); hci_link_keys_clear(hdev); + hci_remote_oob_data_clear(hdev); hci_dev_unlock_bh(hdev); __hci_dev_put(hdev); @@ -1269,7 +1341,7 @@ int hci_recv_frame(struct sk_buff *skb) EXPORT_SYMBOL(hci_recv_frame); static int hci_reassembly(struct hci_dev *hdev, int type, void *data, - int count, __u8 index, gfp_t gfp_mask) + int count, __u8 index) { int len = 0; int hlen = 0; @@ -1299,7 +1371,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data, break; } - skb = bt_skb_alloc(len, gfp_mask); + skb = bt_skb_alloc(len, GFP_ATOMIC); if (!skb) return -ENOMEM; @@ -1385,8 +1457,7 @@ int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) return -EILSEQ; while (count) { - rem = hci_reassembly(hdev, type, data, count, - type - 1, GFP_ATOMIC); + rem = hci_reassembly(hdev, type, data, count, type - 1); if (rem < 0) return rem; @@ -1420,8 +1491,8 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count) } else type = bt_cb(skb)->pkt_type; - rem = hci_reassembly(hdev, type, data, - count, STREAM_REASSEMBLY, GFP_ATOMIC); + rem = hci_reassembly(hdev, type, data, count, + STREAM_REASSEMBLY); if (rem < 0) return rem; @@ -1877,7 +1948,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/hci_event.c b/net/bluetooth/hci_event.c index 3fbfa50c2bff..7a3398d9cd65 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -183,6 +183,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); + clear_bit(HCI_RESET, &hdev->flags); + hci_req_complete(hdev, HCI_OP_RESET, status); } @@ -193,14 +195,17 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); - if (status) - return; - sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME); if (!sent) return; - memcpy(hdev->dev_name, sent, 248); + if (test_bit(HCI_MGMT, &hdev->flags)) + mgmt_set_local_name_complete(hdev->id, sent, status); + + if (status) + return; + + memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); } static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) @@ -212,7 +217,7 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) if (rp->status) return; - memcpy(hdev->dev_name, rp->name, 248); + memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH); } static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) @@ -819,6 +824,17 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, rp->status); } +static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_rp_read_local_oob_data *rp = (void *) skb->data; + + BT_DBG("%s status 0x%x", hdev->name, rp->status); + + mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash, + rp->randomizer, rp->status); +} + static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) { BT_DBG("%s status 0x%x", hdev->name, status); @@ -1212,7 +1228,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * hci_dev_lock(hdev); - for (; num_rsp; num_rsp--) { + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -1221,8 +1237,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * data.clock_offset = info->clock_offset; data.rssi = 0x00; data.ssp_mode = 0x00; - info++; hci_inquiry_cache_update(hdev, &data); + mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0, + NULL); } hci_dev_unlock(hdev); @@ -1480,6 +1497,9 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb hci_dev_lock(hdev); + if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags)) + mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn && hci_outgoing_auth_needed(hdev, conn)) { struct hci_cp_auth_requested cp; @@ -1749,6 +1769,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk hci_cc_pin_code_neg_reply(hdev, skb); break; + case HCI_OP_READ_LOCAL_OOB_DATA: + hci_cc_read_local_oob_data_reply(hdev, skb); + break; + case HCI_OP_LE_READ_BUFFER_SIZE: hci_cc_le_read_buffer_size(hdev, skb); break; @@ -1847,7 +1871,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) if (ev->opcode != HCI_OP_NOP) del_timer(&hdev->cmd_timer); - if (ev->ncmd) { + if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) tasklet_schedule(&hdev->cmd_task); @@ -2138,7 +2162,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct struct inquiry_info_with_rssi_and_pscan_mode *info; info = (void *) (skb->data + 1); - for (; num_rsp; num_rsp--) { + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -2147,13 +2171,15 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x00; - info++; hci_inquiry_cache_update(hdev, &data); + mgmt_device_found(hdev->id, &info->bdaddr, + info->dev_class, info->rssi, + NULL); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); - for (; num_rsp; num_rsp--) { + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -2162,8 +2188,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x00; - info++; hci_inquiry_cache_update(hdev, &data); + mgmt_device_found(hdev->id, &info->bdaddr, + info->dev_class, info->rssi, + NULL); } } @@ -2294,7 +2322,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct hci_dev_lock(hdev); - for (; num_rsp; num_rsp--) { + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -2303,8 +2331,9 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x01; - info++; hci_inquiry_cache_update(hdev, &data); + mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, + info->rssi, info->data); } hci_dev_unlock(hdev); @@ -2353,9 +2382,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff bacpy(&cp.bdaddr, &ev->bdaddr); cp.capability = conn->io_capability; - cp.oob_data = 0; cp.authentication = hci_get_auth_req(conn); + if ((conn->out == 0x01 || conn->remote_oob == 0x01) && + hci_find_remote_oob_data(hdev, &conn->dst)) + cp.oob_data = 0x01; + else + cp.oob_data = 0x00; + hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY, sizeof(cp), &cp); } else { @@ -2453,6 +2487,37 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_ hci_dev_unlock(hdev); } +static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_ev_remote_oob_data_request *ev = (void *) skb->data; + struct oob_data *data; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + data = hci_find_remote_oob_data(hdev, &ev->bdaddr); + if (data) { + struct hci_cp_remote_oob_data_reply cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); + memcpy(cp.hash, data->hash, sizeof(cp.hash)); + memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer)); + + hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp), + &cp); + } else { + struct hci_cp_remote_oob_data_neg_reply cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); + hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp), + &cp); + } + + hci_dev_unlock(hdev); +} + static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_le_conn_complete *ev = (void *) skb->data; @@ -2655,6 +2720,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_le_meta_evt(hdev, skb); break; + case HCI_EV_REMOTE_OOB_DATA_REQUEST: + hci_remote_oob_data_request_evt(hdev, skb); + break; + default: BT_DBG("%s event 0x%x", hdev->name, event); break; diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 3c838a65a75a..8775933ea837 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -216,13 +216,13 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { struct hci_dev *hdev = dev_get_drvdata(dev); - char name[249]; + char name[HCI_MAX_NAME_LENGTH + 1]; int i; - for (i = 0; i < 248; i++) + for (i = 0; i < HCI_MAX_NAME_LENGTH; i++) name[i] = hdev->dev_name[i]; - name[248] = '\0'; + name[HCI_MAX_NAME_LENGTH] = '\0'; return sprintf(buf, "%s\n", name); } @@ -277,10 +277,12 @@ static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *at static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hci_dev *hdev = dev_get_drvdata(dev); - unsigned long val; + unsigned int val; + int rv; - if (strict_strtoul(buf, 0, &val) < 0) - return -EINVAL; + rv = kstrtouint(buf, 0, &val); + if (rv < 0) + return rv; if (val != 0 && (val < 500 || val > 3600000)) return -EINVAL; @@ -299,15 +301,14 @@ static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribu static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hci_dev *hdev = dev_get_drvdata(dev); - unsigned long val; - - if (strict_strtoul(buf, 0, &val) < 0) - return -EINVAL; + u16 val; + int rv; - if (val < 0x0002 || val > 0xFFFE || val % 2) - return -EINVAL; + rv = kstrtou16(buf, 0, &val); + if (rv < 0) + return rv; - if (val < hdev->sniff_min_interval) + if (val == 0 || val % 2 || val < hdev->sniff_min_interval) return -EINVAL; hdev->sniff_max_interval = val; @@ -324,15 +325,14 @@ static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribu static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hci_dev *hdev = dev_get_drvdata(dev); - unsigned long val; + u16 val; + int rv; - if (strict_strtoul(buf, 0, &val) < 0) - return -EINVAL; - - if (val < 0x0002 || val > 0xFFFE || val % 2) - return -EINVAL; + rv = kstrtou16(buf, 0, &val); + if (rv < 0) + return rv; - if (val > hdev->sniff_max_interval) + if (val == 0 || val % 2 || val > hdev->sniff_max_interval) return -EINVAL; hdev->sniff_min_interval = val; diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 5ec12971af6b..ae6ebc6c3481 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -37,6 +37,7 @@ #include <linux/init.h> #include <linux/wait.h> #include <linux/mutex.h> +#include <linux/kthread.h> #include <net/sock.h> #include <linux/input.h> @@ -55,22 +56,24 @@ static DECLARE_RWSEM(hidp_session_sem); static LIST_HEAD(hidp_session_list); static unsigned char hidp_keycode[256] = { - 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, - 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, - 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, - 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, - 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, - 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, - 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, - 150,158,159,128,136,177,178,176,142,152,173,140 + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, + 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, + 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, + 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52, + 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88, + 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69, + 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, + 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135, + 136, 113, 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94, + 95, 0, 0, 0, 122, 123, 90, 91, 85, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115, + 114, 113, 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140 }; static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; @@ -461,8 +464,7 @@ static void hidp_idle_timeout(unsigned long arg) { struct hidp_session *session = (struct hidp_session *) arg; - atomic_inc(&session->terminate); - hidp_schedule(session); + kthread_stop(session->task); } static void hidp_set_timer(struct hidp_session *session) @@ -533,9 +535,7 @@ static void hidp_process_hid_control(struct hidp_session *session, skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - /* Kill session thread */ - atomic_inc(&session->terminate); - hidp_schedule(session); + kthread_stop(session->task); } } @@ -694,22 +694,10 @@ static int hidp_session(void *arg) struct sock *ctrl_sk = session->ctrl_sock->sk; struct sock *intr_sk = session->intr_sock->sk; struct sk_buff *skb; - int vendor = 0x0000, product = 0x0000; wait_queue_t ctrl_wait, intr_wait; BT_DBG("session %p", session); - if (session->input) { - vendor = session->input->id.vendor; - product = session->input->id.product; - } - - if (session->hid) { - vendor = session->hid->vendor; - product = session->hid->product; - } - - daemonize("khidpd_%04x%04x", vendor, product); set_user_nice(current, -15); init_waitqueue_entry(&ctrl_wait, current); @@ -718,10 +706,11 @@ static int hidp_session(void *arg) add_wait_queue(sk_sleep(intr_sk), &intr_wait); session->waiting_for_startup = 0; wake_up_interruptible(&session->startup_queue); - while (!atomic_read(&session->terminate)) { + while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); - if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED) + if (ctrl_sk->sk_state != BT_CONNECTED || + intr_sk->sk_state != BT_CONNECTED) break; while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { @@ -965,6 +954,7 @@ fault: int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) { struct hidp_session *session, *s; + int vendor, product; int err; BT_DBG(""); @@ -1026,9 +1016,24 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, hidp_set_timer(session); - err = kernel_thread(hidp_session, session, CLONE_KERNEL); - if (err < 0) + if (session->hid) { + vendor = session->hid->vendor; + product = session->hid->product; + } else if (session->input) { + vendor = session->input->id.vendor; + product = session->input->id.product; + } else { + vendor = 0x0000; + product = 0x0000; + } + + session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x", + vendor, product); + if (IS_ERR(session->task)) { + err = PTR_ERR(session->task); goto unlink; + } + while (session->waiting_for_startup) { wait_event_interruptible(session->startup_queue, !session->waiting_for_startup); @@ -1053,8 +1058,7 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, err_add_device: hid_destroy_device(session->hid); session->hid = NULL; - atomic_inc(&session->terminate); - hidp_schedule(session); + kthread_stop(session->task); unlink: hidp_del_timer(session); @@ -1105,13 +1109,7 @@ int hidp_del_connection(struct hidp_conndel_req *req) skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - /* Wakeup user-space polling for socket errors */ - session->intr_sock->sk->sk_err = EUNATCH; - session->ctrl_sock->sk->sk_err = EUNATCH; - - /* Kill session thread */ - atomic_inc(&session->terminate); - hidp_schedule(session); + kthread_stop(session->task); } } else err = -ENOENT; diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index 13de5fa03480..12822cde4b49 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -84,8 +84,8 @@ #define HIDP_WAITING_FOR_SEND_ACK 11 struct hidp_connadd_req { - int ctrl_sock; // Connected control socket - int intr_sock; // Connteted interrupt socket + int ctrl_sock; /* Connected control socket */ + int intr_sock; /* Connected interrupt socket */ __u16 parser; __u16 rd_size; __u8 __user *rd_data; @@ -142,7 +142,7 @@ struct hidp_session { uint ctrl_mtu; uint intr_mtu; - atomic_t terminate; + struct task_struct *task; unsigned char keys[8]; unsigned char leds; diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 250dfd46237d..178ac7f127ad 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -85,7 +85,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long return err; } - if (csock->sk->sk_state != BT_CONNECTED || isock->sk->sk_state != BT_CONNECTED) { + if (csock->sk->sk_state != BT_CONNECTED || + isock->sk->sk_state != BT_CONNECTED) { sockfd_put(csock); sockfd_put(isock); return -EBADFD; @@ -140,8 +141,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long #ifdef CONFIG_COMPAT struct compat_hidp_connadd_req { - int ctrl_sock; // Connected control socket - int intr_sock; // Connteted interrupt socket + int ctrl_sock; /* Connected control socket */ + int intr_sock; /* Connected interrupt socket */ __u16 parser; __u16 rd_size; compat_uptr_t rd_data; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c9f9cecca527..c3cebed205cc 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -169,7 +169,7 @@ static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) __sock_put(sk); } -static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) { struct l2cap_chan_list *l = &conn->chan_list; @@ -204,9 +204,6 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so } __l2cap_chan_link(l, sk); - - if (parent) - bt_accept_enqueue(parent, sk); } /* Delete channel. @@ -652,7 +649,9 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->dst, conn->dst); - __l2cap_chan_add(conn, sk, parent); + bt_accept_enqueue(parent, sk); + + __l2cap_chan_add(conn, sk); l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -793,11 +792,11 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree(conn); } -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) { struct l2cap_chan_list *l = &conn->chan_list; write_lock_bh(&l->lock); - __l2cap_chan_add(conn, sk, parent); + __l2cap_chan_add(conn, sk); write_unlock_bh(&l->lock); } @@ -876,7 +875,7 @@ int l2cap_do_connect(struct sock *sk) /* Update source addr of the socket */ bacpy(src, conn->src); - l2cap_chan_add(conn, sk, NULL); + l2cap_chan_add(conn, sk); sk->sk_state = BT_CONNECT; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -1116,7 +1115,9 @@ int l2cap_ertm_send(struct sock *sk) bt_cb(skb)->tx_seq = pi->next_tx_seq; pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; - pi->unacked_frames++; + if (bt_cb(skb)->retries == 1) + pi->unacked_frames++; + pi->frames_sent++; if (skb_queue_is_last(TX_QUEUE(sk), skb)) @@ -2030,7 +2031,9 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_pi(sk)->psm = psm; l2cap_pi(sk)->dcid = scid; - __l2cap_chan_add(conn, sk, parent); + bt_accept_enqueue(parent, sk); + + __l2cap_chan_add(conn, sk); dcid = l2cap_pi(sk)->scid; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -2460,6 +2463,11 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm BT_DBG("type 0x%4.4x result 0x%2.2x", type, result); + /* L2CAP Info req/rsp are unbound to channels, add extra checks */ + if (cmd->ident != conn->info_ident || + conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) + return 0; + del_timer(&conn->info_timer); if (result != L2CAP_IR_SUCCESS) { @@ -2670,7 +2678,8 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, if (err) { struct l2cap_cmd_rej rej; - BT_DBG("error %d", err); + + BT_ERR("Wrong link type (%d)", err); /* FIXME: Map err to a valid reason */ rej.reason = cpu_to_le16(0); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index fc85e7ae33c7..299fe56a9668 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -679,7 +679,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch if (opt == BT_FLUSHABLE_OFF) { struct l2cap_conn *conn = l2cap_pi(sk)->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; @@ -923,8 +923,9 @@ void __l2cap_sock_close(struct sock *sk, int reason) rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); - } else - l2cap_chan_del(sk, reason); + } + + l2cap_chan_del(sk, reason); break; case BT_CONNECT: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0054c74e27b7..c304688252b8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -36,7 +36,7 @@ struct pending_cmd { struct list_head list; __u16 opcode; int index; - void *cmd; + void *param; struct sock *sk; void *user_data; }; @@ -179,10 +179,12 @@ static int read_controller_info(struct sock *sk, u16 index) hci_del_off_timer(hdev); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); set_bit(HCI_MGMT, &hdev->flags); + memset(&rp, 0, sizeof(rp)); + rp.type = hdev->dev_type; rp.powered = test_bit(HCI_UP, &hdev->flags); @@ -204,7 +206,9 @@ static int read_controller_info(struct sock *sk, u16 index) rp.hci_ver = hdev->hci_ver; put_unaligned_le16(hdev->hci_rev, &rp.hci_rev); - hci_dev_unlock_bh(hdev); + memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); + + hci_dev_unlock(hdev); hci_dev_put(hdev); return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp)); @@ -213,7 +217,7 @@ static int read_controller_info(struct sock *sk, u16 index) static void mgmt_pending_free(struct pending_cmd *cmd) { sock_put(cmd->sk); - kfree(cmd->cmd); + kfree(cmd->param); kfree(cmd); } @@ -229,13 +233,14 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, cmd->opcode = opcode; cmd->index = index; - cmd->cmd = kmalloc(len, GFP_ATOMIC); - if (!cmd->cmd) { + cmd->param = kmalloc(len, GFP_ATOMIC); + if (!cmd->param) { kfree(cmd); return NULL; } - memcpy(cmd->cmd, data, len); + if (data) + memcpy(cmd->param, data, len); cmd->sk = sk; sock_hold(sk); @@ -311,7 +316,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); up = test_bit(HCI_UP, &hdev->flags); if ((cp->val && up) || (!cp->val && !up)) { @@ -338,7 +343,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) err = 0; failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } @@ -363,7 +368,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN); @@ -398,7 +403,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -424,7 +429,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN); @@ -458,7 +463,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -517,7 +522,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (cp->val) set_bit(HCI_PAIRABLE, &hdev->flags); @@ -533,12 +538,156 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } +#define EIR_FLAGS 0x01 /* flags */ +#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ +#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ +#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ +#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ +#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ +#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ +#define EIR_NAME_SHORT 0x08 /* shortened local name */ +#define EIR_NAME_COMPLETE 0x09 /* complete local name */ +#define EIR_TX_POWER 0x0A /* transmit power level */ +#define EIR_DEVICE_ID 0x10 /* device ID */ + +#define PNP_INFO_SVCLASS_ID 0x1200 + +static u8 bluetooth_base_uuid[] = { + 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static u16 get_uuid16(u8 *uuid128) +{ + u32 val; + int i; + + for (i = 0; i < 12; i++) { + if (bluetooth_base_uuid[i] != uuid128[i]) + return 0; + } + + memcpy(&val, &uuid128[12], 4); + + val = le32_to_cpu(val); + if (val > 0xffff) + return 0; + + return (u16) val; +} + +static void create_eir(struct hci_dev *hdev, u8 *data) +{ + u8 *ptr = data; + u16 eir_len = 0; + u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)]; + int i, truncated = 0; + struct list_head *p; + size_t name_len; + + name_len = strlen(hdev->dev_name); + + if (name_len > 0) { + /* EIR Data type */ + if (name_len > 48) { + name_len = 48; + ptr[1] = EIR_NAME_SHORT; + } else + ptr[1] = EIR_NAME_COMPLETE; + + /* EIR Data length */ + ptr[0] = name_len + 1; + + memcpy(ptr + 2, hdev->dev_name, name_len); + + eir_len += (name_len + 2); + ptr += (name_len + 2); + } + + memset(uuid16_list, 0, sizeof(uuid16_list)); + + /* Group all UUID16 types */ + list_for_each(p, &hdev->uuids) { + struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list); + u16 uuid16; + + uuid16 = get_uuid16(uuid->uuid); + if (uuid16 == 0) + return; + + if (uuid16 < 0x1100) + continue; + + if (uuid16 == PNP_INFO_SVCLASS_ID) + continue; + + /* Stop if not enough space to put next UUID */ + if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { + truncated = 1; + break; + } + + /* Check for duplicates */ + for (i = 0; uuid16_list[i] != 0; i++) + if (uuid16_list[i] == uuid16) + break; + + if (uuid16_list[i] == 0) { + uuid16_list[i] = uuid16; + eir_len += sizeof(u16); + } + } + + if (uuid16_list[0] != 0) { + u8 *length = ptr; + + /* EIR Data type */ + ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; + + ptr += 2; + eir_len += 2; + + for (i = 0; uuid16_list[i] != 0; i++) { + *ptr++ = (uuid16_list[i] & 0x00ff); + *ptr++ = (uuid16_list[i] & 0xff00) >> 8; + } + + /* EIR Data length */ + *length = (i * sizeof(u16)) + 1; + } +} + +static int update_eir(struct hci_dev *hdev) +{ + struct hci_cp_write_eir cp; + + if (!(hdev->features[6] & LMP_EXT_INQ)) + return 0; + + if (hdev->ssp_mode == 0) + return 0; + + if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) + return 0; + + memset(&cp, 0, sizeof(cp)); + + create_eir(hdev, cp.data); + + if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) + return 0; + + memcpy(hdev->eir, cp.data, sizeof(cp.data)); + + return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); +} + static u8 get_service_classes(struct hci_dev *hdev) { struct list_head *p; @@ -590,7 +739,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); if (!uuid) { @@ -607,10 +756,14 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) if (err < 0) goto failed; + err = update_eir(hdev); + if (err < 0) + goto failed; + err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -635,7 +788,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { err = hci_uuids_clear(hdev); @@ -663,10 +816,14 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) if (err < 0) goto unlock; + err = update_eir(hdev); + if (err < 0) + goto unlock; + err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -690,7 +847,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hdev->major_class = cp->major; hdev->minor_class = cp->minor; @@ -700,7 +857,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, if (err == 0) err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -722,7 +879,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); BT_DBG("hci%u enable %d", index, cp->enable); @@ -732,13 +889,15 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, } else { clear_bit(HCI_SERVICE_CACHE, &hdev->flags); err = update_class(hdev); + if (err == 0) + err = update_eir(hdev); } if (err == 0) err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -772,7 +931,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, key_count); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hci_link_keys_clear(hdev); @@ -790,7 +949,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) key->pin_len); } - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return 0; @@ -812,7 +971,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_remove_link_key(hdev, &cp->bdaddr); if (err < 0) { @@ -835,7 +994,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) } unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -861,7 +1020,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN); @@ -893,7 +1052,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -914,7 +1073,7 @@ static int get_connections(struct sock *sk, u16 index) if (!hdev) return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); count = 0; list_for_each(p, &hdev->conn_hash.list) { @@ -945,7 +1104,7 @@ static int get_connections(struct sock *sk, u16 index) unlock: kfree(rp); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } @@ -970,7 +1129,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN); @@ -992,7 +1151,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1019,7 +1178,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, @@ -1040,7 +1199,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1063,14 +1222,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hdev->io_capability = cp->io_capability; BT_DBG("%s IO capability set to 0x%02x", hdev->name, hdev->io_capability); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); @@ -1156,7 +1315,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (cp->io_cap == 0x03) { sec_level = BT_SECURITY_MEDIUM; @@ -1198,7 +1357,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) err = 0; unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1230,6 +1389,8 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, mgmt_op, ENODEV); + hci_dev_lock(hdev); + if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, mgmt_op, ENETDOWN); goto failed; @@ -1246,7 +1407,163 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +} + +static int set_local_name(struct sock *sk, u16 index, unsigned char *data, + u16 len) +{ + struct mgmt_cp_set_local_name *mgmt_cp = (void *) data; + struct hci_cp_write_local_name hci_cp; + struct hci_dev *hdev; + struct pending_cmd *cmd; + int err; + + BT_DBG(""); + + if (len != sizeof(*mgmt_cp)) + return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV); + + hci_dev_lock(hdev); + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name)); + err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp), + &hci_cp); + if (err < 0) + mgmt_pending_remove(cmd); + +failed: + hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +} + +static int read_local_oob_data(struct sock *sk, u16 index) +{ + struct hci_dev *hdev; + struct pending_cmd *cmd; + int err; + + BT_DBG("hci%u", index); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + ENODEV); + + hci_dev_lock(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + ENETDOWN); + goto unlock; + } + + if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { + err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + EOPNOTSUPP); + goto unlock; + } + + if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) { + err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } + + err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); + if (err < 0) + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +} + +static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, + u16 len) +{ + struct hci_dev *hdev; + struct mgmt_cp_add_remote_oob_data *cp = (void *) data; + int err; + + BT_DBG("hci%u ", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + EINVAL); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + ENODEV); + + hci_dev_lock(hdev); + + err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, + cp->randomizer); + if (err < 0) + err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err); + else + err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, + 0); + + hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +} + +static int remove_remote_oob_data(struct sock *sk, u16 index, + unsigned char *data, u16 len) +{ + struct hci_dev *hdev; + struct mgmt_cp_remove_remote_oob_data *cp = (void *) data; + int err; + + BT_DBG("hci%u ", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + EINVAL); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + ENODEV); + + hci_dev_lock(hdev); + + err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); + if (err < 0) + err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + -err); + else + err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + NULL, 0); + + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1264,7 +1581,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) if (msglen < sizeof(*hdr)) return -EINVAL; - buf = kmalloc(msglen, GFP_ATOMIC); + buf = kmalloc(msglen, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -1347,6 +1664,20 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_USER_CONFIRM_NEG_REPLY: err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0); break; + case MGMT_OP_SET_LOCAL_NAME: + err = set_local_name(sk, index, buf + sizeof(*hdr), len); + break; + case MGMT_OP_READ_LOCAL_OOB_DATA: + err = read_local_oob_data(sk, index); + break; + case MGMT_OP_ADD_REMOTE_OOB_DATA: + err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len); + break; + case MGMT_OP_REMOVE_REMOTE_OOB_DATA: + err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr), + len); + break; + default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, 0x01); @@ -1380,7 +1711,7 @@ struct cmd_lookup { static void mode_rsp(struct pending_cmd *cmd, void *data) { - struct mgmt_mode *cp = cmd->cmd; + struct mgmt_mode *cp = cmd->param; struct cmd_lookup *match = data; if (cp->val != match->val) @@ -1479,7 +1810,7 @@ int mgmt_connected(u16 index, bdaddr_t *bdaddr) static void disconnect_rsp(struct pending_cmd *cmd, void *data) { - struct mgmt_cp_disconnect *cp = cmd->cmd; + struct mgmt_cp_disconnect *cp = cmd->param; struct sock **sk = data; struct mgmt_rp_disconnect rp; @@ -1643,3 +1974,104 @@ int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status) return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL); } + +int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status) +{ + struct pending_cmd *cmd; + struct hci_dev *hdev; + struct mgmt_cp_set_local_name ev; + int err; + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); + + cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index); + if (!cmd) + goto send_event; + + if (status) { + err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO); + goto failed; + } + + hdev = hci_dev_get(index); + if (hdev) { + hci_dev_lock_bh(hdev); + update_eir(hdev); + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + } + + err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev, + sizeof(ev)); + if (err < 0) + goto failed; + +send_event: + err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev), + cmd ? cmd->sk : NULL); + +failed: + if (cmd) + mgmt_pending_remove(cmd); + return err; +} + +int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, + u8 status) +{ + struct pending_cmd *cmd; + int err; + + BT_DBG("hci%u status %u", index, status); + + cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index); + if (!cmd) + return -ENOENT; + + if (status) { + err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + EIO); + } else { + struct mgmt_rp_read_local_oob_data rp; + + memcpy(rp.hash, hash, sizeof(rp.hash)); + memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer)); + + err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + &rp, sizeof(rp)); + } + + mgmt_pending_remove(cmd); + + return err; +} + +int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, + u8 *eir) +{ + struct mgmt_ev_device_found ev; + + memset(&ev, 0, sizeof(ev)); + + bacpy(&ev.bdaddr, bdaddr); + memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); + ev.rssi = rssi; + + if (eir) + memcpy(ev.eir, eir, sizeof(ev.eir)); + + return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL); +} + +int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name) +{ + struct mgmt_ev_remote_name ev; + + memset(&ev, 0, sizeof(ev)); + + bacpy(&ev.bdaddr, bdaddr); + memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); + + return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL); +} diff --git a/net/bridge/br.c b/net/bridge/br.c index 84bbb82599b2..f20c4fd915a8 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 21e5901186ea..45cfd54b06d3 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -74,6 +74,17 @@ 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); @@ -334,6 +345,7 @@ static const struct ethtool_ops br_ethtool_ops = { 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, @@ -357,18 +369,47 @@ 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; + + 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->feature_mask = dev->features; + 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 88485cc74dc3..e0dfbc151dd7 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 718b60366dfe..7f5379c593d9 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -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) diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index e2160792e1bc..785932d7ad32 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); } diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index cb43312b846e..7222fe1d5460 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_netfilter.c b/net/bridge/br_netfilter.c index 008ff6c4eecf..f3bc322c5891 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -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)) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index f8bf4c7f842c..134a2ff6b98b 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) @@ -188,20 +190,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 7d337c9b6082..606b323e8a0c 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) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 387013d33745..e2a40343aa09 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; @@ -353,6 +354,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, @@ -491,6 +495,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 +510,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 8b650f7fbfa0..642ef47a867e 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 7370d14f634d..bb4383e84de9 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 9b61d09de9b9..6f615b8192f4 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 5c1e5559ebba..68b893ea8c3a 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 fd5799c9bc8d..6229b62749e8 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 d522d8c1703e..9b63e4e3910e 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 a42a408306e4..75e00d59eb49 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, ¶m); + + ret = caif_connect_req_to_link_param(cfg, conn_req, ¶m); if (ret) return ret; /* Hook up the adaptation layer. */ - return cfcnfg_add_adaptation_layer(get_caif_conf(), ¶m, + return cfcnfg_add_adaptation_layer(cfg, ¶m, 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 8184c031d028..20212424e2e8 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 f1f98d967d8a..25c0b198e285 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 3cd8f978e309..397a2c099e2c 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 27dab26ad3b8..0382dec84fdc 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 a445043931ae..2423fed8e26c 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 46f34b2e0478..fc2497468571 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 d7e865e2ff65..20c6cb3522e0 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 8303fe3ebf89..2715c84cfa87 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 ab5e542526bf..24ba392f203b 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 315c0d601368..98e027db18ed 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 c3b1dec4acf6..1a588cd818ea 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 bf6fef2a0eff..b2f5989ad455 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 733d66f1b05a..a8dcaa49675a 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 871a0ad51025..57b1aed79014 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) { diff --git a/net/ceph/Kconfig b/net/ceph/Kconfig index ad424049b0cf..be683f2d401f 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 549c1f43e1d5..b4bf4ac090f1 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 7fd5dfcf6e18..1587dc6010c6 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 95f96ab94bba..132963abc266 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 7b505b0c983f..5a8009c9e0cd 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 f9eccace592b..1919d1550d75 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 8a079399174a..cbe31fa45508 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 02212ed50852..50af02737a3d 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 02f56376fe99..3871bf69a386 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2091,7 +2091,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 +2151,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) @@ -2970,8 +2970,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) @@ -3130,6 +3130,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,7 +3183,7 @@ 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)) @@ -3800,7 +3806,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)) { @@ -5203,11 +5209,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"); @@ -5241,6 +5251,8 @@ 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) @@ -5425,6 +5437,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. @@ -6182,6 +6202,10 @@ u32 netdev_increment_features(u32 all, u32 one, u32 mask) } } + /* If device can't no cache copy, don't do for all */ + if (!(one & NETIF_F_NOCACHE_COPY)) + all &= ~NETIF_F_NOCACHE_COPY; + one |= NETIF_F_ALL_CSUM; one |= all & NETIF_F_ONE_FOR_ALL; @@ -6347,7 +6371,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/ethtool.c b/net/core/ethtool.c index 439e4b0e1312..13d79f5a86e5 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. @@ -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" "", }; @@ -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/filter.c b/net/core/filter.c index 232b1873bb28..afb8afb066bb 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -425,7 +425,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) { diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 01a1101b5936..a7b342131869 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_namespace.c b/net/core/net_namespace.c index 3f860261c5ee..1abb50841046 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/pktgen.c b/net/core/pktgen.c index aeeece72b72f..2fa6fee1b46f 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) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 49f7ea5b4c75..d7c4bb4b1820 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) @@ -1440,7 +1440,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); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 801dd08908f9..7ebeed0a877c 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 7dfed792434d..6e819780c232 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/dccp/output.c b/net/dccp/output.c index 784d30210543..136d41cbcd02 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_table.c b/net/decnet/dn_table.c index 99d8d3a40998..bd0a52dd1d40 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 bb2b41bc854e..3da418894efc 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 eb0e0aaa9f1b..61156ca26a0d 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/econet/af_econet.c b/net/econet/af_econet.c index 116d3fd3d669..a1d9f3787dd5 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 ce2d33582859..5761185f884e 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/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 094e150c6260..a0af7ea87870 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 diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 5345b0bee6df..acf553f95b5b 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1203,6 +1203,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, break; /* fall through */ case NETDEV_NOTIFY_PEERS: + case NETDEV_BONDING_FAILOVER: /* Send gratuitous ARP to notify of link change */ inetdev_send_gratuitous_arp(dev, in_dev); break; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 451088330bbb..22524716fe70 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 b9d1f33e5e04..9ac481a10d37 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. @@ -1332,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)); @@ -1697,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); @@ -1987,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)); diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index a91dc1611081..e5f8a71d3a2a 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -704,7 +704,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. diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index f784608a4c45..8514db54a7f4 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; diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index dd1b20eca1a2..9df4e635fb5f 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_options.c b/net/ipv4/ip_options.c index 28a736f3442f..2391b24e8251 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -329,7 +329,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 +371,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]; } @@ -603,7 +603,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 86a284308271..bdad3d60aa82 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -603,7 +603,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; diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 2b097752426b..cbff2ecccf3d 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/netfilter.c b/net/ipv4/netfilter.c index f3c0b549b8e1..4614babdc45f 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 2ea743336836..fd7a3f68917f 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. */ @@ -1878,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 2b6b700949eb..764743843503 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -2229,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 21bcf471b25a..9c71b2755ce3 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/raw.c b/net/ipv4/raw.c index 7d32d9d57152..2b50cc2da90a 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -618,7 +618,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 4b0c81180804..e9aee81de3e3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -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); @@ -1871,8 +1871,8 @@ 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; } @@ -1891,6 +1891,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 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); @@ -1980,8 +1981,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); @@ -2026,6 +2027,7 @@ static int __mkroute_input(struct sk_buff *skb, rth->rt_key_src = saddr; 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); @@ -2148,9 +2150,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 +2176,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) @@ -2202,6 +2204,7 @@ local_input: #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); @@ -2401,7 +2404,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res, rth->rt_mark = oldflp4->flowi4_mark; rth->rt_dst = fl4->daddr; rth->rt_src = fl4->saddr; - rth->rt_iif = 0; + rth->rt_route_iif = 0; + rth->rt_iif = oldflp4->flowi4_oif ? : dev_out->ifindex; /* get references to the devices that are to be hold by the routing cache entry */ rth->dst.dev = dev_out; @@ -2611,7 +2615,9 @@ static struct rtable *ip_route_output_slow(struct net *net, 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) @@ -2716,6 +2722,7 @@ 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_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 +2732,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; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 1a456652086b..321e6e84dbcc 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 b22d45010545..054a59d21eb0 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_lp.c b/net/ipv4/tcp_lp.c index 656d431c99ad..72f7218b03f5 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 dfa5beb0c1c8..17388c7f49c4 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; @@ -1003,7 +1003,8 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, int nlen; u8 flags; - BUG_ON(len > skb->len); + if (WARN_ON(len > skb->len)) + return -EINVAL; nsize = skb_headlen(skb) - len; if (nsize < 0) diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c index dc7f43179c9a..05c3b6f0e8e1 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 ac66132b8edf..a15c8fb653af 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, diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 13e0e7f659ff..d20a05e970d8 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -74,6 +74,7 @@ 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_route_iif = fl4->flowi4_iif; rt->rt_iif = fl4->flowi4_iif; rt->rt_oif = fl4->flowi4_oif; rt->rt_mark = fl4->flowi4_mark; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3daaf3c7703c..129d7e1f311c 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) : @@ -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; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 4b13d5d8890e..afcc7099f96d 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -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/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 166054650466..f2c5b0fc0f21 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_output.c b/net/ipv6/ip6_output.c index 18208876aa8a..c614d02bf429 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; @@ -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/ndisc.c b/net/ipv6/ndisc.c index 92f952d093db..01a0ffc7b402 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -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) @@ -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 @@ -1722,6 +1746,10 @@ 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: + case NETDEV_BONDING_FAILOVER: + ndisc_send_unsol_na(dev); + break; default: break; } diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 39aaca2b4fd2..28bc1f644b7b 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -90,9 +90,18 @@ 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; } diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index ec7cf579cdd4..94874b0bdcdc 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1583,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; @@ -1605,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); @@ -2253,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 679a0a3b7b3c..00d19173db7e 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 97c5b21b9674..cdd6d045e42e 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/route.c b/net/ipv6/route.c index 843406f14d7b..af26cc1073cb 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1325,6 +1325,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)) { @@ -2037,6 +2047,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, + 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 +2242,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 +2387,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/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 2b0c186862c8..4f49e5dd41bb 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -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); @@ -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; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index d7037c006e13..15c37746845e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -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; diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index c9890e25cd4c..cc616974a447 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 783c5f367d29..005b424494a0 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 d434c8880745..ccd214f9d196 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 688222cbf55b..8c004161a843 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 c1fb5db81042..9505a7d06f1a 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 0d82ff5aeff1..979ecb2435a7 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 318766e5dbdf..b9ac598e2116 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 849aaf0dabb5..9715e6e5900b 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 f6054f9ccbe3..9d9af4606970 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 2b00974e5bae..1b51bcf42394 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 0335ba0cc593..f418cb2ad49c 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 9637e45744fa..986b2a5e8769 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 1ee5dab3cfae..8f156bd86be7 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/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 4c1e540732d7..93a41a09458b 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 058f1e9a9128..903242111317 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/Kconfig b/net/mac80211/Kconfig index 513f85cc2ae1..f5fdfcbf552a 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -2,7 +2,6 @@ config MAC80211 tristate "Generic IEEE 802.11 Networking Stack (mac80211)" depends on CFG80211 select CRYPTO - select CRYPTO_ECB select CRYPTO_ARC4 select CRYPTO_AES select CRC32 diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 334213571ad0..bf5d28da46e6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -342,7 +342,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) STATION_INFO_TX_FAILED | STATION_INFO_TX_BITRATE | STATION_INFO_RX_BITRATE | - STATION_INFO_RX_DROP_MISC; + STATION_INFO_RX_DROP_MISC | + STATION_INFO_BSS_PARAM; sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); sinfo->rx_bytes = sta->rx_bytes; @@ -389,6 +390,16 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->plink_state = sta->plink_state; #endif } + + sinfo->bss_param.flags = 0; + if (sdata->vif.bss_conf.use_cts_prot) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; + if (sdata->vif.bss_conf.use_short_preamble) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; + if (sdata->vif.bss_conf.use_short_slot) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; + sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; + sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; } diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 51f0d780dafa..0a602dbfdb2b 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -37,7 +37,7 @@ int mac80211_format_buffer(char __user *userbuf, size_t count, return simple_read_from_buffer(userbuf, count, ppos, buf, res); } -#define DEBUGFS_READONLY_FILE(name, fmt, value...) \ +#define DEBUGFS_READONLY_FILE_FN(name, fmt, value...) \ static ssize_t name## _read(struct file *file, char __user *userbuf, \ size_t count, loff_t *ppos) \ { \ @@ -45,14 +45,19 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ \ return mac80211_format_buffer(userbuf, count, ppos, \ fmt "\n", ##value); \ -} \ - \ +} + +#define DEBUGFS_READONLY_FILE_OPS(name) \ static const struct file_operations name## _ops = { \ .read = name## _read, \ .open = mac80211_open_file_generic, \ .llseek = generic_file_llseek, \ }; +#define DEBUGFS_READONLY_FILE(name, fmt, value...) \ + DEBUGFS_READONLY_FILE_FN(name, fmt, value) \ + DEBUGFS_READONLY_FILE_OPS(name) + #define DEBUGFS_ADD(name) \ debugfs_create_file(#name, 0400, phyd, local, &name## _ops); @@ -291,11 +296,70 @@ static ssize_t channel_type_read(struct file *file, char __user *user_buf, return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); } -static const struct file_operations channel_type_ops = { - .read = channel_type_read, - .open = mac80211_open_file_generic, - .llseek = default_llseek, -}; +static ssize_t hwflags_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + int mxln = 500; + ssize_t rv; + char *buf = kzalloc(mxln, GFP_KERNEL); + int sf = 0; /* how many written so far */ + + sf += snprintf(buf, mxln - sf, "0x%x\n", local->hw.flags); + if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) + sf += snprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n"); + if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) + sf += snprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n"); + if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) + sf += snprintf(buf + sf, mxln - sf, + "HOST_BCAST_PS_BUFFERING\n"); + if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE) + sf += snprintf(buf + sf, mxln - sf, + "2GHZ_SHORT_SLOT_INCAPABLE\n"); + if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE) + sf += snprintf(buf + sf, mxln - sf, + "2GHZ_SHORT_PREAMBLE_INCAPABLE\n"); + if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) + sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n"); + if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) + sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n"); + if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) + sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_PERIOD\n"); + if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT) + sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n"); + if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) + sf += snprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n"); + if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) + sf += snprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); + if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) + sf += snprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); + if (local->hw.flags & IEEE80211_HW_BEACON_FILTER) + sf += snprintf(buf + sf, mxln - sf, "BEACON_FILTER\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_SMPS\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n"); + if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) + sf += snprintf(buf + sf, mxln - sf, "REPORTS_TX_ACK_STATUS\n"); + if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) + sf += snprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_CQM_RSSI\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n"); + if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) + sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); + + rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); + kfree(buf); + return rv; +} static ssize_t queues_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -315,11 +379,9 @@ static ssize_t queues_read(struct file *file, char __user *user_buf, return simple_read_from_buffer(user_buf, count, ppos, buf, res); } -static const struct file_operations queues_ops = { - .read = queues_read, - .open = mac80211_open_file_generic, - .llseek = default_llseek, -}; +DEBUGFS_READONLY_FILE_OPS(hwflags); +DEBUGFS_READONLY_FILE_OPS(channel_type); +DEBUGFS_READONLY_FILE_OPS(queues); /* statistics stuff */ @@ -395,6 +457,7 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(uapsd_queues); DEBUGFS_ADD(uapsd_max_sp_len); DEBUGFS_ADD(channel_type); + DEBUGFS_ADD(hwflags); DEBUGFS_ADD(user_power); DEBUGFS_ADD(power); diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3e81af1fce58..14883966374e 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -661,7 +661,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, struct sk_buff *req) { - struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(req); struct ieee80211_mgmt *mgmt = (void *)req->data; struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; @@ -685,7 +684,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, mgmt->bssid, tx_last_beacon); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ - if (!tx_last_beacon && !(rx_status->rx_flags & IEEE80211_RX_RA_MATCH)) + if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da)) return; if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 && diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a40401701424..89ce1e329b5d 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. @@ -809,8 +809,8 @@ struct ieee80211_local { struct rate_control_ref *rate_ctrl; - struct crypto_blkcipher *wep_tx_tfm; - struct crypto_blkcipher *wep_rx_tfm; + struct crypto_cipher *wep_tx_tfm; + struct crypto_cipher *wep_rx_tfm; u32 wep_iv; /* see iface.c */ diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 8c02469b7176..af3c56482c80 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -342,7 +342,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, if (IS_ERR(key->u.ccmp.tfm)) { err = PTR_ERR(key->u.ccmp.tfm); kfree(key); - key = ERR_PTR(err); + return ERR_PTR(err); } break; case WLAN_CIPHER_SUITE_AES_CMAC: @@ -360,7 +360,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, if (IS_ERR(key->u.aes_cmac.tfm)) { err = PTR_ERR(key->u.aes_cmac.tfm); kfree(key); - key = ERR_PTR(err); + return ERR_PTR(err); } break; } @@ -400,11 +400,12 @@ int ieee80211_key_link(struct ieee80211_key *key, { struct ieee80211_key *old_key; int idx, ret; - bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; + bool pairwise; BUG_ON(!sdata); BUG_ON(!key); + pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; idx = key->conf.keyidx; key->local = sdata->local; key->sdata = sdata; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 562d2984c482..dc50fc3153e5 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -879,10 +879,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) local->dynamic_ps_forced_timeout = -1; - result = sta_info_start(local); - if (result < 0) - goto fail_sta_info; - result = ieee80211_wep_init(local); if (result < 0) wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", @@ -945,7 +941,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) rtnl_unlock(); ieee80211_wep_free(local); sta_info_stop(local); - fail_sta_info: destroy_workqueue(local->workqueue); fail_workqueue: wiphy_unregister(local->hw.wiphy); diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 8d65b47d9837..336ca9d0c5c4 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -628,7 +628,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/mlme.c b/net/mac80211/mlme.c index 64d92d5a7f40..865fed4cc18b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -90,20 +90,11 @@ enum rx_mgmt_action { /* no action required */ RX_MGMT_NONE, - /* caller must call cfg80211_send_rx_auth() */ - RX_MGMT_CFG80211_AUTH, - - /* caller must call cfg80211_send_rx_assoc() */ - RX_MGMT_CFG80211_ASSOC, - /* caller must call cfg80211_send_deauth() */ RX_MGMT_CFG80211_DEAUTH, /* caller must call cfg80211_send_disassoc() */ RX_MGMT_CFG80211_DISASSOC, - - /* caller must tell cfg80211 about internal error */ - RX_MGMT_CFG80211_ASSOC_ERROR, }; /* utils */ diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 8212a8bebf06..c06aa3ac6b9d 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; @@ -659,18 +659,14 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; struct ieee80211_local *local = hw_to_local(mp->hw); u16 sta_cap = sta->ht_cap.cap; + int n_supported = 0; int ack_dur; int stbc; int i; /* fall back to the old minstrel for legacy stations */ - if (!sta->ht_cap.ht_supported) { - msp->is_ht = false; - memset(&msp->legacy, 0, sizeof(msp->legacy)); - msp->legacy.r = msp->ratelist; - msp->legacy.sample_table = msp->sample_table; - return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy); - } + if (!sta->ht_cap.ht_supported) + goto use_legacy; BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS); @@ -725,7 +721,22 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, mi->groups[i].supported = mcs->rx_mask[minstrel_mcs_groups[i].streams - 1]; + + if (mi->groups[i].supported) + n_supported++; } + + if (!n_supported) + goto use_legacy; + + return; + +use_legacy: + msp->is_ht = false; + memset(&msp->legacy, 0, sizeof(msp->legacy)); + msp->legacy.r = msp->ratelist; + msp->legacy.sample_table = msp->sample_table; + return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy); } static void diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h index 6510f8ee738e..19111c7bf454 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 5c1930ba8ebe..1f0b010904b8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -381,7 +381,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. */ @@ -612,7 +612,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, skipped++; continue; } - if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + + if (skipped && + !time_after(jiffies, tid_agg_rx->reorder_time[j] + HT_RX_REORDER_BUF_TIMEOUT)) goto set_release_timer; @@ -706,6 +707,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, /* * If the current MPDU is in the right order and nothing else * is stored we can process it directly, no need to buffer it. + * If it is first but there's something stored, we may be able + * to release frames after this one. */ if (mpdu_seq_num == tid_agg_rx->head_seq_num && tid_agg_rx->stored_mpdu_num == 0) { @@ -2540,7 +2543,6 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx) * same TID from the same station */ rx->skb = skb; - rx->flags = 0; CALL_RXH(ieee80211_rx_h_decrypt) CALL_RXH(ieee80211_rx_h_check_more_data) @@ -2611,6 +2613,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) .sdata = sta->sdata, .local = sta->local, .queue = tid, + .flags = 0, }; struct tid_ampdu_rx *tid_agg_rx; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index d0311a322ddd..52d4b1a695c9 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_*() @@ -698,6 +698,8 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ cancel_work_sync(&sta->drv_unblock_wk); + cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); + rate_control_remove_sta_debugfs(sta); ieee80211_sta_debugfs_remove(sta); @@ -766,9 +768,8 @@ static void sta_info_cleanup(unsigned long data) if (!timer_needed) return; - local->sta_cleanup.expires = - round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); - add_timer(&local->sta_cleanup); + mod_timer(&local->sta_cleanup, + round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL)); } void sta_info_init(struct ieee80211_local *local) @@ -781,14 +782,6 @@ void sta_info_init(struct ieee80211_local *local) setup_timer(&local->sta_cleanup, sta_info_cleanup, (unsigned long)local); - local->sta_cleanup.expires = - round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); -} - -int sta_info_start(struct ieee80211_local *local) -{ - add_timer(&local->sta_cleanup); - return 0; } void sta_info_stop(struct ieee80211_local *local) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 57681149e37f..87b18ba1e0e9 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -173,7 +173,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 @@ -497,7 +497,6 @@ void sta_info_set_tim_bit(struct sta_info *sta); void sta_info_clear_tim_bit(struct sta_info *sta); void sta_info_init(struct ieee80211_local *local); -int sta_info_start(struct ieee80211_local *local); void sta_info_stop(struct ieee80211_local *local); int sta_info_flush(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/status.c b/net/mac80211/status.c index b936dd29e92b..3ed3c835fbbf 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -189,16 +189,19 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) bool acked; for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - /* the HW cannot have attempted that rate */ - if (i >= hw->max_report_rates) { + if (info->status.rates[i].idx < 0) { + break; + } else if (i >= hw->max_report_rates) { + /* the HW cannot have attempted that rate */ info->status.rates[i].idx = -1; info->status.rates[i].count = 0; - } else if (info->status.rates[i].idx >= 0) { - rates_idx = i; + break; } retry_count += info->status.rates[i].count; } + rates_idx = i - 1; + if (retry_count < 0) retry_count = 0; diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index e840c9cd46db..757e4eb2baf7 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -202,7 +202,7 @@ EXPORT_SYMBOL(ieee80211_get_tkip_key); * @payload_len is the length of payload (_not_ including IV/ICV length). * @ta is the transmitter addresses. */ -int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, +int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, struct ieee80211_key *key, u8 *pos, size_t payload_len, u8 *ta) { @@ -223,7 +223,7 @@ int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, * beginning of the buffer containing IEEE 802.11 header payload, i.e., * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the * length of payload, including IV, Ext. IV, MIC, ICV. */ -int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, +int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, struct ieee80211_key *key, u8 *payload, size_t payload_len, u8 *ta, u8 *ra, int only_iv, int queue, diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index 7e83dee976fa..1cab9c86978f 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h @@ -15,7 +15,7 @@ u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16); -int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, +int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, struct ieee80211_key *key, u8 *pos, size_t payload_len, u8 *ta); enum { @@ -24,7 +24,7 @@ enum { TKIP_DECRYPT_INVALID_KEYIDX = -2, TKIP_DECRYPT_REPLAY = -3, }; -int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, +int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, struct ieee80211_key *key, u8 *payload, size_t payload_len, u8 *ta, u8 *ra, int only_iv, int queue, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 556647a910ac..ef0560a2346a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1290,7 +1290,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) } } - add_timer(&local->sta_cleanup); + mod_timer(&local->sta_cleanup, jiffies + 1); mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 2ff6d1e3ed21..a1c6bfd55f0f 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -30,17 +30,15 @@ int ieee80211_wep_init(struct ieee80211_local *local) /* start WEP IV from a random value */ get_random_bytes(&local->wep_iv, WEP_IV_LEN); - local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); + local->wep_tx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(local->wep_tx_tfm)) { local->wep_rx_tfm = ERR_PTR(-EINVAL); return PTR_ERR(local->wep_tx_tfm); } - local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); + local->wep_rx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(local->wep_rx_tfm)) { - crypto_free_blkcipher(local->wep_tx_tfm); + crypto_free_cipher(local->wep_tx_tfm); local->wep_tx_tfm = ERR_PTR(-EINVAL); return PTR_ERR(local->wep_rx_tfm); } @@ -51,9 +49,9 @@ int ieee80211_wep_init(struct ieee80211_local *local) void ieee80211_wep_free(struct ieee80211_local *local) { if (!IS_ERR(local->wep_tx_tfm)) - crypto_free_blkcipher(local->wep_tx_tfm); + crypto_free_cipher(local->wep_tx_tfm); if (!IS_ERR(local->wep_rx_tfm)) - crypto_free_blkcipher(local->wep_rx_tfm); + crypto_free_cipher(local->wep_rx_tfm); } static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen) @@ -127,12 +125,11 @@ static void ieee80211_wep_remove_iv(struct ieee80211_local *local, /* Perform WEP encryption using given key. data buffer must have tailroom * for 4-byte ICV. data_len must not include this ICV. Note: this function * does _not_ add IV. data = RC4(data | CRC32(data)) */ -int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, +int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len) { - struct blkcipher_desc desc = { .tfm = tfm }; - struct scatterlist sg; __le32 icv; + int i; if (IS_ERR(tfm)) return -1; @@ -140,9 +137,9 @@ int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, icv = cpu_to_le32(~crc32_le(~0, data, data_len)); put_unaligned(icv, (__le32 *)(data + data_len)); - crypto_blkcipher_setkey(tfm, rc4key, klen); - sg_init_one(&sg, data, data_len + WEP_ICV_LEN); - crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length); + crypto_cipher_setkey(tfm, rc4key, klen); + for (i = 0; i < data_len + WEP_ICV_LEN; i++) + crypto_cipher_encrypt_one(tfm, data + i, data + i); return 0; } @@ -186,19 +183,18 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, /* Perform WEP decryption using given key. data buffer includes encrypted * payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV. * Return 0 on success and -1 on ICV mismatch. */ -int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, +int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len) { - struct blkcipher_desc desc = { .tfm = tfm }; - struct scatterlist sg; __le32 crc; + int i; if (IS_ERR(tfm)) return -1; - crypto_blkcipher_setkey(tfm, rc4key, klen); - sg_init_one(&sg, data, data_len + WEP_ICV_LEN); - crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length); + crypto_cipher_setkey(tfm, rc4key, klen); + for (i = 0; i < data_len + WEP_ICV_LEN; i++) + crypto_cipher_decrypt_one(tfm, data + i, data + i); crc = cpu_to_le32(~crc32_le(~0, data, data_len)); if (memcmp(&crc, data + data_len, WEP_ICV_LEN) != 0) diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 58654ee33518..01e54840a628 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -18,12 +18,12 @@ int ieee80211_wep_init(struct ieee80211_local *local); void ieee80211_wep_free(struct ieee80211_local *local); -int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, +int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, const u8 *key, int keylen, int keyidx); -int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, +int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index c3f988aa1152..32bff6d86cb2 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 bca96990218d..a113ff066928 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 5e790172deff..00a33242e90c 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c @@ -434,8 +434,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 165f09b1a9cb..6b38eb8f6ed8 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 d6b48230a540..9152e69a162d 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; } @@ -1068,7 +1091,7 @@ 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 */ diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index a47c32982f06..e9159e99fc4b 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 f289306cbf12..c97bd45975be 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 36f4495cfdbf..9930f340908a 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3117,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 f276df9896b3..87e40ea77a95 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 cb1c9913d38b..90f618ab6dda 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 b027ccc49f43..d12ed53ec95f 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 941286ca911d..2e1c11f78419 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 867882313e49..bcd5ed6b7130 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 533a183e6661..18b2ce5c8ced 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 9ae57c57c50e..2e664a69d7db 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 6f4ee70f460b..6772b1154654 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 bcf47eb518ef..237cc1981b89 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 0ae142825881..05e9feb101c3 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 5ab22e2bbd7d..5b466cd1272f 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 985e9b76c916..e0ee010935e7 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/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 6e6b46cb1db9..9e63b43faeed 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 2220b85e9519..b77d383cec78 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 2c0086a4751e..481a86fdc409 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/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index 5f14c8462e30..bae5756b1626 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 d37b7f80fa37..de0d8e4cbfb6 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 998e85e895d0..4f251b19fbcc 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 06cb02796a0e..732152f718e0 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/phonet/socket.c b/net/phonet/socket.c index b1adafab377c..8c5bfcef92cb 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 c47a511f203d..7c4dce8fa5e6 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 712cf2d1f28e..3a60a15d1b4a 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 59509e9a9e72..6deaa77495e3 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 6280ea020d4e..545d8ee3efb1 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 35b9c2e9caf1..d58ae5f9339e 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 a80aef6e3d1f..f9ea925ad9cb 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 08dcd2f29cdc..479cae57d187 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/sched/Kconfig b/net/sched/Kconfig index a7a5583d4f68..aeaa2110b699 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 2e77b8dba22e..dc5889c0a15a 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 15873e14cb54..14b42f4ad791 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 50c7c06c019d..7affe9a92757 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 a4de67eca824..49130e8abff0 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 e1429a85091f..29b942ce9e82 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 edbbf7ad6623..69c35f6cd13f 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 000000000000..103343408593 --- /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/sctp/associola.c b/net/sctp/associola.c index 6b04287913cd..1a21c571aa03 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 ddbbf7c81fa1..865e68fef21c 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/input.c b/net/sctp/input.c index 826661be73e7..5436c6921167 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -1034,7 +1034,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/output.c b/net/sctp/output.c index 60600d337a3a..b4f3cf06d8da 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 26dc005113a0..bf92a5b68f8b 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -177,13 +177,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, @@ -843,7 +843,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: diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index de98665db524..b3434cc7d0cf 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -3106,10 +3106,10 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, /* create an ASCONF_ACK chunk. * Based on the definitions of parameters, we know that the size of - * ASCONF_ACK parameters are less than or equal to the twice of ASCONF + * ASCONF_ACK parameters are less than or equal to the fourfold of ASCONF * parameters. */ - asconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 2); + asconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 4); if (!asconf_ack) goto done; diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index b21b218d564f..5f86ee4b54c1 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++; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 4b4eb7c96bbd..76792083c379 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -551,7 +551,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)) @@ -1546,7 +1546,7 @@ cleanup: } /* - * Handle simultanous INIT. + * Handle simultaneous INIT. * This means we started an INIT and then we got an INIT request from * our peer. * @@ -2079,7 +2079,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 +2120,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 +2381,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. */ @@ -2448,7 +2448,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. */ @@ -3855,7 +3855,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 +4231,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)) @@ -4402,9 +4402,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( diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 3951a10605bc..deb82e35a107 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1193,7 +1193,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. * diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index aa72e89c3ee1..dff27d5e22fd 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; diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 17678189d054..f2d1de7f2ffb 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 5212447c86e7..d25f5a9d6fa2 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 9022f0a6503e..0a9a2ec2e469 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 bcdae78fdfc6..8d0f7d3c71c8 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 1e336a06d3e6..bf005d3c65ef 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 43639ff1cbec..ebf338f7b14e 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 c9fa6dfcf287..80025a1b3bfd 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 1663e1a2efdd..3a43a8304768 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 11f25c7a7a05..f346395314ba 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/mlme.c b/net/wireless/mlme.c index aa5df8865ff7..16881fea4ce6 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -770,6 +770,15 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, } EXPORT_SYMBOL(cfg80211_new_sta); +void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp); +} +EXPORT_SYMBOL(cfg80211_del_sta); + struct cfg80211_mgmt_registration { struct list_head list; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4ebce4284e9d..297d7ce4117b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2002,7 +2002,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, const u8 *mac_addr, struct station_info *sinfo) { void *hdr; - struct nlattr *sinfoattr; + struct nlattr *sinfoattr, *bss_param; hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); if (!hdr) @@ -2062,6 +2062,25 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (sinfo->filled & STATION_INFO_TX_FAILED) NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, sinfo->tx_failed); + if (sinfo->filled & STATION_INFO_BSS_PARAM) { + bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); + if (!bss_param) + goto nla_put_failure; + + if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) + NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_CTS_PROT); + if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) + NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE); + if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) + NLA_PUT_FLAG(msg, + NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME); + NLA_PUT_U8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD, + sinfo->bss_param.dtim_period); + NLA_PUT_U16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL, + sinfo->bss_param.beacon_interval); + + nla_nest_end(msg, bss_param); + } nla_nest_end(msg, sinfoattr); return genlmsg_end(msg, hdr); @@ -5966,6 +5985,40 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, nl80211_mlme_mcgrp.id, gfp); } +void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_STATION); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct net_device *netdev, u32 nlpid, int freq, const u8 *buf, size_t len, gfp_t gfp) diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index e3f7fa886966..dcac5cd6f017 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -79,6 +79,9 @@ void nl80211_send_remain_on_channel_cancel( void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *mac_addr, struct station_info *sinfo, gfp_t gfp); +void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + gfp_t gfp); int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct net_device *netdev, u32 nlpid, int freq, diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 3332d5bce317..58d69959ab28 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -106,6 +106,9 @@ struct reg_beacon { static void reg_todo(struct work_struct *work); static DECLARE_WORK(reg_work, reg_todo); +static void reg_timeout_work(struct work_struct *work); +static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); + /* We keep a static world regulatory domain in case of the absence of CRDA */ static const struct ieee80211_regdomain world_regdom = { .n_reg_rules = 5, @@ -809,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, @@ -838,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 */ @@ -1330,6 +1333,9 @@ static void reg_set_request_processed(void) need_more_processing = true; spin_unlock(®_requests_lock); + if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) + cancel_delayed_work_sync(®_timeout); + if (need_more_processing) schedule_work(®_work); } @@ -1440,8 +1446,17 @@ static void reg_process_hint(struct regulatory_request *reg_request) r = __regulatory_hint(wiphy, reg_request); /* This is required so that the orig_* parameters are saved */ if (r == -EALREADY && wiphy && - wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) + wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { wiphy_update_regulatory(wiphy, initiator); + return; + } + + /* + * We only time out user hints, given that they should be the only + * source of bogus requests. + */ + if (reg_request->initiator == NL80211_REGDOM_SET_BY_USER) + schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); } /* @@ -1744,6 +1759,8 @@ static void restore_regulatory_settings(bool reset_user) { char alpha2[2]; struct reg_beacon *reg_beacon, *btmp; + struct regulatory_request *reg_request, *tmp; + LIST_HEAD(tmp_reg_req_list); mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex); @@ -1751,6 +1768,25 @@ static void restore_regulatory_settings(bool reset_user) reset_regdomains(); restore_alpha2(alpha2, reset_user); + /* + * If there's any pending requests we simply + * stash them to a temporary pending queue and + * add then after we've restored regulatory + * settings. + */ + spin_lock(®_requests_lock); + if (!list_empty(®_requests_list)) { + list_for_each_entry_safe(reg_request, tmp, + ®_requests_list, list) { + if (reg_request->initiator != + NL80211_REGDOM_SET_BY_USER) + continue; + list_del(®_request->list); + list_add_tail(®_request->list, &tmp_reg_req_list); + } + } + spin_unlock(®_requests_lock); + /* Clear beacon hints */ spin_lock_bh(®_pending_beacons_lock); if (!list_empty(®_pending_beacons)) { @@ -1785,8 +1821,31 @@ static void restore_regulatory_settings(bool reset_user) */ if (is_an_alpha2(alpha2)) regulatory_hint_user(user_alpha2); -} + if (list_empty(&tmp_reg_req_list)) + return; + + mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); + + spin_lock(®_requests_lock); + list_for_each_entry_safe(reg_request, tmp, &tmp_reg_req_list, list) { + REG_DBG_PRINT("Adding request for country %c%c back " + "into the queue\n", + reg_request->alpha2[0], + reg_request->alpha2[1]); + list_del(®_request->list); + list_add_tail(®_request->list, ®_requests_list); + } + spin_unlock(®_requests_lock); + + mutex_unlock(®_mutex); + mutex_unlock(&cfg80211_mutex); + + REG_DBG_PRINT("Kicking the queue\n"); + + schedule_work(®_work); +} void regulatory_hint_disconnect(void) { @@ -2125,6 +2184,13 @@ out: mutex_unlock(®_mutex); } +static void reg_timeout_work(struct work_struct *work) +{ + REG_DBG_PRINT("Timeout while waiting for CRDA to reply, " + "restoring regulatory settings"); + restore_regulatory_settings(true); +} + int __init regulatory_init(void) { int err = 0; @@ -2178,6 +2244,7 @@ void /* __init_or_exit */ regulatory_exit(void) struct reg_beacon *reg_beacon, *btmp; cancel_work_sync(®_work); + cancel_delayed_work_sync(®_timeout); mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index ea427f418f64..fbf6f33ae4d0 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -124,6 +124,15 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev, } /* must hold dev->bss_lock! */ +static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev, + struct cfg80211_internal_bss *bss) +{ + list_del_init(&bss->list); + rb_erase(&bss->rbn, &dev->bss_tree); + kref_put(&bss->ref, bss_release); +} + +/* must hold dev->bss_lock! */ void cfg80211_bss_expire(struct cfg80211_registered_device *dev) { struct cfg80211_internal_bss *bss, *tmp; @@ -134,9 +143,7 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev) continue; if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) continue; - list_del(&bss->list); - rb_erase(&bss->rbn, &dev->bss_tree); - kref_put(&bss->ref, bss_release); + __cfg80211_unlink_bss(dev, bss); expired = true; } @@ -585,16 +592,23 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, struct cfg80211_internal_bss *res; size_t ielen = len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - size_t privsz = wiphy->bss_priv_size; + size_t privsz; + + if (WARN_ON(!mgmt)) + return NULL; + + if (WARN_ON(!wiphy)) + return NULL; if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && (signal < 0 || signal > 100))) return NULL; - if (WARN_ON(!mgmt || !wiphy || - len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable))) + if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable))) return NULL; + privsz = wiphy->bss_priv_size; + res = kzalloc(sizeof(*res) + privsz + ielen, gfp); if (!res) return NULL; @@ -662,11 +676,8 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) spin_lock_bh(&dev->bss_lock); if (!list_empty(&bss->list)) { - list_del_init(&bss->list); + __cfg80211_unlink_bss(dev, bss); dev->bss_generation++; - rb_erase(&bss->rbn, &dev->bss_tree); - - kref_put(&bss->ref, bss_release); } spin_unlock_bh(&dev->bss_lock); } diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c index 406207515b5e..f77e4e75f914 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 25a810793968..c541b622ae16 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_user.c b/net/xfrm/xfrm_user.c index 3d15d3e1b2c4..5d1d60d3ca83 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 */ |
