xref: /dflybsd-src/sys/netgraph7/bluetooth/socket/ng_btsocket_l2cap_raw.c (revision 2b3f93ea6d1f70880f3e87f3c2cbe0dc0bfc9332)
1  /*
2   * ng_btsocket_l2cap_raw.c
3   */
4  
5  /*-
6   * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7   * All rights reserved.
8   *
9   * Redistribution and use in source and binary forms, with or without
10   * modification, are permitted provided that the following conditions
11   * are met:
12   * 1. Redistributions of source code must retain the above copyright
13   *    notice, this list of conditions and the following disclaimer.
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in the
16   *    documentation and/or other materials provided with the distribution.
17   *
18   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21   * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28   * SUCH DAMAGE.
29   *
30   * $Id: ng_btsocket_l2cap_raw.c,v 1.12 2003/09/14 23:29:06 max Exp $
31   * $FreeBSD: src/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c,v 1.20 2006/11/06 13:42:04 rwatson Exp $
32   */
33  
34  #include <sys/param.h>
35  #include <sys/systm.h>
36  #include <sys/bitstring.h>
37  #include <sys/domain.h>
38  #include <sys/errno.h>
39  #include <sys/filedesc.h>
40  #include <sys/kernel.h>
41  #include <sys/lock.h>
42  #include <sys/malloc.h>
43  #include <sys/mbuf.h>
44  #include <sys/caps.h>
45  #include <sys/protosw.h>
46  #include <sys/queue.h>
47  #include <sys/socket.h>
48  #include <sys/socketvar.h>
49  #include <sys/sysctl.h>
50  #include <sys/taskqueue.h>
51  #include <sys/msgport2.h>
52  #include <sys/refcount.h>
53  #include <netgraph7/ng_message.h>
54  #include <netgraph7/netgraph.h>
55  #include <netgraph7/netgraph2.h>
56  #include <netgraph7/bluetooth/include/ng_bluetooth.h>
57  #include <netgraph7/bluetooth/include/ng_hci.h>
58  #include <netgraph7/bluetooth/include/ng_l2cap.h>
59  #include <netgraph7/bluetooth/include/ng_btsocket.h>
60  #include <netgraph7/bluetooth/include/ng_btsocket_l2cap.h>
61  
62  /* MALLOC define */
63  #ifdef NG_SEPARATE_MALLOC
64  MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP_RAW, "netgraph_btsocks_l2cap_raw",
65  		"Netgraph Bluetooth raw L2CAP sockets");
66  #else
67  #define M_NETGRAPH_BTSOCKET_L2CAP_RAW M_NETGRAPH
68  #endif /* NG_SEPARATE_MALLOC */
69  
70  /* Netgraph node methods */
71  static ng_constructor_t	ng_btsocket_l2cap_raw_node_constructor;
72  static ng_rcvmsg_t	ng_btsocket_l2cap_raw_node_rcvmsg;
73  static ng_shutdown_t	ng_btsocket_l2cap_raw_node_shutdown;
74  static ng_newhook_t	ng_btsocket_l2cap_raw_node_newhook;
75  static ng_connect_t	ng_btsocket_l2cap_raw_node_connect;
76  static ng_rcvdata_t	ng_btsocket_l2cap_raw_node_rcvdata;
77  static ng_disconnect_t	ng_btsocket_l2cap_raw_node_disconnect;
78  
79  static void		ng_btsocket_l2cap_raw_input     (void *, int);
80  static void		ng_btsocket_l2cap_raw_rtclean   (void *, int);
81  static void		ng_btsocket_l2cap_raw_get_token (u_int32_t *);
82  
83  static int		ng_btsocket_l2cap_raw_send_ngmsg
84  				(hook_p, int, void *, int);
85  static int		ng_btsocket_l2cap_raw_send_sync_ngmsg
86  				(ng_btsocket_l2cap_raw_pcb_p, int, void *, int);
87  
88  #define ng_btsocket_l2cap_raw_wakeup_input_task() \
89  	taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_queue_task)
90  
91  #define ng_btsocket_l2cap_raw_wakeup_route_task() \
92  	taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_rt_task)
93  
94  /* Netgraph type descriptor */
95  static struct ng_type	typestruct = {
96  	.version =	NG_ABI_VERSION,
97  	.name =		NG_BTSOCKET_L2CAP_RAW_NODE_TYPE,
98  	.constructor =	ng_btsocket_l2cap_raw_node_constructor,
99  	.rcvmsg =	ng_btsocket_l2cap_raw_node_rcvmsg,
100  	.shutdown =	ng_btsocket_l2cap_raw_node_shutdown,
101  	.newhook =	ng_btsocket_l2cap_raw_node_newhook,
102  	.connect =	ng_btsocket_l2cap_raw_node_connect,
103  	.rcvdata =	ng_btsocket_l2cap_raw_node_rcvdata,
104  	.disconnect =	ng_btsocket_l2cap_raw_node_disconnect,
105  };
106  
107  /* Globals */
108  extern int					ifqmaxlen;
109  static u_int32_t				ng_btsocket_l2cap_raw_debug_level;
110  static u_int32_t				ng_btsocket_l2cap_raw_ioctl_timeout;
111  static node_p					ng_btsocket_l2cap_raw_node;
112  static struct ng_bt_itemq			ng_btsocket_l2cap_raw_queue;
113  static struct lock				ng_btsocket_l2cap_raw_queue_lock;
114  static struct task				ng_btsocket_l2cap_raw_queue_task;
115  static LIST_HEAD(, ng_btsocket_l2cap_raw_pcb)	ng_btsocket_l2cap_raw_sockets;
116  static struct lock				ng_btsocket_l2cap_raw_sockets_lock;
117  static u_int32_t				ng_btsocket_l2cap_raw_token;
118  static struct lock				ng_btsocket_l2cap_raw_token_lock;
119  static LIST_HEAD(, ng_btsocket_l2cap_rtentry)	ng_btsocket_l2cap_raw_rt;
120  static struct lock				ng_btsocket_l2cap_raw_rt_lock;
121  static struct task				ng_btsocket_l2cap_raw_rt_task;
122  
123  /* Sysctl tree */
124  SYSCTL_DECL(_net_bluetooth_l2cap_sockets);
125  SYSCTL_NODE(_net_bluetooth_l2cap_sockets, OID_AUTO, raw, CTLFLAG_RW,
126  	0, "Bluetooth raw L2CAP sockets family");
127  SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, debug_level,
128  	CTLFLAG_RW,
129  	&ng_btsocket_l2cap_raw_debug_level, NG_BTSOCKET_WARN_LEVEL,
130  	"Bluetooth raw L2CAP sockets debug level");
131  SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, ioctl_timeout,
132  	CTLFLAG_RW,
133  	&ng_btsocket_l2cap_raw_ioctl_timeout, 5,
134  	"Bluetooth raw L2CAP sockets ioctl timeout");
135  SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_len,
136  	CTLFLAG_RD,
137  	&ng_btsocket_l2cap_raw_queue.len, 0,
138  	"Bluetooth raw L2CAP sockets input queue length");
139  SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_maxlen,
140  	CTLFLAG_RD,
141  	&ng_btsocket_l2cap_raw_queue.maxlen, 0,
142  	"Bluetooth raw L2CAP sockets input queue max. length");
143  SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_drops,
144  	CTLFLAG_RD,
145  	&ng_btsocket_l2cap_raw_queue.drops, 0,
146  	"Bluetooth raw L2CAP sockets input queue drops");
147  
148  /* Debug */
149  #define NG_BTSOCKET_L2CAP_RAW_INFO \
150  	if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL) \
151  		kprintf
152  
153  #define NG_BTSOCKET_L2CAP_RAW_WARN \
154  	if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL) \
155  		kprintf
156  
157  #define NG_BTSOCKET_L2CAP_RAW_ERR \
158  	if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL) \
159  		kprintf
160  
161  #define NG_BTSOCKET_L2CAP_RAW_ALERT \
162  	if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL) \
163  		kprintf
164  
165  /*****************************************************************************
166   *****************************************************************************
167   **                        Netgraph node interface
168   *****************************************************************************
169   *****************************************************************************/
170  
171  /*
172   * Netgraph node constructor. Do not allow to create node of this type.
173   */
174  
175  static int
ng_btsocket_l2cap_raw_node_constructor(node_p node)176  ng_btsocket_l2cap_raw_node_constructor(node_p node)
177  {
178  	return (EINVAL);
179  } /* ng_btsocket_l2cap_raw_node_constructor */
180  
181  /*
182   * Do local shutdown processing. Let old node go and create new fresh one.
183   */
184  
185  static int
ng_btsocket_l2cap_raw_node_shutdown(node_p node)186  ng_btsocket_l2cap_raw_node_shutdown(node_p node)
187  {
188  	int	error = 0;
189  
190  	NG_NODE_UNREF(node);
191  
192  	/* Create new node */
193  	error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
194  	if (error != 0) {
195  		NG_BTSOCKET_L2CAP_RAW_ALERT(
196  "%s: Could not create Netgraph node, error=%d\n", __func__, error);
197  
198  		ng_btsocket_l2cap_raw_node = NULL;
199  
200  		return (error);
201  	}
202  
203  	error = ng_name_node(ng_btsocket_l2cap_raw_node,
204  				NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
205  	if (error != 0) {
206  		NG_BTSOCKET_L2CAP_RAW_ALERT(
207  "%s: Could not name Netgraph node, error=%d\n", __func__, error);
208  
209  		NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
210  		ng_btsocket_l2cap_raw_node = NULL;
211  
212  		return (error);
213  	}
214  
215  	return (0);
216  } /* ng_btsocket_l2cap_raw_node_shutdown */
217  
218  /*
219   * We allow any hook to be connected to the node.
220   */
221  
222  static int
ng_btsocket_l2cap_raw_node_newhook(node_p node,hook_p hook,char const * name)223  ng_btsocket_l2cap_raw_node_newhook(node_p node, hook_p hook, char const *name)
224  {
225  	return (0);
226  } /* ng_btsocket_l2cap_raw_node_newhook */
227  
228  /*
229   * Just say "YEP, that's OK by me!"
230   */
231  
232  static int
ng_btsocket_l2cap_raw_node_connect(hook_p hook)233  ng_btsocket_l2cap_raw_node_connect(hook_p hook)
234  {
235  	NG_HOOK_SET_PRIVATE(hook, NULL);
236  	NG_HOOK_REF(hook); /* Keep extra reference to the hook */
237  
238  	return (0);
239  } /* ng_btsocket_l2cap_raw_node_connect */
240  
241  /*
242   * Hook disconnection. Schedule route cleanup task
243   */
244  
245  static int
ng_btsocket_l2cap_raw_node_disconnect(hook_p hook)246  ng_btsocket_l2cap_raw_node_disconnect(hook_p hook)
247  {
248  	/*
249  	 * If hook has private information than we must have this hook in
250  	 * the routing table and must schedule cleaning for the routing table.
251  	 * Otherwise hook was connected but we never got "hook_info" message,
252  	 * so we have never added this hook to the routing table and it save
253  	 * to just delete it.
254  	 */
255  
256  	if (NG_HOOK_PRIVATE(hook) != NULL)
257  		return (ng_btsocket_l2cap_raw_wakeup_route_task());
258  
259  	NG_HOOK_UNREF(hook); /* Remove extra reference */
260  
261  	return (0);
262  } /* ng_btsocket_l2cap_raw_node_disconnect */
263  
264  /*
265   * Process incoming messages
266   */
267  
268  static int
ng_btsocket_l2cap_raw_node_rcvmsg(node_p node,item_p item,hook_p hook)269  ng_btsocket_l2cap_raw_node_rcvmsg(node_p node, item_p item, hook_p hook)
270  {
271  	struct ng_mesg	*msg = NGI_MSG(item); /* item still has message */
272  	int		 error = 0;
273  
274  	if (msg != NULL && msg->header.typecookie == NGM_L2CAP_COOKIE) {
275  
276  		/*
277  		 * NGM_L2CAP_NODE_HOOK_INFO is special message initiated by
278  		 * L2CAP layer. Ignore all other messages if they are not
279  		 * replies or token is zero
280  		 */
281  
282  		if (msg->header.cmd != NGM_L2CAP_NODE_HOOK_INFO) {
283  			if (msg->header.token == 0 ||
284  			    !(msg->header.flags & NGF_RESP)) {
285  				NG_FREE_ITEM(item);
286  				return (0);
287  			}
288  		}
289  
290  		lockmgr(&ng_btsocket_l2cap_raw_queue_lock, LK_EXCLUSIVE);
291  		if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_raw_queue)) {
292  			NG_BTSOCKET_L2CAP_RAW_ERR(
293  "%s: Input queue is full\n", __func__);
294  
295  			NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_raw_queue);
296  			NG_FREE_ITEM(item);
297  			error = ENOBUFS;
298  		} else {
299  			if (hook != NULL) {
300  				NG_HOOK_REF(hook);
301  				NGI_SET_HOOK(item, hook);
302  			}
303  
304  			ng_ref_item(item);
305  			NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_raw_queue, item);
306  			error = ng_btsocket_l2cap_raw_wakeup_input_task();
307  		}
308  		lockmgr(&ng_btsocket_l2cap_raw_queue_lock, LK_RELEASE);
309  	} else {
310  		NG_FREE_ITEM(item);
311  		error = EINVAL;
312  	}
313  
314  	return (error);
315  } /* ng_btsocket_l2cap_raw_node_rcvmsg */
316  
317  /*
318   * Receive data on a hook
319   */
320  
321  static int
ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook,item_p item)322  ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook, item_p item)
323  {
324  	NG_FREE_ITEM(item);
325  
326  	return (EINVAL);
327  } /* ng_btsocket_l2cap_raw_node_rcvdata */
328  
329  /*****************************************************************************
330   *****************************************************************************
331   **                              Socket interface
332   *****************************************************************************
333   *****************************************************************************/
334  
335  /*
336   * L2CAP sockets input routine
337   */
338  
339  static void
ng_btsocket_l2cap_raw_input(void * context,int pending)340  ng_btsocket_l2cap_raw_input(void *context, int pending)
341  {
342  	item_p		 item = NULL;
343  	hook_p		 hook = NULL;
344  	struct ng_mesg  *msg = NULL;
345  
346  	for (;;) {
347  		lockmgr(&ng_btsocket_l2cap_raw_queue_lock, LK_EXCLUSIVE);
348  		NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_raw_queue, item);
349  		lockmgr(&ng_btsocket_l2cap_raw_queue_lock, LK_RELEASE);
350  
351  		if (item == NULL)
352  			break;
353  
354  		KASSERT((item->el_flags & NGQF_TYPE) == NGQF_MESG,
355  ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
356  
357  		NGI_GET_MSG(item, msg);
358  		NGI_GET_HOOK(item, hook);
359  		NG_FREE_ITEM(item);
360  		ng_unref_item(item, 0);
361  
362  		switch (msg->header.cmd) {
363  		case NGM_L2CAP_NODE_HOOK_INFO: {
364  			ng_btsocket_l2cap_rtentry_t	*rt = NULL;
365  
366  			if (hook == NULL || NG_HOOK_NOT_VALID(hook) ||
367  			    msg->header.arglen != sizeof(bdaddr_t))
368  				break;
369  
370  			if (bcmp(msg->data, NG_HCI_BDADDR_ANY,
371  					sizeof(bdaddr_t)) == 0)
372  				break;
373  
374  			rt = (ng_btsocket_l2cap_rtentry_t *)
375  				NG_HOOK_PRIVATE(hook);
376  			if (rt == NULL) {
377  				rt = kmalloc(sizeof(*rt),
378  					     M_NETGRAPH_BTSOCKET_L2CAP_RAW,
379  					     M_WAITOK | M_NULLOK | M_ZERO);
380  				if (rt == NULL)
381  					break;
382  
383  				NG_HOOK_SET_PRIVATE(hook, rt);
384  
385  				lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_EXCLUSIVE);
386  
387  				LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_rt,
388  					rt, next);
389  			} else
390  				lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_EXCLUSIVE);
391  
392  			bcopy(msg->data, &rt->src, sizeof(rt->src));
393  			rt->hook = hook;
394  
395  			NG_BTSOCKET_L2CAP_RAW_INFO(
396  "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n",
397  				__func__, NG_HOOK_NAME(hook),
398  				rt->src.b[5], rt->src.b[4], rt->src.b[3],
399  				rt->src.b[2], rt->src.b[1], rt->src.b[0]);
400  
401  			lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_RELEASE);
402  			} break;
403  
404  		case NGM_L2CAP_NODE_GET_FLAGS:
405  		case NGM_L2CAP_NODE_GET_DEBUG:
406  		case NGM_L2CAP_NODE_GET_CON_LIST:
407  		case NGM_L2CAP_NODE_GET_CHAN_LIST:
408  		case NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO:
409  		case NGM_L2CAP_L2CA_PING:
410  		case NGM_L2CAP_L2CA_GET_INFO: {
411  			ng_btsocket_l2cap_raw_pcb_p	pcb = NULL;
412  
413  			lockmgr(&ng_btsocket_l2cap_raw_sockets_lock, LK_EXCLUSIVE);
414  
415  			LIST_FOREACH(pcb,&ng_btsocket_l2cap_raw_sockets,next) {
416  				lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
417  
418  				if (pcb->token == msg->header.token) {
419  					pcb->msg = msg;
420  					msg = NULL;
421  					wakeup(&pcb->msg);
422  					lockmgr(&pcb->pcb_lock, LK_RELEASE);
423  					break;
424  				}
425  
426  				lockmgr(&pcb->pcb_lock, LK_RELEASE);
427  			}
428  
429  			lockmgr(&ng_btsocket_l2cap_raw_sockets_lock, LK_RELEASE);
430  			} break;
431  
432  		default:
433  			NG_BTSOCKET_L2CAP_RAW_WARN(
434  "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
435  			break;
436  		}
437  
438  		if (hook != NULL)
439  			NG_HOOK_UNREF(hook); /* remove extra reference */
440  
441  		NG_FREE_MSG(msg); /* Checks for msg != NULL */
442  	}
443  } /* ng_btsocket_l2cap_raw_input */
444  
445  /*
446   * Route cleanup task. Gets scheduled when hook is disconnected. Here we
447   * will find all sockets that use "invalid" hook and disconnect them.
448   */
449  
450  static void
ng_btsocket_l2cap_raw_rtclean(void * context,int pending)451  ng_btsocket_l2cap_raw_rtclean(void *context, int pending)
452  {
453  	ng_btsocket_l2cap_raw_pcb_p	pcb = NULL;
454  	ng_btsocket_l2cap_rtentry_p	rt = NULL;
455  
456  	/*
457  	 * First disconnect all sockets that use "invalid" hook
458  	 */
459  
460  	lockmgr(&ng_btsocket_l2cap_raw_sockets_lock, LK_EXCLUSIVE);
461  
462  	LIST_FOREACH(pcb, &ng_btsocket_l2cap_raw_sockets, next) {
463  		lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
464  
465  		if (pcb->rt != NULL &&
466  		    pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
467  			if (pcb->so != NULL &&
468  			    pcb->so->so_state & SS_ISCONNECTED)
469  				soisdisconnected(pcb->so);
470  
471  			pcb->rt = NULL;
472  		}
473  
474  		lockmgr(&pcb->pcb_lock, LK_RELEASE);
475  	}
476  
477  	lockmgr(&ng_btsocket_l2cap_raw_sockets_lock, LK_RELEASE);
478  
479  	/*
480  	 * Now cleanup routing table
481  	 */
482  
483  	lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_EXCLUSIVE);
484  
485  	for (rt = LIST_FIRST(&ng_btsocket_l2cap_raw_rt); rt != NULL; ) {
486  		ng_btsocket_l2cap_rtentry_p	rt_next = LIST_NEXT(rt, next);
487  
488  		if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
489  			LIST_REMOVE(rt, next);
490  
491  			NG_HOOK_SET_PRIVATE(rt->hook, NULL);
492  			NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
493  
494  			bzero(rt, sizeof(*rt));
495  			kfree(rt, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
496  		}
497  
498  		rt = rt_next;
499  	}
500  
501  	lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_RELEASE);
502  } /* ng_btsocket_l2cap_raw_rtclean */
503  
504  /*
505   * Initialize everything
506   */
507  
508  void
ng_btsocket_l2cap_raw_init(void)509  ng_btsocket_l2cap_raw_init(void)
510  {
511  	int	error = 0;
512  
513  	ng_btsocket_l2cap_raw_node = NULL;
514  	ng_btsocket_l2cap_raw_debug_level = NG_BTSOCKET_WARN_LEVEL;
515  	ng_btsocket_l2cap_raw_ioctl_timeout = 5;
516  
517  	/* Register Netgraph node type */
518  	error = ng_newtype(&typestruct);
519  	if (error != 0) {
520  		NG_BTSOCKET_L2CAP_RAW_ALERT(
521  "%s: Could not register Netgraph node type, error=%d\n", __func__, error);
522  
523                  return;
524  	}
525  
526  	/* Create Netgrapg node */
527  	error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
528  	if (error != 0) {
529  		NG_BTSOCKET_L2CAP_RAW_ALERT(
530  "%s: Could not create Netgraph node, error=%d\n", __func__, error);
531  
532  		ng_btsocket_l2cap_raw_node = NULL;
533  
534  		return;
535  	}
536  
537  	error = ng_name_node(ng_btsocket_l2cap_raw_node,
538  				NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
539  	if (error != 0) {
540  		NG_BTSOCKET_L2CAP_RAW_ALERT(
541  "%s: Could not name Netgraph node, error=%d\n", __func__, error);
542  
543  		NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
544  		ng_btsocket_l2cap_raw_node = NULL;
545  
546  		return;
547  	}
548  
549  	/* Create input queue */
550  	NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_raw_queue, ifqmaxlen);
551  	lockinit(&ng_btsocket_l2cap_raw_queue_lock,
552  		"btsocks_l2cap_raw_queue_lock", 0, 0);
553  	TASK_INIT(&ng_btsocket_l2cap_raw_queue_task, 0,
554  		ng_btsocket_l2cap_raw_input, NULL);
555  
556  	/* Create list of sockets */
557  	LIST_INIT(&ng_btsocket_l2cap_raw_sockets);
558  	lockinit(&ng_btsocket_l2cap_raw_sockets_lock,
559  		"btsocks_l2cap_raw_sockets_lock", 0, 0);
560  
561  	/* Tokens */
562  	ng_btsocket_l2cap_raw_token = 0;
563  	lockinit(&ng_btsocket_l2cap_raw_token_lock,
564  		"btsocks_l2cap_raw_token_lock", 0, 0);
565  
566  	/* Routing table */
567  	LIST_INIT(&ng_btsocket_l2cap_raw_rt);
568  	lockinit(&ng_btsocket_l2cap_raw_rt_lock,
569  		"btsocks_l2cap_raw_rt_lock", 0, 0);
570  	TASK_INIT(&ng_btsocket_l2cap_raw_rt_task, 0,
571  		ng_btsocket_l2cap_raw_rtclean, NULL);
572  } /* ng_btsocket_l2cap_raw_init */
573  
574  /*
575   * Abort connection on socket
576   */
577  
578  void
ng_btsocket_l2cap_raw_abort(netmsg_t msg)579  ng_btsocket_l2cap_raw_abort(netmsg_t msg)
580  {
581  
582  	(void)ng_btsocket_l2cap_raw_disconnect(msg);
583  } /* ng_btsocket_l2cap_raw_abort */
584  
585  #if 0 /* XXX */
586  void
587  ng_btsocket_l2cap_raw_close(struct socket *so)
588  {
589  
590  	(void)ng_btsocket_l2cap_raw_disconnect(so);
591  } /* ng_btsocket_l2cap_raw_close */
592  #endif
593  
594  /*
595   * Create and attach new socket
596   */
597  
598  void
ng_btsocket_l2cap_raw_attach(netmsg_t msg)599  ng_btsocket_l2cap_raw_attach(netmsg_t msg)
600  {
601  	struct socket			*so = msg->attach.base.nm_so;
602  	ng_btsocket_l2cap_raw_pcb_p	 pcb = so2l2cap_raw_pcb(so);
603  	int				 error = 0;
604  
605  	if (pcb != NULL) {
606  		error = EISCONN;
607  		goto out;
608  	}
609  
610  	if (ng_btsocket_l2cap_raw_node == NULL) {
611  		error = EPROTONOSUPPORT;
612  		goto out;
613  	}
614  	if (so->so_type != SOCK_RAW) {
615  		error = ESOCKTNOSUPPORT;
616  		goto out;
617  	}
618  
619  	/* Reserve send and receive space if it is not reserved yet */
620  	error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE,
621  			NG_BTSOCKET_L2CAP_RAW_RECVSPACE, NULL);
622  	if (error != 0)
623  		goto out;
624  
625  	/* Allocate the PCB */
626          pcb = kmalloc(sizeof(*pcb), M_NETGRAPH_BTSOCKET_L2CAP_RAW,
627  		      M_WAITOK | M_NULLOK | M_ZERO);
628          if (pcb == NULL) {
629  		error = ENOMEM;
630  		goto out;
631  	}
632  
633  	/* Link the PCB and the socket */
634  	so->so_pcb = (caddr_t) pcb;
635  	pcb->so = so;
636  
637  	if (curproc == NULL ||
638  	    caps_priv_check_self(SYSCAP_NONET_BT_RAW) == 0)
639  	{
640  		pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED;
641  	}
642  
643  	lockinit(&pcb->pcb_lock, "btsocks_l2cap_raw_pcb_lock", 0, 0);
644  
645          /* Add the PCB to the list */
646  	lockmgr(&ng_btsocket_l2cap_raw_sockets_lock, LK_EXCLUSIVE);
647  	LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next);
648  	lockmgr(&ng_btsocket_l2cap_raw_sockets_lock, LK_RELEASE);
649  
650  out:
651  	lwkt_replymsg(&msg->attach.base.lmsg, error);
652  } /* ng_btsocket_l2cap_raw_attach */
653  
654  /*
655   * Bind socket
656   */
657  
658  void
ng_btsocket_l2cap_raw_bind(netmsg_t msg)659  ng_btsocket_l2cap_raw_bind(netmsg_t msg)
660  {
661  	struct socket			*so = msg->bind.base.nm_so;
662  	struct sockaddr			*nam = msg->bind.nm_nam;
663  	ng_btsocket_l2cap_raw_pcb_t	*pcb = so2l2cap_raw_pcb(so);
664  	struct sockaddr_l2cap		*sa = (struct sockaddr_l2cap *) nam;
665  	ng_btsocket_l2cap_rtentry_t	*rt = NULL;
666  	int				 error = 0;
667  
668  	if (pcb == NULL) {
669  		error = EINVAL;
670  		goto out;
671  	}
672  	if (ng_btsocket_l2cap_raw_node == NULL) {
673  		error = EINVAL;
674  		goto out;
675  	}
676  
677  	if (sa == NULL) {
678  		error = EINVAL;
679  		goto out;
680  	}
681  	if (sa->l2cap_family != AF_BLUETOOTH) {
682  		error = EAFNOSUPPORT;
683  		goto out;
684  	}
685  	if (sa->l2cap_len != sizeof(*sa)) {
686  		error = EINVAL;
687  		goto out;
688  	}
689  
690  	if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY,
691  				sizeof(sa->l2cap_bdaddr)) != 0) {
692  		lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_EXCLUSIVE);
693  
694  		LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
695  			if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
696  				continue;
697  
698  			if (bcmp(&sa->l2cap_bdaddr, &rt->src,
699  					sizeof(rt->src)) == 0)
700  				break;
701  		}
702  
703  		lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_RELEASE);
704  
705  		if (rt == NULL) {
706  			error = ENETDOWN;
707  			goto out;
708  		}
709  	} else
710  		rt = NULL;
711  
712  	lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
713  	bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src));
714  	pcb->rt = rt;
715  	lockmgr(&pcb->pcb_lock, LK_RELEASE);
716  
717  out:
718  	lwkt_replymsg(&msg->bind.base.lmsg, error);
719  } /* ng_btsocket_l2cap_raw_bind */
720  
721  /*
722   * Connect socket
723   */
724  
725  void
ng_btsocket_l2cap_raw_connect(netmsg_t msg)726  ng_btsocket_l2cap_raw_connect(netmsg_t msg)
727  {
728  	struct socket			*so = msg->connect.base.nm_so;
729  	struct sockaddr			*nam = msg->connect.nm_nam;
730  	ng_btsocket_l2cap_raw_pcb_t	*pcb = so2l2cap_raw_pcb(so);
731  	struct sockaddr_l2cap		*sa = (struct sockaddr_l2cap *) nam;
732  	ng_btsocket_l2cap_rtentry_t	*rt = NULL;
733  	int				 error = 0;
734  
735  	if (pcb == NULL) {
736  		error = EINVAL;
737  		goto out;
738  	}
739  	if (ng_btsocket_l2cap_raw_node == NULL) {
740  		error = EINVAL;
741  		goto out;
742  	}
743  
744  	if (sa == NULL) {
745  		error = EINVAL;
746  		goto out;
747  	}
748  	if (sa->l2cap_family != AF_BLUETOOTH) {
749  		error = EAFNOSUPPORT;
750  		goto out;
751  	}
752  	if (sa->l2cap_len != sizeof(*sa)) {
753  		error = EINVAL;
754  		goto out;
755  	}
756  	if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) {
757  		error = EINVAL;
758  		goto out;
759  	}
760  
761  	lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
762  
763  	bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));
764  
765  	if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) {
766  		lockmgr(&pcb->pcb_lock, LK_RELEASE);
767  		error = EADDRNOTAVAIL;
768  		goto out;
769  	}
770  
771  	/*
772  	 * If there is route already - use it
773  	 */
774  
775  	if (pcb->rt != NULL) {
776  		soisconnected(so);
777  		lockmgr(&pcb->pcb_lock, LK_RELEASE);
778  		goto out;
779  	}
780  
781  	/*
782  	 * Find the first hook that does not match specified destination address
783  	 */
784  
785  	lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_EXCLUSIVE);
786  
787  	LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
788  		if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
789  			continue;
790  
791  		if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
792  			break;
793  	}
794  
795  	if (rt != NULL) {
796  		soisconnected(so);
797  
798  		pcb->rt = rt;
799  		bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
800  	} else
801  		error = ENETDOWN;
802  
803  	lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_RELEASE);
804  	lockmgr(&pcb->pcb_lock, LK_RELEASE);
805  
806  out:
807  	lwkt_replymsg(&msg->connect.base.lmsg, error);
808  } /* ng_btsocket_l2cap_raw_connect */
809  
810  /*
811   * Process ioctl's calls on socket
812   */
813  
814  void
ng_btsocket_l2cap_raw_control(netmsg_t msg)815  ng_btsocket_l2cap_raw_control(netmsg_t msg)
816  {
817  	struct socket			*so = msg->control.base.nm_so;
818  	u_long				 cmd = msg->control.nm_cmd;
819  	caddr_t				 data = msg->control.nm_data;
820  	ng_btsocket_l2cap_raw_pcb_p	 pcb = so2l2cap_raw_pcb(so);
821  	struct ng_mesg			*ngmsg = NULL;
822  	int				 error = 0;
823  
824  	if (pcb == NULL) {
825  		error = EINVAL;
826  		goto out;
827  	}
828  	if (ng_btsocket_l2cap_raw_node == NULL) {
829  		error = EINVAL;
830  		goto out;
831  	}
832  
833  	lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
834  
835  	/* Check if we route info */
836  	if (pcb->rt == NULL) {
837  		lockmgr(&pcb->pcb_lock, LK_RELEASE);
838  		error = EHOSTUNREACH;
839  		goto out;
840  	}
841  
842  	/* Check if we have pending ioctl() */
843  	if (pcb->token != 0) {
844  		lockmgr(&pcb->pcb_lock, LK_RELEASE);
845  		error = EBUSY;
846  		goto out;
847  	}
848  
849  	switch (cmd) {
850  	case SIOC_L2CAP_NODE_GET_FLAGS: {
851  		struct ng_btsocket_l2cap_raw_node_flags	*p =
852  			(struct ng_btsocket_l2cap_raw_node_flags *) data;
853  
854  		error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
855  				NGM_L2CAP_NODE_GET_FLAGS,
856  				&p->flags, sizeof(p->flags));
857  		} break;
858  
859  	case SIOC_L2CAP_NODE_GET_DEBUG: {
860  		struct ng_btsocket_l2cap_raw_node_debug	*p =
861  			(struct ng_btsocket_l2cap_raw_node_debug *) data;
862  
863  		error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
864  				NGM_L2CAP_NODE_GET_DEBUG,
865  				&p->debug, sizeof(p->debug));
866  		} break;
867  
868  	case SIOC_L2CAP_NODE_SET_DEBUG: {
869  		struct ng_btsocket_l2cap_raw_node_debug	*p =
870  			(struct ng_btsocket_l2cap_raw_node_debug *) data;
871  
872  		if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
873  			error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
874  					NGM_L2CAP_NODE_SET_DEBUG,
875  					&p->debug, sizeof(p->debug));
876  		else
877  			error = EPERM;
878  		} break;
879  
880  	case SIOC_L2CAP_NODE_GET_CON_LIST: {
881  		struct ng_btsocket_l2cap_raw_con_list	*p =
882  			(struct ng_btsocket_l2cap_raw_con_list *) data;
883  		ng_l2cap_node_con_list_ep		*p1 = NULL;
884                  ng_l2cap_node_con_ep			*p2 = NULL;
885  
886  		if (p->num_connections == 0 ||
887  		    p->num_connections > NG_L2CAP_MAX_CON_NUM ||
888  		    p->connections == NULL) {
889  			error = EINVAL;
890  			break;
891  		}
892  
893  		NG_MKMESSAGE(ngmsg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST,
894  			0, M_WAITOK | M_NULLOK);
895  		if (ngmsg == NULL) {
896  			error = ENOMEM;
897  			break;
898  		}
899  		ng_btsocket_l2cap_raw_get_token(&ngmsg->header.token);
900  		pcb->token = ngmsg->header.token;
901  		pcb->msg = NULL;
902  
903  		NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, ngmsg,
904  			pcb->rt->hook, 0);
905  		if (error != 0) {
906  			pcb->token = 0;
907  			break;
908  		}
909  
910  		error = lksleep(&pcb->msg, &pcb->pcb_lock, PCATCH, "l2ctl",
911  				ng_btsocket_l2cap_raw_ioctl_timeout * hz);
912  		pcb->token = 0;
913  
914  		if (error != 0)
915  			break;
916  
917  		if (pcb->msg != NULL &&
918  		    pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) {
919  			/* Return data back to user space */
920  			p1 = (ng_l2cap_node_con_list_ep *)(pcb->msg->data);
921  			p2 = (ng_l2cap_node_con_ep *)(p1 + 1);
922  
923  			p->num_connections = min(p->num_connections,
924  						p1->num_connections);
925  			if (p->num_connections > 0)
926  				error = copyout((caddr_t) p2,
927  					(caddr_t) p->connections,
928  					p->num_connections * sizeof(*p2));
929  		} else
930  			error = EINVAL;
931  
932  		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
933  		} break;
934  
935  	case SIOC_L2CAP_NODE_GET_CHAN_LIST: {
936  		struct ng_btsocket_l2cap_raw_chan_list	*p =
937  			(struct ng_btsocket_l2cap_raw_chan_list *) data;
938  		ng_l2cap_node_chan_list_ep		*p1 = NULL;
939                  ng_l2cap_node_chan_ep			*p2 = NULL;
940  
941  		if (p->num_channels == 0 ||
942  		    p->num_channels > NG_L2CAP_MAX_CHAN_NUM ||
943  		    p->channels == NULL) {
944  			error = EINVAL;
945  			break;
946  		}
947  
948  		NG_MKMESSAGE(ngmsg, NGM_L2CAP_COOKIE,
949  			NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_WAITOK | M_NULLOK);
950  		if (ngmsg == NULL) {
951  			error = ENOMEM;
952  			break;
953  		}
954  		ng_btsocket_l2cap_raw_get_token(&ngmsg->header.token);
955  		pcb->token = ngmsg->header.token;
956  		pcb->msg = NULL;
957  
958  		NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, ngmsg,
959  			pcb->rt->hook, 0);
960  		if (error != 0) {
961  			pcb->token = 0;
962  			break;
963  		}
964  
965  		error = lksleep(&pcb->msg, &pcb->pcb_lock, PCATCH, "l2ctl",
966  				ng_btsocket_l2cap_raw_ioctl_timeout * hz);
967  		pcb->token = 0;
968  
969  		if (error != 0)
970  			break;
971  
972  		if (pcb->msg != NULL &&
973  		    pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) {
974  			/* Return data back to user space */
975  			p1 = (ng_l2cap_node_chan_list_ep *)(pcb->msg->data);
976  			p2 = (ng_l2cap_node_chan_ep *)(p1 + 1);
977  
978  			p->num_channels = min(p->num_channels,
979  						p1->num_channels);
980  			if (p->num_channels > 0)
981  				error = copyout((caddr_t) p2,
982  						(caddr_t) p->channels,
983  						p->num_channels * sizeof(*p2));
984  		} else
985  			error = EINVAL;
986  
987  		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
988  		} break;
989  
990  	case SIOC_L2CAP_L2CA_PING: {
991  		struct ng_btsocket_l2cap_raw_ping	*p =
992  			(struct ng_btsocket_l2cap_raw_ping *) data;
993  		ng_l2cap_l2ca_ping_ip			*ip = NULL;
994  		ng_l2cap_l2ca_ping_op			*op = NULL;
995  
996  		if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
997  			error = EPERM;
998  			break;
999  		}
1000  
1001  		if ((p->echo_size != 0 && p->echo_data == NULL) ||
1002  		     p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
1003  			error = EINVAL;
1004  			break;
1005  		}
1006  
1007  		NG_MKMESSAGE(ngmsg, NGM_L2CAP_COOKIE,
1008  			NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size,
1009  			M_WAITOK | M_NULLOK);
1010  		if (ngmsg == NULL) {
1011  			error = ENOMEM;
1012  			break;
1013  		}
1014  		ng_btsocket_l2cap_raw_get_token(&ngmsg->header.token);
1015  		pcb->token = ngmsg->header.token;
1016  		pcb->msg = NULL;
1017  
1018  		ip = (ng_l2cap_l2ca_ping_ip *)(ngmsg->data);
1019  		bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
1020  		ip->echo_size = p->echo_size;
1021  
1022  		if (ip->echo_size > 0) {
1023  			error = copyin(p->echo_data, ip + 1, p->echo_size);
1024  			if (error != 0) {
1025  				NG_FREE_MSG(ngmsg);
1026  				pcb->token = 0;
1027  				break;
1028  			}
1029  		}
1030  
1031  		NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, ngmsg,
1032  			pcb->rt->hook, 0);
1033  		if (error != 0) {
1034  			pcb->token = 0;
1035  			break;
1036  		}
1037  
1038  		error = lksleep(&pcb->msg, &pcb->pcb_lock, PCATCH, "l2ctl",
1039  				bluetooth_l2cap_rtx_timeout());
1040  		pcb->token = 0;
1041  
1042  		if (error != 0)
1043  			break;
1044  
1045  		if (pcb->msg != NULL &&
1046  		    pcb->msg->header.cmd == NGM_L2CAP_L2CA_PING) {
1047  			/* Return data back to the user space */
1048  			op = (ng_l2cap_l2ca_ping_op *)(pcb->msg->data);
1049  			p->result = op->result;
1050  			p->echo_size = min(p->echo_size, op->echo_size);
1051  
1052  			if (p->echo_size > 0)
1053  				error = copyout(op + 1, p->echo_data,
1054  						p->echo_size);
1055  		} else
1056  			error = EINVAL;
1057  
1058  		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1059  		} break;
1060  
1061  	case SIOC_L2CAP_L2CA_GET_INFO: {
1062  		struct ng_btsocket_l2cap_raw_get_info	*p =
1063  			(struct ng_btsocket_l2cap_raw_get_info *) data;
1064  		ng_l2cap_l2ca_get_info_ip		*ip = NULL;
1065  		ng_l2cap_l2ca_get_info_op		*op = NULL;
1066  
1067  		if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
1068  			error = EPERM;
1069  			break;
1070  		}
1071  
1072  		if (p->info_size != 0 && p->info_data == NULL) {
1073  			error = EINVAL;
1074  			break;
1075  		}
1076  
1077  		NG_MKMESSAGE(ngmsg, NGM_L2CAP_COOKIE,
1078  			NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size,
1079  			M_WAITOK | M_NULLOK);
1080  		if (ngmsg == NULL) {
1081  			error = ENOMEM;
1082  			break;
1083  		}
1084  		ng_btsocket_l2cap_raw_get_token(&ngmsg->header.token);
1085  		pcb->token = ngmsg->header.token;
1086  		pcb->msg = NULL;
1087  
1088  		ip = (ng_l2cap_l2ca_get_info_ip *)(ngmsg->data);
1089  		bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
1090  		ip->info_type = p->info_type;
1091  
1092  		NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, ngmsg,
1093  			pcb->rt->hook, 0);
1094  		if (error != 0) {
1095  			pcb->token = 0;
1096  			break;
1097  		}
1098  
1099  		error = lksleep(&pcb->msg, &pcb->pcb_lock, PCATCH, "l2ctl",
1100  				bluetooth_l2cap_rtx_timeout());
1101  		pcb->token = 0;
1102  
1103  		if (error != 0)
1104  			break;
1105  
1106  		if (pcb->msg != NULL &&
1107  		    pcb->msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) {
1108  			/* Return data back to the user space */
1109  			op = (ng_l2cap_l2ca_get_info_op *)(pcb->msg->data);
1110  			p->result = op->result;
1111  			p->info_size = min(p->info_size, op->info_size);
1112  
1113  			if (p->info_size > 0)
1114  				error = copyout(op + 1, p->info_data,
1115  						p->info_size);
1116  		} else
1117  			error = EINVAL;
1118  
1119  		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1120  		} break;
1121  
1122  	case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: {
1123  		struct ng_btsocket_l2cap_raw_auto_discon_timo	*p =
1124  			(struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1125  
1126  		error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
1127  				NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO,
1128  				&p->timeout, sizeof(p->timeout));
1129  		} break;
1130  
1131  	case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: {
1132  		struct ng_btsocket_l2cap_raw_auto_discon_timo	*p =
1133  			(struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1134  
1135  		if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
1136  			error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
1137  					NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO,
1138  					&p->timeout, sizeof(p->timeout));
1139  		else
1140  			error = EPERM;
1141  		} break;
1142  
1143  	default:
1144  		error = EINVAL;
1145  		break;
1146  	}
1147  
1148  	lockmgr(&pcb->pcb_lock, LK_RELEASE);
1149  
1150  out:
1151  	lwkt_replymsg(&msg->control.base.lmsg, error);
1152  } /* ng_btsocket_l2cap_raw_control */
1153  
1154  /*
1155   * Detach and destroy socket
1156   */
1157  
1158  void
ng_btsocket_l2cap_raw_detach(netmsg_t msg)1159  ng_btsocket_l2cap_raw_detach(netmsg_t msg)
1160  {
1161  	struct socket			*so = msg->detach.base.nm_so;
1162  	ng_btsocket_l2cap_raw_pcb_p	 pcb = so2l2cap_raw_pcb(so);
1163  	int				 error = 0;
1164  
1165  	KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL"));
1166  	if (ng_btsocket_l2cap_raw_node == NULL)
1167  		goto out;
1168  
1169  	lockmgr(&ng_btsocket_l2cap_raw_sockets_lock, LK_EXCLUSIVE);
1170  	lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
1171  
1172  	LIST_REMOVE(pcb, next);
1173  
1174  	lockmgr(&pcb->pcb_lock, LK_RELEASE);
1175  	lockmgr(&ng_btsocket_l2cap_raw_sockets_lock, LK_RELEASE);
1176  
1177  	lockuninit(&pcb->pcb_lock);
1178  
1179  	bzero(pcb, sizeof(*pcb));
1180  	kfree(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
1181  
1182  	so->so_pcb = NULL;
1183  
1184  out:
1185  	lwkt_replymsg(&msg->detach.base.lmsg, error);
1186  } /* ng_btsocket_l2cap_raw_detach */
1187  
1188  /*
1189   * Disconnect socket
1190   */
1191  
1192  void
ng_btsocket_l2cap_raw_disconnect(netmsg_t msg)1193  ng_btsocket_l2cap_raw_disconnect(netmsg_t msg)
1194  {
1195  	struct socket			*so = msg->disconnect.base.nm_so;
1196  	ng_btsocket_l2cap_raw_pcb_p	 pcb = so2l2cap_raw_pcb(so);
1197  	int				 error = 0;
1198  
1199  	if (pcb == NULL) {
1200  		error = EINVAL;
1201  		goto out;
1202  	}
1203  	if (ng_btsocket_l2cap_raw_node == NULL) {
1204  		error = EINVAL;
1205  		goto out;
1206  	}
1207  
1208  	lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
1209  	pcb->rt = NULL;
1210  	soisdisconnected(so);
1211  	lockmgr(&pcb->pcb_lock, LK_RELEASE);
1212  
1213  out:
1214  	lwkt_replymsg(&msg->disconnect.base.lmsg, error);
1215  } /* ng_btsocket_l2cap_raw_disconnect */
1216  
1217  /*
1218   * Get peer address
1219   */
1220  
1221  void
ng_btsocket_l2cap_raw_peeraddr(netmsg_t msg)1222  ng_btsocket_l2cap_raw_peeraddr(netmsg_t msg)
1223  {
1224  	struct socket			 *so = msg->peeraddr.base.nm_so;
1225  	struct sockaddr			**nam = msg->peeraddr.nm_nam;
1226  	ng_btsocket_l2cap_raw_pcb_p	  pcb = so2l2cap_raw_pcb(so);
1227  	struct sockaddr_l2cap		  sa;
1228  	int				  error = 0;
1229  
1230  	if (pcb == NULL) {
1231  		error = EINVAL;
1232  		goto out;
1233  	}
1234  	if (ng_btsocket_l2cap_raw_node == NULL) {
1235  		error = EINVAL;
1236  		goto out;
1237  	}
1238  
1239  	lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
1240  	bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1241  	lockmgr(&pcb->pcb_lock, LK_RELEASE);
1242  
1243  	sa.l2cap_psm = 0;
1244  	sa.l2cap_len = sizeof(sa);
1245  	sa.l2cap_family = AF_BLUETOOTH;
1246  
1247  	*nam = dup_sockaddr((struct sockaddr *) &sa);
1248  
1249  	if (*nam == NULL)
1250  		error = ENOMEM;
1251  
1252  out:
1253  	lwkt_replymsg(&msg->peeraddr.base.lmsg, error);
1254  } /* ng_btsocket_l2cap_raw_peeraddr */
1255  
1256  /*
1257   * Send data to socket
1258   */
1259  
1260  void
ng_btsocket_l2cap_raw_send(netmsg_t msg)1261  ng_btsocket_l2cap_raw_send(netmsg_t msg)
1262  {
1263  	struct mbuf			*control = msg->send.nm_control;
1264  	struct mbuf			*m = msg->send.nm_m;
1265  
1266  	NG_FREE_M(m); /* Checks for m != NULL */
1267  	NG_FREE_M(control);
1268  
1269  	lwkt_replymsg(&msg->send.base.lmsg, EOPNOTSUPP);
1270  } /* ng_btsocket_l2cap_raw_send */
1271  
1272  /*
1273   * Get socket address
1274   */
1275  
1276  void
ng_btsocket_l2cap_raw_sockaddr(netmsg_t msg)1277  ng_btsocket_l2cap_raw_sockaddr(netmsg_t msg)
1278  {
1279  	struct socket			 *so = msg->sockaddr.base.nm_so;
1280  	struct sockaddr			**nam = msg->sockaddr.nm_nam;
1281  	ng_btsocket_l2cap_raw_pcb_p	  pcb = so2l2cap_raw_pcb(so);
1282  	struct sockaddr_l2cap		  sa;
1283  	int				  error = 0;
1284  
1285  	if (pcb == NULL) {
1286  		error = EINVAL;
1287  		goto out;
1288  	}
1289  	if (ng_btsocket_l2cap_raw_node == NULL) {
1290  		error = EINVAL;
1291  		goto out;
1292  	}
1293  
1294  	lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
1295  	bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1296  	lockmgr(&pcb->pcb_lock, LK_RELEASE);
1297  
1298  	sa.l2cap_psm = 0;
1299  	sa.l2cap_len = sizeof(sa);
1300  	sa.l2cap_family = AF_BLUETOOTH;
1301  
1302  	*nam = dup_sockaddr((struct sockaddr *) &sa);
1303  
1304  	if (*nam == NULL)
1305  		error = ENOMEM;
1306  
1307  out:
1308  	lwkt_replymsg(&msg->sockaddr.base.lmsg, error);
1309  } /* ng_btsocket_l2cap_raw_sockaddr */
1310  
1311  /*
1312   * Get next token
1313   */
1314  
1315  static void
ng_btsocket_l2cap_raw_get_token(u_int32_t * token)1316  ng_btsocket_l2cap_raw_get_token(u_int32_t *token)
1317  {
1318  	lockmgr(&ng_btsocket_l2cap_raw_token_lock, LK_EXCLUSIVE);
1319  
1320  	if (++ ng_btsocket_l2cap_raw_token == 0)
1321  		ng_btsocket_l2cap_raw_token = 1;
1322  
1323  	*token = ng_btsocket_l2cap_raw_token;
1324  
1325  	lockmgr(&ng_btsocket_l2cap_raw_token_lock, LK_RELEASE);
1326  } /* ng_btsocket_l2cap_raw_get_token */
1327  
1328  /*
1329   * Send Netgraph message to the node - do not expect reply
1330   */
1331  
1332  static int
ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook,int cmd,void * arg,int arglen)1333  ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen)
1334  {
1335  	struct ng_mesg	*msg = NULL;
1336  	int		 error = 0;
1337  
1338  	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_WAITOK | M_NULLOK);
1339  	if (msg == NULL)
1340  		return (ENOMEM);
1341  
1342  	if (arg != NULL && arglen > 0)
1343  		bcopy(arg, msg->data, arglen);
1344  
1345  	NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0);
1346  
1347  	return (error);
1348  } /* ng_btsocket_l2cap_raw_send_ngmsg */
1349  
1350  /*
1351   * Send Netgraph message to the node (no data) and wait for reply
1352   */
1353  
1354  static int
ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,int cmd,void * rsp,int rsplen)1355  ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,
1356  		int cmd, void *rsp, int rsplen)
1357  {
1358  	struct ng_mesg	*msg = NULL;
1359  	int		 error = 0;
1360  
1361  	KKASSERT(lockowned(&pcb->pcb_lock) != 0);
1362  
1363  	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_WAITOK | M_NULLOK);
1364  	if (msg == NULL)
1365  		return (ENOMEM);
1366  
1367  	ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1368  	pcb->token = msg->header.token;
1369  	pcb->msg = NULL;
1370  
1371  	NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1372  		pcb->rt->hook, 0);
1373  	if (error != 0) {
1374  		pcb->token = 0;
1375  		return (error);
1376  	}
1377  
1378  	error = lksleep(&pcb->msg, &pcb->pcb_lock, PCATCH, "l2ctl",
1379  			ng_btsocket_l2cap_raw_ioctl_timeout * hz);
1380  	pcb->token = 0;
1381  
1382  	if (error != 0)
1383  		return (error);
1384  
1385  	if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)
1386  		bcopy(pcb->msg->data, rsp, rsplen);
1387  	else
1388  		error = EINVAL;
1389  
1390  	NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1391  
1392  	return (0);
1393  } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */
1394  
1395