diff options
Diffstat (limited to 'net')
31 files changed, 905 insertions, 399 deletions
| diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 3948949a609a..458031bfff55 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 87a454f5c89c..121bf6f49148 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 9be5c15e63d3..136c3aefa9de 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 5ac98250797b..51b7bdaf27eb 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 51f867062e1d..788ea7a2b744 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 5c0c2b1ef34a..420ed4d7e57e 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 f67240beb0dd..54e8e5ea2154 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, "e))) {  		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 618bacee1b1c..3896dabab11d 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 19b234c86f33..3987d167f04e 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 770101177da1..eaaad658d11d 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 bd46e8927f29..155a2b93760e 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 4e9962c8cfa6..220fee04e7f2 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 a5f1e44db5d3..85defccc0287 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 881d7d1a732a..06abb6634f5b 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 7cfbdb215ba2..44f6a181a754 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 533b9317144b..51fcfbc041a7 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 8d157157bf8e..318d4674faa1 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 da44fabf4dc5..2dc6dbb28467 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 804458712d88..f6a2d9223d07 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 8355b729fa95..5a886e6efbbe 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 e0851697ad5e..0ccb7cb22b15 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 c28e5c287447..0c17dec11c8d 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 7ef143c0ebf6..f26898b00347 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 70cee82a98bf..55c0adc8f115 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 eba6df054b1f..389a4119e1b4 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 7799fe82aeb6..d0a67bb31363 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 9d0bf2a1ea3f..7c279e2659ec 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 6db6006616c6..dc6cb93c8830 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 86f54f3512f1..762aac2572be 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 c6831c75cfa4..c10e18a49b96 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 aca650109425..f70475bfb62a 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); | 
