1b06ebda0SMatthew Dillon /*-
222ff886eSAlex Hornung * (MPSAFE)
322ff886eSAlex Hornung *
4b06ebda0SMatthew Dillon * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5b06ebda0SMatthew Dillon * All rights reserved.
6b06ebda0SMatthew Dillon *
722ff886eSAlex Hornung * ng_h4.c
822ff886eSAlex Hornung *
9b06ebda0SMatthew Dillon * Redistribution and use in source and binary forms, with or without
10b06ebda0SMatthew Dillon * modification, are permitted provided that the following conditions
11b06ebda0SMatthew Dillon * are met:
12b06ebda0SMatthew Dillon * 1. Redistributions of source code must retain the above copyright
13b06ebda0SMatthew Dillon * notice, this list of conditions and the following disclaimer.
14b06ebda0SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
15b06ebda0SMatthew Dillon * notice, this list of conditions and the following disclaimer in the
16b06ebda0SMatthew Dillon * documentation and/or other materials provided with the distribution.
17b06ebda0SMatthew Dillon *
18b06ebda0SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19b06ebda0SMatthew Dillon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20b06ebda0SMatthew Dillon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21b06ebda0SMatthew Dillon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22b06ebda0SMatthew Dillon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23b06ebda0SMatthew Dillon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24b06ebda0SMatthew Dillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25b06ebda0SMatthew Dillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26b06ebda0SMatthew Dillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27b06ebda0SMatthew Dillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28b06ebda0SMatthew Dillon * SUCH DAMAGE.
29b06ebda0SMatthew Dillon *
30b06ebda0SMatthew Dillon * $Id: ng_h4.c,v 1.10 2005/10/31 17:57:43 max Exp $
31e85b99abSSascha Wildner * $FreeBSD: head/sys/netgraph/bluetooth/drivers/h4/ng_h4.c 243882 2012-12-05 08:04:20Z glebius $
32b06ebda0SMatthew Dillon *
33b06ebda0SMatthew Dillon * Based on:
34b06ebda0SMatthew Dillon * ---------
35b06ebda0SMatthew Dillon *
36b06ebda0SMatthew Dillon * FreeBSD: src/sys/netgraph/ng_tty.c
37b06ebda0SMatthew Dillon * Author: Archie Cobbs <archie@freebsd.org>
38b06ebda0SMatthew Dillon *
39b06ebda0SMatthew Dillon */
40b06ebda0SMatthew Dillon
41b06ebda0SMatthew Dillon #include <sys/param.h>
42b06ebda0SMatthew Dillon #include <sys/systm.h>
43b06ebda0SMatthew Dillon #include <sys/kernel.h>
44b06ebda0SMatthew Dillon #include <sys/conf.h>
45b06ebda0SMatthew Dillon #include <sys/endian.h>
46b06ebda0SMatthew Dillon #include <sys/errno.h>
47b06ebda0SMatthew Dillon #include <sys/fcntl.h>
48b06ebda0SMatthew Dillon #include <sys/malloc.h>
49b06ebda0SMatthew Dillon #include <sys/mbuf.h>
502b3f93eaSMatthew Dillon #include <sys/caps.h>
51b06ebda0SMatthew Dillon #include <sys/socket.h>
52b06ebda0SMatthew Dillon #include <sys/tty.h>
53b06ebda0SMatthew Dillon #include <sys/ttycom.h>
54b06ebda0SMatthew Dillon #include <net/if.h>
55b06ebda0SMatthew Dillon #include <net/if_var.h>
56e85b99abSSascha Wildner #include <netgraph7/ng_message.h>
57e85b99abSSascha Wildner #include <netgraph7/netgraph.h>
58e85b99abSSascha Wildner #include <netgraph7/ng_parse.h>
59e85b99abSSascha Wildner #include <netgraph7/bluetooth/include/ng_bluetooth.h>
60e85b99abSSascha Wildner #include <netgraph7/bluetooth/include/ng_hci.h>
61e85b99abSSascha Wildner #include <netgraph7/bluetooth/include/ng_h4.h>
62e85b99abSSascha Wildner #include <netgraph7/bluetooth/drivers/h4/ng_h4_var.h>
63e85b99abSSascha Wildner #include <netgraph7/bluetooth/drivers/h4/ng_h4_prse.h>
64b06ebda0SMatthew Dillon
65b06ebda0SMatthew Dillon /*****************************************************************************
66b06ebda0SMatthew Dillon *****************************************************************************
67b06ebda0SMatthew Dillon ** This node implements a Bluetooth HCI UART transport layer as per chapter
68b06ebda0SMatthew Dillon ** H4 of the Bluetooth Specification Book v1.1. It is a terminal line
69b06ebda0SMatthew Dillon ** discipline that is also a netgraph node. Installing this line discipline
70b06ebda0SMatthew Dillon ** on a terminal device instantiates a new netgraph node of this type, which
71b06ebda0SMatthew Dillon ** allows access to the device via the "hook" hook of the node.
72b06ebda0SMatthew Dillon **
73b06ebda0SMatthew Dillon ** Once the line discipline is installed, you can find out the name of the
74b06ebda0SMatthew Dillon ** corresponding netgraph node via a NGIOCGINFO ioctl().
75b06ebda0SMatthew Dillon *****************************************************************************
76b06ebda0SMatthew Dillon *****************************************************************************/
77b06ebda0SMatthew Dillon
78b06ebda0SMatthew Dillon /* MALLOC define */
79b06ebda0SMatthew Dillon #ifndef NG_SEPARATE_MALLOC
80b06ebda0SMatthew Dillon MALLOC_DEFINE(M_NETGRAPH_H4, "netgraph_h4", "Netgraph Bluetooth H4 node");
81b06ebda0SMatthew Dillon #else
82b06ebda0SMatthew Dillon #define M_NETGRAPH_H4 M_NETGRAPH
83b06ebda0SMatthew Dillon #endif /* NG_SEPARATE_MALLOC */
84b06ebda0SMatthew Dillon
85b06ebda0SMatthew Dillon /* Line discipline methods */
86b06ebda0SMatthew Dillon static int ng_h4_open (struct cdev *, struct tty *);
87b06ebda0SMatthew Dillon static int ng_h4_close (struct tty *, int);
88b06ebda0SMatthew Dillon static int ng_h4_read (struct tty *, struct uio *, int);
89b06ebda0SMatthew Dillon static int ng_h4_write (struct tty *, struct uio *, int);
90b06ebda0SMatthew Dillon static int ng_h4_input (int, struct tty *);
91b06ebda0SMatthew Dillon static int ng_h4_start (struct tty *);
92b06ebda0SMatthew Dillon static int ng_h4_ioctl (struct tty *, u_long, caddr_t,
93e85b99abSSascha Wildner int, struct ucred *);
94b06ebda0SMatthew Dillon
95b06ebda0SMatthew Dillon /* Line discipline descriptor */
96b06ebda0SMatthew Dillon static struct linesw ng_h4_disc = {
97b06ebda0SMatthew Dillon ng_h4_open, /* open */
98b06ebda0SMatthew Dillon ng_h4_close, /* close */
99b06ebda0SMatthew Dillon ng_h4_read, /* read */
100b06ebda0SMatthew Dillon ng_h4_write, /* write */
101b06ebda0SMatthew Dillon ng_h4_ioctl, /* ioctl */
102b06ebda0SMatthew Dillon ng_h4_input, /* input */
103b06ebda0SMatthew Dillon ng_h4_start, /* start */
104b06ebda0SMatthew Dillon ttymodem /* modem */
105b06ebda0SMatthew Dillon };
106b06ebda0SMatthew Dillon
107b06ebda0SMatthew Dillon /* Netgraph methods */
108b06ebda0SMatthew Dillon static ng_constructor_t ng_h4_constructor;
109b06ebda0SMatthew Dillon static ng_rcvmsg_t ng_h4_rcvmsg;
110b06ebda0SMatthew Dillon static ng_shutdown_t ng_h4_shutdown;
111b06ebda0SMatthew Dillon static ng_newhook_t ng_h4_newhook;
112b06ebda0SMatthew Dillon static ng_connect_t ng_h4_connect;
113b06ebda0SMatthew Dillon static ng_rcvdata_t ng_h4_rcvdata;
114b06ebda0SMatthew Dillon static ng_disconnect_t ng_h4_disconnect;
115b06ebda0SMatthew Dillon
116b06ebda0SMatthew Dillon /* Other stuff */
117b06ebda0SMatthew Dillon static void ng_h4_process_timeout (node_p, hook_p, void *, int);
118b06ebda0SMatthew Dillon static int ng_h4_mod_event (module_t, int, void *);
119b06ebda0SMatthew Dillon
120b06ebda0SMatthew Dillon /* Netgraph node type descriptor */
121b06ebda0SMatthew Dillon static struct ng_type typestruct = {
122b06ebda0SMatthew Dillon .version = NG_ABI_VERSION,
123b06ebda0SMatthew Dillon .name = NG_H4_NODE_TYPE,
124b06ebda0SMatthew Dillon .mod_event = ng_h4_mod_event,
125b06ebda0SMatthew Dillon .constructor = ng_h4_constructor,
126b06ebda0SMatthew Dillon .rcvmsg = ng_h4_rcvmsg,
127b06ebda0SMatthew Dillon .shutdown = ng_h4_shutdown,
128b06ebda0SMatthew Dillon .newhook = ng_h4_newhook,
129b06ebda0SMatthew Dillon .connect = ng_h4_connect,
130b06ebda0SMatthew Dillon .rcvdata = ng_h4_rcvdata,
131b06ebda0SMatthew Dillon .disconnect = ng_h4_disconnect,
132b06ebda0SMatthew Dillon .cmdlist = ng_h4_cmdlist
133b06ebda0SMatthew Dillon };
134b06ebda0SMatthew Dillon NETGRAPH_INIT(h4, &typestruct);
135b06ebda0SMatthew Dillon MODULE_VERSION(ng_h4, NG_BLUETOOTH_VERSION);
136b06ebda0SMatthew Dillon
137b06ebda0SMatthew Dillon static int ng_h4_node = 0;
138b06ebda0SMatthew Dillon
139b06ebda0SMatthew Dillon /*****************************************************************************
140b06ebda0SMatthew Dillon *****************************************************************************
141b06ebda0SMatthew Dillon ** Line discipline methods
142b06ebda0SMatthew Dillon *****************************************************************************
143b06ebda0SMatthew Dillon *****************************************************************************/
144b06ebda0SMatthew Dillon
145b06ebda0SMatthew Dillon /*
146b06ebda0SMatthew Dillon * Set our line discipline on the tty.
147b06ebda0SMatthew Dillon */
148b06ebda0SMatthew Dillon
149b06ebda0SMatthew Dillon static int
ng_h4_open(struct cdev * dev,struct tty * tp)150b06ebda0SMatthew Dillon ng_h4_open(struct cdev *dev, struct tty *tp)
151b06ebda0SMatthew Dillon {
152b06ebda0SMatthew Dillon char name[NG_NODESIZ];
153b06ebda0SMatthew Dillon ng_h4_info_p sc = NULL;
154b06ebda0SMatthew Dillon int error;
155b06ebda0SMatthew Dillon
156b06ebda0SMatthew Dillon /* Super-user only */
1572b3f93eaSMatthew Dillon error = caps_priv_check_self(SYSCAP_NONET_NETGRAPH);
158b06ebda0SMatthew Dillon if (error != 0)
159b06ebda0SMatthew Dillon return (error);
160b06ebda0SMatthew Dillon
161b06ebda0SMatthew Dillon /* Initialize private struct */
162fc025606SSascha Wildner sc = kmalloc(sizeof(*sc), M_NETGRAPH_H4, M_WAITOK | M_NULLOK | M_ZERO);
163b06ebda0SMatthew Dillon if (sc == NULL)
164b06ebda0SMatthew Dillon return (ENOMEM);
165b06ebda0SMatthew Dillon
1662efb75f3SMatthew Dillon lwkt_gettoken(&tp->t_token);
167b06ebda0SMatthew Dillon sc->tp = tp;
168b06ebda0SMatthew Dillon sc->debug = NG_H4_WARN_LEVEL;
169b06ebda0SMatthew Dillon
170b06ebda0SMatthew Dillon sc->state = NG_H4_W4_PKT_IND;
171b06ebda0SMatthew Dillon sc->want = 1;
172b06ebda0SMatthew Dillon sc->got = 0;
173b06ebda0SMatthew Dillon
174e85b99abSSascha Wildner sc->outq.ifq_maxlen = NG_H4_DEFAULTQLEN;
175b06ebda0SMatthew Dillon ng_callout_init(&sc->timo);
176b06ebda0SMatthew Dillon
177b06ebda0SMatthew Dillon NG_H4_LOCK(sc);
178b06ebda0SMatthew Dillon
179b06ebda0SMatthew Dillon /* Setup netgraph node */
180b06ebda0SMatthew Dillon error = ng_make_node_common(&typestruct, &sc->node);
181b06ebda0SMatthew Dillon if (error != 0) {
182b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
183b06ebda0SMatthew Dillon
184a62226e4SSascha Wildner kprintf("%s: Unable to create new node!\n", __func__);
185b06ebda0SMatthew Dillon
186b06ebda0SMatthew Dillon bzero(sc, sizeof(*sc));
187fc025606SSascha Wildner kfree(sc, M_NETGRAPH_H4);
188b06ebda0SMatthew Dillon
1892efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
190b06ebda0SMatthew Dillon return (error);
191b06ebda0SMatthew Dillon }
192b06ebda0SMatthew Dillon
193b06ebda0SMatthew Dillon /* Assign node its name */
194a62226e4SSascha Wildner ksnprintf(name, sizeof(name), "%s%d", typestruct.name, ng_h4_node ++);
195b06ebda0SMatthew Dillon
196b06ebda0SMatthew Dillon error = ng_name_node(sc->node, name);
197b06ebda0SMatthew Dillon if (error != 0) {
198b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
199b06ebda0SMatthew Dillon
200a62226e4SSascha Wildner kprintf("%s: %s - node name exists?\n", __func__, name);
201b06ebda0SMatthew Dillon
202b06ebda0SMatthew Dillon NG_NODE_UNREF(sc->node);
203b06ebda0SMatthew Dillon bzero(sc, sizeof(*sc));
204fc025606SSascha Wildner kfree(sc, M_NETGRAPH_H4);
205b06ebda0SMatthew Dillon
2062efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
207b06ebda0SMatthew Dillon return (error);
208b06ebda0SMatthew Dillon }
209b06ebda0SMatthew Dillon
210b06ebda0SMatthew Dillon /* Set back pointers */
211b06ebda0SMatthew Dillon NG_NODE_SET_PRIVATE(sc->node, sc);
212e85b99abSSascha Wildner tp->t_sc = (caddr_t) sc;
213b06ebda0SMatthew Dillon
214b06ebda0SMatthew Dillon /* The node has to be a WRITER because data can change node status */
215b06ebda0SMatthew Dillon NG_NODE_FORCE_WRITER(sc->node);
216b06ebda0SMatthew Dillon
217b06ebda0SMatthew Dillon /*
218b06ebda0SMatthew Dillon * Pre-allocate cblocks to the an appropriate amount.
219b06ebda0SMatthew Dillon * I'm not sure what is appropriate.
220b06ebda0SMatthew Dillon */
221b06ebda0SMatthew Dillon
222b06ebda0SMatthew Dillon ttyflush(tp, FREAD | FWRITE);
2234725869bSMatthew Dillon clist_alloc_cblocks(&tp->t_canq, 0);
2244725869bSMatthew Dillon clist_alloc_cblocks(&tp->t_rawq, 0);
2254725869bSMatthew Dillon clist_alloc_cblocks(&tp->t_outq, MLEN + NG_H4_HIWATER);
226b06ebda0SMatthew Dillon
227b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
228b06ebda0SMatthew Dillon
2292efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
230b06ebda0SMatthew Dillon return (error);
231b06ebda0SMatthew Dillon } /* ng_h4_open */
232b06ebda0SMatthew Dillon
233b06ebda0SMatthew Dillon /*
234b06ebda0SMatthew Dillon * Line specific close routine, called from device close routine
235b06ebda0SMatthew Dillon * and from ttioctl. This causes the node to be destroyed as well.
236b06ebda0SMatthew Dillon */
237b06ebda0SMatthew Dillon
238b06ebda0SMatthew Dillon static int
ng_h4_close(struct tty * tp,int flag)239b06ebda0SMatthew Dillon ng_h4_close(struct tty *tp, int flag)
240b06ebda0SMatthew Dillon {
241e85b99abSSascha Wildner ng_h4_info_p sc = (ng_h4_info_p) tp->t_sc;
242b06ebda0SMatthew Dillon
2432efb75f3SMatthew Dillon lwkt_gettoken(&tp->t_token);
244b06ebda0SMatthew Dillon ttyflush(tp, FREAD | FWRITE);
245b06ebda0SMatthew Dillon clist_free_cblocks(&tp->t_outq);
246b06ebda0SMatthew Dillon
247b06ebda0SMatthew Dillon if (sc != NULL) {
248b06ebda0SMatthew Dillon NG_H4_LOCK(sc);
249b06ebda0SMatthew Dillon
250b06ebda0SMatthew Dillon if (callout_pending(&sc->timo))
251b06ebda0SMatthew Dillon ng_uncallout(&sc->timo, sc->node);
252b06ebda0SMatthew Dillon
253e85b99abSSascha Wildner tp->t_sc = NULL;
254b06ebda0SMatthew Dillon sc->dying = 1;
255b06ebda0SMatthew Dillon
256b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
257b06ebda0SMatthew Dillon
258b06ebda0SMatthew Dillon ng_rmnode_self(sc->node);
259b06ebda0SMatthew Dillon }
260b06ebda0SMatthew Dillon
2612efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
262b06ebda0SMatthew Dillon return (0);
263b06ebda0SMatthew Dillon } /* ng_h4_close */
264b06ebda0SMatthew Dillon
265b06ebda0SMatthew Dillon /*
266b06ebda0SMatthew Dillon * Once the device has been turned into a node, we don't allow reading.
267b06ebda0SMatthew Dillon */
268b06ebda0SMatthew Dillon
269b06ebda0SMatthew Dillon static int
ng_h4_read(struct tty * tp,struct uio * uio,int flag)270b06ebda0SMatthew Dillon ng_h4_read(struct tty *tp, struct uio *uio, int flag)
271b06ebda0SMatthew Dillon {
272b06ebda0SMatthew Dillon return (EIO);
273b06ebda0SMatthew Dillon } /* ng_h4_read */
274b06ebda0SMatthew Dillon
275b06ebda0SMatthew Dillon /*
276b06ebda0SMatthew Dillon * Once the device has been turned into a node, we don't allow writing.
277b06ebda0SMatthew Dillon */
278b06ebda0SMatthew Dillon
279b06ebda0SMatthew Dillon static int
ng_h4_write(struct tty * tp,struct uio * uio,int flag)280b06ebda0SMatthew Dillon ng_h4_write(struct tty *tp, struct uio *uio, int flag)
281b06ebda0SMatthew Dillon {
282b06ebda0SMatthew Dillon return (EIO);
283b06ebda0SMatthew Dillon } /* ng_h4_write */
284b06ebda0SMatthew Dillon
285b06ebda0SMatthew Dillon /*
286b06ebda0SMatthew Dillon * We implement the NGIOCGINFO ioctl() defined in ng_message.h.
287b06ebda0SMatthew Dillon */
288b06ebda0SMatthew Dillon
289b06ebda0SMatthew Dillon static int
ng_h4_ioctl(struct tty * tp,u_long cmd,caddr_t data,int flag,struct ucred * cred)290b06ebda0SMatthew Dillon ng_h4_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
291e85b99abSSascha Wildner struct ucred *cred)
292b06ebda0SMatthew Dillon {
293e85b99abSSascha Wildner ng_h4_info_p sc = (ng_h4_info_p) tp->t_sc;
294b06ebda0SMatthew Dillon int error = 0;
295b06ebda0SMatthew Dillon
296b06ebda0SMatthew Dillon if (sc == NULL)
297b06ebda0SMatthew Dillon return (ENXIO);
298b06ebda0SMatthew Dillon
2992efb75f3SMatthew Dillon lwkt_gettoken(&tp->t_token);
300b06ebda0SMatthew Dillon NG_H4_LOCK(sc);
301b06ebda0SMatthew Dillon
302b06ebda0SMatthew Dillon switch (cmd) {
303b06ebda0SMatthew Dillon case NGIOCGINFO:
304b06ebda0SMatthew Dillon #undef NI
305b06ebda0SMatthew Dillon #define NI(x) ((struct nodeinfo *)(x))
306b06ebda0SMatthew Dillon
307b06ebda0SMatthew Dillon bzero(data, sizeof(*NI(data)));
308b06ebda0SMatthew Dillon
309b06ebda0SMatthew Dillon if (NG_NODE_HAS_NAME(sc->node))
310b06ebda0SMatthew Dillon strncpy(NI(data)->name, NG_NODE_NAME(sc->node),
311b06ebda0SMatthew Dillon sizeof(NI(data)->name) - 1);
312b06ebda0SMatthew Dillon
313b06ebda0SMatthew Dillon strncpy(NI(data)->type, sc->node->nd_type->name,
314b06ebda0SMatthew Dillon sizeof(NI(data)->type) - 1);
315b06ebda0SMatthew Dillon
316b06ebda0SMatthew Dillon NI(data)->id = (u_int32_t) ng_node2ID(sc->node);
317b06ebda0SMatthew Dillon NI(data)->hooks = NG_NODE_NUMHOOKS(sc->node);
318b06ebda0SMatthew Dillon break;
319b06ebda0SMatthew Dillon
320b06ebda0SMatthew Dillon default:
321b06ebda0SMatthew Dillon error = ENOIOCTL;
322b06ebda0SMatthew Dillon break;
323b06ebda0SMatthew Dillon }
324b06ebda0SMatthew Dillon
325b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
326b06ebda0SMatthew Dillon
3272efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
328b06ebda0SMatthew Dillon return (error);
329b06ebda0SMatthew Dillon } /* ng_h4_ioctl */
330b06ebda0SMatthew Dillon
331b06ebda0SMatthew Dillon /*
332b06ebda0SMatthew Dillon * Receive data coming from the device. We get one character at a time, which
333b06ebda0SMatthew Dillon * is kindof silly.
334b06ebda0SMatthew Dillon */
335b06ebda0SMatthew Dillon
336b06ebda0SMatthew Dillon static int
ng_h4_input(int c,struct tty * tp)337b06ebda0SMatthew Dillon ng_h4_input(int c, struct tty *tp)
338b06ebda0SMatthew Dillon {
339e85b99abSSascha Wildner ng_h4_info_p sc = (ng_h4_info_p) tp->t_sc;
340b06ebda0SMatthew Dillon
3412efb75f3SMatthew Dillon lwkt_gettoken(&tp->t_token);
342b06ebda0SMatthew Dillon if (sc == NULL || tp != sc->tp ||
34322ff886eSAlex Hornung sc->node == NULL || NG_NODE_NOT_VALID(sc->node)) {
3442efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
345b06ebda0SMatthew Dillon return (0);
34622ff886eSAlex Hornung }
347b06ebda0SMatthew Dillon
348b06ebda0SMatthew Dillon NG_H4_LOCK(sc);
349b06ebda0SMatthew Dillon
350b06ebda0SMatthew Dillon /* Check for error conditions */
351b06ebda0SMatthew Dillon if ((tp->t_state & TS_CONNECTED) == 0) {
352b06ebda0SMatthew Dillon NG_H4_INFO("%s: %s - no carrier\n", __func__,
353b06ebda0SMatthew Dillon NG_NODE_NAME(sc->node));
354b06ebda0SMatthew Dillon
355b06ebda0SMatthew Dillon sc->state = NG_H4_W4_PKT_IND;
356b06ebda0SMatthew Dillon sc->want = 1;
357b06ebda0SMatthew Dillon sc->got = 0;
358b06ebda0SMatthew Dillon
359b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
360b06ebda0SMatthew Dillon
3612efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
362b06ebda0SMatthew Dillon return (0); /* XXX Loss of synchronization here! */
363b06ebda0SMatthew Dillon }
364b06ebda0SMatthew Dillon
365b06ebda0SMatthew Dillon /* Check for framing error or overrun on this char */
366b06ebda0SMatthew Dillon if (c & TTY_ERRORMASK) {
367b06ebda0SMatthew Dillon NG_H4_ERR("%s: %s - line error %#x, c=%#x\n", __func__,
368b06ebda0SMatthew Dillon NG_NODE_NAME(sc->node), c & TTY_ERRORMASK,
369b06ebda0SMatthew Dillon c & TTY_CHARMASK);
370b06ebda0SMatthew Dillon
371b06ebda0SMatthew Dillon NG_H4_STAT_IERROR(sc->stat);
372b06ebda0SMatthew Dillon
373b06ebda0SMatthew Dillon sc->state = NG_H4_W4_PKT_IND;
374b06ebda0SMatthew Dillon sc->want = 1;
375b06ebda0SMatthew Dillon sc->got = 0;
376b06ebda0SMatthew Dillon
377b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
378b06ebda0SMatthew Dillon
3792efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
380b06ebda0SMatthew Dillon return (0); /* XXX Loss of synchronization here! */
381b06ebda0SMatthew Dillon }
382b06ebda0SMatthew Dillon
383b06ebda0SMatthew Dillon NG_H4_STAT_BYTES_RECV(sc->stat, 1);
384b06ebda0SMatthew Dillon
385b06ebda0SMatthew Dillon /* Append char to mbuf */
386b06ebda0SMatthew Dillon if (sc->got >= sizeof(sc->ibuf)) {
387b06ebda0SMatthew Dillon NG_H4_ALERT("%s: %s - input buffer overflow, c=%#x, got=%d\n",
388b06ebda0SMatthew Dillon __func__, NG_NODE_NAME(sc->node), c & TTY_CHARMASK,
389b06ebda0SMatthew Dillon sc->got);
390b06ebda0SMatthew Dillon
391b06ebda0SMatthew Dillon NG_H4_STAT_IERROR(sc->stat);
392b06ebda0SMatthew Dillon
393b06ebda0SMatthew Dillon sc->state = NG_H4_W4_PKT_IND;
394b06ebda0SMatthew Dillon sc->want = 1;
395b06ebda0SMatthew Dillon sc->got = 0;
396b06ebda0SMatthew Dillon
397b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
398b06ebda0SMatthew Dillon
3992efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
400b06ebda0SMatthew Dillon return (0); /* XXX Loss of synchronization here! */
401b06ebda0SMatthew Dillon }
402b06ebda0SMatthew Dillon
403b06ebda0SMatthew Dillon sc->ibuf[sc->got ++] = (c & TTY_CHARMASK);
404b06ebda0SMatthew Dillon
405b06ebda0SMatthew Dillon NG_H4_INFO("%s: %s - got char %#x, want=%d, got=%d\n", __func__,
406b06ebda0SMatthew Dillon NG_NODE_NAME(sc->node), c, sc->want, sc->got);
407b06ebda0SMatthew Dillon
408b06ebda0SMatthew Dillon if (sc->got < sc->want) {
409b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
410b06ebda0SMatthew Dillon
4112efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
412b06ebda0SMatthew Dillon return (0); /* Wait for more */
413b06ebda0SMatthew Dillon }
414b06ebda0SMatthew Dillon
415b06ebda0SMatthew Dillon switch (sc->state) {
416b06ebda0SMatthew Dillon /* Got packet indicator */
417b06ebda0SMatthew Dillon case NG_H4_W4_PKT_IND:
418b06ebda0SMatthew Dillon NG_H4_INFO("%s: %s - got packet indicator %#x\n", __func__,
419b06ebda0SMatthew Dillon NG_NODE_NAME(sc->node), sc->ibuf[0]);
420b06ebda0SMatthew Dillon
421b06ebda0SMatthew Dillon sc->state = NG_H4_W4_PKT_HDR;
422b06ebda0SMatthew Dillon
423b06ebda0SMatthew Dillon /*
424b06ebda0SMatthew Dillon * Since packet indicator included in the packet header
425b06ebda0SMatthew Dillon * just set sc->want to sizeof(packet header).
426b06ebda0SMatthew Dillon */
427b06ebda0SMatthew Dillon
428b06ebda0SMatthew Dillon switch (sc->ibuf[0]) {
429b06ebda0SMatthew Dillon case NG_HCI_ACL_DATA_PKT:
430b06ebda0SMatthew Dillon sc->want = sizeof(ng_hci_acldata_pkt_t);
431b06ebda0SMatthew Dillon break;
432b06ebda0SMatthew Dillon
433b06ebda0SMatthew Dillon case NG_HCI_SCO_DATA_PKT:
434b06ebda0SMatthew Dillon sc->want = sizeof(ng_hci_scodata_pkt_t);
435b06ebda0SMatthew Dillon break;
436b06ebda0SMatthew Dillon
437b06ebda0SMatthew Dillon case NG_HCI_EVENT_PKT:
438b06ebda0SMatthew Dillon sc->want = sizeof(ng_hci_event_pkt_t);
439b06ebda0SMatthew Dillon break;
440b06ebda0SMatthew Dillon
441b06ebda0SMatthew Dillon default:
442b06ebda0SMatthew Dillon NG_H4_WARN("%s: %s - ignoring unknown packet " \
443b06ebda0SMatthew Dillon "type=%#x\n", __func__, NG_NODE_NAME(sc->node),
444b06ebda0SMatthew Dillon sc->ibuf[0]);
445b06ebda0SMatthew Dillon
446b06ebda0SMatthew Dillon NG_H4_STAT_IERROR(sc->stat);
447b06ebda0SMatthew Dillon
448b06ebda0SMatthew Dillon sc->state = NG_H4_W4_PKT_IND;
449b06ebda0SMatthew Dillon sc->want = 1;
450b06ebda0SMatthew Dillon sc->got = 0;
451b06ebda0SMatthew Dillon break;
452b06ebda0SMatthew Dillon }
453b06ebda0SMatthew Dillon break;
454b06ebda0SMatthew Dillon
455b06ebda0SMatthew Dillon /* Got packet header */
456b06ebda0SMatthew Dillon case NG_H4_W4_PKT_HDR:
457b06ebda0SMatthew Dillon sc->state = NG_H4_W4_PKT_DATA;
458b06ebda0SMatthew Dillon
459b06ebda0SMatthew Dillon switch (sc->ibuf[0]) {
460b06ebda0SMatthew Dillon case NG_HCI_ACL_DATA_PKT:
461b06ebda0SMatthew Dillon c = le16toh(((ng_hci_acldata_pkt_t *)
462b06ebda0SMatthew Dillon (sc->ibuf))->length);
463b06ebda0SMatthew Dillon break;
464b06ebda0SMatthew Dillon
465b06ebda0SMatthew Dillon case NG_HCI_SCO_DATA_PKT:
466b06ebda0SMatthew Dillon c = ((ng_hci_scodata_pkt_t *)(sc->ibuf))->length;
467b06ebda0SMatthew Dillon break;
468b06ebda0SMatthew Dillon
469b06ebda0SMatthew Dillon case NG_HCI_EVENT_PKT:
470b06ebda0SMatthew Dillon c = ((ng_hci_event_pkt_t *)(sc->ibuf))->length;
471b06ebda0SMatthew Dillon break;
472b06ebda0SMatthew Dillon
473b06ebda0SMatthew Dillon default:
474ed20d0e3SSascha Wildner KASSERT((0), ("Invalid packet type=%#x",
475b06ebda0SMatthew Dillon sc->ibuf[0]));
476b06ebda0SMatthew Dillon break;
477b06ebda0SMatthew Dillon }
478b06ebda0SMatthew Dillon
479b06ebda0SMatthew Dillon NG_H4_INFO("%s: %s - got packet header, packet type=%#x, " \
480b06ebda0SMatthew Dillon "packet size=%d, payload size=%d\n", __func__,
481b06ebda0SMatthew Dillon NG_NODE_NAME(sc->node), sc->ibuf[0], sc->got, c);
482b06ebda0SMatthew Dillon
483b06ebda0SMatthew Dillon if (c > 0) {
484b06ebda0SMatthew Dillon sc->want += c;
485b06ebda0SMatthew Dillon
486b06ebda0SMatthew Dillon /*
487b06ebda0SMatthew Dillon * Try to prevent possible buffer overrun
488b06ebda0SMatthew Dillon *
489b06ebda0SMatthew Dillon * XXX I'm *really* confused here. It turns out
490b06ebda0SMatthew Dillon * that Xircom card sends us packets with length
491b06ebda0SMatthew Dillon * greater then 512 bytes! This is greater then
492b06ebda0SMatthew Dillon * our old receive buffer (ibuf) size. In the same
493b06ebda0SMatthew Dillon * time the card demands from us *not* to send
494b06ebda0SMatthew Dillon * packets greater then 192 bytes. Weird! How the
495b06ebda0SMatthew Dillon * hell i should know how big *receive* buffer
496b06ebda0SMatthew Dillon * should be? For now increase receiving buffer
497b06ebda0SMatthew Dillon * size to 1K and add the following check.
498b06ebda0SMatthew Dillon */
499b06ebda0SMatthew Dillon
500b06ebda0SMatthew Dillon if (sc->want >= sizeof(sc->ibuf)) {
501b06ebda0SMatthew Dillon int b;
502b06ebda0SMatthew Dillon
503b06ebda0SMatthew Dillon NG_H4_ALERT("%s: %s - packet too big for " \
504b06ebda0SMatthew Dillon "buffer, type=%#x, got=%d, want=%d, " \
505b06ebda0SMatthew Dillon "length=%d\n", __func__,
506b06ebda0SMatthew Dillon NG_NODE_NAME(sc->node), sc->ibuf[0],
507b06ebda0SMatthew Dillon sc->got, sc->want, c);
508b06ebda0SMatthew Dillon
509b06ebda0SMatthew Dillon NG_H4_ALERT("Packet header:\n");
510b06ebda0SMatthew Dillon for (b = 0; b < sc->got; b++)
511b06ebda0SMatthew Dillon NG_H4_ALERT("%#x ", sc->ibuf[b]);
512b06ebda0SMatthew Dillon NG_H4_ALERT("\n");
513b06ebda0SMatthew Dillon
514b06ebda0SMatthew Dillon /* Reset state */
515b06ebda0SMatthew Dillon NG_H4_STAT_IERROR(sc->stat);
516b06ebda0SMatthew Dillon
517b06ebda0SMatthew Dillon sc->state = NG_H4_W4_PKT_IND;
518b06ebda0SMatthew Dillon sc->want = 1;
519b06ebda0SMatthew Dillon sc->got = 0;
520b06ebda0SMatthew Dillon }
521b06ebda0SMatthew Dillon
522b06ebda0SMatthew Dillon break;
523b06ebda0SMatthew Dillon }
524b06ebda0SMatthew Dillon
525b06ebda0SMatthew Dillon /* else FALLTHROUGH and deliver frame */
526b06ebda0SMatthew Dillon /* XXX Is this true? Should we deliver empty frame? */
527b06ebda0SMatthew Dillon
528b06ebda0SMatthew Dillon /* Got packet data */
529b06ebda0SMatthew Dillon case NG_H4_W4_PKT_DATA:
530b06ebda0SMatthew Dillon NG_H4_INFO("%s: %s - got full packet, packet type=%#x, " \
531b06ebda0SMatthew Dillon "packet size=%d\n", __func__,
532b06ebda0SMatthew Dillon NG_NODE_NAME(sc->node), sc->ibuf[0], sc->got);
533b06ebda0SMatthew Dillon
534b06ebda0SMatthew Dillon if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) {
535b06ebda0SMatthew Dillon struct mbuf *m = NULL;
536b06ebda0SMatthew Dillon
537b5523eacSSascha Wildner MGETHDR(m, M_NOWAIT, MT_DATA);
538*44647b48SAaron LI if (m != NULL && m_copyback2(m, 0, sc->got, sc->ibuf,
539*44647b48SAaron LI M_NOWAIT) == 0) {
540b06ebda0SMatthew Dillon NG_SEND_DATA_ONLY(c, sc->hook, m);
541b06ebda0SMatthew Dillon } else {
542b06ebda0SMatthew Dillon NG_H4_ERR("%s: %s - could not get mbuf\n",
543b06ebda0SMatthew Dillon __func__, NG_NODE_NAME(sc->node));
544b06ebda0SMatthew Dillon NG_H4_STAT_IERROR(sc->stat);
545*44647b48SAaron LI m_freem(m);
546b06ebda0SMatthew Dillon }
547b06ebda0SMatthew Dillon }
548b06ebda0SMatthew Dillon
549b06ebda0SMatthew Dillon sc->state = NG_H4_W4_PKT_IND;
550b06ebda0SMatthew Dillon sc->want = 1;
551b06ebda0SMatthew Dillon sc->got = 0;
552b06ebda0SMatthew Dillon
553b06ebda0SMatthew Dillon NG_H4_STAT_PCKTS_RECV(sc->stat);
554b06ebda0SMatthew Dillon break;
555b06ebda0SMatthew Dillon
556b06ebda0SMatthew Dillon default:
557b06ebda0SMatthew Dillon KASSERT((0), ("Invalid H4 node state=%d", sc->state));
558b06ebda0SMatthew Dillon break;
559b06ebda0SMatthew Dillon }
560b06ebda0SMatthew Dillon
561b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
562b06ebda0SMatthew Dillon
5632efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
564b06ebda0SMatthew Dillon return (0);
565b06ebda0SMatthew Dillon } /* ng_h4_input */
566b06ebda0SMatthew Dillon
567b06ebda0SMatthew Dillon /*
568b06ebda0SMatthew Dillon * This is called when the device driver is ready for more output. Called from
569b06ebda0SMatthew Dillon * tty system.
570b06ebda0SMatthew Dillon */
571b06ebda0SMatthew Dillon
572b06ebda0SMatthew Dillon static int
ng_h4_start(struct tty * tp)573b06ebda0SMatthew Dillon ng_h4_start(struct tty *tp)
574b06ebda0SMatthew Dillon {
575e85b99abSSascha Wildner ng_h4_info_p sc = (ng_h4_info_p) tp->t_sc;
576b06ebda0SMatthew Dillon struct mbuf *m = NULL;
577b06ebda0SMatthew Dillon int size;
578b06ebda0SMatthew Dillon
5792efb75f3SMatthew Dillon lwkt_gettoken(&tp->t_token);
580b06ebda0SMatthew Dillon if (sc == NULL || tp != sc->tp ||
58122ff886eSAlex Hornung sc->node == NULL || NG_NODE_NOT_VALID(sc->node)) {
5822efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
583b06ebda0SMatthew Dillon return (0);
58422ff886eSAlex Hornung }
585b06ebda0SMatthew Dillon
586b06ebda0SMatthew Dillon #if 0
587b06ebda0SMatthew Dillon while (tp->t_outq.c_cc < NG_H4_HIWATER) { /* XXX 2.2 specific ? */
588b06ebda0SMatthew Dillon #else
589b06ebda0SMatthew Dillon while (1) {
590b06ebda0SMatthew Dillon #endif
591b06ebda0SMatthew Dillon /* Remove first mbuf from queue */
592b06ebda0SMatthew Dillon IF_DEQUEUE(&sc->outq, m);
593b06ebda0SMatthew Dillon if (m == NULL)
594b06ebda0SMatthew Dillon break;
595b06ebda0SMatthew Dillon
596b06ebda0SMatthew Dillon /* Send as much of it as possible */
597b06ebda0SMatthew Dillon while (m != NULL) {
5984725869bSMatthew Dillon size = m->m_len - clist_btoq(mtod(m, u_char *),
599b06ebda0SMatthew Dillon m->m_len, &tp->t_outq);
600b06ebda0SMatthew Dillon
601b06ebda0SMatthew Dillon NG_H4_LOCK(sc);
602b06ebda0SMatthew Dillon NG_H4_STAT_BYTES_SENT(sc->stat, size);
603b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
604b06ebda0SMatthew Dillon
605b06ebda0SMatthew Dillon m->m_data += size;
606b06ebda0SMatthew Dillon m->m_len -= size;
607b06ebda0SMatthew Dillon if (m->m_len > 0)
608b06ebda0SMatthew Dillon break; /* device can't take no more */
609b06ebda0SMatthew Dillon
610b06ebda0SMatthew Dillon m = m_free(m);
611b06ebda0SMatthew Dillon }
612b06ebda0SMatthew Dillon
613b06ebda0SMatthew Dillon /* Put remainder of mbuf chain (if any) back on queue */
614b06ebda0SMatthew Dillon if (m != NULL) {
615b06ebda0SMatthew Dillon IF_PREPEND(&sc->outq, m);
616b06ebda0SMatthew Dillon break;
617b06ebda0SMatthew Dillon }
618b06ebda0SMatthew Dillon
619b06ebda0SMatthew Dillon /* Full packet has been sent */
620b06ebda0SMatthew Dillon NG_H4_LOCK(sc);
621b06ebda0SMatthew Dillon NG_H4_STAT_PCKTS_SENT(sc->stat);
622b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
623b06ebda0SMatthew Dillon }
624b06ebda0SMatthew Dillon
625b06ebda0SMatthew Dillon /*
626b06ebda0SMatthew Dillon * Call output process whether or not there is any output. We are
627b06ebda0SMatthew Dillon * being called in lieu of ttstart and must do what it would.
628b06ebda0SMatthew Dillon */
629b06ebda0SMatthew Dillon
630e85b99abSSascha Wildner if (tp->t_oproc != NULL)
631e85b99abSSascha Wildner (*tp->t_oproc) (tp);
632b06ebda0SMatthew Dillon
633b06ebda0SMatthew Dillon /*
634b06ebda0SMatthew Dillon * This timeout is needed for operation on a pseudo-tty, because the
635b06ebda0SMatthew Dillon * pty code doesn't call pppstart after it has drained the t_outq.
636b06ebda0SMatthew Dillon */
637b06ebda0SMatthew Dillon
638b06ebda0SMatthew Dillon NG_H4_LOCK(sc);
639b06ebda0SMatthew Dillon
640e85b99abSSascha Wildner if (!IF_QEMPTY(&sc->outq) && !callout_pending(&sc->timo))
641b06ebda0SMatthew Dillon ng_callout(&sc->timo, sc->node, NULL, 1,
642b06ebda0SMatthew Dillon ng_h4_process_timeout, NULL, 0);
643b06ebda0SMatthew Dillon
644b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
645b06ebda0SMatthew Dillon
6462efb75f3SMatthew Dillon lwkt_reltoken(&tp->t_token);
647b06ebda0SMatthew Dillon return (0);
648b06ebda0SMatthew Dillon } /* ng_h4_start */
649b06ebda0SMatthew Dillon
650b06ebda0SMatthew Dillon /*****************************************************************************
651b06ebda0SMatthew Dillon *****************************************************************************
652b06ebda0SMatthew Dillon ** Netgraph node methods
653b06ebda0SMatthew Dillon *****************************************************************************
654b06ebda0SMatthew Dillon *****************************************************************************/
655b06ebda0SMatthew Dillon
656b06ebda0SMatthew Dillon /*
657b06ebda0SMatthew Dillon * Initialize a new node of this type. We only allow nodes to be created as
658b06ebda0SMatthew Dillon * a result of setting the line discipline on a tty, so always return an error
659b06ebda0SMatthew Dillon * if not.
660b06ebda0SMatthew Dillon */
661b06ebda0SMatthew Dillon
662b06ebda0SMatthew Dillon static int
663b06ebda0SMatthew Dillon ng_h4_constructor(node_p node)
664b06ebda0SMatthew Dillon {
665b06ebda0SMatthew Dillon return (EOPNOTSUPP);
666b06ebda0SMatthew Dillon } /* ng_h4_constructor */
667b06ebda0SMatthew Dillon
668b06ebda0SMatthew Dillon /*
669b06ebda0SMatthew Dillon * Add a new hook. There can only be one.
670b06ebda0SMatthew Dillon */
671b06ebda0SMatthew Dillon
672b06ebda0SMatthew Dillon static int
673b06ebda0SMatthew Dillon ng_h4_newhook(node_p node, hook_p hook, const char *name)
674b06ebda0SMatthew Dillon {
675b06ebda0SMatthew Dillon ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
676b06ebda0SMatthew Dillon
677b06ebda0SMatthew Dillon if (strcmp(name, NG_H4_HOOK) != 0)
678b06ebda0SMatthew Dillon return (EINVAL);
679b06ebda0SMatthew Dillon
680b06ebda0SMatthew Dillon NG_H4_LOCK(sc);
681b06ebda0SMatthew Dillon
682b06ebda0SMatthew Dillon if (sc->hook != NULL) {
683b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
684b06ebda0SMatthew Dillon return (EISCONN);
685b06ebda0SMatthew Dillon }
686b06ebda0SMatthew Dillon sc->hook = hook;
687b06ebda0SMatthew Dillon
688b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
689b06ebda0SMatthew Dillon
690b06ebda0SMatthew Dillon return (0);
691b06ebda0SMatthew Dillon } /* ng_h4_newhook */
692b06ebda0SMatthew Dillon
693b06ebda0SMatthew Dillon /*
694b06ebda0SMatthew Dillon * Connect hook. Just say yes.
695b06ebda0SMatthew Dillon */
696b06ebda0SMatthew Dillon
697b06ebda0SMatthew Dillon static int
698b06ebda0SMatthew Dillon ng_h4_connect(hook_p hook)
699b06ebda0SMatthew Dillon {
700b06ebda0SMatthew Dillon ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
701b06ebda0SMatthew Dillon
702b06ebda0SMatthew Dillon if (hook != sc->hook)
703ed20d0e3SSascha Wildner panic("%s: hook != sc->hook", __func__);
704b06ebda0SMatthew Dillon
705b06ebda0SMatthew Dillon NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
706b06ebda0SMatthew Dillon NG_HOOK_FORCE_QUEUE(hook);
707b06ebda0SMatthew Dillon
708b06ebda0SMatthew Dillon return (0);
709b06ebda0SMatthew Dillon } /* ng_h4_connect */
710b06ebda0SMatthew Dillon
711b06ebda0SMatthew Dillon /*
712b06ebda0SMatthew Dillon * Disconnect the hook
713b06ebda0SMatthew Dillon */
714b06ebda0SMatthew Dillon
715b06ebda0SMatthew Dillon static int
716b06ebda0SMatthew Dillon ng_h4_disconnect(hook_p hook)
717b06ebda0SMatthew Dillon {
718b06ebda0SMatthew Dillon ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
719b06ebda0SMatthew Dillon
720b06ebda0SMatthew Dillon /*
721b06ebda0SMatthew Dillon * We need to check for sc != NULL because we can be called from
722b06ebda0SMatthew Dillon * ng_h4_close() via ng_rmnode_self()
723b06ebda0SMatthew Dillon */
724b06ebda0SMatthew Dillon
725b06ebda0SMatthew Dillon if (sc != NULL) {
726b06ebda0SMatthew Dillon if (hook != sc->hook)
727ed20d0e3SSascha Wildner panic("%s: hook != sc->hook", __func__);
728b06ebda0SMatthew Dillon
729b06ebda0SMatthew Dillon NG_H4_LOCK(sc);
730b06ebda0SMatthew Dillon
731b06ebda0SMatthew Dillon /* XXX do we have to untimeout and drain out queue? */
732b06ebda0SMatthew Dillon if (callout_pending(&sc->timo))
733b06ebda0SMatthew Dillon ng_uncallout(&sc->timo, sc->node);
734b06ebda0SMatthew Dillon
735e85b99abSSascha Wildner IF_DRAIN(&sc->outq);
736b06ebda0SMatthew Dillon
737b06ebda0SMatthew Dillon sc->state = NG_H4_W4_PKT_IND;
738b06ebda0SMatthew Dillon sc->want = 1;
739b06ebda0SMatthew Dillon sc->got = 0;
740b06ebda0SMatthew Dillon
741b06ebda0SMatthew Dillon sc->hook = NULL;
742b06ebda0SMatthew Dillon
743b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
744b06ebda0SMatthew Dillon }
745b06ebda0SMatthew Dillon
746b06ebda0SMatthew Dillon return (0);
747b06ebda0SMatthew Dillon } /* ng_h4_disconnect */
748b06ebda0SMatthew Dillon
749b06ebda0SMatthew Dillon /*
750b06ebda0SMatthew Dillon * Remove this node. The does the netgraph portion of the shutdown.
751b06ebda0SMatthew Dillon * This should only be called indirectly from ng_h4_close().
752b06ebda0SMatthew Dillon */
753b06ebda0SMatthew Dillon
754b06ebda0SMatthew Dillon static int
755b06ebda0SMatthew Dillon ng_h4_shutdown(node_p node)
756b06ebda0SMatthew Dillon {
757b06ebda0SMatthew Dillon ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
758b06ebda0SMatthew Dillon
759b06ebda0SMatthew Dillon NG_H4_LOCK(sc);
760b06ebda0SMatthew Dillon
761b06ebda0SMatthew Dillon if (!sc->dying) {
762b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
763b06ebda0SMatthew Dillon
764b06ebda0SMatthew Dillon NG_NODE_REVIVE(node); /* we will persist */
765b06ebda0SMatthew Dillon
766b06ebda0SMatthew Dillon return (EOPNOTSUPP);
767b06ebda0SMatthew Dillon }
768b06ebda0SMatthew Dillon
769b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
770b06ebda0SMatthew Dillon
771b06ebda0SMatthew Dillon NG_NODE_SET_PRIVATE(node, NULL);
772b06ebda0SMatthew Dillon
773e85b99abSSascha Wildner IF_DRAIN(&sc->outq);
774b06ebda0SMatthew Dillon
775b06ebda0SMatthew Dillon NG_NODE_UNREF(node);
776b06ebda0SMatthew Dillon bzero(sc, sizeof(*sc));
777fc025606SSascha Wildner kfree(sc, M_NETGRAPH_H4);
778b06ebda0SMatthew Dillon
779b06ebda0SMatthew Dillon return (0);
780b06ebda0SMatthew Dillon } /* ng_h4_shutdown */
781b06ebda0SMatthew Dillon
782b06ebda0SMatthew Dillon /*
783b06ebda0SMatthew Dillon * Receive incoming data from Netgraph system. Put it on our
784b06ebda0SMatthew Dillon * output queue and start output if necessary.
785b06ebda0SMatthew Dillon */
786b06ebda0SMatthew Dillon
787b06ebda0SMatthew Dillon static int
788b06ebda0SMatthew Dillon ng_h4_rcvdata(hook_p hook, item_p item)
789b06ebda0SMatthew Dillon {
790b06ebda0SMatthew Dillon ng_h4_info_p sc = (ng_h4_info_p)NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
791b06ebda0SMatthew Dillon struct mbuf *m = NULL;
792b06ebda0SMatthew Dillon int qlen;
793b06ebda0SMatthew Dillon
794b06ebda0SMatthew Dillon if (sc == NULL)
795b06ebda0SMatthew Dillon return (EHOSTDOWN);
796b06ebda0SMatthew Dillon
797b06ebda0SMatthew Dillon if (hook != sc->hook)
798ed20d0e3SSascha Wildner panic("%s: hook != sc->hook", __func__);
799b06ebda0SMatthew Dillon
800b06ebda0SMatthew Dillon NGI_GET_M(item, m);
801b06ebda0SMatthew Dillon NG_FREE_ITEM(item);
802b06ebda0SMatthew Dillon
803b06ebda0SMatthew Dillon NG_H4_LOCK(sc);
804b06ebda0SMatthew Dillon
805e85b99abSSascha Wildner if (IF_QFULL(&sc->outq)) {
806b06ebda0SMatthew Dillon NG_H4_ERR("%s: %s - dropping mbuf, len=%d\n", __func__,
807b06ebda0SMatthew Dillon NG_NODE_NAME(sc->node), m->m_pkthdr.len);
808b06ebda0SMatthew Dillon
809b06ebda0SMatthew Dillon NG_H4_STAT_OERROR(sc->stat);
810e85b99abSSascha Wildner IF_DROP(&sc->outq);
811b06ebda0SMatthew Dillon
812b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
813b06ebda0SMatthew Dillon
814b06ebda0SMatthew Dillon NG_FREE_M(m);
815b06ebda0SMatthew Dillon
816b06ebda0SMatthew Dillon return (ENOBUFS);
817b06ebda0SMatthew Dillon }
818b06ebda0SMatthew Dillon
819b06ebda0SMatthew Dillon NG_H4_INFO("%s: %s - queue mbuf, len=%d\n", __func__,
820b06ebda0SMatthew Dillon NG_NODE_NAME(sc->node), m->m_pkthdr.len);
821b06ebda0SMatthew Dillon
822e85b99abSSascha Wildner IF_ENQUEUE(&sc->outq, m);
823e85b99abSSascha Wildner qlen = IF_QLEN(&sc->outq);
824b06ebda0SMatthew Dillon
825b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
826b06ebda0SMatthew Dillon
827b06ebda0SMatthew Dillon /*
828b06ebda0SMatthew Dillon * If qlen > 1, then we should already have a scheduled callout
829b06ebda0SMatthew Dillon */
830b06ebda0SMatthew Dillon
831e85b99abSSascha Wildner if (qlen == 1)
832b06ebda0SMatthew Dillon ng_h4_start(sc->tp);
833b06ebda0SMatthew Dillon
834b06ebda0SMatthew Dillon return (0);
835b06ebda0SMatthew Dillon } /* ng_h4_rcvdata */
836b06ebda0SMatthew Dillon
837b06ebda0SMatthew Dillon /*
838b06ebda0SMatthew Dillon * Receive control message
839b06ebda0SMatthew Dillon */
840b06ebda0SMatthew Dillon
841b06ebda0SMatthew Dillon static int
842b06ebda0SMatthew Dillon ng_h4_rcvmsg(node_p node, item_p item, hook_p lasthook)
843b06ebda0SMatthew Dillon {
844b06ebda0SMatthew Dillon ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
845b06ebda0SMatthew Dillon struct ng_mesg *msg = NULL, *resp = NULL;
846b06ebda0SMatthew Dillon int error = 0;
847b06ebda0SMatthew Dillon
848b06ebda0SMatthew Dillon if (sc == NULL)
849b06ebda0SMatthew Dillon return (EHOSTDOWN);
850b06ebda0SMatthew Dillon
851b06ebda0SMatthew Dillon NGI_GET_MSG(item, msg);
852b06ebda0SMatthew Dillon NG_H4_LOCK(sc);
853b06ebda0SMatthew Dillon
854b06ebda0SMatthew Dillon switch (msg->header.typecookie) {
855b06ebda0SMatthew Dillon case NGM_GENERIC_COOKIE:
856b06ebda0SMatthew Dillon switch (msg->header.cmd) {
857b06ebda0SMatthew Dillon case NGM_TEXT_STATUS:
8585a975a3dSMatthew Dillon NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_WAITOK | M_NULLOK);
859b06ebda0SMatthew Dillon if (resp == NULL)
860b06ebda0SMatthew Dillon error = ENOMEM;
861b06ebda0SMatthew Dillon else
862a62226e4SSascha Wildner ksnprintf(resp->data, NG_TEXTRESPONSE,
863b06ebda0SMatthew Dillon "Hook: %s\n" \
864b06ebda0SMatthew Dillon "Debug: %d\n" \
865b06ebda0SMatthew Dillon "State: %d\n" \
866b06ebda0SMatthew Dillon "Queue: [have:%d,max:%d]\n" \
867b06ebda0SMatthew Dillon "Input: [got:%d,want:%d]",
868b06ebda0SMatthew Dillon (sc->hook != NULL)? NG_H4_HOOK : "",
869b06ebda0SMatthew Dillon sc->debug,
870b06ebda0SMatthew Dillon sc->state,
871e85b99abSSascha Wildner IF_QLEN(&sc->outq),
872b06ebda0SMatthew Dillon sc->outq.ifq_maxlen,
873b06ebda0SMatthew Dillon sc->got,
874b06ebda0SMatthew Dillon sc->want);
875b06ebda0SMatthew Dillon break;
876b06ebda0SMatthew Dillon
877b06ebda0SMatthew Dillon default:
878b06ebda0SMatthew Dillon error = EINVAL;
879b06ebda0SMatthew Dillon break;
880b06ebda0SMatthew Dillon }
881b06ebda0SMatthew Dillon break;
882b06ebda0SMatthew Dillon
883b06ebda0SMatthew Dillon case NGM_H4_COOKIE:
884b06ebda0SMatthew Dillon switch (msg->header.cmd) {
885b06ebda0SMatthew Dillon case NGM_H4_NODE_RESET:
886e85b99abSSascha Wildner IF_DRAIN(&sc->outq);
887b06ebda0SMatthew Dillon sc->state = NG_H4_W4_PKT_IND;
888b06ebda0SMatthew Dillon sc->want = 1;
889b06ebda0SMatthew Dillon sc->got = 0;
890b06ebda0SMatthew Dillon break;
891b06ebda0SMatthew Dillon
892b06ebda0SMatthew Dillon case NGM_H4_NODE_GET_STATE:
893b06ebda0SMatthew Dillon NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_state_ep),
8945a975a3dSMatthew Dillon M_WAITOK | M_NULLOK);
895b06ebda0SMatthew Dillon if (resp == NULL)
896b06ebda0SMatthew Dillon error = ENOMEM;
897b06ebda0SMatthew Dillon else
898b06ebda0SMatthew Dillon *((ng_h4_node_state_ep *)(resp->data)) =
899b06ebda0SMatthew Dillon sc->state;
900b06ebda0SMatthew Dillon break;
901b06ebda0SMatthew Dillon
902b06ebda0SMatthew Dillon case NGM_H4_NODE_GET_DEBUG:
903b06ebda0SMatthew Dillon NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_debug_ep),
9045a975a3dSMatthew Dillon M_WAITOK | M_NULLOK);
905b06ebda0SMatthew Dillon if (resp == NULL)
906b06ebda0SMatthew Dillon error = ENOMEM;
907b06ebda0SMatthew Dillon else
908b06ebda0SMatthew Dillon *((ng_h4_node_debug_ep *)(resp->data)) =
909b06ebda0SMatthew Dillon sc->debug;
910b06ebda0SMatthew Dillon break;
911b06ebda0SMatthew Dillon
912b06ebda0SMatthew Dillon case NGM_H4_NODE_SET_DEBUG:
913b06ebda0SMatthew Dillon if (msg->header.arglen != sizeof(ng_h4_node_debug_ep))
914b06ebda0SMatthew Dillon error = EMSGSIZE;
915b06ebda0SMatthew Dillon else
916b06ebda0SMatthew Dillon sc->debug =
917b06ebda0SMatthew Dillon *((ng_h4_node_debug_ep *)(msg->data));
918b06ebda0SMatthew Dillon break;
919b06ebda0SMatthew Dillon
920b06ebda0SMatthew Dillon case NGM_H4_NODE_GET_QLEN:
921b06ebda0SMatthew Dillon NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_qlen_ep),
9225a975a3dSMatthew Dillon M_WAITOK | M_NULLOK);
923b06ebda0SMatthew Dillon if (resp == NULL)
924b06ebda0SMatthew Dillon error = ENOMEM;
925b06ebda0SMatthew Dillon else
926b06ebda0SMatthew Dillon *((ng_h4_node_qlen_ep *)(resp->data)) =
927b06ebda0SMatthew Dillon sc->outq.ifq_maxlen;
928b06ebda0SMatthew Dillon break;
929b06ebda0SMatthew Dillon
930b06ebda0SMatthew Dillon case NGM_H4_NODE_SET_QLEN:
931b06ebda0SMatthew Dillon if (msg->header.arglen != sizeof(ng_h4_node_qlen_ep))
932b06ebda0SMatthew Dillon error = EMSGSIZE;
933b06ebda0SMatthew Dillon else if (*((ng_h4_node_qlen_ep *)(msg->data)) <= 0)
934b06ebda0SMatthew Dillon error = EINVAL;
935b06ebda0SMatthew Dillon else
936e85b99abSSascha Wildner sc->outq.ifq_maxlen =
937e85b99abSSascha Wildner *((ng_h4_node_qlen_ep *)(msg->data));
938b06ebda0SMatthew Dillon break;
939b06ebda0SMatthew Dillon
940b06ebda0SMatthew Dillon case NGM_H4_NODE_GET_STAT:
941b06ebda0SMatthew Dillon NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_stat_ep),
9425a975a3dSMatthew Dillon M_WAITOK | M_NULLOK);
943b06ebda0SMatthew Dillon if (resp == NULL)
944b06ebda0SMatthew Dillon error = ENOMEM;
945b06ebda0SMatthew Dillon else
946b06ebda0SMatthew Dillon bcopy(&sc->stat, resp->data,
947b06ebda0SMatthew Dillon sizeof(ng_h4_node_stat_ep));
948b06ebda0SMatthew Dillon break;
949b06ebda0SMatthew Dillon
950b06ebda0SMatthew Dillon case NGM_H4_NODE_RESET_STAT:
951b06ebda0SMatthew Dillon NG_H4_STAT_RESET(sc->stat);
952b06ebda0SMatthew Dillon break;
953b06ebda0SMatthew Dillon
954b06ebda0SMatthew Dillon default:
955b06ebda0SMatthew Dillon error = EINVAL;
956b06ebda0SMatthew Dillon break;
957b06ebda0SMatthew Dillon }
958b06ebda0SMatthew Dillon break;
959b06ebda0SMatthew Dillon
960b06ebda0SMatthew Dillon default:
961b06ebda0SMatthew Dillon error = EINVAL;
962b06ebda0SMatthew Dillon break;
963b06ebda0SMatthew Dillon }
964b06ebda0SMatthew Dillon
965b06ebda0SMatthew Dillon NG_H4_UNLOCK(sc);
966b06ebda0SMatthew Dillon
967b06ebda0SMatthew Dillon NG_RESPOND_MSG(error, node, item, resp);
968b06ebda0SMatthew Dillon NG_FREE_MSG(msg);
969b06ebda0SMatthew Dillon
970b06ebda0SMatthew Dillon return (error);
971b06ebda0SMatthew Dillon } /* ng_h4_rcvmsg */
972b06ebda0SMatthew Dillon
973b06ebda0SMatthew Dillon /*
974b06ebda0SMatthew Dillon * Timeout processing function.
975b06ebda0SMatthew Dillon * We still have data to output to the device, so try sending more.
976b06ebda0SMatthew Dillon */
977b06ebda0SMatthew Dillon
978b06ebda0SMatthew Dillon static void
979b06ebda0SMatthew Dillon ng_h4_process_timeout(node_p node, hook_p hook, void *arg1, int arg2)
980b06ebda0SMatthew Dillon {
981b06ebda0SMatthew Dillon ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
982b06ebda0SMatthew Dillon
983b06ebda0SMatthew Dillon ng_h4_start(sc->tp);
984b06ebda0SMatthew Dillon } /* ng_h4_process_timeout */
985b06ebda0SMatthew Dillon
986b06ebda0SMatthew Dillon /*
987b06ebda0SMatthew Dillon * Handle loading and unloading for this node type
988b06ebda0SMatthew Dillon */
989b06ebda0SMatthew Dillon
990b06ebda0SMatthew Dillon static int
991b06ebda0SMatthew Dillon ng_h4_mod_event(module_t mod, int event, void *data)
992b06ebda0SMatthew Dillon {
993b06ebda0SMatthew Dillon static int ng_h4_ldisc;
994b06ebda0SMatthew Dillon int error = 0;
995b06ebda0SMatthew Dillon
996b06ebda0SMatthew Dillon switch (event) {
997b06ebda0SMatthew Dillon case MOD_LOAD:
998b06ebda0SMatthew Dillon /* Register line discipline */
999e85b99abSSascha Wildner crit_enter();
1000e85b99abSSascha Wildner ng_h4_ldisc = ldisc_register(BTUARTDISC, &ng_h4_disc);
1001e85b99abSSascha Wildner crit_exit();
1002b06ebda0SMatthew Dillon
1003b06ebda0SMatthew Dillon if (ng_h4_ldisc < 0) {
1004a62226e4SSascha Wildner kprintf("%s: can't register H4 line discipline\n",
1005b06ebda0SMatthew Dillon __func__);
1006b06ebda0SMatthew Dillon error = EIO;
1007b06ebda0SMatthew Dillon }
1008b06ebda0SMatthew Dillon break;
1009b06ebda0SMatthew Dillon
1010b06ebda0SMatthew Dillon case MOD_UNLOAD:
1011b06ebda0SMatthew Dillon /* Unregister line discipline */
1012e85b99abSSascha Wildner crit_enter();
1013b06ebda0SMatthew Dillon ldisc_deregister(ng_h4_ldisc);
1014e85b99abSSascha Wildner crit_exit();
1015b06ebda0SMatthew Dillon break;
1016b06ebda0SMatthew Dillon
1017b06ebda0SMatthew Dillon default:
1018b06ebda0SMatthew Dillon error = EOPNOTSUPP;
1019b06ebda0SMatthew Dillon break;
1020b06ebda0SMatthew Dillon }
1021b06ebda0SMatthew Dillon
1022b06ebda0SMatthew Dillon return (error);
1023b06ebda0SMatthew Dillon } /* ng_h4_mod_event */
1024b06ebda0SMatthew Dillon
1025