1/*
2 * ng_UI.c
3 */
4
5/*-
6 * Copyright (c) 1996-1999 Whistle Communications, Inc.
7 * All rights reserved.
8 *
9 * Subject to the following obligations and disclaimer of warranty, use and
10 * redistribution of this software, in source or object code forms, with or
11 * without modifications are expressly permitted by Whistle Communications;
12 * provided, however, that:
13 * 1. Any and all reproductions of the source or object code must include the
14 *    copyright notice above and the following disclaimer of warranties; and
15 * 2. No rights are granted, in any manner or form, to use Whistle
16 *    Communications, Inc. trademarks, including the mark "WHISTLE
17 *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18 *    such appears in the above copyright notice or in the software.
19 *
20 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36 * OF SUCH DAMAGE.
37 *
38 * Author: Julian Elischer <julian@freebsd.org>
39 * $Whistle: ng_UI.c,v 1.14 1999/11/01 09:24:51 julian Exp $
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/errno.h>
45#include <sys/kernel.h>
46#include <sys/malloc.h>
47#include <sys/mbuf.h>
48#include <sys/errno.h>
49
50#include <netgraph/ng_message.h>
51#include <netgraph/netgraph.h>
52#include <netgraph/ng_UI.h>
53
54/*
55 * DEFINITIONS
56 */
57
58/* Everything, starting with sdlc on has defined UI as 0x03 */
59#define HDLC_UI	0x03
60
61/* Node private data */
62struct ng_UI_private {
63	hook_p  downlink;
64	hook_p  uplink;
65};
66typedef struct ng_UI_private *priv_p;
67
68/* Netgraph node methods */
69static ng_constructor_t	ng_UI_constructor;
70static ng_rcvmsg_t	ng_UI_rcvmsg;
71static ng_shutdown_t	ng_UI_shutdown;
72static ng_newhook_t	ng_UI_newhook;
73static ng_rcvdata_t	ng_UI_rcvdata;
74static ng_disconnect_t	ng_UI_disconnect;
75
76/* Node type descriptor */
77static struct ng_type typestruct = {
78	.version =	NG_ABI_VERSION,
79	.name =		NG_UI_NODE_TYPE,
80	.constructor =	ng_UI_constructor,
81	.rcvmsg =	ng_UI_rcvmsg,
82	.shutdown =	ng_UI_shutdown,
83	.newhook =	ng_UI_newhook,
84	.rcvdata =	ng_UI_rcvdata,
85	.disconnect =	ng_UI_disconnect,
86};
87NETGRAPH_INIT(UI, &typestruct);
88
89/************************************************************************
90			NETGRAPH NODE STUFF
91 ************************************************************************/
92
93/*
94 * Create a newborn node. We start with an implicit reference.
95 */
96
97static int
98ng_UI_constructor(node_p node)
99{
100	priv_p  priv;
101
102	/* Allocate private structure */
103	priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
104	NG_NODE_SET_PRIVATE(node, priv);
105	return (0);
106}
107
108/*
109 * Give our ok for a hook to be added
110 */
111static int
112ng_UI_newhook(node_p node, hook_p hook, const char *name)
113{
114	const priv_p priv = NG_NODE_PRIVATE(node);
115
116	if (!strcmp(name, NG_UI_HOOK_DOWNSTREAM)) {
117		if (priv->downlink)
118			return (EISCONN);
119		priv->downlink = hook;
120	} else if (!strcmp(name, NG_UI_HOOK_UPSTREAM)) {
121		if (priv->uplink)
122			return (EISCONN);
123		priv->uplink = hook;
124	} else
125		return (EINVAL);
126	return (0);
127}
128
129/*
130 * Receive a control message
131 */
132static int
133ng_UI_rcvmsg(node_p node, item_p item, hook_p lasthook)
134{
135	int	error;
136	const priv_p priv = NG_NODE_PRIVATE(node);
137	struct ng_mesg *msg;
138
139	msg = NGI_MSG(item); /* only peeking */
140	if ((msg->header.typecookie == NGM_FLOW_COOKIE) && lasthook)  {
141		if (lasthook == priv->downlink) {
142			if (priv->uplink) {
143				NG_FWD_ITEM_HOOK(error, item, priv->uplink);
144				return (error);
145			}
146		} else {
147			if (priv->downlink) {
148				NG_FWD_ITEM_HOOK(error, item, priv->downlink);
149				return (error);
150			}
151		}
152	}
153
154	NG_FREE_ITEM(item);
155	return (EINVAL);
156}
157
158#define MAX_ENCAPS_HDR	1
159#define ERROUT(x)	do { error = (x); goto done; } while (0)
160
161/*
162 * Receive a data frame
163 */
164static int
165ng_UI_rcvdata(hook_p hook, item_p item)
166{
167	const node_p node = NG_HOOK_NODE(hook);
168	const priv_p priv = NG_NODE_PRIVATE(node);
169	struct mbuf *m;
170	int error = 0;
171
172	NGI_GET_M(item, m);
173	if (hook == priv->downlink) {
174		u_char *start, *ptr;
175
176		if (m->m_len < MAX_ENCAPS_HDR
177		    && !(m = m_pullup(m, MAX_ENCAPS_HDR)))
178			ERROUT(ENOBUFS);
179		ptr = start = mtod(m, u_char *);
180
181		/* Must be UI frame */
182		if (*ptr++ != HDLC_UI)
183			ERROUT(0);
184
185		m_adj(m, ptr - start);
186		NG_FWD_NEW_DATA(error, item, priv->uplink, m);	/* m -> NULL */
187	} else if (hook == priv->uplink) {
188		M_PREPEND(m, 1, M_NOWAIT);	/* Prepend IP NLPID */
189		if (!m)
190			ERROUT(ENOBUFS);
191		mtod(m, u_char *)[0] = HDLC_UI;
192		NG_FWD_NEW_DATA(error, item, priv->downlink, m);	/* m -> NULL */
193	} else
194		panic("%s", __func__);
195
196done:
197	NG_FREE_M(m);	/* does nothing if m == NULL */
198	if (item)
199		NG_FREE_ITEM(item);
200	return (error);
201}
202
203/*
204 * Shutdown node
205 */
206static int
207ng_UI_shutdown(node_p node)
208{
209	const priv_p priv = NG_NODE_PRIVATE(node);
210
211	/* Take down netgraph node */
212	free(priv, M_NETGRAPH);
213	NG_NODE_SET_PRIVATE(node, NULL);
214	NG_NODE_UNREF(node);
215	return (0);
216}
217
218/*
219 * Hook disconnection
220 */
221static int
222ng_UI_disconnect(hook_p hook)
223{
224	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
225
226	if (hook == priv->downlink)
227		priv->downlink = NULL;
228	else if (hook == priv->uplink)
229		priv->uplink = NULL;
230	else
231		panic("%s", __func__);
232	/*
233	 * If we are not already shutting down,
234	 * and we have no more hooks, then DO shut down.
235	 */
236	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
237	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) {
238			ng_rmnode_self(NG_HOOK_NODE(hook));
239	}
240	return (0);
241}
242