xref: /trueos/sys/netgraph/atm/sscfu/ng_sscfu.c (revision b972b67ed72b5687a023c92602aaef64163b2f59)
1 /*-
2  * Copyright (c) 2001-2003
3  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  * 	All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * Author: Hartmut Brandt <harti@freebsd.org>
28  *
29  * Netgraph module for ITU-T Q.2120 UNI SSCF.
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/mbuf.h>
40 #include <sys/errno.h>
41 #include <sys/syslog.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/sbuf.h>
45 #include <machine/stdarg.h>
46 
47 #include <netgraph/ng_message.h>
48 #include <netgraph/netgraph.h>
49 #include <netgraph/ng_parse.h>
50 #include <netnatm/saal/sscopdef.h>
51 #include <netnatm/saal/sscfudef.h>
52 #include <netgraph/atm/ng_sscop.h>
53 #include <netgraph/atm/ng_sscfu.h>
54 #include <netgraph/atm/sscfu/ng_sscfu_cust.h>
55 #include <netnatm/saal/sscfu.h>
56 
57 MALLOC_DEFINE(M_NG_SSCFU, "netgraph_sscfu", "netgraph uni sscf node");
58 
59 MODULE_DEPEND(ng_sscfu, ngatmbase, 1, 1, 1);
60 
61 /*
62  * Private data
63  */
64 struct priv {
65 	hook_p		upper;	/* SAAL interface */
66 	hook_p		lower;	/* SSCOP interface */
67 	struct sscfu	*sscf;	/* the instance */
68 	int		enabled;
69 };
70 
71 /*
72  * PARSING
73  */
74 /*
75  * Parse PARAM type
76  */
77 static const struct ng_parse_struct_field ng_sscop_param_type_info[] =
78     NG_SSCOP_PARAM_INFO;
79 
80 static const struct ng_parse_type ng_sscop_param_type = {
81 	&ng_parse_struct_type,
82 	ng_sscop_param_type_info
83 };
84 
85 static const struct ng_parse_struct_field ng_sscfu_getdefparam_type_info[] =
86     NG_SSCFU_GETDEFPARAM_INFO;
87 
88 static const struct ng_parse_type ng_sscfu_getdefparam_type = {
89 	&ng_parse_struct_type,
90 	ng_sscfu_getdefparam_type_info
91 };
92 
93 
94 static const struct ng_cmdlist ng_sscfu_cmdlist[] = {
95 	{
96 	  NGM_SSCFU_COOKIE,
97 	  NGM_SSCFU_GETDEFPARAM,
98 	  "getdefparam",
99 	  NULL,
100 	  &ng_sscfu_getdefparam_type
101 	},
102 	{
103 	  NGM_SSCFU_COOKIE,
104 	  NGM_SSCFU_ENABLE,
105 	  "enable",
106 	  NULL,
107 	  NULL
108 	},
109 	{
110 	  NGM_SSCFU_COOKIE,
111 	  NGM_SSCFU_DISABLE,
112 	  "disable",
113 	  NULL,
114 	  NULL
115 	},
116 	{
117 	  NGM_SSCFU_COOKIE,
118 	  NGM_SSCFU_GETDEBUG,
119 	  "getdebug",
120 	  NULL,
121 	  &ng_parse_hint32_type
122 	},
123 	{
124 	  NGM_SSCFU_COOKIE,
125 	  NGM_SSCFU_SETDEBUG,
126 	  "setdebug",
127 	  &ng_parse_hint32_type,
128 	  NULL
129 	},
130 	{
131 	  NGM_SSCFU_COOKIE,
132 	  NGM_SSCFU_GETSTATE,
133 	  "getstate",
134 	  NULL,
135 	  &ng_parse_uint32_type
136 	},
137 	{ 0 }
138 };
139 
140 static ng_constructor_t ng_sscfu_constructor;
141 static ng_shutdown_t	ng_sscfu_shutdown;
142 static ng_rcvmsg_t	ng_sscfu_rcvmsg;
143 static ng_newhook_t	ng_sscfu_newhook;
144 static ng_disconnect_t	ng_sscfu_disconnect;
145 static ng_rcvdata_t	ng_sscfu_rcvupper;
146 static ng_rcvdata_t	ng_sscfu_rcvlower;
147 
148 static int ng_sscfu_mod_event(module_t, int, void *);
149 
150 static struct ng_type ng_sscfu_typestruct = {
151 	.version =	NG_ABI_VERSION,
152 	.name =		NG_SSCFU_NODE_TYPE,
153 	.mod_event =	ng_sscfu_mod_event,
154 	.constructor =	ng_sscfu_constructor,
155 	.rcvmsg =	ng_sscfu_rcvmsg,
156 	.shutdown =	ng_sscfu_shutdown,
157 	.newhook =	ng_sscfu_newhook,
158 	.rcvdata =	ng_sscfu_rcvupper,
159 	.disconnect =	ng_sscfu_disconnect,
160 	.cmdlist =	ng_sscfu_cmdlist,
161 };
162 NETGRAPH_INIT(sscfu, &ng_sscfu_typestruct);
163 
164 static void sscfu_send_upper(struct sscfu *, void *, enum saal_sig,
165 	struct mbuf *);
166 static void sscfu_send_lower(struct sscfu *, void *, enum sscop_aasig,
167 	struct mbuf *, u_int);
168 static void sscfu_window(struct sscfu *, void *, u_int);
169 static void sscfu_verbose(struct sscfu *, void *, const char *, ...)
170 	__printflike(3, 4);
171 
172 static const struct sscfu_funcs sscfu_funcs = {
173 	sscfu_send_upper,
174 	sscfu_send_lower,
175 	sscfu_window,
176 	sscfu_verbose
177 };
178 
179 /************************************************************/
180 /*
181  * CONTROL MESSAGES
182  */
183 static int
text_status(node_p node,struct priv * priv,char * arg,u_int len)184 text_status(node_p node, struct priv *priv, char *arg, u_int len)
185 {
186 	struct sbuf sbuf;
187 
188 	sbuf_new(&sbuf, arg, len, 0);
189 
190 	if (priv->upper)
191 		sbuf_printf(&sbuf, "upper hook: %s connected to %s:%s\n",
192 		    NG_HOOK_NAME(priv->upper),
193 		    NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
194 		    NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
195 	else
196 		sbuf_printf(&sbuf, "upper hook: <not connected>\n");
197 
198 	if (priv->lower)
199 		sbuf_printf(&sbuf, "lower hook: %s connected to %s:%s\n",
200 		    NG_HOOK_NAME(priv->lower),
201 		    NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
202 		    NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
203 	else
204 		sbuf_printf(&sbuf, "lower hook: <not connected>\n");
205 
206 	sbuf_printf(&sbuf, "sscf state: %s\n",
207 	    priv->enabled == 0 ? "<disabled>" :
208 	    sscfu_statename(sscfu_getstate(priv->sscf)));
209 
210 	sbuf_finish(&sbuf);
211 	return (sbuf_len(&sbuf));
212 }
213 
214 static int
ng_sscfu_rcvmsg(node_p node,item_p item,hook_p lasthook)215 ng_sscfu_rcvmsg(node_p node, item_p item, hook_p lasthook)
216 {
217 	struct priv *priv = NG_NODE_PRIVATE(node);
218 	struct ng_mesg *resp = NULL;
219 	struct ng_mesg *msg;
220 	int error = 0;
221 
222 	NGI_GET_MSG(item, msg);
223 
224 	switch (msg->header.typecookie) {
225 
226 	  case NGM_GENERIC_COOKIE:
227 		switch (msg->header.cmd) {
228 
229 		  case NGM_TEXT_STATUS:
230 			NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
231 			if (resp == NULL) {
232 				error = ENOMEM;
233 				break;
234 			}
235 			resp->header.arglen = text_status(node, priv,
236 			    (char *)resp->data, resp->header.arglen) + 1;
237 			break;
238 
239 		  default:
240 			error = EINVAL;
241 			break;
242 		}
243 		break;
244 
245 	  case NGM_SSCFU_COOKIE:
246 		switch (msg->header.cmd) {
247 
248 		  case NGM_SSCFU_GETDEFPARAM:
249 		    {
250 			struct ng_sscfu_getdefparam *p;
251 
252 			if (msg->header.arglen != 0) {
253 				error = EINVAL;
254 				break;
255 			}
256 			NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
257 			if (resp == NULL) {
258 				error = ENOMEM;
259 				break;
260 			}
261 			p = (struct ng_sscfu_getdefparam *)resp->data;
262 			p->mask = sscfu_getdefparam(&p->param);
263 			break;
264 		    }
265 
266 		  case NGM_SSCFU_ENABLE:
267 			if (msg->header.arglen != 0) {
268 				error = EINVAL;
269 				break;
270 			}
271 			if (priv->enabled) {
272 				error = EISCONN;
273 				break;
274 			}
275 			priv->enabled = 1;
276 			break;
277 
278 		  case NGM_SSCFU_DISABLE:
279 			if (msg->header.arglen != 0) {
280 				error = EINVAL;
281 				break;
282 			}
283 			if (!priv->enabled) {
284 				error = ENOTCONN;
285 				break;
286 			}
287 			priv->enabled = 0;
288 			sscfu_reset(priv->sscf);
289 			break;
290 
291 		  case NGM_SSCFU_GETSTATE:
292 			if (msg->header.arglen != 0) {
293 				error = EINVAL;
294 				break;
295 			}
296 			NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
297 			if(resp == NULL) {
298 				error = ENOMEM;
299 				break;
300 			}
301 			*(uint32_t *)resp->data =
302 			    priv->enabled ? (sscfu_getstate(priv->sscf) + 1)
303 			                  : 0;
304 			break;
305 
306 		  case NGM_SSCFU_GETDEBUG:
307 			if (msg->header.arglen != 0) {
308 				error = EINVAL;
309 				break;
310 			}
311 			NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
312 			if(resp == NULL) {
313 				error = ENOMEM;
314 				break;
315 			}
316 			*(uint32_t *)resp->data = sscfu_getdebug(priv->sscf);
317 			break;
318 
319 		  case NGM_SSCFU_SETDEBUG:
320 			if (msg->header.arglen != sizeof(uint32_t)) {
321 				error = EINVAL;
322 				break;
323 			}
324 			sscfu_setdebug(priv->sscf, *(uint32_t *)msg->data);
325 			break;
326 
327 		  default:
328 			error = EINVAL;
329 			break;
330 		}
331 		break;
332 
333 	  default:
334 		error = EINVAL;
335 		break;
336 	}
337 
338 	NG_RESPOND_MSG(error, node, item, resp);
339 	NG_FREE_MSG(msg);
340 
341 	return (error);
342 }
343 
344 /************************************************************/
345 /*
346  * HOOK MANAGEMENT
347  */
348 static int
ng_sscfu_newhook(node_p node,hook_p hook,const char * name)349 ng_sscfu_newhook(node_p node, hook_p hook, const char *name)
350 {
351 	struct priv *priv = NG_NODE_PRIVATE(node);
352 
353 	if (strcmp(name, "upper") == 0)
354 		priv->upper = hook;
355 	else if (strcmp(name, "lower") == 0) {
356 		priv->lower = hook;
357 		NG_HOOK_SET_RCVDATA(hook, ng_sscfu_rcvlower);
358 	} else
359 		return (EINVAL);
360 	return (0);
361 }
362 
363 static int
ng_sscfu_disconnect(hook_p hook)364 ng_sscfu_disconnect(hook_p hook)
365 {
366 	node_p node = NG_HOOK_NODE(hook);
367 	struct priv *priv = NG_NODE_PRIVATE(node);
368 
369 	if (hook == priv->upper)
370 		priv->upper = NULL;
371 	else if (hook == priv->lower)
372 		priv->lower = NULL;
373 	else {
374 		log(LOG_ERR, "bogus hook");
375 		return (EINVAL);
376 	}
377 
378 	if (NG_NODE_NUMHOOKS(node) == 0) {
379 		if (NG_NODE_IS_VALID(node))
380 			ng_rmnode_self(node);
381 	} else {
382 		/*
383 		 * Because there are no timeouts reset the protocol
384 		 * if the lower layer is disconnected.
385 		 */
386 		if (priv->lower == NULL &&
387 		    priv->enabled &&
388 		    sscfu_getstate(priv->sscf) != SSCFU_RELEASED)
389 			sscfu_reset(priv->sscf);
390 	}
391 	return (0);
392 }
393 
394 /************************************************************/
395 /*
396  * DATA
397  */
398 static int
ng_sscfu_rcvupper(hook_p hook,item_p item)399 ng_sscfu_rcvupper(hook_p hook, item_p item)
400 {
401 	node_p node = NG_HOOK_NODE(hook);
402 	struct priv *priv = NG_NODE_PRIVATE(node);
403 	struct mbuf *m;
404 	struct sscfu_arg a;
405 
406 	if (!priv->enabled || priv->lower == NULL) {
407 		NG_FREE_ITEM(item);
408 		return (0);
409 	}
410 
411 	NGI_GET_M(item, m);
412 	NG_FREE_ITEM(item);
413 
414 	if (!(m->m_flags & M_PKTHDR)) {
415 		printf("no pkthdr\n");
416 		m_freem(m);
417 		return (EINVAL);
418 	}
419 	if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
420 		return (ENOMEM);
421 	bcopy((caddr_t)mtod(m, struct sscfu_arg *), &a, sizeof(a));
422 	m_adj(m, sizeof(a));
423 
424 	return (sscfu_saalsig(priv->sscf, a.sig, m));
425 }
426 
427 static void
sscfu_send_upper(struct sscfu * sscf,void * p,enum saal_sig sig,struct mbuf * m)428 sscfu_send_upper(struct sscfu *sscf, void *p, enum saal_sig sig, struct mbuf *m)
429 {
430 	node_p node = (node_p)p;
431 	struct priv *priv = NG_NODE_PRIVATE(node);
432 	int error;
433 	struct sscfu_arg *a;
434 
435 	if (priv->upper == NULL) {
436 		if (m != NULL)
437 			m_freem(m);
438 		return;
439 	}
440 	if (m == NULL) {
441 		MGETHDR(m, M_NOWAIT, MT_DATA);
442 		if (m == NULL)
443 			return;
444 		m->m_len = sizeof(struct sscfu_arg);
445 		m->m_pkthdr.len = m->m_len;
446 	} else {
447 		M_PREPEND(m, sizeof(struct sscfu_arg), M_NOWAIT);
448 		if (m == NULL)
449 			return;
450 	}
451 	a = mtod(m, struct sscfu_arg *);
452 	a->sig = sig;
453 
454 	NG_SEND_DATA_ONLY(error, priv->upper, m);
455 }
456 
457 static int
ng_sscfu_rcvlower(hook_p hook,item_p item)458 ng_sscfu_rcvlower(hook_p hook, item_p item)
459 {
460 	node_p node = NG_HOOK_NODE(hook);
461 	struct priv *priv = NG_NODE_PRIVATE(node);
462 	struct mbuf *m;
463 	struct sscop_arg a;
464 
465 	if (!priv->enabled || priv->upper == NULL) {
466 		NG_FREE_ITEM(item);
467 		return (0);
468 	}
469 
470 	NGI_GET_M(item, m);
471 	NG_FREE_ITEM(item);
472 
473 	if (!(m->m_flags & M_PKTHDR)) {
474 		printf("no pkthdr\n");
475 		m_freem(m);
476 		return (EINVAL);
477 	}
478 
479 	/*
480 	 * Strip of the SSCOP header.
481 	 */
482 	if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
483 		return (ENOMEM);
484 	bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a));
485 	m_adj(m, sizeof(a));
486 
487 	sscfu_input(priv->sscf, a.sig, m, a.arg);
488 
489 	return (0);
490 }
491 
492 static void
sscfu_send_lower(struct sscfu * sscf,void * p,enum sscop_aasig sig,struct mbuf * m,u_int arg)493 sscfu_send_lower(struct sscfu *sscf, void *p, enum sscop_aasig sig,
494     struct mbuf *m, u_int arg)
495 {
496 	node_p node = (node_p)p;
497 	struct priv *priv = NG_NODE_PRIVATE(node);
498 	int error;
499 	struct sscop_arg *a;
500 
501 	if (priv->lower == NULL) {
502 		if (m != NULL)
503 			m_freem(m);
504 		return;
505 	}
506 	if (m == NULL) {
507 		MGETHDR(m, M_NOWAIT, MT_DATA);
508 		if (m == NULL)
509 			return;
510 		m->m_len = sizeof(struct sscop_arg);
511 		m->m_pkthdr.len = m->m_len;
512 	} else {
513 		M_PREPEND(m, sizeof(struct sscop_arg), M_NOWAIT);
514 		if (m == NULL)
515 			return;
516 	}
517 	a = mtod(m, struct sscop_arg *);
518 	a->sig = sig;
519 	a->arg = arg;
520 
521 	NG_SEND_DATA_ONLY(error, priv->lower, m);
522 }
523 
524 /*
525  * Window is handled by ng_sscop so make this a NOP.
526  */
527 static void
sscfu_window(struct sscfu * sscfu,void * arg,u_int w)528 sscfu_window(struct sscfu *sscfu, void *arg, u_int w)
529 {
530 }
531 
532 /************************************************************/
533 /*
534  * NODE MANAGEMENT
535  */
536 static int
ng_sscfu_constructor(node_p node)537 ng_sscfu_constructor(node_p node)
538 {
539 	struct priv *priv;
540 
541 	priv = malloc(sizeof(*priv), M_NG_SSCFU, M_WAITOK | M_ZERO);
542 
543 	if ((priv->sscf = sscfu_create(node, &sscfu_funcs)) == NULL) {
544 		free(priv, M_NG_SSCFU);
545 		return (ENOMEM);
546 	}
547 
548 	NG_NODE_SET_PRIVATE(node, priv);
549 
550 	return (0);
551 }
552 
553 static int
ng_sscfu_shutdown(node_p node)554 ng_sscfu_shutdown(node_p node)
555 {
556 	struct priv *priv = NG_NODE_PRIVATE(node);
557 
558 	sscfu_destroy(priv->sscf);
559 
560 	free(priv, M_NG_SSCFU);
561 	NG_NODE_SET_PRIVATE(node, NULL);
562 
563 	NG_NODE_UNREF(node);
564 
565 	return (0);
566 }
567 
568 static void
sscfu_verbose(struct sscfu * sscfu,void * arg,const char * fmt,...)569 sscfu_verbose(struct sscfu *sscfu, void *arg, const char *fmt, ...)
570 {
571 	va_list ap;
572 
573 	va_start(ap, fmt);
574 	printf("sscfu(%p): ", sscfu);
575 	vprintf(fmt, ap);
576 	va_end(ap);
577 	printf("\n");
578 }
579 
580 /************************************************************/
581 /*
582  * INITIALISATION
583  */
584 /*
585  * Loading and unloading of node type
586  */
587 static int
ng_sscfu_mod_event(module_t mod,int event,void * data)588 ng_sscfu_mod_event(module_t mod, int event, void *data)
589 {
590 	int error = 0;
591 
592 	switch (event) {
593 
594 	  case MOD_LOAD:
595 		break;
596 
597 	  case MOD_UNLOAD:
598 		break;
599 
600 	  default:
601 		error = EOPNOTSUPP;
602 		break;
603 	}
604 	return (error);
605 }
606