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