Vendor import of netgraph from FreeBSD-current 20080626
[dragonfly.git] / sys / netgraph7 / atm / sscfu / ng_sscfu.c
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: src/sys/netgraph/atm/sscfu/ng_sscfu.c,v 1.4 2005/01/07 01:45:41 imp Exp $");
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
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
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
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
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
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
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
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
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
528 sscfu_window(struct sscfu *sscfu, void *arg, u_int w)
529 {
530 }
531
532 /************************************************************/
533 /*
534  * NODE MANAGEMENT
535  */
536 static int
537 ng_sscfu_constructor(node_p node)
538 {
539         struct priv *priv;
540
541         if ((priv = malloc(sizeof(*priv), M_NG_SSCFU, M_NOWAIT|M_ZERO)) == NULL)
542                 return (ENOMEM);
543
544         if ((priv->sscf = sscfu_create(node, &sscfu_funcs)) == NULL) {
545                 free(priv, M_NG_SSCFU);
546                 return (ENOMEM);
547         }
548
549         NG_NODE_SET_PRIVATE(node, priv);
550
551         return (0);
552 }
553
554 static int
555 ng_sscfu_shutdown(node_p node)
556 {
557         struct priv *priv = NG_NODE_PRIVATE(node);
558
559         sscfu_destroy(priv->sscf);
560
561         free(priv, M_NG_SSCFU);
562         NG_NODE_SET_PRIVATE(node, NULL);
563
564         NG_NODE_UNREF(node);
565
566         return (0);
567 }
568
569 static void
570 sscfu_verbose(struct sscfu *sscfu, void *arg, const char *fmt, ...)
571 {
572         va_list ap;
573
574         va_start(ap, fmt);
575         printf("sscfu(%p): ", sscfu);
576         vprintf(fmt, ap);
577         va_end(ap);
578         printf("\n");
579 }
580
581 /************************************************************/
582 /*
583  * INITIALISATION
584  */
585 /*
586  * Loading and unloading of node type
587  */
588 static int
589 ng_sscfu_mod_event(module_t mod, int event, void *data)
590 {
591         int s;
592         int error = 0;
593
594         s = splnet();
595         switch (event) {
596
597           case MOD_LOAD:
598                 break;
599
600           case MOD_UNLOAD:
601                 break;
602
603           default:
604                 error = EOPNOTSUPP;
605                 break;
606         }
607         splx(s);
608         return (error);
609 }