1139823Simp/*-
2121461Sharti * Copyright (c) 2001-2003
3121461Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4121461Sharti *	All rights reserved.
5121461Sharti *
6121461Sharti * Author: Harti Brandt <harti@freebsd.org>
7121461Sharti *
8121461Sharti * Redistribution of this software and documentation and use in source and
9121461Sharti * binary forms, with or without modification, are permitted provided that
10121461Sharti * the following conditions are met:
11121461Sharti *
12121461Sharti * 1. Redistributions of source code or documentation must retain the above
13121461Sharti *    copyright notice, this list of conditions and the following disclaimer.
14121461Sharti * 2. Redistributions in binary form must reproduce the above copyright
15121461Sharti *    notice, this list of conditions and the following disclaimer in the
16121461Sharti *    documentation and/or other materials provided with the distribution.
17121461Sharti *
18121461Sharti * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
19121461Sharti * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20121461Sharti * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21121461Sharti * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
22121461Sharti * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
23121461Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24121461Sharti * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
25121461Sharti * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26121461Sharti * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27121461Sharti * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28121461Sharti * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29121461Sharti *
30121461Sharti * Netgraph module for ITU-T Q.2110 SSCOP.
31121461Sharti */
32121461Sharti
33121461Sharti#include <sys/cdefs.h>
34121461Sharti__FBSDID("$FreeBSD$");
35121461Sharti
36121461Sharti#include <sys/param.h>
37121461Sharti#include <sys/systm.h>
38121461Sharti#include <sys/kernel.h>
39121461Sharti#include <sys/malloc.h>
40121461Sharti#include <sys/mbuf.h>
41121461Sharti#include <sys/errno.h>
42121461Sharti#include <sys/syslog.h>
43121461Sharti#include <sys/socket.h>
44121461Sharti#include <sys/socketvar.h>
45121461Sharti#include <sys/callout.h>
46121461Sharti#include <sys/sbuf.h>
47121461Sharti#include <sys/stdint.h>
48121461Sharti#include <machine/stdarg.h>
49121461Sharti
50121461Sharti#include <netgraph/ng_message.h>
51121461Sharti#include <netgraph/netgraph.h>
52121461Sharti#include <netgraph/ng_parse.h>
53121461Sharti#include <netnatm/saal/sscopdef.h>
54121461Sharti#include <netgraph/atm/ng_sscop.h>
55121461Sharti#include <netgraph/atm/sscop/ng_sscop_cust.h>
56121461Sharti#include <netnatm/saal/sscop.h>
57121461Sharti
58148915Sobrien#define DDD printf("%s: %d\n", __func__, __LINE__)
59121461Sharti
60121461Sharti#ifdef SSCOP_DEBUG
61121461Sharti#define VERBOSE(P,M,F)							\
62121461Sharti    do {								\
63121461Sharti	if (sscop_getdebug((P)->sscop) & (M))				\
64121461Sharti		sscop_verbose F ;					\
65121461Sharti    } while(0)
66121461Sharti#else
67121461Sharti#define VERBOSE(P,M,F)
68121461Sharti#endif
69121461Sharti
70121461ShartiMALLOC_DEFINE(M_NG_SSCOP, "netgraph_sscop", "netgraph sscop node");
71121461Sharti
72121461ShartiMODULE_DEPEND(ng_sscop, ngatmbase, 1, 1, 1);
73121461Sharti
74121461Shartistruct stats {
75121461Sharti	uint64_t	in_packets;
76121461Sharti	uint64_t	out_packets;
77121461Sharti	uint64_t	aa_signals;
78121461Sharti	uint64_t	errors;
79121461Sharti	uint64_t	data_delivered;
80121461Sharti	uint64_t	aa_dropped;
81121461Sharti	uint64_t	maa_dropped;
82121461Sharti	uint64_t	maa_signals;
83121461Sharti	uint64_t	in_dropped;
84121461Sharti	uint64_t	out_dropped;
85121461Sharti};
86121461Sharti
87121461Sharti/*
88121461Sharti * Private data
89121461Sharti */
90121461Shartistruct priv {
91121461Sharti	hook_p		upper;		/* SAAL interface */
92121461Sharti	hook_p		lower;		/* AAL5 interface */
93121461Sharti	hook_p		manage;		/* management interface */
94121461Sharti
95121461Sharti	struct sscop	*sscop;		/* sscop state */
96121461Sharti	int		enabled;	/* whether the protocol is enabled */
97121461Sharti	int		flow;		/* flow control states */
98121461Sharti	struct stats	stats;		/* sadistics */
99121461Sharti};
100121461Sharti
101121461Sharti/*
102121461Sharti * Parse PARAM type
103121461Sharti */
104121461Shartistatic const struct ng_parse_struct_field ng_sscop_param_type_info[] =
105121461Sharti    NG_SSCOP_PARAM_INFO;
106121461Sharti
107121461Shartistatic const struct ng_parse_type ng_sscop_param_type = {
108121461Sharti	&ng_parse_struct_type,
109121461Sharti	ng_sscop_param_type_info
110121461Sharti};
111121461Sharti
112121461Sharti/*
113121461Sharti * Parse a SET PARAM type.
114121461Sharti */
115121461Shartistatic const struct ng_parse_struct_field ng_sscop_setparam_type_info[] =
116121461Sharti    NG_SSCOP_SETPARAM_INFO;
117121461Sharti
118121461Shartistatic const struct ng_parse_type ng_sscop_setparam_type = {
119121461Sharti	&ng_parse_struct_type,
120121461Sharti	ng_sscop_setparam_type_info,
121121461Sharti};
122121461Sharti
123121461Sharti/*
124121461Sharti * Parse a SET PARAM response
125121461Sharti */
126121461Shartistatic const struct ng_parse_struct_field ng_sscop_setparam_resp_type_info[] =
127121461Sharti    NG_SSCOP_SETPARAM_RESP_INFO;
128121461Sharti
129121461Shartistatic const struct ng_parse_type ng_sscop_setparam_resp_type = {
130121461Sharti	&ng_parse_struct_type,
131121461Sharti	ng_sscop_setparam_resp_type_info,
132121461Sharti};
133121461Sharti
134121461Shartistatic const struct ng_cmdlist ng_sscop_cmdlist[] = {
135121461Sharti	{
136121461Sharti	  NGM_SSCOP_COOKIE,
137121461Sharti	  NGM_SSCOP_GETPARAM,
138121461Sharti	  "getparam",
139121461Sharti	  NULL,
140121461Sharti	  &ng_sscop_param_type
141121461Sharti	},
142121461Sharti	{
143121461Sharti	  NGM_SSCOP_COOKIE,
144121461Sharti	  NGM_SSCOP_SETPARAM,
145121461Sharti	  "setparam",
146121461Sharti	  &ng_sscop_setparam_type,
147121461Sharti	  &ng_sscop_setparam_resp_type
148121461Sharti	},
149121461Sharti	{
150121461Sharti	  NGM_SSCOP_COOKIE,
151121461Sharti	  NGM_SSCOP_ENABLE,
152121461Sharti	  "enable",
153121461Sharti	  NULL,
154121461Sharti	  NULL
155121461Sharti	},
156121461Sharti	{
157121461Sharti	  NGM_SSCOP_COOKIE,
158121461Sharti	  NGM_SSCOP_DISABLE,
159121461Sharti	  "disable",
160121461Sharti	  NULL,
161121461Sharti	  NULL
162121461Sharti	},
163121461Sharti	{
164121461Sharti	  NGM_SSCOP_COOKIE,
165121461Sharti	  NGM_SSCOP_GETDEBUG,
166121461Sharti	  "getdebug",
167121461Sharti	  NULL,
168121461Sharti	  &ng_parse_hint32_type
169121461Sharti	},
170121461Sharti	{
171121461Sharti	  NGM_SSCOP_COOKIE,
172121461Sharti	  NGM_SSCOP_SETDEBUG,
173121461Sharti	  "setdebug",
174121461Sharti	  &ng_parse_hint32_type,
175121461Sharti	  NULL
176121461Sharti	},
177121461Sharti	{
178121461Sharti	  NGM_SSCOP_COOKIE,
179121461Sharti	  NGM_SSCOP_GETSTATE,
180121461Sharti	  "getstate",
181121461Sharti	  NULL,
182121461Sharti	  &ng_parse_uint32_type
183121461Sharti	},
184121461Sharti	{ 0 }
185121461Sharti};
186121461Sharti
187121461Shartistatic ng_constructor_t ng_sscop_constructor;
188121461Shartistatic ng_shutdown_t	ng_sscop_shutdown;
189121461Shartistatic ng_rcvmsg_t	ng_sscop_rcvmsg;
190121461Shartistatic ng_newhook_t	ng_sscop_newhook;
191121461Shartistatic ng_disconnect_t	ng_sscop_disconnect;
192121461Shartistatic ng_rcvdata_t	ng_sscop_rcvlower;
193121461Shartistatic ng_rcvdata_t	ng_sscop_rcvupper;
194121461Shartistatic ng_rcvdata_t	ng_sscop_rcvmanage;
195121461Sharti
196121461Shartistatic int ng_sscop_mod_event(module_t, int, void *);
197121461Sharti
198121461Shartistatic struct ng_type ng_sscop_typestruct = {
199129823Sjulian	.version =	NG_ABI_VERSION,
200129823Sjulian	.name =		NG_SSCOP_NODE_TYPE,
201129823Sjulian	.mod_event =	ng_sscop_mod_event,
202129823Sjulian	.constructor =	ng_sscop_constructor,
203129823Sjulian	.rcvmsg =	ng_sscop_rcvmsg,
204129823Sjulian	.shutdown =	ng_sscop_shutdown,
205129823Sjulian	.newhook =	ng_sscop_newhook,
206129823Sjulian	.rcvdata =	ng_sscop_rcvlower,
207129823Sjulian	.disconnect =	ng_sscop_disconnect,
208129823Sjulian	.cmdlist =	ng_sscop_cmdlist,
209121461Sharti};
210121461ShartiNETGRAPH_INIT(sscop, &ng_sscop_typestruct);
211121461Sharti
212121461Shartistatic void sscop_send_manage(struct sscop *, void *, enum sscop_maasig,
213121461Sharti	struct SSCOP_MBUF_T *, u_int, u_int);
214121461Shartistatic void sscop_send_upper(struct sscop *, void *, enum sscop_aasig,
215121461Sharti	struct SSCOP_MBUF_T *, u_int);
216121461Shartistatic void sscop_send_lower(struct sscop *, void *,
217121461Sharti	struct SSCOP_MBUF_T *);
218121461Shartistatic void sscop_verbose(struct sscop *, void *, const char *, ...)
219121461Sharti	__printflike(3, 4);
220121461Sharti
221121461Shartistatic const struct sscop_funcs sscop_funcs = {
222121461Sharti	sscop_send_manage,
223121461Sharti	sscop_send_upper,
224121461Sharti	sscop_send_lower,
225121461Sharti	sscop_verbose
226121461Sharti};
227121461Sharti
228121461Shartistatic void
229121461Shartisscop_verbose(struct sscop *sscop, void *arg, const char *fmt, ...)
230121461Sharti{
231121461Sharti	va_list ap;
232121461Sharti
233121461Sharti	va_start(ap, fmt);
234121461Sharti	printf("sscop(%p): ", sscop);
235121461Sharti	vprintf(fmt, ap);
236121461Sharti	va_end(ap);
237121461Sharti	printf("\n");
238121461Sharti}
239121461Sharti
240121461Sharti/************************************************************/
241121461Sharti/*
242121461Sharti * NODE MANAGEMENT
243121461Sharti */
244121461Shartistatic int
245121461Sharting_sscop_constructor(node_p node)
246121461Sharti{
247121461Sharti	struct priv *p;
248121461Sharti
249220768Sglebius	p = malloc(sizeof(*p), M_NG_SSCOP, M_WAITOK | M_ZERO);
250121461Sharti
251121461Sharti	if ((p->sscop = sscop_create(node, &sscop_funcs)) == NULL) {
252121461Sharti		free(p, M_NG_SSCOP);
253121461Sharti		return (ENOMEM);
254121461Sharti	}
255121461Sharti	NG_NODE_SET_PRIVATE(node, p);
256121461Sharti
257121461Sharti	/* All data message received by the node are expected to change the
258121461Sharti	 * node's state. Therefor we must ensure, that we have a writer lock. */
259121461Sharti	NG_NODE_FORCE_WRITER(node);
260121461Sharti
261121461Sharti	return (0);
262121461Sharti}
263121461Shartistatic int
264121461Sharting_sscop_shutdown(node_p node)
265121461Sharti{
266121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
267121461Sharti
268121461Sharti	sscop_destroy(priv->sscop);
269121461Sharti
270121461Sharti	free(priv, M_NG_SSCOP);
271121461Sharti	NG_NODE_SET_PRIVATE(node, NULL);
272121461Sharti
273121461Sharti	NG_NODE_UNREF(node);
274121461Sharti
275121461Sharti	return (0);
276121461Sharti}
277121461Sharti
278121461Sharti/************************************************************/
279121461Sharti/*
280121461Sharti * CONTROL MESSAGES
281121461Sharti */
282121461Sharti/*
283121461Sharti * Flow control message from upper layer.
284121461Sharti * This is very experimental:
285121461Sharti * If we get a message from the upper layer, that somebody has passed its
286121461Sharti * high water mark, we stop updating the receive window.
287121461Sharti * If we get a low watermark passed, then we raise the window up
288121461Sharti * to max - current.
289121461Sharti * If we get a queue status and it indicates a current below the
290121461Sharti * high watermark, we unstop window updates (if they are stopped) and
291121461Sharti * raise the window to highwater - current.
292121461Sharti */
293121461Shartistatic int
294121461Shartiflow_upper(node_p node, struct ng_mesg *msg)
295121461Sharti{
296121461Sharti	struct ngm_queue_state *q;
297121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
298121461Sharti	u_int window, space;
299121461Sharti
300121461Sharti	if (msg->header.arglen != sizeof(struct ngm_queue_state))
301121461Sharti		return (EINVAL);
302121461Sharti	q = (struct ngm_queue_state *)msg->data;
303121461Sharti
304121461Sharti	switch (msg->header.cmd) {
305121461Sharti
306121461Sharti	  case NGM_HIGH_WATER_PASSED:
307121461Sharti		if (priv->flow) {
308121461Sharti			VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv,
309121461Sharti			    "flow control stopped"));
310121461Sharti			priv->flow = 0;
311121461Sharti		}
312121461Sharti		break;
313121461Sharti
314121461Sharti	  case NGM_LOW_WATER_PASSED:
315121461Sharti		window = sscop_window(priv->sscop, 0);
316121461Sharti		space = q->max_queuelen_packets - q->current;
317121461Sharti		if (space > window) {
318121461Sharti			VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv,
319121461Sharti			    "flow control opened window by %u messages",
320121461Sharti			    space - window));
321121461Sharti			(void)sscop_window(priv->sscop, space - window);
322121461Sharti		}
323121461Sharti		priv->flow = 1;
324121461Sharti		break;
325121461Sharti
326121461Sharti	  case NGM_SYNC_QUEUE_STATE:
327121461Sharti		if (q->high_watermark <= q->current)
328121461Sharti			break;
329121461Sharti		window = sscop_window(priv->sscop, 0);
330121461Sharti		if (priv->flow)
331121461Sharti			space = q->max_queuelen_packets - q->current;
332121461Sharti		else
333121461Sharti			space = q->high_watermark - q->current;
334121461Sharti		if (space > window) {
335121461Sharti			VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv,
336121461Sharti			    "flow control opened window by %u messages",
337121461Sharti			    space - window));
338121461Sharti			(void)sscop_window(priv->sscop, space - window);
339121461Sharti		}
340121461Sharti		priv->flow = 1;
341121461Sharti		break;
342121461Sharti
343121461Sharti	  default:
344121461Sharti		return (EINVAL);
345121461Sharti	}
346121461Sharti	return (0);
347121461Sharti}
348121461Sharti
349121461Shartistatic int
350121461Shartiflow_lower(node_p node, struct ng_mesg *msg)
351121461Sharti{
352121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
353121461Sharti
354121461Sharti	if (msg->header.arglen != sizeof(struct ngm_queue_state))
355121461Sharti		return (EINVAL);
356121461Sharti
357121461Sharti	switch (msg->header.cmd) {
358121461Sharti
359121461Sharti	  case NGM_HIGH_WATER_PASSED:
360121461Sharti		sscop_setbusy(priv->sscop, 1);
361121461Sharti		break;
362121461Sharti
363121461Sharti	  case NGM_LOW_WATER_PASSED:
364121461Sharti		sscop_setbusy(priv->sscop, 1);
365121461Sharti		break;
366121461Sharti
367121461Sharti	  default:
368121461Sharti		return (EINVAL);
369121461Sharti	}
370121461Sharti	return (0);
371121461Sharti}
372121461Sharti
373121461Sharti/*
374121461Sharti * Produce a readable status description
375121461Sharti */
376121461Shartistatic int
377121461Shartitext_status(node_p node, struct priv *priv, char *arg, u_int len)
378121461Sharti{
379121461Sharti	struct sbuf sbuf;
380121461Sharti
381121461Sharti	sbuf_new(&sbuf, arg, len, 0);
382121461Sharti
383121461Sharti	if (priv->upper)
384121461Sharti		sbuf_printf(&sbuf, "upper hook: %s connected to %s:%s\n",
385121461Sharti		    NG_HOOK_NAME(priv->upper),
386121461Sharti		    NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
387121461Sharti		    NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
388121461Sharti	else
389121461Sharti		sbuf_printf(&sbuf, "upper hook: <not connected>\n");
390121461Sharti
391121461Sharti	if (priv->lower)
392121461Sharti		sbuf_printf(&sbuf, "lower hook: %s connected to %s:%s\n",
393121461Sharti		    NG_HOOK_NAME(priv->lower),
394121461Sharti		    NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
395121461Sharti		    NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
396121461Sharti	else
397121461Sharti		sbuf_printf(&sbuf, "lower hook: <not connected>\n");
398121461Sharti
399121461Sharti	if (priv->manage)
400121461Sharti		sbuf_printf(&sbuf, "manage hook: %s connected to %s:%s\n",
401121461Sharti		    NG_HOOK_NAME(priv->manage),
402121461Sharti		    NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->manage))),
403121461Sharti		    NG_HOOK_NAME(NG_HOOK_PEER(priv->manage)));
404121461Sharti	else
405121461Sharti		sbuf_printf(&sbuf, "manage hook: <not connected>\n");
406121461Sharti
407121461Sharti	sbuf_printf(&sbuf, "sscop state: %s\n",
408121461Sharti	    !priv->enabled ? "<disabled>" :
409121461Sharti	    sscop_statename(sscop_getstate(priv->sscop)));
410121461Sharti
411121461Sharti	sbuf_printf(&sbuf, "input packets:  %ju\n",
412121461Sharti	    (uintmax_t)priv->stats.in_packets);
413121461Sharti	sbuf_printf(&sbuf, "input dropped:  %ju\n",
414121461Sharti	    (uintmax_t)priv->stats.in_dropped);
415121461Sharti	sbuf_printf(&sbuf, "output packets: %ju\n",
416121461Sharti	    (uintmax_t)priv->stats.out_packets);
417121461Sharti	sbuf_printf(&sbuf, "output dropped: %ju\n",
418121461Sharti	    (uintmax_t)priv->stats.out_dropped);
419121461Sharti	sbuf_printf(&sbuf, "aa signals:     %ju\n",
420121461Sharti	    (uintmax_t)priv->stats.aa_signals);
421121461Sharti	sbuf_printf(&sbuf, "aa dropped:     %ju\n",
422121461Sharti	    (uintmax_t)priv->stats.aa_dropped);
423121461Sharti	sbuf_printf(&sbuf, "maa signals:    %ju\n",
424121461Sharti	    (uintmax_t)priv->stats.maa_signals);
425121461Sharti	sbuf_printf(&sbuf, "maa dropped:    %ju\n",
426121461Sharti	    (uintmax_t)priv->stats.maa_dropped);
427121461Sharti	sbuf_printf(&sbuf, "errors:         %ju\n",
428121461Sharti	    (uintmax_t)priv->stats.errors);
429121461Sharti	sbuf_printf(&sbuf, "data delivered: %ju\n",
430121461Sharti	    (uintmax_t)priv->stats.data_delivered);
431121461Sharti	sbuf_printf(&sbuf, "window:         %u\n",
432121461Sharti	    sscop_window(priv->sscop, 0));
433121461Sharti
434121461Sharti	sbuf_finish(&sbuf);
435121461Sharti	return (sbuf_len(&sbuf));
436121461Sharti}
437121461Sharti
438121461Sharti
439121461Sharti/*
440121461Sharti * Control message received.
441121461Sharti */
442121461Shartistatic int
443121461Sharting_sscop_rcvmsg(node_p node, item_p item, hook_p lasthook)
444121461Sharti{
445121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
446121461Sharti	struct ng_mesg *resp = NULL;
447121461Sharti	struct ng_mesg *msg;
448121461Sharti	int error = 0;
449121461Sharti
450121461Sharti	NGI_GET_MSG(item, msg);
451121461Sharti
452121461Sharti	switch (msg->header.typecookie) {
453121461Sharti
454121461Sharti	  case NGM_GENERIC_COOKIE:
455121461Sharti		switch (msg->header.cmd) {
456121461Sharti
457121461Sharti		  case NGM_TEXT_STATUS:
458121461Sharti			NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
459121461Sharti			if (resp == NULL) {
460121461Sharti				error = ENOMEM;
461121461Sharti				break;
462121461Sharti			}
463121461Sharti
464121461Sharti			resp->header.arglen = text_status(node, priv,
465121461Sharti			    (char *)resp->data, resp->header.arglen) + 1;
466121461Sharti			break;
467121461Sharti
468121461Sharti		  default:
469121461Sharti			error = EINVAL;
470121461Sharti			break;
471121461Sharti		}
472121461Sharti		break;
473121461Sharti
474121461Sharti	  case NGM_FLOW_COOKIE:
475121461Sharti		if (priv->enabled && lasthook != NULL) {
476121461Sharti			if (lasthook == priv->upper)
477121461Sharti				error = flow_upper(node, msg);
478121461Sharti			else if (lasthook == priv->lower)
479121461Sharti				error = flow_lower(node, msg);
480121461Sharti		}
481121461Sharti		break;
482121461Sharti
483121461Sharti	  case NGM_SSCOP_COOKIE:
484121461Sharti		switch (msg->header.cmd) {
485121461Sharti
486121461Sharti		  case NGM_SSCOP_GETPARAM:
487121461Sharti		    {
488121461Sharti			struct sscop_param *p;
489121461Sharti
490121461Sharti			NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
491121461Sharti			if (resp == NULL) {
492121461Sharti				error = ENOMEM;
493121461Sharti				break;
494121461Sharti			}
495121461Sharti			p = (struct sscop_param *)resp->data;
496121461Sharti			sscop_getparam(priv->sscop, p);
497121461Sharti			break;
498121461Sharti		    }
499121461Sharti
500121461Sharti		  case NGM_SSCOP_SETPARAM:
501121461Sharti		    {
502121461Sharti			struct ng_sscop_setparam *arg;
503121461Sharti			struct ng_sscop_setparam_resp *p;
504121461Sharti
505121461Sharti			if (msg->header.arglen != sizeof(*arg)) {
506121461Sharti				error = EINVAL;
507121461Sharti				break;
508121461Sharti			}
509121461Sharti			if (priv->enabled) {
510121461Sharti				error = EISCONN;
511121461Sharti				break;
512121461Sharti			}
513121461Sharti			arg = (struct ng_sscop_setparam *)msg->data;
514121461Sharti			NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
515121461Sharti			if (resp == NULL) {
516121461Sharti				error = ENOMEM;
517121461Sharti				break;
518121461Sharti			}
519121461Sharti			p = (struct ng_sscop_setparam_resp *)resp->data;
520121461Sharti			p->mask = arg->mask;
521121461Sharti			p->error = sscop_setparam(priv->sscop,
522121461Sharti			    &arg->param, &p->mask);
523121461Sharti			break;
524121461Sharti		    }
525121461Sharti
526121461Sharti		  case NGM_SSCOP_ENABLE:
527121461Sharti			if (msg->header.arglen != 0) {
528121461Sharti				error = EINVAL;
529121461Sharti				break;
530121461Sharti			}
531121461Sharti			if (priv->enabled) {
532121461Sharti				error = EBUSY;
533121461Sharti				break;
534121461Sharti			}
535121461Sharti			priv->enabled = 1;
536121461Sharti			priv->flow = 1;
537121461Sharti			memset(&priv->stats, 0, sizeof(priv->stats));
538121461Sharti			break;
539121461Sharti
540121461Sharti		  case NGM_SSCOP_DISABLE:
541121461Sharti			if (msg->header.arglen != 0) {
542121461Sharti				error = EINVAL;
543121461Sharti				break;
544121461Sharti			}
545121461Sharti			if (!priv->enabled) {
546121461Sharti				error = ENOTCONN;
547121461Sharti				break;
548121461Sharti			}
549121461Sharti			priv->enabled = 0;
550121461Sharti			sscop_reset(priv->sscop);
551121461Sharti			break;
552121461Sharti
553121461Sharti		  case NGM_SSCOP_GETDEBUG:
554121461Sharti			if (msg->header.arglen != 0) {
555121461Sharti				error = EINVAL;
556121461Sharti				break;
557121461Sharti			}
558121461Sharti			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
559121461Sharti			if(resp == NULL) {
560121461Sharti				error = ENOMEM;
561121461Sharti				break;
562121461Sharti			}
563121461Sharti			*(u_int32_t *)resp->data = sscop_getdebug(priv->sscop);
564121461Sharti			break;
565121461Sharti
566121461Sharti		  case NGM_SSCOP_SETDEBUG:
567121461Sharti			if (msg->header.arglen != sizeof(u_int32_t)) {
568121461Sharti				error = EINVAL;
569121461Sharti				break;
570121461Sharti			}
571121461Sharti			sscop_setdebug(priv->sscop, *(u_int32_t *)msg->data);
572121461Sharti			break;
573121461Sharti
574121461Sharti		  case NGM_SSCOP_GETSTATE:
575121461Sharti			if (msg->header.arglen != 0) {
576121461Sharti				error = EINVAL;
577121461Sharti				break;
578121461Sharti			}
579121461Sharti			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
580121461Sharti			if(resp == NULL) {
581121461Sharti				error = ENOMEM;
582121461Sharti				break;
583121461Sharti			}
584121461Sharti			*(u_int32_t *)resp->data =
585121461Sharti			    priv->enabled ? (sscop_getstate(priv->sscop) + 1)
586121461Sharti			                  : 0;
587121461Sharti			break;
588121461Sharti
589121461Sharti		  default:
590121461Sharti			error = EINVAL;
591121461Sharti			break;
592121461Sharti		}
593121461Sharti		break;
594121461Sharti
595121461Sharti	  default:
596121461Sharti		error = EINVAL;
597121461Sharti		break;
598121461Sharti	}
599121461Sharti
600121461Sharti	NG_RESPOND_MSG(error, node, item, resp);
601121461Sharti	NG_FREE_MSG(msg);
602121461Sharti
603121461Sharti	return (error);
604121461Sharti}
605121461Sharti
606121461Sharti/************************************************************/
607121461Sharti/*
608121461Sharti * HOOK MANAGEMENT
609121461Sharti */
610121461Shartistatic int
611121461Sharting_sscop_newhook(node_p node, hook_p hook, const char *name)
612121461Sharti{
613121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
614121461Sharti
615121461Sharti	if(strcmp(name, "upper") == 0) {
616121461Sharti		priv->upper = hook;
617121461Sharti		NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvupper);
618121461Sharti	} else if(strcmp(name, "lower") == 0) {
619121461Sharti		priv->lower = hook;
620121461Sharti	} else if(strcmp(name, "manage") == 0) {
621121461Sharti		priv->manage = hook;
622121461Sharti		NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvmanage);
623121461Sharti	} else
624121461Sharti		return EINVAL;
625121461Sharti
626121461Sharti	return 0;
627121461Sharti}
628121461Shartistatic int
629121461Sharting_sscop_disconnect(hook_p hook)
630121461Sharti{
631121461Sharti	node_p node = NG_HOOK_NODE(hook);
632121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
633121461Sharti
634121461Sharti	if(hook == priv->upper)
635121461Sharti		priv->upper = NULL;
636121461Sharti	else if(hook == priv->lower)
637121461Sharti		priv->lower = NULL;
638121461Sharti	else if(hook == priv->manage)
639121461Sharti		priv->manage = NULL;
640121461Sharti
641121461Sharti	if(NG_NODE_NUMHOOKS(node) == 0) {
642121461Sharti		if(NG_NODE_IS_VALID(node))
643121461Sharti			ng_rmnode_self(node);
644121461Sharti	} else {
645121461Sharti		/*
646121461Sharti		 * Imply a release request, if the upper layer is
647121461Sharti		 * disconnected.
648121461Sharti		 */
649121461Sharti		if(priv->upper == NULL && priv->lower != NULL &&
650121461Sharti		   priv->enabled &&
651121461Sharti		   sscop_getstate(priv->sscop) != SSCOP_IDLE) {
652121461Sharti			sscop_aasig(priv->sscop, SSCOP_RELEASE_request,
653121461Sharti			    NULL, 0);
654121461Sharti		}
655121461Sharti	}
656121461Sharti	return 0;
657121461Sharti}
658121461Sharti
659121461Sharti/************************************************************/
660121461Sharti/*
661121461Sharti * DATA
662121461Sharti */
663121461Shartistatic int
664121461Sharting_sscop_rcvlower(hook_p hook, item_p item)
665121461Sharti{
666121461Sharti	struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
667121461Sharti	struct mbuf *m;
668121461Sharti
669121461Sharti	if (!priv->enabled) {
670121461Sharti		NG_FREE_ITEM(item);
671121461Sharti		return EINVAL;
672121461Sharti	}
673121461Sharti
674121461Sharti	/*
675121461Sharti	 * If we are disconnected at the upper layer and in the IDLE
676121461Sharti	 * state, drop any incoming packet.
677121461Sharti	 */
678121461Sharti	if (priv->upper != NULL || sscop_getstate(priv->sscop) != SSCOP_IDLE) {
679121461Sharti		NGI_GET_M(item, m);
680121461Sharti		priv->stats.in_packets++;
681121461Sharti		sscop_input(priv->sscop, m);
682121461Sharti	} else {
683121461Sharti		priv->stats.in_dropped++;
684121461Sharti	}
685121461Sharti	NG_FREE_ITEM(item);
686121461Sharti
687121461Sharti	return (0);
688121461Sharti}
689121461Sharti
690121461Shartistatic void
691121461Shartisscop_send_lower(struct sscop *sscop, void *p, struct mbuf *m)
692121461Sharti{
693121461Sharti	node_p node = (node_p)p;
694121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
695121461Sharti	int error;
696121461Sharti
697121461Sharti	if (priv->lower == NULL) {
698121461Sharti		m_freem(m);
699121461Sharti		priv->stats.out_dropped++;
700121461Sharti		return;
701121461Sharti	}
702121461Sharti
703121461Sharti	priv->stats.out_packets++;
704121461Sharti	NG_SEND_DATA_ONLY(error, priv->lower, m);
705121461Sharti}
706121461Sharti
707121461Shartistatic int
708121461Sharting_sscop_rcvupper(hook_p hook, item_p item)
709121461Sharti{
710121461Sharti	struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
711121461Sharti	struct sscop_arg a;
712121461Sharti	struct mbuf *m;
713121461Sharti
714121461Sharti	if (!priv->enabled) {
715121461Sharti		NG_FREE_ITEM(item);
716121461Sharti		return (EINVAL);
717121461Sharti	}
718121461Sharti
719121461Sharti	/*
720121461Sharti	 * If the lower layer is not connected allow to proceed.
721121461Sharti	 * The lower layer sending function will drop outgoing frames,
722121461Sharti	 * and the sscop will timeout any establish requests.
723121461Sharti	 */
724121461Sharti	NGI_GET_M(item, m);
725121461Sharti	NG_FREE_ITEM(item);
726121461Sharti
727121461Sharti	if (!(m->m_flags & M_PKTHDR)) {
728121461Sharti		printf("no pkthdr\n");
729121461Sharti		m_freem(m);
730121461Sharti		return (EINVAL);
731121461Sharti	}
732121461Sharti	if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
733121461Sharti		return (ENOBUFS);
734121461Sharti	bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a));
735121461Sharti	m_adj(m, sizeof(a));
736121461Sharti
737121461Sharti	return (sscop_aasig(priv->sscop, a.sig, m, a.arg));
738121461Sharti}
739121461Sharti
740121461Shartistatic void
741121461Shartisscop_send_upper(struct sscop *sscop, void *p, enum sscop_aasig sig,
742121461Sharti    struct SSCOP_MBUF_T *m, u_int arg)
743121461Sharti{
744121461Sharti	node_p node = (node_p)p;
745121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
746121461Sharti	int error;
747121461Sharti	struct sscop_arg *a;
748121461Sharti
749121461Sharti	if (sig == SSCOP_DATA_indication && priv->flow)
750121461Sharti		sscop_window(priv->sscop, 1);
751121461Sharti
752121461Sharti	if (priv->upper == NULL) {
753121461Sharti		if (m != NULL)
754121461Sharti			m_freem(m);
755121461Sharti		priv->stats.aa_dropped++;
756121461Sharti		return;
757121461Sharti	}
758121461Sharti
759121461Sharti	priv->stats.aa_signals++;
760121461Sharti	if (sig == SSCOP_DATA_indication)
761121461Sharti		priv->stats.data_delivered++;
762121461Sharti
763121461Sharti	if (m == NULL) {
764121461Sharti		MGETHDR(m, M_NOWAIT, MT_DATA);
765121461Sharti		if (m == NULL)
766121461Sharti			return;
767121461Sharti		m->m_len = sizeof(struct sscop_arg);
768121461Sharti		m->m_pkthdr.len = m->m_len;
769121461Sharti	} else {
770121461Sharti		M_PREPEND(m, sizeof(struct sscop_arg), M_NOWAIT);
771121461Sharti		if (m == NULL)
772121461Sharti			return;
773121461Sharti	}
774121461Sharti	a = mtod(m, struct sscop_arg *);
775121461Sharti	a->sig = sig;
776121461Sharti	a->arg = arg;
777121461Sharti
778121461Sharti	NG_SEND_DATA_ONLY(error, priv->upper, m);
779121461Sharti}
780121461Sharti
781121461Shartistatic int
782121461Sharting_sscop_rcvmanage(hook_p hook, item_p item)
783121461Sharti{
784121461Sharti	struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
785121461Sharti	struct sscop_marg a;
786121461Sharti	struct mbuf *m;
787121461Sharti
788121461Sharti	if (!priv->enabled) {
789121461Sharti		NG_FREE_ITEM(item);
790121461Sharti		return (EINVAL);
791121461Sharti	}
792121461Sharti
793121461Sharti	NGI_GET_M(item, m);
794121461Sharti	NG_FREE_ITEM(item);
795121461Sharti
796121461Sharti	if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
797121461Sharti		return (ENOBUFS);
798121461Sharti	bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a));
799121461Sharti	m_adj(m, sizeof(a));
800121461Sharti
801121461Sharti	return (sscop_maasig(priv->sscop, a.sig, m));
802121461Sharti}
803121461Sharti
804121461Shartistatic void
805121461Shartisscop_send_manage(struct sscop *sscop, void *p, enum sscop_maasig sig,
806121461Sharti    struct SSCOP_MBUF_T *m, u_int err, u_int cnt)
807121461Sharti{
808121461Sharti	node_p node = (node_p)p;
809121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
810121461Sharti	int error;
811121461Sharti	struct sscop_merr *e;
812121461Sharti	struct sscop_marg *a;
813121461Sharti
814121461Sharti	if (priv->manage == NULL) {
815121461Sharti		if (m != NULL)
816121461Sharti			m_freem(m);
817121461Sharti		priv->stats.maa_dropped++;
818121461Sharti		return;
819121461Sharti	}
820121461Sharti
821121461Sharti	if (sig == SSCOP_MERROR_indication) {
822121461Sharti		MGETHDR(m, M_NOWAIT, MT_DATA);
823121461Sharti		if (m == NULL)
824121461Sharti			return;
825121461Sharti		m->m_len = sizeof(*e);
826121461Sharti		m->m_pkthdr.len = m->m_len;
827121461Sharti		e = mtod(m, struct sscop_merr *);
828121461Sharti		e->sig = sig;
829121461Sharti		e->err = err;
830121461Sharti		e->cnt = cnt;
831121461Sharti		priv->stats.errors++;
832121461Sharti	} else if (m == NULL) {
833121461Sharti		MGETHDR(m, M_NOWAIT, MT_DATA);
834121461Sharti		if (m == NULL)
835121461Sharti			return;
836121461Sharti		m->m_len = sizeof(*a);
837121461Sharti		m->m_pkthdr.len = m->m_len;
838121461Sharti		a = mtod(m, struct sscop_marg *);
839121461Sharti		a->sig = sig;
840121461Sharti		priv->stats.maa_signals++;
841121461Sharti	} else {
842121461Sharti		M_PREPEND(m, sizeof(*a), M_NOWAIT);
843121461Sharti		if (m == NULL)
844121461Sharti			return;
845121461Sharti		a = mtod(m, struct sscop_marg *);
846121461Sharti		a->sig = sig;
847121461Sharti		priv->stats.maa_signals++;
848121461Sharti	}
849121461Sharti
850121461Sharti	NG_SEND_DATA_ONLY(error, priv->manage, m);
851121461Sharti}
852121461Sharti
853121461Sharti/************************************************************/
854121461Sharti/*
855121461Sharti * INITIALISATION
856121461Sharti */
857121461Sharti
858121461Sharti/*
859121461Sharti * Loading and unloading of node type
860121461Sharti */
861121461Shartistatic int
862121461Sharting_sscop_mod_event(module_t mod, int event, void *data)
863121461Sharti{
864121461Sharti	int error = 0;
865121461Sharti
866121461Sharti	switch (event) {
867121461Sharti
868121461Sharti	  case MOD_LOAD:
869121461Sharti		break;
870121461Sharti
871121461Sharti	  case MOD_UNLOAD:
872121461Sharti		break;
873121461Sharti
874121461Sharti	  default:
875121461Sharti		error = EOPNOTSUPP;
876121461Sharti		break;
877121461Sharti	}
878121461Sharti	return (error);
879121461Sharti}
880