aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2006-07-05 08:27:42 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2006-07-05 08:27:42 -0400
commitcf57a308436653f3094590202c77459aab250ff3 (patch)
tree8a9e7096e494141911147a1f24865c3d79d583c1 /net
parentfaac9bd0e3ce7cb0572ec66e0a426cacf6afa970 (diff)
parentca78f6baca863afe2e6a244a0fe94b3a70211d46 (diff)
Merge branch 'master'
Diffstat (limited to 'net')
-rw-r--r--net/8021q/vlan.c11
-rw-r--r--net/atm/clip.c3
-rw-r--r--net/ax25/ax25_ip.c23
-rw-r--r--net/ax25/ax25_route.c49
-rw-r--r--net/bluetooth/af_bluetooth.c20
-rw-r--r--net/bluetooth/hci_conn.c100
-rw-r--r--net/bluetooth/hci_core.c38
-rw-r--r--net/bluetooth/hci_event.c206
-rw-r--r--net/bluetooth/hci_sysfs.c211
-rw-r--r--net/bluetooth/l2cap.c361
-rw-r--r--net/bluetooth/rfcomm/core.c27
-rw-r--r--net/bluetooth/rfcomm/sock.c4
-rw-r--r--net/bluetooth/sco.c4
-rw-r--r--net/bridge/br_netlink.c3
-rw-r--r--net/core/skbuff.c7
-rw-r--r--net/core/sock.c111
-rw-r--r--net/ipv4/af_inet.c14
-rw-r--r--net/ipv4/route.c26
-rw-r--r--net/ipv4/tcp.c13
-rw-r--r--net/ipv4/tcp_ipv4.c4
-rw-r--r--net/ipv4/tcp_minisocks.c2
-rw-r--r--net/ipv6/ipv6_sockglue.c11
-rw-r--r--net/ipv6/netfilter/ip6_tables.c3
-rw-r--r--net/netlink/af_netlink.c8
-rw-r--r--net/netrom/af_netrom.c4
-rw-r--r--net/rose/af_rose.c7
-rw-r--r--net/rose/rose_dev.c5
-rw-r--r--net/sunrpc/rpc_pipe.c8
-rw-r--r--net/tipc/core.h5
-rw-r--r--net/tipc/link.c2
-rw-r--r--net/unix/af_unix.c14
31 files changed, 905 insertions, 399 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 3948949a609..458031bfff5 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -364,6 +364,14 @@ static void vlan_transfer_operstate(const struct net_device *dev, struct net_dev
}
}
+/*
+ * vlan network devices have devices nesting below it, and are a special
+ * "super class" of normal network devices; split their locks off into a
+ * separate class since they always nest.
+ */
+static struct lock_class_key vlan_netdev_xmit_lock_key;
+
+
/* Attach a VLAN device to a mac address (ie Ethernet Card).
* Returns the device that was created, or NULL if there was
* an error of some kind.
@@ -460,6 +468,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name,
vlan_setup);
+
if (new_dev == NULL)
goto out_unlock;
@@ -518,6 +527,8 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
if (register_netdevice(new_dev))
goto out_free_newdev;
+ lockdep_set_class(&new_dev->_xmit_lock, &vlan_netdev_xmit_lock_key);
+
new_dev->iflink = real_dev->ifindex;
vlan_transfer_operstate(real_dev, new_dev);
linkwatch_fire_event(new_dev); /* _MUST_ call rfc2863_policy() */
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 87a454f5c89..121bf6f4914 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -23,6 +23,7 @@
#include <linux/if.h> /* for IFF_UP */
#include <linux/inetdevice.h>
#include <linux/bitops.h>
+#include <linux/poison.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/rcupdate.h>
@@ -266,7 +267,7 @@ static void clip_neigh_destroy(struct neighbour *neigh)
DPRINTK("clip_neigh_destroy (neigh %p)\n", neigh);
if (NEIGH2ENTRY(neigh)->vccs)
printk(KERN_CRIT "clip_neigh_destroy: vccs != NULL !!!\n");
- NEIGH2ENTRY(neigh)->vccs = (void *) 0xdeadbeef;
+ NEIGH2ENTRY(neigh)->vccs = (void *) NEIGHBOR_DEAD;
}
static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb)
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
index 9be5c15e63d..136c3aefa9d 100644
--- a/net/ax25/ax25_ip.c
+++ b/net/ax25/ax25_ip.c
@@ -103,11 +103,13 @@ int ax25_rebuild_header(struct sk_buff *skb)
{
struct sk_buff *ourskb;
unsigned char *bp = skb->data;
- struct net_device *dev;
+ ax25_route *route;
+ struct net_device *dev = NULL;
ax25_address *src, *dst;
+ ax25_digi *digipeat = NULL;
ax25_dev *ax25_dev;
- ax25_route _route, *route = &_route;
ax25_cb *ax25;
+ char ip_mode = ' ';
dst = (ax25_address *)(bp + 1);
src = (ax25_address *)(bp + 8);
@@ -115,8 +117,12 @@ int ax25_rebuild_header(struct sk_buff *skb)
if (arp_find(bp + 1, skb))
return 1;
- route = ax25_rt_find_route(route, dst, NULL);
- dev = route->dev;
+ route = ax25_get_route(dst, NULL);
+ if (route) {
+ digipeat = route->digipeat;
+ dev = route->dev;
+ ip_mode = route->ip_mode;
+ };
if (dev == NULL)
dev = skb->dev;
@@ -126,7 +132,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
}
if (bp[16] == AX25_P_IP) {
- if (route->ip_mode == 'V' || (route->ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
+ if (ip_mode == 'V' || (ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
/*
* We copy the buffer and release the original thereby
* keeping it straight
@@ -172,7 +178,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
ourskb,
ax25_dev->values[AX25_VALUES_PACLEN],
&src_c,
- &dst_c, route->digipeat, dev);
+ &dst_c, digipeat, dev);
if (ax25) {
ax25_cb_put(ax25);
}
@@ -190,7 +196,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
skb_pull(skb, AX25_KISS_HEADER_LEN);
- if (route->digipeat != NULL) {
+ if (digipeat != NULL) {
if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
kfree_skb(skb);
goto put;
@@ -202,7 +208,8 @@ int ax25_rebuild_header(struct sk_buff *skb)
ax25_queue_xmit(skb, dev);
put:
- ax25_put_route(route);
+ if (route)
+ ax25_put_route(route);
return 1;
}
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index 5ac98250797..51b7bdaf27e 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -41,8 +41,6 @@
static ax25_route *ax25_route_list;
static DEFINE_RWLOCK(ax25_route_lock);
-static ax25_route *ax25_get_route(ax25_address *, struct net_device *);
-
void ax25_rt_device_down(struct net_device *dev)
{
ax25_route *s, *t, *ax25_rt;
@@ -115,7 +113,7 @@ static int ax25_rt_add(struct ax25_routes_struct *route)
return -ENOMEM;
}
- atomic_set(&ax25_rt->ref, 0);
+ atomic_set(&ax25_rt->refcount, 1);
ax25_rt->callsign = route->dest_addr;
ax25_rt->dev = ax25_dev->dev;
ax25_rt->digipeat = NULL;
@@ -140,23 +138,10 @@ static int ax25_rt_add(struct ax25_routes_struct *route)
return 0;
}
-static void ax25_rt_destroy(ax25_route *ax25_rt)
+void __ax25_put_route(ax25_route *ax25_rt)
{
- if (atomic_read(&ax25_rt->ref) == 0) {
- kfree(ax25_rt->digipeat);
- kfree(ax25_rt);
- return;
- }
-
- /*
- * Uh... Route is still in use; we can't yet destroy it. Retry later.
- */
- init_timer(&ax25_rt->timer);
- ax25_rt->timer.data = (unsigned long) ax25_rt;
- ax25_rt->timer.function = (void *) ax25_rt_destroy;
- ax25_rt->timer.expires = jiffies + 5 * HZ;
-
- add_timer(&ax25_rt->timer);
+ kfree(ax25_rt->digipeat);
+ kfree(ax25_rt);
}
static int ax25_rt_del(struct ax25_routes_struct *route)
@@ -177,12 +162,12 @@ static int ax25_rt_del(struct ax25_routes_struct *route)
ax25cmp(&route->dest_addr, &s->callsign) == 0) {
if (ax25_route_list == s) {
ax25_route_list = s->next;
- ax25_rt_destroy(s);
+ ax25_put_route(s);
} else {
for (t = ax25_route_list; t != NULL; t = t->next) {
if (t->next == s) {
t->next = s->next;
- ax25_rt_destroy(s);
+ ax25_put_route(s);
break;
}
}
@@ -362,7 +347,7 @@ struct file_operations ax25_route_fops = {
*
* Only routes with a reference count of zero can be destroyed.
*/
-static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
+ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
{
ax25_route *ax25_spe_rt = NULL;
ax25_route *ax25_def_rt = NULL;
@@ -392,7 +377,7 @@ static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
ax25_rt = ax25_spe_rt;
if (ax25_rt != NULL)
- atomic_inc(&ax25_rt->ref);
+ ax25_hold_route(ax25_rt);
read_unlock(&ax25_route_lock);
@@ -467,24 +452,6 @@ put:
return 0;
}
-ax25_route *ax25_rt_find_route(ax25_route * route, ax25_address *addr,
- struct net_device *dev)
-{
- ax25_route *ax25_rt;
-
- if ((ax25_rt = ax25_get_route(addr, dev)))
- return ax25_rt;
-
- route->next = NULL;
- atomic_set(&route->ref, 1);
- route->callsign = *addr;
- route->dev = dev;
- route->digipeat = NULL;
- route->ip_mode = ' ';
-
- return route;
-}
-
struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
ax25_address *dest, ax25_digi *digi)
{
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 51f867062e1..788ea7a2b74 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -48,7 +48,7 @@
#define BT_DBG(D...)
#endif
-#define VERSION "2.8"
+#define VERSION "2.10"
/* Bluetooth sockets */
#define BT_MAX_PROTO 8
@@ -307,13 +307,21 @@ static struct net_proto_family bt_sock_family_ops = {
static int __init bt_init(void)
{
+ int err;
+
BT_INFO("Core ver %s", VERSION);
- sock_register(&bt_sock_family_ops);
+ err = bt_sysfs_init();
+ if (err < 0)
+ return err;
- BT_INFO("HCI device and connection manager initialized");
+ err = sock_register(&bt_sock_family_ops);
+ if (err < 0) {
+ bt_sysfs_cleanup();
+ return err;
+ }
- bt_sysfs_init();
+ BT_INFO("HCI device and connection manager initialized");
hci_sock_init();
@@ -324,9 +332,9 @@ static void __exit bt_exit(void)
{
hci_sock_cleanup();
- bt_sysfs_cleanup();
-
sock_unregister(PF_BLUETOOTH);
+
+ bt_sysfs_cleanup();
}
subsys_initcall(bt_init);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 5c0c2b1ef34..420ed4d7e57 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -115,8 +115,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
static void hci_conn_timeout(unsigned long arg)
{
- struct hci_conn *conn = (void *)arg;
- struct hci_dev *hdev = conn->hdev;
+ struct hci_conn *conn = (void *) arg;
+ struct hci_dev *hdev = conn->hdev;
BT_DBG("conn %p state %d", conn, conn->state);
@@ -132,11 +132,13 @@ static void hci_conn_timeout(unsigned long arg)
return;
}
-static void hci_conn_init_timer(struct hci_conn *conn)
+static void hci_conn_idle(unsigned long arg)
{
- init_timer(&conn->timer);
- conn->timer.function = hci_conn_timeout;
- conn->timer.data = (unsigned long)conn;
+ struct hci_conn *conn = (void *) arg;
+
+ BT_DBG("conn %p mode %d", conn, conn->mode);
+
+ hci_conn_enter_sniff_mode(conn);
}
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
@@ -145,17 +147,27 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
BT_DBG("%s dst %s", hdev->name, batostr(dst));
- if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
+ conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC);
+ if (!conn)
return NULL;
- memset(conn, 0, sizeof(struct hci_conn));
bacpy(&conn->dst, dst);
- conn->type = type;
conn->hdev = hdev;
+ conn->type = type;
+ conn->mode = HCI_CM_ACTIVE;
conn->state = BT_OPEN;
+ conn->power_save = 1;
+
skb_queue_head_init(&conn->data_q);
- hci_conn_init_timer(conn);
+
+ init_timer(&conn->disc_timer);
+ conn->disc_timer.function = hci_conn_timeout;
+ conn->disc_timer.data = (unsigned long) conn;
+
+ init_timer(&conn->idle_timer);
+ conn->idle_timer.function = hci_conn_idle;
+ conn->idle_timer.data = (unsigned long) conn;
atomic_set(&conn->refcnt, 0);
@@ -178,7 +190,9 @@ int hci_conn_del(struct hci_conn *conn)
BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
- hci_conn_del_timer(conn);
+ del_timer(&conn->idle_timer);
+
+ del_timer(&conn->disc_timer);
if (conn->type == SCO_LINK) {
struct hci_conn *acl = conn->link;
@@ -364,6 +378,70 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
}
EXPORT_SYMBOL(hci_conn_switch_role);
+/* Enter active mode */
+void hci_conn_enter_active_mode(struct hci_conn *conn)
+{
+ struct hci_dev *hdev = conn->hdev;
+
+ BT_DBG("conn %p mode %d", conn, conn->mode);
+
+ if (test_bit(HCI_RAW, &hdev->flags))
+ return;
+
+ if (conn->mode != HCI_CM_SNIFF || !conn->power_save)
+ goto timer;
+
+ if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+ struct hci_cp_exit_sniff_mode cp;
+ cp.handle = __cpu_to_le16(conn->handle);
+ hci_send_cmd(hdev, OGF_LINK_POLICY,
+ OCF_EXIT_SNIFF_MODE, sizeof(cp), &cp);
+ }
+
+timer:
+ if (hdev->idle_timeout > 0)
+ mod_timer(&conn->idle_timer,
+ jiffies + msecs_to_jiffies(hdev->idle_timeout));
+}
+
+/* Enter sniff mode */
+void hci_conn_enter_sniff_mode(struct hci_conn *conn)
+{
+ struct hci_dev *hdev = conn->hdev;
+
+ BT_DBG("conn %p mode %d", conn, conn->mode);
+
+ if (test_bit(HCI_RAW, &hdev->flags))
+ return;
+
+ if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn))
+ return;
+
+ if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF))
+ return;
+
+ if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
+ struct hci_cp_sniff_subrate cp;
+ cp.handle = __cpu_to_le16(conn->handle);
+ cp.max_latency = __constant_cpu_to_le16(0);
+ cp.min_remote_timeout = __constant_cpu_to_le16(0);
+ cp.min_local_timeout = __constant_cpu_to_le16(0);
+ hci_send_cmd(hdev, OGF_LINK_POLICY,
+ OCF_SNIFF_SUBRATE, sizeof(cp), &cp);
+ }
+
+ if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+ struct hci_cp_sniff_mode cp;
+ cp.handle = __cpu_to_le16(conn->handle);
+ cp.max_interval = __cpu_to_le16(hdev->sniff_max_interval);
+ cp.min_interval = __cpu_to_le16(hdev->sniff_min_interval);
+ cp.attempt = __constant_cpu_to_le16(4);
+ cp.timeout = __constant_cpu_to_le16(1);
+ hci_send_cmd(hdev, OGF_LINK_POLICY,
+ OCF_SNIFF_MODE, sizeof(cp), &cp);
+ }
+}
+
/* Drop all connection on the device */
void hci_conn_hash_flush(struct hci_dev *hdev)
{
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index f67240beb0d..54e8e5ea215 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -411,7 +411,7 @@ int hci_inquiry(void __user *arg)
}
hci_dev_unlock_bh(hdev);
- timeo = ir.length * 2 * HZ;
+ timeo = ir.length * msecs_to_jiffies(2000);
if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
goto done;
@@ -479,7 +479,8 @@ int hci_dev_open(__u16 dev)
set_bit(HCI_INIT, &hdev->flags);
//__hci_request(hdev, hci_reset_req, 0, HZ);
- ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
+ ret = __hci_request(hdev, hci_init_req, 0,
+ msecs_to_jiffies(HCI_INIT_TIMEOUT));
clear_bit(HCI_INIT, &hdev->flags);
}
@@ -546,7 +547,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
atomic_set(&hdev->cmd_cnt, 1);
if (!test_bit(HCI_RAW, &hdev->flags)) {
set_bit(HCI_INIT, &hdev->flags);
- __hci_request(hdev, hci_reset_req, 0, HZ/4);
+ __hci_request(hdev, hci_reset_req, 0,
+ msecs_to_jiffies(250));
clear_bit(HCI_INIT, &hdev->flags);
}
@@ -619,7 +621,8 @@ int hci_dev_reset(__u16 dev)
hdev->acl_cnt = 0; hdev->sco_cnt = 0;
if (!test_bit(HCI_RAW, &hdev->flags))
- ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
+ ret = __hci_request(hdev, hci_reset_req, 0,
+ msecs_to_jiffies(HCI_INIT_TIMEOUT));
done:
tasklet_enable(&hdev->tx_task);
@@ -657,7 +660,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
switch (cmd) {
case HCISETAUTH:
- err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+ err = hci_request(hdev, hci_auth_req, dr.dev_opt,
+ msecs_to_jiffies(HCI_INIT_TIMEOUT));
break;
case HCISETENCRYPT:
@@ -668,18 +672,19 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
if (!test_bit(HCI_AUTH, &hdev->flags)) {
/* Auth must be enabled first */
- err = hci_request(hdev, hci_auth_req,
- dr.dev_opt, HCI_INIT_TIMEOUT);
+ err = hci_request(hdev, hci_auth_req, dr.dev_opt,
+ msecs_to_jiffies(HCI_INIT_TIMEOUT));
if (err)
break;
}
- err = hci_request(hdev, hci_encrypt_req,
- dr.dev_opt, HCI_INIT_TIMEOUT);
+ err = hci_request(hdev, hci_encrypt_req, dr.dev_opt,
+ msecs_to_jiffies(HCI_INIT_TIMEOUT));
break;
case HCISETSCAN:
- err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+ err = hci_request(hdev, hci_scan_req, dr.dev_opt,
+ msecs_to_jiffies(HCI_INIT_TIMEOUT));
break;
case HCISETPTYPE:
@@ -812,8 +817,8 @@ void hci_free_dev(struct hci_dev *hdev)
{
skb_queue_purge(&hdev->driver_init);
- /* will free via class release */
- class_device_put(&hdev->class_dev);
+ /* will free via device release */
+ put_device(&hdev->dev);
}
EXPORT_SYMBOL(hci_free_dev);
@@ -848,6 +853,10 @@ int hci_register_dev(struct hci_dev *hdev)
hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
hdev->link_mode = (HCI_LM_ACCEPT);
+ hdev->idle_timeout = 0;
+ hdev->sniff_max_interval = 800;
+ hdev->sniff_min_interval = 80;
+
tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev);
tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
@@ -1220,6 +1229,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len);
+
+ hci_conn_enter_active_mode(conn);
+
hci_send_frame(skb);
hdev->acl_last_tx = jiffies;
@@ -1298,6 +1310,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
if (conn) {
register struct hci_proto *hp;
+ hci_conn_enter_active_mode(conn);
+
/* Send to upper protocol */
if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) {
hp->recv_acldata(conn, skb, flags);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 618bacee1b1..3896dabab11 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -83,6 +83,8 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *
{
struct hci_conn *conn;
struct hci_rp_role_discovery *rd;
+ struct hci_rp_write_link_policy *lp;
+ void *sent;
BT_DBG("%s ocf 0x%x", hdev->name, ocf);
@@ -106,6 +108,27 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *
hci_dev_unlock(hdev);
break;
+ case OCF_WRITE_LINK_POLICY:
+ sent = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY);
+ if (!sent)
+ break;
+
+ lp = (struct hci_rp_write_link_policy *) skb->data;
+
+ if (lp->status)
+ break;
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(lp->handle));
+ if (conn) {
+ __le16 policy = get_unaligned((__le16 *) (sent + 2));
+ conn->link_policy = __le16_to_cpu(policy);
+ }
+
+ hci_dev_unlock(hdev);
+ break;
+
default:
BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x",
hdev->name, ocf);
@@ -274,7 +297,7 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
/* Command Complete OGF INFO_PARAM */
static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
{
- struct hci_rp_read_loc_features *lf;
+ struct hci_rp_read_local_features *lf;
struct hci_rp_read_buffer_size *bs;
struct hci_rp_read_bd_addr *ba;
@@ -282,7 +305,7 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
switch (ocf) {
case OCF_READ_LOCAL_FEATURES:
- lf = (struct hci_rp_read_loc_features *) skb->data;
+ lf = (struct hci_rp_read_local_features *) skb->data;
if (lf->status) {
BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
@@ -319,9 +342,17 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
}
hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu);
- hdev->sco_mtu = bs->sco_mtu ? bs->sco_mtu : 64;
- hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
- hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
+ hdev->sco_mtu = bs->sco_mtu;
+ hdev->acl_pkts = __le16_to_cpu(bs->acl_max_pkt);
+ hdev->sco_pkts = __le16_to_cpu(bs->sco_max_pkt);
+
+ if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
+ hdev->sco_mtu = 64;
+ hdev->sco_pkts = 8;
+ }
+
+ hdev->acl_cnt = hdev->acl_pkts;
+ hdev->sco_cnt = hdev->sco_pkts;
BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
@@ -439,8 +470,46 @@ static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
BT_DBG("%s ocf 0x%x", hdev->name, ocf);
switch (ocf) {
+ case OCF_SNIFF_MODE:
+ if (status) {
+ struct hci_conn *conn;
+ struct hci_cp_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_SNIFF_MODE);
+
+ if (!cp)
+ break;
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+ if (conn) {
+ clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+ }
+
+ hci_dev_unlock(hdev);
+ }
+ break;
+
+ case OCF_EXIT_SNIFF_MODE:
+ if (status) {
+ struct hci_conn *conn;
+ struct hci_cp_exit_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_EXIT_SNIFF_MODE);
+
+ if (!cp)
+ break;
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+ if (conn) {
+ clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+ }
+
+ hci_dev_unlock(hdev);
+ }
+ break;
+
default:
- BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
+ BT_DBG("%s Command status: ogf LINK_POLICY ocf %x", hdev->name, ocf);
break;
}
}
@@ -622,14 +691,16 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
else
cp.role = 0x01; /* Remain slave */
- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp);
+ hci_send_cmd(hdev, OGF_LINK_CTL,
+ OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp);
} else {
/* Connection rejected */
struct hci_cp_reject_conn_req cp;
bacpy(&cp.bdaddr, &ev->bdaddr);
cp.reason = 0x0f;
- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ, sizeof(cp), &cp);
+ hci_send_cmd(hdev, OGF_LINK_CTL,
+ OCF_REJECT_CONN_REQ, sizeof(cp), &cp);
}
}
@@ -637,7 +708,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data;
- struct hci_conn *conn = NULL;
+ struct hci_conn *conn;
BT_DBG("%s", hdev->name);
@@ -659,12 +730,21 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
if (test_bit(HCI_ENCRYPT, &hdev->flags))
conn->link_mode |= HCI_LM_ENCRYPT;
+ /* Get remote features */
+ if (conn->type == ACL_LINK) {
+ struct hci_cp_read_remote_features cp;
+ cp.handle = ev->handle;
+ hci_send_cmd(hdev, OGF_LINK_CTL,
+ OCF_READ_REMOTE_FEATURES, sizeof(cp), &cp);
+ }
+
/* Set link policy */
if (conn->type == ACL_LINK && hdev->link_policy) {
struct hci_cp_write_link_policy cp;
cp.handle = ev->handle;
cp.policy = __cpu_to_le16(hdev->link_policy);
- hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY, sizeof(cp), &cp);
+ hci_send_cmd(hdev, OGF_LINK_POLICY,
+ OCF_WRITE_LINK_POLICY, sizeof(cp), &cp);
}
/* Set packet type for incoming connection */
@@ -675,7 +755,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
__cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
__cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
+ hci_send_cmd(hdev, OGF_LINK_CTL,
+ OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
}
} else
conn->state = BT_CLOSED;
@@ -703,8 +784,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_disconn_complete *ev = (struct hci_ev_disconn_complete *) skb->data;
- struct hci_conn *conn = NULL;
- __u16 handle = __le16_to_cpu(ev->handle);
+ struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status);
@@ -713,7 +793,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, handle);
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
conn->state = BT_CLOSED;
hci_proto_disconn_ind(conn, ev->reason);
@@ -770,7 +850,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_role_change *ev = (struct hci_ev_role_change *) skb->data;
- struct hci_conn *conn = NULL;
+ struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status);
@@ -793,18 +873,43 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
hci_dev_unlock(hdev);
}
+/* Mode Change */
+static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_ev_mode_change *ev = (struct hci_ev_mode_change *) skb->data;
+ struct hci_conn *conn;
+
+ BT_DBG("%s status %d", hdev->name, ev->status);
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+ if (conn) {
+ conn->mode = ev->mode;
+ conn->interval = __le16_to_cpu(ev->interval);
+
+ if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+ if (conn->mode == HCI_CM_ACTIVE)
+ conn->power_save = 1;
+ else
+ conn->power_save = 0;
+ }
+ }
+
+ hci_dev_unlock(hdev);
+}
+
/* Authentication Complete */
static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_auth_complete *ev = (struct hci_ev_auth_complete *) skb->data;
- struct hci_conn *conn = NULL;
- __u16 handle = __le16_to_cpu(ev->handle);
+ struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status);
hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, handle);
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
if (!ev->status)
conn->link_mode |= HCI_LM_AUTH;
@@ -819,8 +924,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
cp.handle = __cpu_to_le16(conn->handle);
cp.encrypt = 1;
hci_send_cmd(conn->hdev, OGF_LINK_CTL,
- OCF_SET_CONN_ENCRYPT,
- sizeof(cp), &cp);
+ OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp);
} else {
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
hci_encrypt_cfm(conn, ev->status, 0x00);
@@ -835,14 +939,13 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_encrypt_change *ev = (struct hci_ev_encrypt_change *) skb->data;
- struct hci_conn *conn = NULL;
- __u16 handle = __le16_to_cpu(ev->handle);
+ struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status);
hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, handle);
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
if (!ev->status) {
if (ev->encrypt)
@@ -863,14 +966,13 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) skb->data;
- struct hci_conn *conn = NULL;
- __u16 handle = __le16_to_cpu(ev->handle);
+ struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status);
hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, handle);
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
if (!ev->status)
conn->link_mode |= HCI_LM_SECURE;
@@ -898,18 +1000,35 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
{
}
+/* Remote Features */
+static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_ev_remote_features *ev = (struct hci_ev_remote_features *) skb->data;
+ struct hci_conn *conn;
+
+ BT_DBG("%s status %d", hdev->name, ev->status);
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+ if (conn && !ev->status) {
+ memcpy(conn->features, ev->features, sizeof(conn->features));
+ }
+
+ hci_dev_unlock(hdev);
+}
+
/* Clock Offset */
static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_clock_offset *ev = (struct hci_ev_clock_offset *) skb->data;
- struct hci_conn *conn = NULL;
- __u16 handle = __le16_to_cpu(ev->handle);
+ struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status);
hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, handle);
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn && !ev->status) {
struct inquiry_entry *ie;
@@ -940,6 +1059,23 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *
hci_dev_unlock(hdev);
}
+/* Sniff Subrate */
+static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_ev_sniff_subrate *ev = (struct hci_ev_sniff_subrate *) skb->data;
+ struct hci_conn *conn;
+
+ BT_DBG("%s status %d", hdev->name, ev->status);
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+ if (conn) {
+ }
+
+ hci_dev_unlock(hdev);
+}
+
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data;
@@ -988,6 +1124,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_role_change_evt(hdev, skb);
break;
+ case HCI_EV_MODE_CHANGE:
+ hci_mode_change_evt(hdev, skb);
+ break;
+
case HCI_EV_AUTH_COMPLETE:
hci_auth_complete_evt(hdev, skb);
break;
@@ -1012,6 +1152,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_link_key_notify_evt(hdev, skb);
break;
+ case HCI_EV_REMOTE_FEATURES:
+ hci_remote_features_evt(hdev, skb);
+ break;
+
case HCI_EV_CLOCK_OFFSET:
hci_clock_offset_evt(hdev, skb);
break;
@@ -1020,6 +1164,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_pscan_rep_mode_evt(hdev, skb);
break;
+ case HCI_EV_SNIFF_SUBRATE:
+ hci_sniff_subrate_evt(hdev, skb);
+ break;
+
case HCI_EV_CMD_STATUS:
cs = (struct hci_ev_cmd_status *) skb->data;
skb_pull(skb, sizeof(cs));
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 19b234c86f3..3987d167f04 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -3,6 +3,8 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
+
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -11,35 +13,35 @@
#define BT_DBG(D...)
#endif
-static ssize_t show_name(struct class_device *cdev, char *buf)
+static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct hci_dev *hdev = class_get_devdata(cdev);
+ struct hci_dev *hdev = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", hdev->name);
}
-static ssize_t show_type(struct class_device *cdev, char *buf)
+static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct hci_dev *hdev = class_get_devdata(cdev);
+ struct hci_dev *hdev = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", hdev->type);
}
-static ssize_t show_address(struct class_device *cdev, char *buf)
+static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct hci_dev *hdev = class_get_devdata(cdev);
+ struct hci_dev *hdev = dev_get_drvdata(dev);
bdaddr_t bdaddr;
baswap(&bdaddr, &hdev->bdaddr);
return sprintf(buf, "%s\n", batostr(&bdaddr));
}
-static ssize_t show_flags(struct class_device *cdev, char *buf)
+static ssize_t show_flags(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct hci_dev *hdev = class_get_devdata(cdev);
+ struct hci_dev *hdev = dev_get_drvdata(dev);
return sprintf(buf, "0x%lx\n", hdev->flags);
}
-static ssize_t show_inquiry_cache(struct class_device *cdev, char *buf)
+static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct hci_dev *hdev = class_get_devdata(cdev);
+ struct hci_dev *hdev = dev_get_drvdata(dev);
struct inquiry_cache *cache = &hdev->inq_cache;
struct inquiry_entry *e;
int n = 0;
@@ -61,94 +63,193 @@ static ssize_t show_inquiry_cache(struct class_device *cdev, char *buf)
return n;
}
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-static CLASS_DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
-static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
-static CLASS_DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
-static CLASS_DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL);
+static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct hci_dev *hdev = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", hdev->idle_timeout);
+}
-static struct class_device_attribute *bt_attrs[] = {
- &class_device_attr_name,
- &class_device_attr_type,
- &class_device_attr_address,
- &class_device_attr_flags,
- &class_device_attr_inquiry_cache,
- NULL
-};
+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);
+ char *ptr;
+ __u32 val;
+
+ val = simple_strtoul(buf, &ptr, 10);
+ if (ptr == buf)
+ return -EINVAL;
-#ifdef CONFIG_HOTPLUG
-static int bt_uevent(struct class_device *cdev, char **envp, int num_envp, char *buf, int size)
+ if (val != 0 && (val < 500 || val > 3600000))
+ return -EINVAL;
+
+ hdev->idle_timeout = val;
+
+ return count;
+}
+
+static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct hci_dev *hdev = class_get_devdata(cdev);
- int n, i = 0;
+ struct hci_dev *hdev = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", hdev->sniff_max_interval);
+}
- envp[i++] = buf;
- n = snprintf(buf, size, "INTERFACE=%s", hdev->name) + 1;
- buf += n;
- size -= n;
+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);
+ char *ptr;
+ __u16 val;
- if ((size <= 0) || (i >= num_envp))
- return -ENOMEM;
+ val = simple_strtoul(buf, &ptr, 10);
+ if (ptr == buf)
+ return -EINVAL;
- envp[i] = NULL;
- return 0;
+ if (val < 0x0002 || val > 0xFFFE || val % 2)
+ return -EINVAL;
+
+ if (val < hdev->sniff_min_interval)
+ return -EINVAL;
+
+ hdev->sniff_max_interval = val;
+
+ return count;
+}
+
+static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct hci_dev *hdev = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", hdev->sniff_min_interval);
}
-#endif
-static void bt_release(struct class_device *cdev)
+static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct hci_dev *hdev = class_get_devdata(cdev);
+ struct hci_dev *hdev = dev_get_drvdata(dev);
+ char *ptr;
+ __u16 val;
- kfree(hdev);
+ val = simple_strtoul(buf, &ptr, 10);
+ if (ptr == buf)
+ return -EINVAL;
+
+ if (val < 0x0002 || val > 0xFFFE || val % 2)
+ return -EINVAL;
+
+ if (val > hdev->sniff_max_interval)
+ return -EINVAL;
+
+ hdev->sniff_min_interval = val;
+
+ return count;
}
-struct class bt_class = {
- .name = "bluetooth",
- .release = bt_release,
-#ifdef CONFIG_HOTPLUG
- .uevent = bt_uevent,
-#endif
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
+static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
+static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
+static DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL);
+
+static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR,
+ show_idle_timeout, store_idle_timeout);
+static DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR,
+ show_sniff_max_interval, store_sniff_max_interval);
+static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
+ show_sniff_min_interval, store_sniff_min_interval);
+
+static struct device_attribute *bt_attrs[] = {
+ &dev_attr_name,
+ &dev_attr_type,
+ &dev_attr_address,
+ &dev_attr_flags,
+ &dev_attr_inquiry_cache,
+ &dev_attr_idle_timeout,
+ &dev_attr_sniff_max_interval,
+ &dev_attr_sniff_min_interval,
+ NULL
};
+struct class *bt_class = NULL;
EXPORT_SYMBOL_GPL(bt_class);
+static struct bus_type bt_bus = {
+ .name = "bluetooth",
+};
+
+static struct platform_device *bt_platform;
+
+static void bt_release(struct device *dev)
+{
+ struct hci_dev *hdev = dev_get_drvdata(dev);
+ kfree(hdev);
+}
+
int hci_register_sysfs(struct hci_dev *hdev)
{
- struct class_device *cdev = &hdev->class_dev;
+ struct device *dev = &hdev->dev;
unsigned int i;
int err;
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
- cdev->class = &bt_class;
- class_set_devdata(cdev, hdev);
+ dev->class = bt_class;
+
+ if (hdev->parent)
+ dev->parent = hdev->parent;
+ else
+ dev->parent = &bt_platform->dev;
+
+ strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE);
+
+ dev->release = bt_release;
- strlcpy(cdev->class_id, hdev->name, BUS_ID_SIZE);
- err = class_device_register(cdev);
+ dev_set_drvdata(dev, hdev);
+
+ err = device_register(dev);
if (err < 0)
return err;
for (i = 0; bt_attrs[i]; i++)
- class_device_create_file(cdev, bt_attrs[i]);
+ device_create_file(dev, bt_attrs[i]);
return 0;
}
void hci_unregister_sysfs(struct hci_dev *hdev)
{
- struct class_device * cdev = &hdev->class_dev;
+ struct device *dev = &hdev->dev;
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
- class_device_del(cdev);
+ device_del(dev);
}
int __init bt_sysfs_init(void)
{
- return class_register(&bt_class);
+ int err;
+
+ bt_platform = platform_device_register_simple("bluetooth", -1, NULL, 0);
+ if (IS_ERR(bt_platform))
+ return PTR_ERR(bt_platform);
+
+ err = bus_register(&bt_bus);
+ if (err < 0) {
+ platform_device_unregister(bt_platform);
+ return err;
+ }
+
+ bt_class = class_create(THIS_MODULE, "bluetooth");
+ if (IS_ERR(bt_class)) {
+ bus_unregister(&bt_bus);
+ platform_device_unregister(bt_platform);
+ return PTR_ERR(bt_class);
+ }
+
+ return 0;
}
void __exit bt_sysfs_cleanup(void)
{
- class_unregister(&bt_class);
+ class_destroy(bt_class);
+
+ bus_unregister(&bt_bus);
+
+ platform_device_unregister(bt_platform);
}
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 770101177da..eaaad658d11 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -63,11 +63,6 @@ static struct bt_sock_list l2cap_sk_list = {
.lock = RW_LOCK_UNLOCKED
};
-static int l2cap_conn_del(struct hci_conn *conn, int err);
-
-static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
-static void l2cap_chan_del(struct sock *sk, int err);
-
static void __l2cap_sock_close(struct sock *sk, int reason);
static void l2cap_sock_close(struct sock *sk);
static void l2cap_sock_kill(struct sock *sk);
@@ -109,24 +104,177 @@ static void l2cap_sock_init_timer(struct sock *sk)
sk->sk_timer.data = (unsigned long)sk;
}
+/* ---- L2CAP channels ---- */
+static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
+{
+ struct sock *s;
+ for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+ if (l2cap_pi(s)->dcid == cid)
+ break;
+ }
+ return s;
+}
+
+static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid)
+{
+ struct sock *s;
+ for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+ if (l2cap_pi(s)->scid == cid)
+ break;
+ }
+ return s;
+}
+
+/* Find channel with given SCID.
+ * Returns locked socket */
+static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid)
+{
+ struct sock *s;
+ read_lock(&l->lock);
+ s = __l2cap_get_chan_by_scid(l, cid);
+ if (s) bh_lock_sock(s);
+ read_unlock(&l->lock);
+ return s;
+}
+
+static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
+{
+ struct sock *s;
+ for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+ if (l2cap_pi(s)->ident == ident)
+ break;
+ }
+ return s;
+}
+
+static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
+{
+ struct sock *s;
+ read_lock(&l->lock);
+ s = __l2cap_get_chan_by_ident(l, ident);
+ if (s) bh_lock_sock(s);
+ read_unlock(&l->lock);
+ return s;
+}
+
+static u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
+{
+ u16 cid = 0x0040;
+
+ for (; cid < 0xffff; cid++) {
+ if(!__l2cap_get_chan_by_scid(l, cid))
+ return cid;
+ }
+
+ return 0;
+}
+
+static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
+{
+ sock_hold(sk);
+
+ if (l->head)
+ l2cap_pi(l->head)->prev_c = sk;
+
+ l2cap_pi(sk)->next_c = l->head;
+ l2cap_pi(sk)->prev_c = NULL;
+ l->head = sk;
+}
+
+static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
+{
+ struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
+
+ write_lock(&l->lock);
+ if (sk == l->head)
+ l->head = next;
+
+ if (next)
+ l2cap_pi(next)->prev_c = prev;
+ if (prev)
+ l2cap_pi(prev)->next_c = next;
+ write_unlock(&l->lock);
+
+ __sock_put(sk);
+}
+
+static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+{
+ struct l2cap_chan_list *l = &conn->chan_list;
+
+ BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
+
+ l2cap_pi(sk)->conn = conn;
+
+ if (sk->sk_type == SOCK_SEQPACKET) {
+ /* Alloc CID for connection-oriented socket */
+ l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
+ } else if (sk->sk_type == SOCK_DGRAM) {
+ /* Connectionless socket */
+ l2cap_pi(sk)->scid = 0x0002;
+ l2cap_pi(sk)->dcid = 0x0002;
+ l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+ } else {
+ /* Raw socket can send/recv signalling messages only */
+ l2cap_pi(sk)->scid = 0x0001;
+ l2cap_pi(sk)->dcid = 0x0001;
+ l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+ }
+
+ __l2cap_chan_link(l, sk);
+
+ if (parent)
+ bt_accept_enqueue(parent, sk);
+}
+
+/* Delete channel.
+ * Must be called on the locked socket. */
+static void l2cap_chan_del(struct sock *sk, int err)
+{
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+ struct sock *parent = bt_sk(sk)->parent;
+
+ l2cap_sock_clear_timer(sk);
+
+ BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
+
+ if (conn) {
+ /* Unlink from channel list */
+ l2cap_chan_unlink(&conn->chan_list, sk);
+ l2cap_pi(sk)->conn = NULL;
+ hci_conn_put(conn->hcon);
+ }
+
+ sk->sk_state = BT_CLOSED;
+ sock_set_flag(sk, SOCK_ZAPPED);
+
+ if (err)
+ sk->sk_err = err;
+
+ if (parent) {
+ bt_accept_unlink(sk);
+ parent->sk_data_ready(parent, 0);
+ } else
+ sk->sk_state_change(sk);
+}
+
/* ---- L2CAP connections ---- */
static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
{
- struct l2cap_conn *conn;
-
- if ((conn = hcon->l2cap_data))
- return conn;
+ struct l2cap_conn *conn = hcon->l2cap_data;
- if (status)
+ if (conn || status)
return conn;
- if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_ATOMIC)))
+ conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
+ if (!conn)
return NULL;
- memset(conn, 0, sizeof(struct l2cap_conn));
hcon->l2cap_data = conn;
conn->hcon = hcon;
+ BT_DBG("hcon %p conn %p", hcon, conn);
+
conn->mtu = hcon->hdev->acl_mtu;
conn->src = &hcon->hdev->bdaddr;
conn->dst = &hcon->dst;
@@ -134,17 +282,16 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
spin_lock_init(&conn->lock);
rwlock_init(&conn->chan_list.lock);
- BT_DBG("hcon %p conn %p", hcon, conn);
return conn;
}
-static int l2cap_conn_del(struct hci_conn *hcon, int err)
+static void l2cap_conn_del(struct hci_conn *hcon, int err)
{
- struct l2cap_conn *conn;
+ struct l2cap_conn *conn = hcon->l2cap_data;
struct sock *sk;
- if (!(conn = hcon->l2cap_data))
- return 0;
+ if (!conn)
+ return;
BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
@@ -161,7 +308,6 @@ static int l2cap_conn_del(struct hci_conn *hcon, int err)
hcon->l2cap_data = NULL;
kfree(conn);
- return 0;
}
static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
@@ -925,160 +1071,6 @@ static int l2cap_sock_release(struct socket *sock)
return err;
}
-/* ---- L2CAP channels ---- */
-static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
-{
- struct sock *s;
- for (s = l->head; s; s = l2cap_pi(s)->next_c) {
- if (l2cap_pi(s)->dcid == cid)
- break;
- }
- return s;
-}
-
-static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid)
-{
- struct sock *s;
- for (s = l->head; s; s = l2cap_pi(s)->next_c) {
- if (l2cap_pi(s)->scid == cid)
- break;
- }
- return s;
-}
-
-/* Find channel with given SCID.
- * Returns locked socket */
-static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid)
-{
- struct sock *s;
- read_lock(&l->lock);
- s = __l2cap_get_chan_by_scid(l, cid);
- if (s) bh_lock_sock(s);
- read_unlock(&l->lock);
- return s;
-}
-
-static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
-{
- struct sock *s;
- for (s = l->head; s; s = l2cap_pi(s)->next_c) {
- if (l2cap_pi(s)->ident == ident)
- break;
- }
- return s;
-}
-
-static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
-{
- struct sock *s;
- read_lock(&l->lock);
- s = __l2cap_get_chan_by_ident(l, ident);
- if (s) bh_lock_sock(s);
- read_unlock(&l->lock);
- return s;
-}
-
-static u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
-{
- u16 cid = 0x0040;
-
- for (; cid < 0xffff; cid++) {
- if(!__l2cap_get_chan_by_scid(l, cid))
- return cid;
- }
-
- return 0;
-}
-
-static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
-{
- sock_hold(sk);
-
- if (l->head)
- l2cap_pi(l->head)->prev_c = sk;
-
- l2cap_pi(sk)->next_c = l->head;
- l2cap_pi(sk)->prev_c = NULL;
- l->head = sk;
-}
-
-static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
-{
- struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
-
- write_lock(&l->lock);
- if (sk == l->head)
- l->head = next;
-
- if (next)
- l2cap_pi(next)->prev_c = prev;
- if (prev)
- l2cap_pi(prev)->next_c = next;
- write_unlock(&l->lock);
-
- __sock_put(sk);
-}
-
-static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
-{
- struct l2cap_chan_list *l = &conn->chan_list;
-
- BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
-
- l2cap_pi(sk)->conn = conn;
-
- if (sk->sk_type == SOCK_SEQPACKET) {
- /* Alloc CID for connection-oriented socket */
- l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
- } else if (sk->sk_type == SOCK_DGRAM) {
- /* Connectionless socket */
- l2cap_pi(sk)->scid = 0x0002;
- l2cap_pi(sk)->dcid = 0x0002;
- l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
- } else {
- /* Raw socket can send/recv signalling messages only */
- l2cap_pi(sk)->scid = 0x0001;
- l2cap_pi(sk)->dcid = 0x0001;
- l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
- }
-
- __l2cap_chan_link(l, sk);
-
- if (parent)
- bt_accept_enqueue(parent, sk);
-}
-
-/* Delete channel.
- * Must be called on the locked socket. */
-static void l2cap_chan_del(struct sock *sk, int err)
-{
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- struct sock *parent = bt_sk(sk)->parent;
-
- l2cap_sock_clear_timer(sk);
-
- BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
-
- if (conn) {
- /* Unlink from channel list */
- l2cap_chan_unlink(&conn->chan_list, sk);
- l2cap_pi(sk)->conn = NULL;
- hci_conn_put(conn->hcon);
- }
-
- sk->sk_state = BT_CLOSED;
- sock_set_flag(sk, SOCK_ZAPPED);
-
- if (err)
- sk->sk_err = err;
-
- if (parent) {
- bt_accept_unlink(sk);
- parent->sk_data_ready(parent, 0);
- } else
- sk->sk_state_change(sk);
-}
-
static void l2cap_conn_ready(struct l2cap_conn *conn)
{
struct l2cap_chan_list *l = &conn->chan_list;
@@ -1834,7 +1826,9 @@ drop:
kfree_skb(skb);
done:
- if (sk) bh_unlock_sock(sk);
+ if (sk)
+ bh_unlock_sock(sk);
+
return 0;
}
@@ -1925,18 +1919,18 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
{
+ struct l2cap_conn *conn;
+
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
if (hcon->type != ACL_LINK)
return 0;
if (!status) {
- struct l2cap_conn *conn;
-
conn = l2cap_conn_add(hcon, status);
if (conn)
l2cap_conn_ready(conn);
- } else
+ } else
l2cap_conn_del(hcon, bt_err(status));
return 0;
@@ -1950,19 +1944,21 @@ static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason)
return 0;
l2cap_conn_del(hcon, bt_err(reason));
+
return 0;
}
static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
{
struct l2cap_chan_list *l;
- struct l2cap_conn *conn;
+ struct l2cap_conn *conn = conn = hcon->l2cap_data;
struct l2cap_conn_rsp rsp;
struct sock *sk;
int result;
- if (!(conn = hcon->l2cap_data))
+ if (!conn)
return 0;
+
l = &conn->chan_list;
BT_DBG("conn %p", conn);
@@ -2005,13 +2001,14 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status)
{
struct l2cap_chan_list *l;
- struct l2cap_conn *conn;
+ struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_conn_rsp rsp;
struct sock *sk;
int result;
- if (!(conn = hcon->l2cap_data))
+ if (!conn)
return 0;
+
l = &conn->chan_list;
BT_DBG("conn %p", conn);
@@ -2219,7 +2216,7 @@ static int __init l2cap_init(void)
goto error;
}
- class_create_file(&bt_class, &class_attr_l2cap);
+ class_create_file(bt_class, &class_attr_l2cap);
BT_INFO("L2CAP ver %s", VERSION);
BT_INFO("L2CAP socket layer initialized");
@@ -2233,7 +2230,7 @@ error:
static void __exit l2cap_exit(void)
{
- class_remove_file(&bt_class, &class_attr_l2cap);
+ class_remove_file(bt_class, &class_attr_l2cap);
if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
BT_ERR("L2CAP socket unregistration failed");
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index bd46e8927f2..155a2b93760 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -52,8 +52,9 @@
#define BT_DBG(D...)
#endif
-#define VERSION "1.7"
+#define VERSION "1.8"
+static int disable_cfc = 0;
static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU;
static struct task_struct *rfcomm_thread;
@@ -533,7 +534,7 @@ static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
s->sock = sock;
s->mtu = RFCOMM_DEFAULT_MTU;
- s->cfc = RFCOMM_CFC_UNKNOWN;
+ s->cfc = disable_cfc ? RFCOMM_CFC_DISABLED : RFCOMM_CFC_UNKNOWN;
/* Do not increment module usage count for listening sessions.
* Otherwise we won't be able to unload the module. */
@@ -1149,6 +1150,8 @@ static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
{
+ struct sock *sk = d->session->sock->sk;
+
BT_DBG("dlc %p", d);
rfcomm_send_ua(d->session, d->dlci);
@@ -1158,6 +1161,9 @@ static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
d->state_change(d, 0);
rfcomm_dlc_unlock(d);
+ if (d->link_mode & RFCOMM_LM_MASTER)
+ hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00);
+
rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
}
@@ -1222,14 +1228,18 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d",
d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
- if (pn->flow_ctrl == 0xf0 || pn->flow_ctrl == 0xe0) {
- d->cfc = s->cfc = RFCOMM_CFC_ENABLED;
+ if ((pn->flow_ctrl == 0xf0 && s->cfc != RFCOMM_CFC_DISABLED) ||
+ pn->flow_ctrl == 0xe0) {
+ d->cfc = RFCOMM_CFC_ENABLED;
d->tx_credits = pn->credits;
} else {
- d->cfc = s->cfc = RFCOMM_CFC_DISABLED;
+ d->cfc = RFCOMM_CFC_DISABLED;
set_bit(RFCOMM_TX_THROTTLED, &d->flags);
}
+ if (s->cfc == RFCOMM_CFC_UNKNOWN)
+ s->cfc = d->cfc;
+
d->priority = pn->priority;
d->mtu = s->mtu = btohs(pn->mtu);
@@ -2035,7 +2045,7 @@ static int __init rfcomm_init(void)
kernel_thread(rfcomm_run, NULL, CLONE_KERNEL);
- class_create_file(&bt_class, &class_attr_rfcomm_dlc);
+ class_create_file(bt_class, &class_attr_rfcomm_dlc);
rfcomm_init_sockets();
@@ -2050,7 +2060,7 @@ static int __init rfcomm_init(void)
static void __exit rfcomm_exit(void)
{
- class_remove_file(&bt_class, &class_attr_rfcomm_dlc);
+ class_remove_file(bt_class, &class_attr_rfcomm_dlc);
hci_unregister_cb(&rfcomm_cb);
@@ -2073,6 +2083,9 @@ static void __exit rfcomm_exit(void)
module_init(rfcomm_init);
module_exit(rfcomm_exit);
+module_param(disable_cfc, bool, 0644);
+MODULE_PARM_DESC(disable_cfc, "Disable credit based flow control");
+
module_param(l2cap_mtu, uint, 0644);
MODULE_PARM_DESC(l2cap_mtu, "Default MTU for the L2CAP connection");
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 4e9962c8cfa..220fee04e7f 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -944,7 +944,7 @@ int __init rfcomm_init_sockets(void)
if (err < 0)
goto error;
- class_create_file(&bt_class, &class_attr_rfcomm);
+ class_create_file(bt_class, &class_attr_rfcomm);
BT_INFO("RFCOMM socket layer initialized");
@@ -958,7 +958,7 @@ error:
void __exit rfcomm_cleanup_sockets(void)
{
- class_remove_file(&bt_class, &class_attr_rfcomm);
+ class_remove_file(bt_class, &class_attr_rfcomm);
if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
BT_ERR("RFCOMM socket layer unregistration failed");
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index a5f1e44db5d..85defccc028 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -969,7 +969,7 @@ static int __init sco_init(void)
goto error;
}
- class_create_file(&bt_class, &class_attr_sco);
+ class_create_file(bt_class, &class_attr_sco);
BT_INFO("SCO (Voice Link) ver %s", VERSION);
BT_INFO("SCO socket layer initialized");
@@ -983,7 +983,7 @@ error:
static void __exit sco_exit(void)
{
- class_remove_file(&bt_class, &class_attr_sco);
+ class_remove_file(bt_class, &class_attr_sco);
if (bt_sock_unregister(BTPROTO_SCO) < 0)
BT_ERR("SCO socket unregistration failed");
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 881d7d1a732..06abb6634f5 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -117,12 +117,13 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
continue;
if (idx < s_idx)
- continue;
+ goto cont;
err = br_fill_ifinfo(skb, p, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI);
if (err <= 0)
break;
+cont:
++idx;
}
read_unlock(&dev_base_lock);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 7cfbdb215ba..44f6a181a75 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -71,6 +71,13 @@ static kmem_cache_t *skbuff_head_cache __read_mostly;
static kmem_cache_t *skbuff_fclone_cache __read_mostly;
/*
+ * lockdep: lock class key used by skb_queue_head_init():
+ */
+struct lock_class_key skb_queue_lock_key;
+
+EXPORT_SYMBOL(skb_queue_lock_key);
+
+/*
* Keep out-of-line to prevent kernel bloat.
* __builtin_return_address is not used because it is not always
* reliable.
diff --git a/net/core/sock.c b/net/core/sock.c
index 533b9317144..51fcfbc041a 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -129,6 +129,53 @@
#include <net/tcp.h>
#endif
+/*
+ * Each address family might have different locking rules, so we have
+ * one slock key per address family:
+ */
+static struct lock_class_key af_family_keys[AF_MAX];
+static struct lock_class_key af_family_slock_keys[AF_MAX];
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+/*
+ * Make lock validator output more readable. (we pre-construct these
+ * strings build-time, so that runtime initialization of socket
+ * locks is fast):
+ */
+static const char *af_family_key_strings[AF_MAX+1] = {
+ "sk_lock-AF_UNSPEC", "sk_lock-AF_UNIX" , "sk_lock-AF_INET" ,
+ "sk_lock-AF_AX25" , "sk_lock-AF_IPX" , "sk_lock-AF_APPLETALK",
+ "sk_lock-AF_NETROM", "sk_lock-AF_BRIDGE" , "sk_lock-AF_ATMPVC" ,
+ "sk_lock-AF_X25" , "sk_lock-AF_INET6" , "sk_lock-AF_ROSE" ,
+ "sk_lock-AF_DECnet", "sk_lock-AF_NETBEUI" , "sk_lock-AF_SECURITY" ,
+ "sk_lock-AF_KEY" , "sk_lock-AF_NETLINK" , "sk_lock-AF_PACKET" ,
+ "sk_lock-AF_ASH" , "sk_lock-AF_ECONET" , "sk_lock-AF_ATMSVC" ,
+ "sk_lock-21" , "sk_lock-AF_SNA" , "sk_lock-AF_IRDA" ,
+ "sk_lock-AF_PPPOX" , "sk_lock-AF_WANPIPE" , "sk_lock-AF_LLC" ,
+ "sk_lock-27" , "sk_lock-28" , "sk_lock-29" ,
+ "sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-AF_MAX"
+};
+static const char *af_family_slock_key_strings[AF_MAX+1] = {
+ "slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" ,
+ "slock-AF_AX25" , "slock-AF_IPX" , "slock-AF_APPLETALK",
+ "slock-AF_NETROM", "slock-AF_BRIDGE" , "slock-AF_ATMPVC" ,
+ "slock-AF_X25" , "slock-AF_INET6" , "slock-AF_ROSE" ,
+ "slock-AF_DECnet", "slock-AF_NETBEUI" , "slock-AF_SECURITY" ,
+ "slock-AF_KEY" , "slock-AF_NETLINK" , "slock-AF_PACKET" ,
+ "slock-AF_ASH" , "slock-AF_ECONET" , "slock-AF_ATMSVC" ,
+ "slock-21" , "slock-AF_SNA" , "slock-AF_IRDA" ,
+ "slock-AF_PPPOX" , "slock-AF_WANPIPE" , "slock-AF_LLC" ,
+ "slock-27" , "slock-28" , "slock-29" ,
+ "slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_MAX"
+};
+#endif
+
+/*
+ * sk_callback_lock locking rules are per-address-family,
+ * so split the lock classes by using a per-AF key:
+ */
+static struct lock_class_key af_callback_keys[AF_MAX];
+
/* Take into consideration the size of the struct sk_buff overhead in the
* determination of these values, since that is non-constant across
* platforms. This makes socket queueing behavior and performance
@@ -237,9 +284,16 @@ int sk_receive_skb(struct sock *sk, struct sk_buff *skb)
skb->dev = NULL;
bh_lock_sock(sk);
- if (!sock_owned_by_user(sk))
+ if (!sock_owned_by_user(sk)) {
+ /*
+ * trylock + unlock semantics:
+ */
+ mutex_acquire(&sk->sk_lock.dep_map, 0, 1, _RET_IP_);
+
rc = sk->sk_backlog_rcv(sk, skb);
- else
+
+ mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_);
+ } else
sk_add_backlog(sk, skb);
bh_unlock_sock(sk);
out:
@@ -749,6 +803,33 @@ lenout:
return 0;
}
+/*
+ * Initialize an sk_lock.
+ *
+ * (We also register the sk_lock with the lock validator.)
+ */
+static void inline sock_lock_init(struct sock *sk)
+{
+ spin_lock_init(&sk->sk_lock.slock);
+ sk->sk_lock.owner = NULL;
+ init_waitqueue_head(&sk->sk_lock.wq);
+ /*
+ * Make sure we are not reinitializing a held lock:
+ */
+ debug_check_no_locks_freed((void *)&sk->sk_lock, sizeof(sk->sk_lock));
+
+ /*
+ * Mark both the sk_lock and the sk_lock.slock as a
+ * per-address-family lock class:
+ */
+ lockdep_set_class_and_name(&sk->sk_lock.slock,
+ af_family_slock_keys + sk->sk_family,
+ af_family_slock_key_strings[sk->sk_family]);
+ lockdep_init_map(&sk->sk_lock.dep_map,
+ af_family_key_strings[sk->sk_family],
+ af_family_keys + sk->sk_family);
+}
+
/**
* sk_alloc - All socket objects are allocated here
* @family: protocol family
@@ -848,6 +929,8 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
rwlock_init(&newsk->sk_dst_lock);
rwlock_init(&newsk->sk_callback_lock);
+ lockdep_set_class(&newsk->sk_callback_lock,
+ af_callback_keys + newsk->sk_family);
newsk->sk_dst_cache = NULL;
newsk->sk_wmem_queued = 0;
@@ -1422,6 +1505,8 @@ void sock_init_data(struct socket *sock, struct sock *sk)
rwlock_init(&sk->sk_dst_lock);
rwlock_init(&sk->sk_callback_lock);
+ lockdep_set_class(&sk->sk_callback_lock,
+ af_callback_keys + sk->sk_family);
sk->sk_state_change = sock_def_wakeup;
sk->sk_data_ready = sock_def_readable;
@@ -1449,24 +1534,34 @@ void sock_init_data(struct socket *sock, struct sock *sk)
void fastcall lock_sock(struct sock *sk)
{
might_sleep();
- spin_lock_bh(&(sk->sk_lock.slock));
+ spin_lock_bh(&sk->sk_lock.slock);
if (sk->sk_lock.owner)
__lock_sock(sk);
sk->sk_lock.owner = (void *)1;
- spin_unlock_bh(&(sk->sk_lock.slock));
+ spin_unlock(&sk->sk_lock.slock);
+ /*
+ * The sk_lock has mutex_lock() semantics here:
+ */
+ mutex_acquire(&sk->sk_lock.dep_map, 0, 0, _RET_IP_);
+ local_bh_enable();
}
EXPORT_SYMBOL(lock_sock);
void fastcall release_sock(struct sock *sk)
{
- spin_lock_bh(&(sk->sk_lock.slock));
+ /*
+ * The sk_lock has mutex_unlock() semantics:
+ */
+ mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_);
+
+ spin_lock_bh(&sk->sk_lock.slock);
if (sk->sk_backlog.tail)
__release_sock(sk);
sk->sk_lock.owner = NULL;
- if (waitqueue_active(&(sk->sk_lock.wq)))
- wake_up(&(sk->sk_lock.wq));
- spin_unlock_bh(&(sk->sk_lock.slock));
+ if (waitqueue_active(&sk->sk_lock.wq))
+ wake_up(&sk->sk_lock.wq);
+ spin_unlock_bh(&sk->sk_lock.slock);
}
EXPORT_SYMBOL(release_sock);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 8d157157bf8..318d4674faa 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1106,7 +1106,15 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
int ihl;
int id;
- if (!pskb_may_pull(skb, sizeof(*iph)))
+ if (unlikely(skb_shinfo(skb)->gso_type &
+ ~(SKB_GSO_TCPV4 |
+ SKB_GSO_UDP |
+ SKB_GSO_DODGY |
+ SKB_GSO_TCP_ECN |
+ 0)))
+ goto out;
+
+ if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
goto out;
iph = skb->nh.iph;
@@ -1114,7 +1122,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
if (ihl < sizeof(*iph))
goto out;
- if (!pskb_may_pull(skb, ihl))
+ if (unlikely(!pskb_may_pull(skb, ihl)))
goto out;
skb->h.raw = __skb_pull(skb, ihl);
@@ -1125,7 +1133,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
rcu_read_lock();
ops = rcu_dereference(inet_protos[proto]);
- if (ops && ops->gso_segment)
+ if (likely(ops && ops->gso_segment))
segs = ops->gso_segment(skb, features);
rcu_read_unlock();
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index da44fabf4dc..2dc6dbb2846 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -205,21 +205,27 @@ __u8 ip_tos2prio[16] = {
struct rt_hash_bucket {
struct rtable *chain;
};
-#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \
+ defined(CONFIG_PROVE_LOCKING)
/*
* Instead of using one spinlock for each rt_hash_bucket, we use a table of spinlocks
* The size of this table is a power of two and depends on the number of CPUS.
+ * (on lockdep we have a quite big spinlock_t, so keep the size down there)
*/
-#if NR_CPUS >= 32
-#define RT_HASH_LOCK_SZ 4096
-#elif NR_CPUS >= 16
-#define RT_HASH_LOCK_SZ 2048
-#elif NR_CPUS >= 8
-#define RT_HASH_LOCK_SZ 1024
-#elif NR_CPUS >= 4
-#define RT_HASH_LOCK_SZ 512
+#ifdef CONFIG_LOCKDEP
+# define RT_HASH_LOCK_SZ 256
#else
-#define RT_HASH_LOCK_SZ 256
+# if NR_CPUS >= 32
+# define RT_HASH_LOCK_SZ 4096
+# elif NR_CPUS >= 16
+# define RT_HASH_LOCK_SZ 2048
+# elif NR_CPUS >= 8
+# define RT_HASH_LOCK_SZ 1024
+# elif NR_CPUS >= 4
+# define RT_HASH_LOCK_SZ 512
+# else
+# define RT_HASH_LOCK_SZ 256
+# endif
#endif
static spinlock_t *rt_hash_locks;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 804458712d8..f6a2d9223d0 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2170,8 +2170,19 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
/* Packet is from an untrusted source, reset gso_segs. */
- int mss = skb_shinfo(skb)->gso_size;
+ int type = skb_shinfo(skb)->gso_type;
+ int mss;
+
+ if (unlikely(type &
+ ~(SKB_GSO_TCPV4 |
+ SKB_GSO_DODGY |
+ SKB_GSO_TCP_ECN |
+ SKB_GSO_TCPV6 |
+ 0) ||
+ !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))))
+ goto out;
+ mss = skb_shinfo(skb)->gso_size;
skb_shinfo(skb)->gso_segs = (skb->len + mss - 1) / mss;
segs = NULL;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 8355b729fa9..5a886e6efbb 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -90,7 +90,7 @@ static struct socket *tcp_socket;
void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb);
struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
- .lhash_lock = RW_LOCK_UNLOCKED,
+ .lhash_lock = __RW_LOCK_UNLOCKED(tcp_hashinfo.lhash_lock),
.lhash_users = ATOMIC_INIT(0),
.lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait),
};
@@ -1090,7 +1090,7 @@ process:
skb->dev = NULL;
- bh_lock_sock(sk);
+ bh_lock_sock_nested(sk);
ret = 0;
if (!sock_owned_by_user(sk)) {
#ifdef CONFIG_NET_DMA
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index e0851697ad5..0ccb7cb22b1 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -40,7 +40,7 @@ int sysctl_tcp_abort_on_overflow;
struct inet_timewait_death_row tcp_death_row = {
.sysctl_max_tw_buckets = NR_FILE * 2,
.period = TCP_TIMEWAIT_LEN / INET_TWDR_TWKILL_SLOTS,
- .death_lock = SPIN_LOCK_UNLOCKED,
+ .death_lock = __SPIN_LOCK_UNLOCKED(tcp_death_row.death_lock),
.hashinfo = &tcp_hashinfo,
.tw_timer = TIMER_INITIALIZER(inet_twdr_hangman, 0,
(unsigned long)&tcp_death_row),
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index c28e5c28744..0c17dec11c8 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -64,6 +64,14 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
struct inet6_protocol *ops;
int proto;
+ if (unlikely(skb_shinfo(skb)->gso_type &
+ ~(SKB_GSO_UDP |
+ SKB_GSO_DODGY |
+ SKB_GSO_TCP_ECN |
+ SKB_GSO_TCPV6 |
+ 0)))
+ goto out;
+
if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
goto out;
@@ -111,7 +119,8 @@ unlock:
for (skb = segs; skb; skb = skb->next) {
ipv6h = skb->nh.ipv6h;
- ipv6h->payload_len = htons(skb->len - skb->mac_len);
+ ipv6h->payload_len = htons(skb->len - skb->mac_len -
+ sizeof(*ipv6h));
}
out:
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 7ef143c0ebf..f26898b0034 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -25,6 +25,7 @@
#include <linux/vmalloc.h>
#include <linux/netdevice.h>
#include <linux/module.h>
+#include <linux/poison.h>
#include <linux/icmpv6.h>
#include <net/ipv6.h>
#include <asm/uaccess.h>
@@ -376,7 +377,7 @@ ip6t_do_table(struct sk_buff **pskb,
} while (!hotdrop);
#ifdef CONFIG_NETFILTER_DEBUG
- ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
+ ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
#endif
read_unlock_bh(&table->lock);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 70cee82a98b..55c0adc8f11 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -156,7 +156,7 @@ static void netlink_sock_destruct(struct sock *sk)
static void netlink_table_grab(void)
{
- write_lock_bh(&nl_table_lock);
+ write_lock_irq(&nl_table_lock);
if (atomic_read(&nl_table_users)) {
DECLARE_WAITQUEUE(wait, current);
@@ -166,9 +166,9 @@ static void netlink_table_grab(void)
set_current_state(TASK_UNINTERRUPTIBLE);
if (atomic_read(&nl_table_users) == 0)
break;
- write_unlock_bh(&nl_table_lock);
+ write_unlock_irq(&nl_table_lock);
schedule();
- write_lock_bh(&nl_table_lock);
+ write_lock_irq(&nl_table_lock);
}
__set_current_state(TASK_RUNNING);
@@ -178,7 +178,7 @@ static void netlink_table_grab(void)
static __inline__ void netlink_table_ungrab(void)
{
- write_unlock_bh(&nl_table_lock);
+ write_unlock_irq(&nl_table_lock);
wake_up(&nl_table_wait);
}
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index eba6df054b1..389a4119e1b 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -800,7 +800,7 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
/* Now attach up the new socket */
kfree_skb(skb);
- sk->sk_ack_backlog--;
+ sk_acceptq_removed(sk);
newsock->sk = newsk;
out:
@@ -985,7 +985,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
nr_make->vr = 0;
nr_make->vl = 0;
nr_make->state = NR_STATE_3;
- sk->sk_ack_backlog++;
+ sk_acceptq_added(sk);
nr_insert_socket(make);
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 7799fe82aeb..d0a67bb3136 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -752,7 +752,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
rose_insert_socket(sk); /* Finish the bind */
}
-
+rose_try_next_neigh:
rose->dest_addr = addr->srose_addr;
rose->dest_call = addr->srose_call;
rose->rand = ((long)rose & 0xFFFF) + rose->lci;
@@ -810,6 +810,11 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
}
if (sk->sk_state != TCP_ESTABLISHED) {
+ /* Try next neighbour */
+ rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic);
+ if (rose->neighbour)
+ goto rose_try_next_neigh;
+ /* No more neighbour */
sock->state = SS_UNCONNECTED;
return sock_error(sk); /* Always set at this point */
}
diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c
index 9d0bf2a1ea3..7c279e2659e 100644
--- a/net/rose/rose_dev.c
+++ b/net/rose/rose_dev.c
@@ -59,6 +59,7 @@ static int rose_rebuild_header(struct sk_buff *skb)
struct net_device_stats *stats = netdev_priv(dev);
unsigned char *bp = (unsigned char *)skb->data;
struct sk_buff *skbn;
+ unsigned int len;
#ifdef CONFIG_INET
if (arp_find(bp + 7, skb)) {
@@ -75,6 +76,8 @@ static int rose_rebuild_header(struct sk_buff *skb)
kfree_skb(skb);
+ len = skbn->len;
+
if (!rose_route_frame(skbn, NULL)) {
kfree_skb(skbn);
stats->tx_errors++;
@@ -82,7 +85,7 @@ static int rose_rebuild_header(struct sk_buff *skb)
}
stats->tx_packets++;
- stats->tx_bytes += skbn->len;
+ stats->tx_bytes += len;
#endif
return 1;
}
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 6db6006616c..dc6cb93c883 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -515,7 +515,7 @@ rpc_depopulate(struct dentry *parent)
struct dentry *dentry, *dvec[10];
int n = 0;
- mutex_lock(&dir->i_mutex);
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD);
repeat:
spin_lock(&dcache_lock);
list_for_each_safe(pos, next, &parent->d_subdirs) {
@@ -631,7 +631,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd)
if ((error = rpc_lookup_parent(path, nd)) != 0)
return ERR_PTR(error);
dir = nd->dentry->d_inode;
- mutex_lock(&dir->i_mutex);
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
dentry = lookup_one_len(nd->last.name, nd->dentry, nd->last.len);
if (IS_ERR(dentry))
goto out_err;
@@ -693,7 +693,7 @@ rpc_rmdir(char *path)
if ((error = rpc_lookup_parent(path, &nd)) != 0)
return error;
dir = nd.dentry->d_inode;
- mutex_lock(&dir->i_mutex);
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
if (IS_ERR(dentry)) {
error = PTR_ERR(dentry);
@@ -754,7 +754,7 @@ rpc_unlink(char *path)
if ((error = rpc_lookup_parent(path, &nd)) != 0)
return error;
dir = nd.dentry->d_inode;
- mutex_lock(&dir->i_mutex);
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
if (IS_ERR(dentry)) {
error = PTR_ERR(dentry);
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 86f54f3512f..762aac2572b 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -297,7 +297,10 @@ static inline struct tipc_msg *buf_msg(struct sk_buff *skb)
* buf_acquire - creates a TIPC message buffer
* @size: message size (including TIPC header)
*
- * Returns a new buffer. Space is reserved for a data link header.
+ * Returns a new buffer with data pointers set to the specified size.
+ *
+ * NOTE: Headroom is reserved to allow prepending of a data link header.
+ * There may also be unrequested tailroom present at the buffer's end.
*/
static inline struct sk_buff *buf_acquire(u32 size)
diff --git a/net/tipc/link.c b/net/tipc/link.c
index c6831c75cfa..c10e18a49b9 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -998,6 +998,8 @@ static int link_bundle_buf(struct link *l_ptr,
return 0;
if (skb_tailroom(bundler) < (pad + size))
return 0;
+ if (link_max_pkt(l_ptr) < (to_pos + size))
+ return 0;
skb_put(bundler, pad + size);
memcpy(bundler->data + to_pos, buf->data, size);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index aca65010942..f70475bfb62 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -144,7 +144,7 @@ static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
scm->seclen = *UNIXSECLEN(skb);
}
#else
-static void unix_get_peersec_dgram(struct sk_buff *skb)
+static inline void unix_get_peersec_dgram(struct sk_buff *skb)
{ }
static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
@@ -565,6 +565,14 @@ static struct proto unix_proto = {
.obj_size = sizeof(struct unix_sock),
};
+/*
+ * AF_UNIX sockets do not interact with hardware, hence they
+ * dont trigger interrupts - so it's safe for them to have
+ * bh-unsafe locking for their sk_receive_queue.lock. Split off
+ * this special lock-class by reinitializing the spinlock key:
+ */
+static struct lock_class_key af_unix_sk_receive_queue_lock_key;
+
static struct sock * unix_create1(struct socket *sock)
{
struct sock *sk = NULL;
@@ -580,6 +588,8 @@ static struct sock * unix_create1(struct socket *sock)
atomic_inc(&unix_nr_socks);
sock_init_data(sock,sk);
+ lockdep_set_class(&sk->sk_receive_queue.lock,
+ &af_unix_sk_receive_queue_lock_key);
sk->sk_write_space = unix_write_space;
sk->sk_max_ack_backlog = sysctl_unix_max_dgram_qlen;
@@ -1045,7 +1055,7 @@ restart:
goto out_unlock;
}
- unix_state_wlock(sk);
+ unix_state_wlock_nested(sk);
if (sk->sk_state != st) {
unix_state_wunlock(sk);