Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / sys / netgraph7 / 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  * $FreeBSD: src/sys/netgraph/atm/sscop/ng_sscop.c,v 1.4 2005/08/10 06:25:40 obrien Exp $
33  * $DragonFly: src/sys/netgraph7/atm/sscop/ng_sscop.c,v 1.2 2008/06/26 23:05:39 dillon Exp $
34  * $DragonFly: src/sys/netgraph7/atm/sscop/ng_sscop.c,v 1.2 2008/06/26 23:05:39 dillon Exp $
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 "ng_message.h"
51 #include "netgraph.h"
52 #include "ng_parse.h"
53 #include <netnatm/saal/sscopdef.h>
54 #include "atm/ng_sscop.h"
55 #include "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         if ((p = kmalloc(sizeof(*p), M_NG_SSCOP, M_WAITOK | M_NULLOK | M_ZERO)) == NULL)
250                 return (ENOMEM);
251
252         if ((p->sscop = sscop_create(node, &sscop_funcs)) == NULL) {
253                 kfree(p, M_NG_SSCOP);
254                 return (ENOMEM);
255         }
256         NG_NODE_SET_PRIVATE(node, p);
257
258         /* All data message received by the node are expected to change the
259          * node's state. Therefor we must ensure, that we have a writer lock. */
260         NG_NODE_FORCE_WRITER(node);
261
262         return (0);
263 }
264 static int
265 ng_sscop_shutdown(node_p node)
266 {
267         struct priv *priv = NG_NODE_PRIVATE(node);
268
269         sscop_destroy(priv->sscop);
270
271         kfree(priv, M_NG_SSCOP);
272         NG_NODE_SET_PRIVATE(node, NULL);
273
274         NG_NODE_UNREF(node);
275
276         return (0);
277 }
278
279 /************************************************************/
280 /*
281  * CONTROL MESSAGES
282  */
283 /*
284  * Flow control message from upper layer.
285  * This is very experimental:
286  * If we get a message from the upper layer, that somebody has passed its
287  * high water mark, we stop updating the receive window.
288  * If we get a low watermark passed, then we raise the window up
289  * to max - current.
290  * If we get a queue status and it indicates a current below the
291  * high watermark, we unstop window updates (if they are stopped) and
292  * raise the window to highwater - current.
293  */
294 static int
295 flow_upper(node_p node, struct ng_mesg *msg)
296 {
297         struct ngm_queue_state *q;
298         struct priv *priv = NG_NODE_PRIVATE(node);
299         u_int window, space;
300
301         if (msg->header.arglen != sizeof(struct ngm_queue_state))
302                 return (EINVAL);
303         q = (struct ngm_queue_state *)msg->data;
304
305         switch (msg->header.cmd) {
306
307           case NGM_HIGH_WATER_PASSED:
308                 if (priv->flow) {
309                         VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv,
310                             "flow control stopped"));
311                         priv->flow = 0;
312                 }
313                 break;
314
315           case NGM_LOW_WATER_PASSED:
316                 window = sscop_window(priv->sscop, 0);
317                 space = q->max_queuelen_packets - q->current;
318                 if (space > window) {
319                         VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv,
320                             "flow control opened window by %u messages",
321                             space - window));
322                         (void)sscop_window(priv->sscop, space - window);
323                 }
324                 priv->flow = 1;
325                 break;
326
327           case NGM_SYNC_QUEUE_STATE:
328                 if (q->high_watermark <= q->current)
329                         break;
330                 window = sscop_window(priv->sscop, 0);
331                 if (priv->flow)
332                         space = q->max_queuelen_packets - q->current;
333                 else
334                         space = q->high_watermark - q->current;
335                 if (space > window) {
336                         VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv,
337                             "flow control opened window by %u messages",
338                             space - window));
339                         (void)sscop_window(priv->sscop, space - window);
340                 }
341                 priv->flow = 1;
342                 break;
343
344           default:
345                 return (EINVAL);
346         }
347         return (0);
348 }
349
350 static int
351 flow_lower(node_p node, struct ng_mesg *msg)
352 {
353         struct priv *priv = NG_NODE_PRIVATE(node);
354
355         if (msg->header.arglen != sizeof(struct ngm_queue_state))
356                 return (EINVAL);
357
358         switch (msg->header.cmd) {
359
360           case NGM_HIGH_WATER_PASSED:
361                 sscop_setbusy(priv->sscop, 1);
362                 break;
363
364           case NGM_LOW_WATER_PASSED:
365                 sscop_setbusy(priv->sscop, 1);
366                 break;
367
368           default:
369                 return (EINVAL);
370         }
371         return (0);
372 }
373
374 /*
375  * Produce a readable status description
376  */
377 static int
378 text_status(node_p node, struct priv *priv, char *arg, u_int len)
379 {
380         struct sbuf sbuf;
381
382         sbuf_new(&sbuf, arg, len, 0);
383
384         if (priv->upper)
385                 sbuf_printf(&sbuf, "upper hook: %s connected to %s:%s\n",
386                     NG_HOOK_NAME(priv->upper),
387                     NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
388                     NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
389         else
390                 sbuf_printf(&sbuf, "upper hook: <not connected>\n");
391
392         if (priv->lower)
393                 sbuf_printf(&sbuf, "lower hook: %s connected to %s:%s\n",
394                     NG_HOOK_NAME(priv->lower),
395                     NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
396                     NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
397         else
398                 sbuf_printf(&sbuf, "lower hook: <not connected>\n");
399
400         if (priv->manage)
401                 sbuf_printf(&sbuf, "manage hook: %s connected to %s:%s\n",
402                     NG_HOOK_NAME(priv->manage),
403                     NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->manage))),
404                     NG_HOOK_NAME(NG_HOOK_PEER(priv->manage)));
405         else
406                 sbuf_printf(&sbuf, "manage hook: <not connected>\n");
407
408         sbuf_printf(&sbuf, "sscop state: %s\n",
409             !priv->enabled ? "<disabled>" :
410             sscop_statename(sscop_getstate(priv->sscop)));
411
412         sbuf_printf(&sbuf, "input packets:  %ju\n",
413             (uintmax_t)priv->stats.in_packets);
414         sbuf_printf(&sbuf, "input dropped:  %ju\n",
415             (uintmax_t)priv->stats.in_dropped);
416         sbuf_printf(&sbuf, "output packets: %ju\n",
417             (uintmax_t)priv->stats.out_packets);
418         sbuf_printf(&sbuf, "output dropped: %ju\n",
419             (uintmax_t)priv->stats.out_dropped);
420         sbuf_printf(&sbuf, "aa signals:     %ju\n",
421             (uintmax_t)priv->stats.aa_signals);
422         sbuf_printf(&sbuf, "aa dropped:     %ju\n",
423             (uintmax_t)priv->stats.aa_dropped);
424         sbuf_printf(&sbuf, "maa signals:    %ju\n",
425             (uintmax_t)priv->stats.maa_signals);
426         sbuf_printf(&sbuf, "maa dropped:    %ju\n",
427             (uintmax_t)priv->stats.maa_dropped);
428         sbuf_printf(&sbuf, "errors:         %ju\n",
429             (uintmax_t)priv->stats.errors);
430         sbuf_printf(&sbuf, "data delivered: %ju\n",
431             (uintmax_t)priv->stats.data_delivered);
432         sbuf_printf(&sbuf, "window:         %u\n",
433             sscop_window(priv->sscop, 0));
434
435         sbuf_finish(&sbuf);
436         return (sbuf_len(&sbuf));
437 }
438
439
440 /*
441  * Control message received.
442  */
443 static int
444 ng_sscop_rcvmsg(node_p node, item_p item, hook_p lasthook)
445 {
446         struct priv *priv = NG_NODE_PRIVATE(node);
447         struct ng_mesg *resp = NULL;
448         struct ng_mesg *msg;
449         int error = 0;
450
451         NGI_GET_MSG(item, msg);
452
453         switch (msg->header.typecookie) {
454
455           case NGM_GENERIC_COOKIE:
456                 switch (msg->header.cmd) {
457
458                   case NGM_TEXT_STATUS:
459                         NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_WAITOK | M_NULLOK);
460                         if (resp == NULL) {
461                                 error = ENOMEM;
462                                 break;
463                         }
464
465                         resp->header.arglen = text_status(node, priv,
466                             (char *)resp->data, resp->header.arglen) + 1;
467                         break;
468
469                   default:
470                         error = EINVAL;
471                         break;
472                 }
473                 break;
474
475           case NGM_FLOW_COOKIE:
476                 if (priv->enabled && lasthook != NULL) {
477                         if (lasthook == priv->upper)
478                                 error = flow_upper(node, msg);
479                         else if (lasthook == priv->lower)
480                                 error = flow_lower(node, msg);
481                 }
482                 break;
483
484           case NGM_SSCOP_COOKIE:
485                 switch (msg->header.cmd) {
486
487                   case NGM_SSCOP_GETPARAM:
488                     {
489                         struct sscop_param *p;
490
491                         NG_MKRESPONSE(resp, msg, sizeof(*p), M_WAITOK | M_NULLOK);
492                         if (resp == NULL) {
493                                 error = ENOMEM;
494                                 break;
495                         }
496                         p = (struct sscop_param *)resp->data;
497                         sscop_getparam(priv->sscop, p);
498                         break;
499                     }
500
501                   case NGM_SSCOP_SETPARAM:
502                     {
503                         struct ng_sscop_setparam *arg;
504                         struct ng_sscop_setparam_resp *p;
505
506                         if (msg->header.arglen != sizeof(*arg)) {
507                                 error = EINVAL;
508                                 break;
509                         }
510                         if (priv->enabled) {
511                                 error = EISCONN;
512                                 break;
513                         }
514                         arg = (struct ng_sscop_setparam *)msg->data;
515                         NG_MKRESPONSE(resp, msg, sizeof(*p), M_WAITOK | M_NULLOK);
516                         if (resp == NULL) {
517                                 error = ENOMEM;
518                                 break;
519                         }
520                         p = (struct ng_sscop_setparam_resp *)resp->data;
521                         p->mask = arg->mask;
522                         p->error = sscop_setparam(priv->sscop,
523                             &arg->param, &p->mask);
524                         break;
525                     }
526
527                   case NGM_SSCOP_ENABLE:
528                         if (msg->header.arglen != 0) {
529                                 error = EINVAL;
530                                 break;
531                         }
532                         if (priv->enabled) {
533                                 error = EBUSY;
534                                 break;
535                         }
536                         priv->enabled = 1;
537                         priv->flow = 1;
538                         memset(&priv->stats, 0, sizeof(priv->stats));
539                         break;
540
541                   case NGM_SSCOP_DISABLE:
542                         if (msg->header.arglen != 0) {
543                                 error = EINVAL;
544                                 break;
545                         }
546                         if (!priv->enabled) {
547                                 error = ENOTCONN;
548                                 break;
549                         }
550                         priv->enabled = 0;
551                         sscop_reset(priv->sscop);
552                         break;
553
554                   case NGM_SSCOP_GETDEBUG:
555                         if (msg->header.arglen != 0) {
556                                 error = EINVAL;
557                                 break;
558                         }
559                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_WAITOK | M_NULLOK);
560                         if(resp == NULL) {
561                                 error = ENOMEM;
562                                 break;
563                         }
564                         *(u_int32_t *)resp->data = sscop_getdebug(priv->sscop);
565                         break;
566
567                   case NGM_SSCOP_SETDEBUG:
568                         if (msg->header.arglen != sizeof(u_int32_t)) {
569                                 error = EINVAL;
570                                 break;
571                         }
572                         sscop_setdebug(priv->sscop, *(u_int32_t *)msg->data);
573                         break;
574
575                   case NGM_SSCOP_GETSTATE:
576                         if (msg->header.arglen != 0) {
577                                 error = EINVAL;
578                                 break;
579                         }
580                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_WAITOK | M_NULLOK);
581                         if(resp == NULL) {
582                                 error = ENOMEM;
583                                 break;
584                         }
585                         *(u_int32_t *)resp->data =
586                             priv->enabled ? (sscop_getstate(priv->sscop) + 1)
587                                           : 0;
588                         break;
589
590                   default:
591                         error = EINVAL;
592                         break;
593                 }
594                 break;
595
596           default:
597                 error = EINVAL;
598                 break;
599         }
600
601         NG_RESPOND_MSG(error, node, item, resp);
602         NG_FREE_MSG(msg);
603
604         return (error);
605 }
606
607 /************************************************************/
608 /*
609  * HOOK MANAGEMENT
610  */
611 static int
612 ng_sscop_newhook(node_p node, hook_p hook, const char *name)
613 {
614         struct priv *priv = NG_NODE_PRIVATE(node);
615
616         if(strcmp(name, "upper") == 0) {
617                 priv->upper = hook;
618                 NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvupper);
619         } else if(strcmp(name, "lower") == 0) {
620                 priv->lower = hook;
621         } else if(strcmp(name, "manage") == 0) {
622                 priv->manage = hook;
623                 NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvmanage);
624         } else
625                 return EINVAL;
626
627         return 0;
628 }
629 static int
630 ng_sscop_disconnect(hook_p hook)
631 {
632         node_p node = NG_HOOK_NODE(hook);
633         struct priv *priv = NG_NODE_PRIVATE(node);
634
635         if(hook == priv->upper)
636                 priv->upper = NULL;
637         else if(hook == priv->lower)
638                 priv->lower = NULL;
639         else if(hook == priv->manage)
640                 priv->manage = NULL;
641
642         if(NG_NODE_NUMHOOKS(node) == 0) {
643                 if(NG_NODE_IS_VALID(node))
644                         ng_rmnode_self(node);
645         } else {
646                 /*
647                  * Imply a release request, if the upper layer is
648                  * disconnected.
649                  */
650                 if(priv->upper == NULL && priv->lower != NULL &&
651                    priv->enabled &&
652                    sscop_getstate(priv->sscop) != SSCOP_IDLE) {
653                         sscop_aasig(priv->sscop, SSCOP_RELEASE_request,
654                             NULL, 0);
655                 }
656         }
657         return 0;
658 }
659
660 /************************************************************/
661 /*
662  * DATA
663  */
664 static int
665 ng_sscop_rcvlower(hook_p hook, item_p item)
666 {
667         struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
668         struct mbuf *m;
669
670         if (!priv->enabled) {
671                 NG_FREE_ITEM(item);
672                 return EINVAL;
673         }
674
675         /*
676          * If we are disconnected at the upper layer and in the IDLE
677          * state, drop any incoming packet.
678          */
679         if (priv->upper != NULL || sscop_getstate(priv->sscop) != SSCOP_IDLE) {
680                 NGI_GET_M(item, m);
681                 priv->stats.in_packets++;
682                 sscop_input(priv->sscop, m);
683         } else {
684                 priv->stats.in_dropped++;
685         }
686         NG_FREE_ITEM(item);
687
688         return (0);
689 }
690
691 static void
692 sscop_send_lower(struct sscop *sscop, void *p, struct mbuf *m)
693 {
694         node_p node = (node_p)p;
695         struct priv *priv = NG_NODE_PRIVATE(node);
696         int error;
697
698         if (priv->lower == NULL) {
699                 m_freem(m);
700                 priv->stats.out_dropped++;
701                 return;
702         }
703
704         priv->stats.out_packets++;
705         NG_SEND_DATA_ONLY(error, priv->lower, m);
706 }
707
708 static int
709 ng_sscop_rcvupper(hook_p hook, item_p item)
710 {
711         struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
712         struct sscop_arg a;
713         struct mbuf *m;
714
715         if (!priv->enabled) {
716                 NG_FREE_ITEM(item);
717                 return (EINVAL);
718         }
719
720         /*
721          * If the lower layer is not connected allow to proceed.
722          * The lower layer sending function will drop outgoing frames,
723          * and the sscop will timeout any establish requests.
724          */
725         NGI_GET_M(item, m);
726         NG_FREE_ITEM(item);
727
728         if (!(m->m_flags & M_PKTHDR)) {
729                 printf("no pkthdr\n");
730                 m_freem(m);
731                 return (EINVAL);
732         }
733         if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
734                 return (ENOBUFS);
735         bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a));
736         m_adj(m, sizeof(a));
737
738         return (sscop_aasig(priv->sscop, a.sig, m, a.arg));
739 }
740
741 static void
742 sscop_send_upper(struct sscop *sscop, void *p, enum sscop_aasig sig,
743     struct SSCOP_MBUF_T *m, u_int arg)
744 {
745         node_p node = (node_p)p;
746         struct priv *priv = NG_NODE_PRIVATE(node);
747         int error;
748         struct sscop_arg *a;
749
750         if (sig == SSCOP_DATA_indication && priv->flow)
751                 sscop_window(priv->sscop, 1);
752
753         if (priv->upper == NULL) {
754                 if (m != NULL)
755                         m_freem(m);
756                 priv->stats.aa_dropped++;
757                 return;
758         }
759
760         priv->stats.aa_signals++;
761         if (sig == SSCOP_DATA_indication)
762                 priv->stats.data_delivered++;
763
764         if (m == NULL) {
765                 MGETHDR(m, MB_DONTWAIT, MT_DATA);
766                 if (m == NULL)
767                         return;
768                 m->m_len = sizeof(struct sscop_arg);
769                 m->m_pkthdr.len = m->m_len;
770         } else {
771                 M_PREPEND(m, sizeof(struct sscop_arg), MB_DONTWAIT);
772                 if (m == NULL)
773                         return;
774         }
775         a = mtod(m, struct sscop_arg *);
776         a->sig = sig;
777         a->arg = arg;
778
779         NG_SEND_DATA_ONLY(error, priv->upper, m);
780 }
781
782 static int
783 ng_sscop_rcvmanage(hook_p hook, item_p item)
784 {
785         struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
786         struct sscop_marg a;
787         struct mbuf *m;
788
789         if (!priv->enabled) {
790                 NG_FREE_ITEM(item);
791                 return (EINVAL);
792         }
793
794         NGI_GET_M(item, m);
795         NG_FREE_ITEM(item);
796
797         if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
798                 return (ENOBUFS);
799         bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a));
800         m_adj(m, sizeof(a));
801
802         return (sscop_maasig(priv->sscop, a.sig, m));
803 }
804
805 static void
806 sscop_send_manage(struct sscop *sscop, void *p, enum sscop_maasig sig,
807     struct SSCOP_MBUF_T *m, u_int err, u_int cnt)
808 {
809         node_p node = (node_p)p;
810         struct priv *priv = NG_NODE_PRIVATE(node);
811         int error;
812         struct sscop_merr *e;
813         struct sscop_marg *a;
814
815         if (priv->manage == NULL) {
816                 if (m != NULL)
817                         m_freem(m);
818                 priv->stats.maa_dropped++;
819                 return;
820         }
821
822         if (sig == SSCOP_MERROR_indication) {
823                 MGETHDR(m, MB_DONTWAIT, MT_DATA);
824                 if (m == NULL)
825                         return;
826                 m->m_len = sizeof(*e);
827                 m->m_pkthdr.len = m->m_len;
828                 e = mtod(m, struct sscop_merr *);
829                 e->sig = sig;
830                 e->err = err;
831                 e->cnt = cnt;
832                 priv->stats.errors++;
833         } else if (m == NULL) {
834                 MGETHDR(m, MB_DONTWAIT, MT_DATA);
835                 if (m == NULL)
836                         return;
837                 m->m_len = sizeof(*a);
838                 m->m_pkthdr.len = m->m_len;
839                 a = mtod(m, struct sscop_marg *);
840                 a->sig = sig;
841                 priv->stats.maa_signals++;
842         } else {
843                 M_PREPEND(m, sizeof(*a), MB_DONTWAIT);
844                 if (m == NULL)
845                         return;
846                 a = mtod(m, struct sscop_marg *);
847                 a->sig = sig;
848                 priv->stats.maa_signals++;
849         }
850
851         NG_SEND_DATA_ONLY(error, priv->manage, m);
852 }
853
854 /************************************************************/
855 /*
856  * INITIALISATION
857  */
858
859 /*
860  * Loading and unloading of node type
861  */
862 static int
863 ng_sscop_mod_event(module_t mod, int event, void *data)
864 {
865         int s;
866         int error = 0;
867
868         s = splnet();
869         switch (event) {
870
871           case MOD_LOAD:
872                 break;
873
874           case MOD_UNLOAD:
875                 break;
876
877           default:
878                 error = EOPNOTSUPP;
879                 break;
880         }
881         splx(s);
882         return (error);
883 }