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