]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/netgraph/atm/sscop/ng_sscop.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / netgraph / atm / sscop / ng_sscop.c
1 /*-
2  * Copyright (c) 2001-2003
3  *      Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  *      All rights reserved.
5  *
6  * Author: Harti Brandt <harti@freebsd.org>
7  *
8  * Redistribution of this software and documentation and use in source and
9  * binary forms, with or without modification, are permitted provided that
10  * the following conditions are met:
11  *
12  * 1. Redistributions of source code or documentation must retain the above
13  *    copyright notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
19  * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
22  * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
25  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * Netgraph module for ITU-T Q.2110 SSCOP.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/mbuf.h>
41 #include <sys/errno.h>
42 #include <sys/syslog.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/callout.h>
46 #include <sys/sbuf.h>
47 #include <sys/stdint.h>
48 #include <machine/stdarg.h>
49
50 #include <netgraph/ng_message.h>
51 #include <netgraph/netgraph.h>
52 #include <netgraph/ng_parse.h>
53 #include <netnatm/saal/sscopdef.h>
54 #include <netgraph/atm/ng_sscop.h>
55 #include <netgraph/atm/sscop/ng_sscop_cust.h>
56 #include <netnatm/saal/sscop.h>
57
58 #define DDD printf("%s: %d\n", __func__, __LINE__)
59
60 #ifdef SSCOP_DEBUG
61 #define VERBOSE(P,M,F)                                                  \
62     do {                                                                \
63         if (sscop_getdebug((P)->sscop) & (M))                           \
64                 sscop_verbose F ;                                       \
65     } while(0)
66 #else
67 #define VERBOSE(P,M,F)
68 #endif
69
70 MALLOC_DEFINE(M_NG_SSCOP, "netgraph_sscop", "netgraph sscop node");
71
72 MODULE_DEPEND(ng_sscop, ngatmbase, 1, 1, 1);
73
74 struct stats {
75         uint64_t        in_packets;
76         uint64_t        out_packets;
77         uint64_t        aa_signals;
78         uint64_t        errors;
79         uint64_t        data_delivered;
80         uint64_t        aa_dropped;
81         uint64_t        maa_dropped;
82         uint64_t        maa_signals;
83         uint64_t        in_dropped;
84         uint64_t        out_dropped;
85 };
86
87 /*
88  * Private data
89  */
90 struct priv {
91         hook_p          upper;          /* SAAL interface */
92         hook_p          lower;          /* AAL5 interface */
93         hook_p          manage;         /* management interface */
94
95         struct sscop    *sscop;         /* sscop state */
96         int             enabled;        /* whether the protocol is enabled */
97         int             flow;           /* flow control states */
98         struct stats    stats;          /* sadistics */
99 };
100
101 /*
102  * Parse PARAM type
103  */
104 static const struct ng_parse_struct_field ng_sscop_param_type_info[] = 
105     NG_SSCOP_PARAM_INFO;
106
107 static const struct ng_parse_type ng_sscop_param_type = {
108         &ng_parse_struct_type,
109         ng_sscop_param_type_info
110 };
111
112 /*
113  * Parse a SET PARAM type.
114  */
115 static const struct ng_parse_struct_field ng_sscop_setparam_type_info[] =
116     NG_SSCOP_SETPARAM_INFO;
117
118 static const struct ng_parse_type ng_sscop_setparam_type = {
119         &ng_parse_struct_type,
120         ng_sscop_setparam_type_info,
121 };
122
123 /*
124  * Parse a SET PARAM response
125  */
126 static const struct ng_parse_struct_field ng_sscop_setparam_resp_type_info[] =
127     NG_SSCOP_SETPARAM_RESP_INFO;
128
129 static const struct ng_parse_type ng_sscop_setparam_resp_type = {
130         &ng_parse_struct_type,
131         ng_sscop_setparam_resp_type_info,
132 };
133
134 static const struct ng_cmdlist ng_sscop_cmdlist[] = {
135         {
136           NGM_SSCOP_COOKIE,
137           NGM_SSCOP_GETPARAM,
138           "getparam",
139           NULL,
140           &ng_sscop_param_type
141         },
142         {
143           NGM_SSCOP_COOKIE,
144           NGM_SSCOP_SETPARAM,
145           "setparam",
146           &ng_sscop_setparam_type,
147           &ng_sscop_setparam_resp_type
148         },
149         {
150           NGM_SSCOP_COOKIE,
151           NGM_SSCOP_ENABLE,
152           "enable",
153           NULL,
154           NULL
155         },
156         {
157           NGM_SSCOP_COOKIE,
158           NGM_SSCOP_DISABLE,
159           "disable",
160           NULL,
161           NULL
162         },
163         {
164           NGM_SSCOP_COOKIE,
165           NGM_SSCOP_GETDEBUG,
166           "getdebug",
167           NULL,
168           &ng_parse_hint32_type
169         },
170         {
171           NGM_SSCOP_COOKIE,
172           NGM_SSCOP_SETDEBUG,
173           "setdebug",
174           &ng_parse_hint32_type,
175           NULL
176         },
177         {
178           NGM_SSCOP_COOKIE,
179           NGM_SSCOP_GETSTATE,
180           "getstate",
181           NULL,
182           &ng_parse_uint32_type
183         },
184         { 0 }
185 };
186
187 static ng_constructor_t ng_sscop_constructor;
188 static ng_shutdown_t    ng_sscop_shutdown;
189 static ng_rcvmsg_t      ng_sscop_rcvmsg;
190 static ng_newhook_t     ng_sscop_newhook;
191 static ng_disconnect_t  ng_sscop_disconnect;
192 static ng_rcvdata_t     ng_sscop_rcvlower;
193 static ng_rcvdata_t     ng_sscop_rcvupper;
194 static ng_rcvdata_t     ng_sscop_rcvmanage;
195
196 static int ng_sscop_mod_event(module_t, int, void *);
197
198 static struct ng_type ng_sscop_typestruct = {
199         .version =      NG_ABI_VERSION,
200         .name =         NG_SSCOP_NODE_TYPE,
201         .mod_event =    ng_sscop_mod_event,
202         .constructor =  ng_sscop_constructor,
203         .rcvmsg =       ng_sscop_rcvmsg,
204         .shutdown =     ng_sscop_shutdown,
205         .newhook =      ng_sscop_newhook,
206         .rcvdata =      ng_sscop_rcvlower,
207         .disconnect =   ng_sscop_disconnect,
208         .cmdlist =      ng_sscop_cmdlist,
209 };
210 NETGRAPH_INIT(sscop, &ng_sscop_typestruct);
211
212 static void sscop_send_manage(struct sscop *, void *, enum sscop_maasig,
213         struct SSCOP_MBUF_T *, u_int, u_int);
214 static void sscop_send_upper(struct sscop *, void *, enum sscop_aasig,
215         struct SSCOP_MBUF_T *, u_int);
216 static void sscop_send_lower(struct sscop *, void *,
217         struct SSCOP_MBUF_T *);
218 static void sscop_verbose(struct sscop *, void *, const char *, ...)
219         __printflike(3, 4);
220
221 static const struct sscop_funcs sscop_funcs = {
222         sscop_send_manage,
223         sscop_send_upper,
224         sscop_send_lower,
225         sscop_verbose
226 };
227
228 static void
229 sscop_verbose(struct sscop *sscop, void *arg, const char *fmt, ...)
230 {
231         va_list ap;
232
233         va_start(ap, fmt);
234         printf("sscop(%p): ", sscop);
235         vprintf(fmt, ap);
236         va_end(ap);
237         printf("\n");
238 }
239
240 /************************************************************/
241 /*
242  * NODE MANAGEMENT
243  */
244 static int
245 ng_sscop_constructor(node_p node)
246 {
247         struct priv *p;
248
249         p = malloc(sizeof(*p), M_NG_SSCOP, M_WAITOK | M_ZERO);
250
251         if ((p->sscop = sscop_create(node, &sscop_funcs)) == NULL) {
252                 free(p, M_NG_SSCOP);
253                 return (ENOMEM);
254         }
255         NG_NODE_SET_PRIVATE(node, p);
256
257         /* All data message received by the node are expected to change the
258          * node's state. Therefor we must ensure, that we have a writer lock. */
259         NG_NODE_FORCE_WRITER(node);
260
261         return (0);
262 }
263 static int
264 ng_sscop_shutdown(node_p node)
265 {
266         struct priv *priv = NG_NODE_PRIVATE(node);
267
268         sscop_destroy(priv->sscop);
269
270         free(priv, M_NG_SSCOP);
271         NG_NODE_SET_PRIVATE(node, NULL);
272
273         NG_NODE_UNREF(node);
274
275         return (0);
276 }
277
278 /************************************************************/
279 /*
280  * CONTROL MESSAGES
281  */
282 /*
283  * Flow control message from upper layer.
284  * This is very experimental:
285  * If we get a message from the upper layer, that somebody has passed its
286  * high water mark, we stop updating the receive window.
287  * If we get a low watermark passed, then we raise the window up
288  * to max - current.
289  * If we get a queue status and it indicates a current below the
290  * high watermark, we unstop window updates (if they are stopped) and
291  * raise the window to highwater - current.
292  */
293 static int
294 flow_upper(node_p node, struct ng_mesg *msg)
295 {
296         struct ngm_queue_state *q;
297         struct priv *priv = NG_NODE_PRIVATE(node);
298         u_int window, space;
299
300         if (msg->header.arglen != sizeof(struct ngm_queue_state))
301                 return (EINVAL);
302         q = (struct ngm_queue_state *)msg->data;
303
304         switch (msg->header.cmd) {
305
306           case NGM_HIGH_WATER_PASSED:
307                 if (priv->flow) {
308                         VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv,
309                             "flow control stopped"));
310                         priv->flow = 0;
311                 }
312                 break;
313
314           case NGM_LOW_WATER_PASSED:
315                 window = sscop_window(priv->sscop, 0);
316                 space = q->max_queuelen_packets - q->current;
317                 if (space > window) {
318                         VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv,
319                             "flow control opened window by %u messages",
320                             space - window));
321                         (void)sscop_window(priv->sscop, space - window);
322                 }
323                 priv->flow = 1;
324                 break;
325
326           case NGM_SYNC_QUEUE_STATE:
327                 if (q->high_watermark <= q->current)
328                         break;
329                 window = sscop_window(priv->sscop, 0);
330                 if (priv->flow)
331                         space = q->max_queuelen_packets - q->current;
332                 else
333                         space = q->high_watermark - q->current;
334                 if (space > window) {
335                         VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv,
336                             "flow control opened window by %u messages",
337                             space - window));
338                         (void)sscop_window(priv->sscop, space - window);
339                 }
340                 priv->flow = 1;
341                 break;
342
343           default:
344                 return (EINVAL);
345         }
346         return (0);
347 }
348
349 static int
350 flow_lower(node_p node, struct ng_mesg *msg)
351 {
352         struct priv *priv = NG_NODE_PRIVATE(node);
353
354         if (msg->header.arglen != sizeof(struct ngm_queue_state))
355                 return (EINVAL);
356
357         switch (msg->header.cmd) {
358
359           case NGM_HIGH_WATER_PASSED:
360                 sscop_setbusy(priv->sscop, 1);
361                 break;
362
363           case NGM_LOW_WATER_PASSED:
364                 sscop_setbusy(priv->sscop, 1);
365                 break;
366
367           default:
368                 return (EINVAL);
369         }
370         return (0);
371 }
372
373 /*
374  * Produce a readable status description
375  */
376 static int
377 text_status(node_p node, struct priv *priv, char *arg, u_int len)
378 {
379         struct sbuf sbuf;
380
381         sbuf_new(&sbuf, arg, len, 0);
382
383         if (priv->upper)
384                 sbuf_printf(&sbuf, "upper hook: %s connected to %s:%s\n",
385                     NG_HOOK_NAME(priv->upper),
386                     NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
387                     NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
388         else
389                 sbuf_printf(&sbuf, "upper hook: <not connected>\n");
390
391         if (priv->lower)
392                 sbuf_printf(&sbuf, "lower hook: %s connected to %s:%s\n",
393                     NG_HOOK_NAME(priv->lower),
394                     NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
395                     NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
396         else
397                 sbuf_printf(&sbuf, "lower hook: <not connected>\n");
398
399         if (priv->manage)
400                 sbuf_printf(&sbuf, "manage hook: %s connected to %s:%s\n",
401                     NG_HOOK_NAME(priv->manage),
402                     NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->manage))),
403                     NG_HOOK_NAME(NG_HOOK_PEER(priv->manage)));
404         else
405                 sbuf_printf(&sbuf, "manage hook: <not connected>\n");
406
407         sbuf_printf(&sbuf, "sscop state: %s\n",
408             !priv->enabled ? "<disabled>" :
409             sscop_statename(sscop_getstate(priv->sscop)));
410
411         sbuf_printf(&sbuf, "input packets:  %ju\n",
412             (uintmax_t)priv->stats.in_packets);
413         sbuf_printf(&sbuf, "input dropped:  %ju\n",
414             (uintmax_t)priv->stats.in_dropped);
415         sbuf_printf(&sbuf, "output packets: %ju\n",
416             (uintmax_t)priv->stats.out_packets);
417         sbuf_printf(&sbuf, "output dropped: %ju\n",
418             (uintmax_t)priv->stats.out_dropped);
419         sbuf_printf(&sbuf, "aa signals:     %ju\n",
420             (uintmax_t)priv->stats.aa_signals);
421         sbuf_printf(&sbuf, "aa dropped:     %ju\n",
422             (uintmax_t)priv->stats.aa_dropped);
423         sbuf_printf(&sbuf, "maa signals:    %ju\n",
424             (uintmax_t)priv->stats.maa_signals);
425         sbuf_printf(&sbuf, "maa dropped:    %ju\n",
426             (uintmax_t)priv->stats.maa_dropped);
427         sbuf_printf(&sbuf, "errors:         %ju\n",
428             (uintmax_t)priv->stats.errors);
429         sbuf_printf(&sbuf, "data delivered: %ju\n",
430             (uintmax_t)priv->stats.data_delivered);
431         sbuf_printf(&sbuf, "window:         %u\n",
432             sscop_window(priv->sscop, 0));
433
434         sbuf_finish(&sbuf);
435         return (sbuf_len(&sbuf));
436 }
437
438
439 /*
440  * Control message received.
441  */
442 static int
443 ng_sscop_rcvmsg(node_p node, item_p item, hook_p lasthook)
444 {
445         struct priv *priv = NG_NODE_PRIVATE(node);
446         struct ng_mesg *resp = NULL;
447         struct ng_mesg *msg;
448         int error = 0;
449
450         NGI_GET_MSG(item, msg);
451
452         switch (msg->header.typecookie) {
453
454           case NGM_GENERIC_COOKIE:
455                 switch (msg->header.cmd) {
456
457                   case NGM_TEXT_STATUS:
458                         NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
459                         if (resp == NULL) {
460                                 error = ENOMEM;
461                                 break;
462                         }
463
464                         resp->header.arglen = text_status(node, priv,
465                             (char *)resp->data, resp->header.arglen) + 1;
466                         break;
467
468                   default:
469                         error = EINVAL;
470                         break;
471                 }
472                 break;
473
474           case NGM_FLOW_COOKIE:
475                 if (priv->enabled && lasthook != NULL) {
476                         if (lasthook == priv->upper)
477                                 error = flow_upper(node, msg);
478                         else if (lasthook == priv->lower)
479                                 error = flow_lower(node, msg);
480                 }
481                 break;
482
483           case NGM_SSCOP_COOKIE:
484                 switch (msg->header.cmd) {
485
486                   case NGM_SSCOP_GETPARAM:
487                     {
488                         struct sscop_param *p;
489
490                         NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
491                         if (resp == NULL) {
492                                 error = ENOMEM;
493                                 break;
494                         }
495                         p = (struct sscop_param *)resp->data;
496                         sscop_getparam(priv->sscop, p);
497                         break;
498                     }
499
500                   case NGM_SSCOP_SETPARAM:
501                     {
502                         struct ng_sscop_setparam *arg;
503                         struct ng_sscop_setparam_resp *p;
504
505                         if (msg->header.arglen != sizeof(*arg)) {
506                                 error = EINVAL;
507                                 break;
508                         }
509                         if (priv->enabled) {
510                                 error = EISCONN;
511                                 break;
512                         }
513                         arg = (struct ng_sscop_setparam *)msg->data;
514                         NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
515                         if (resp == NULL) {
516                                 error = ENOMEM;
517                                 break;
518                         }
519                         p = (struct ng_sscop_setparam_resp *)resp->data;
520                         p->mask = arg->mask;
521                         p->error = sscop_setparam(priv->sscop,
522                             &arg->param, &p->mask);
523                         break;
524                     }
525
526                   case NGM_SSCOP_ENABLE:
527                         if (msg->header.arglen != 0) {
528                                 error = EINVAL;
529                                 break;
530                         }
531                         if (priv->enabled) {
532                                 error = EBUSY;
533                                 break;
534                         }
535                         priv->enabled = 1;
536                         priv->flow = 1;
537                         memset(&priv->stats, 0, sizeof(priv->stats));
538                         break;
539
540                   case NGM_SSCOP_DISABLE:
541                         if (msg->header.arglen != 0) {
542                                 error = EINVAL;
543                                 break;
544                         }
545                         if (!priv->enabled) {
546                                 error = ENOTCONN;
547                                 break;
548                         }
549                         priv->enabled = 0;
550                         sscop_reset(priv->sscop);
551                         break;
552
553                   case NGM_SSCOP_GETDEBUG:
554                         if (msg->header.arglen != 0) {
555                                 error = EINVAL;
556                                 break;
557                         }
558                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
559                         if(resp == NULL) {
560                                 error = ENOMEM;
561                                 break;
562                         }
563                         *(u_int32_t *)resp->data = sscop_getdebug(priv->sscop);
564                         break;
565
566                   case NGM_SSCOP_SETDEBUG:
567                         if (msg->header.arglen != sizeof(u_int32_t)) {
568                                 error = EINVAL;
569                                 break;
570                         }
571                         sscop_setdebug(priv->sscop, *(u_int32_t *)msg->data);
572                         break;
573
574                   case NGM_SSCOP_GETSTATE:
575                         if (msg->header.arglen != 0) {
576                                 error = EINVAL;
577                                 break;
578                         }
579                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
580                         if(resp == NULL) {
581                                 error = ENOMEM;
582                                 break;
583                         }
584                         *(u_int32_t *)resp->data =
585                             priv->enabled ? (sscop_getstate(priv->sscop) + 1)
586                                           : 0;
587                         break;
588
589                   default:
590                         error = EINVAL;
591                         break;
592                 }
593                 break;
594
595           default:
596                 error = EINVAL;
597                 break;
598         }
599
600         NG_RESPOND_MSG(error, node, item, resp);
601         NG_FREE_MSG(msg);
602
603         return (error);
604 }
605
606 /************************************************************/
607 /*
608  * HOOK MANAGEMENT
609  */
610 static int
611 ng_sscop_newhook(node_p node, hook_p hook, const char *name)
612 {
613         struct priv *priv = NG_NODE_PRIVATE(node);
614
615         if(strcmp(name, "upper") == 0) {
616                 priv->upper = hook;
617                 NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvupper);
618         } else if(strcmp(name, "lower") == 0) {
619                 priv->lower = hook;
620         } else if(strcmp(name, "manage") == 0) {
621                 priv->manage = hook;
622                 NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvmanage);
623         } else
624                 return EINVAL;
625
626         return 0;
627 }
628 static int
629 ng_sscop_disconnect(hook_p hook)
630 {
631         node_p node = NG_HOOK_NODE(hook);
632         struct priv *priv = NG_NODE_PRIVATE(node);
633
634         if(hook == priv->upper)
635                 priv->upper = NULL;
636         else if(hook == priv->lower)
637                 priv->lower = NULL;
638         else if(hook == priv->manage)
639                 priv->manage = NULL;
640
641         if(NG_NODE_NUMHOOKS(node) == 0) {
642                 if(NG_NODE_IS_VALID(node))
643                         ng_rmnode_self(node);
644         } else {
645                 /*
646                  * Imply a release request, if the upper layer is
647                  * disconnected.
648                  */
649                 if(priv->upper == NULL && priv->lower != NULL &&
650                    priv->enabled &&
651                    sscop_getstate(priv->sscop) != SSCOP_IDLE) {
652                         sscop_aasig(priv->sscop, SSCOP_RELEASE_request,
653                             NULL, 0);
654                 }
655         }
656         return 0;
657 }
658
659 /************************************************************/
660 /*
661  * DATA
662  */
663 static int
664 ng_sscop_rcvlower(hook_p hook, item_p item)
665 {
666         struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
667         struct mbuf *m;
668
669         if (!priv->enabled) {
670                 NG_FREE_ITEM(item);
671                 return EINVAL;
672         }
673
674         /*
675          * If we are disconnected at the upper layer and in the IDLE
676          * state, drop any incoming packet.
677          */
678         if (priv->upper != NULL || sscop_getstate(priv->sscop) != SSCOP_IDLE) {
679                 NGI_GET_M(item, m);
680                 priv->stats.in_packets++;
681                 sscop_input(priv->sscop, m);
682         } else {
683                 priv->stats.in_dropped++;
684         }
685         NG_FREE_ITEM(item);
686
687         return (0);
688 }
689
690 static void
691 sscop_send_lower(struct sscop *sscop, void *p, struct mbuf *m)
692 {
693         node_p node = (node_p)p;
694         struct priv *priv = NG_NODE_PRIVATE(node);
695         int error;
696
697         if (priv->lower == NULL) {
698                 m_freem(m);
699                 priv->stats.out_dropped++;
700                 return;
701         }
702
703         priv->stats.out_packets++;
704         NG_SEND_DATA_ONLY(error, priv->lower, m);
705 }
706
707 static int
708 ng_sscop_rcvupper(hook_p hook, item_p item)
709 {
710         struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
711         struct sscop_arg a;
712         struct mbuf *m;
713
714         if (!priv->enabled) {
715                 NG_FREE_ITEM(item);
716                 return (EINVAL);
717         }
718
719         /*
720          * If the lower layer is not connected allow to proceed.
721          * The lower layer sending function will drop outgoing frames,
722          * and the sscop will timeout any establish requests.
723          */
724         NGI_GET_M(item, m);
725         NG_FREE_ITEM(item);
726
727         if (!(m->m_flags & M_PKTHDR)) {
728                 printf("no pkthdr\n");
729                 m_freem(m);
730                 return (EINVAL);
731         }
732         if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
733                 return (ENOBUFS);
734         bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a));
735         m_adj(m, sizeof(a));
736
737         return (sscop_aasig(priv->sscop, a.sig, m, a.arg));
738 }
739
740 static void
741 sscop_send_upper(struct sscop *sscop, void *p, enum sscop_aasig sig,
742     struct SSCOP_MBUF_T *m, u_int arg)
743 {
744         node_p node = (node_p)p;
745         struct priv *priv = NG_NODE_PRIVATE(node);
746         int error;
747         struct sscop_arg *a;
748
749         if (sig == SSCOP_DATA_indication && priv->flow)
750                 sscop_window(priv->sscop, 1);
751
752         if (priv->upper == NULL) {
753                 if (m != NULL)
754                         m_freem(m);
755                 priv->stats.aa_dropped++;
756                 return;
757         }
758
759         priv->stats.aa_signals++;
760         if (sig == SSCOP_DATA_indication)
761                 priv->stats.data_delivered++;
762
763         if (m == NULL) {
764                 MGETHDR(m, M_NOWAIT, MT_DATA);
765                 if (m == NULL)
766                         return;
767                 m->m_len = sizeof(struct sscop_arg);
768                 m->m_pkthdr.len = m->m_len;
769         } else {
770                 M_PREPEND(m, sizeof(struct sscop_arg), M_NOWAIT);
771                 if (m == NULL)
772                         return;
773         }
774         a = mtod(m, struct sscop_arg *);
775         a->sig = sig;
776         a->arg = arg;
777
778         NG_SEND_DATA_ONLY(error, priv->upper, m);
779 }
780
781 static int
782 ng_sscop_rcvmanage(hook_p hook, item_p item)
783 {
784         struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
785         struct sscop_marg a;
786         struct mbuf *m;
787
788         if (!priv->enabled) {
789                 NG_FREE_ITEM(item);
790                 return (EINVAL);
791         }
792
793         NGI_GET_M(item, m);
794         NG_FREE_ITEM(item);
795
796         if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
797                 return (ENOBUFS);
798         bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a));
799         m_adj(m, sizeof(a));
800
801         return (sscop_maasig(priv->sscop, a.sig, m));
802 }
803
804 static void
805 sscop_send_manage(struct sscop *sscop, void *p, enum sscop_maasig sig,
806     struct SSCOP_MBUF_T *m, u_int err, u_int cnt)
807 {
808         node_p node = (node_p)p;
809         struct priv *priv = NG_NODE_PRIVATE(node);
810         int error;
811         struct sscop_merr *e;
812         struct sscop_marg *a;
813
814         if (priv->manage == NULL) {
815                 if (m != NULL)
816                         m_freem(m);
817                 priv->stats.maa_dropped++;
818                 return;
819         }
820
821         if (sig == SSCOP_MERROR_indication) {
822                 MGETHDR(m, M_NOWAIT, MT_DATA);
823                 if (m == NULL)
824                         return;
825                 m->m_len = sizeof(*e);
826                 m->m_pkthdr.len = m->m_len;
827                 e = mtod(m, struct sscop_merr *);
828                 e->sig = sig;
829                 e->err = err;
830                 e->cnt = cnt;
831                 priv->stats.errors++;
832         } else if (m == NULL) {
833                 MGETHDR(m, M_NOWAIT, MT_DATA);
834                 if (m == NULL)
835                         return;
836                 m->m_len = sizeof(*a);
837                 m->m_pkthdr.len = m->m_len;
838                 a = mtod(m, struct sscop_marg *);
839                 a->sig = sig;
840                 priv->stats.maa_signals++;
841         } else {
842                 M_PREPEND(m, sizeof(*a), M_NOWAIT);
843                 if (m == NULL)
844                         return;
845                 a = mtod(m, struct sscop_marg *);
846                 a->sig = sig;
847                 priv->stats.maa_signals++;
848         }
849
850         NG_SEND_DATA_ONLY(error, priv->manage, m);
851 }
852
853 /************************************************************/
854 /*
855  * INITIALISATION
856  */
857
858 /*
859  * Loading and unloading of node type
860  */
861 static int
862 ng_sscop_mod_event(module_t mod, int event, void *data)
863 {
864         int error = 0;
865
866         switch (event) {
867
868           case MOD_LOAD:
869                 break;
870
871           case MOD_UNLOAD:
872                 break;
873
874           default:
875                 error = EOPNOTSUPP;
876                 break;
877         }
878         return (error);
879 }