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