ng_ccatm.c revision 139823
1170530Ssam/*-
2178354Ssam * Copyright (c) 2001-2002
3170530Ssam *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4170530Ssam *	All rights reserved.
5170530Ssam * Copyright (c) 2003-2004
6170530Ssam *	Hartmut Brandt
7170530Ssam *	All rights reserved.
8170530Ssam *
9170530Ssam * Author: Harti Brandt <harti@freebsd.org>
10170530Ssam *
11170530Ssam * Redistribution of this software and documentation and use in source and
12170530Ssam * binary forms, with or without modification, are permitted provided that
13170530Ssam * the following conditions are met:
14170530Ssam *
15170530Ssam * 1. Redistributions of source code or documentation must retain the above
16170530Ssam *    copyright notice, this list of conditions and the following disclaimer.
17170530Ssam * 2. Redistributions in binary form must reproduce the above copyright
18170530Ssam *    notice, this list of conditions and the following disclaimer in the
19170530Ssam *    documentation and/or other materials provided with the distribution.
20170530Ssam *
21170530Ssam * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR
22170530Ssam * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23170530Ssam * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24170530Ssam * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
25170530Ssam * THE AUTHOR OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
26170530Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27170530Ssam * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28170530Ssam * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29170530Ssam * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30170530Ssam * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31170530Ssam * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32170530Ssam *
33170530Ssam * $FreeBSD: head/sys/netgraph/atm/ccatm/ng_ccatm.c 139823 2005-01-07 01:45:51Z imp $
34170530Ssam *
35170530Ssam * ATM call control and API
36178354Ssam */
37170530Ssam
38170530Ssam#include <sys/cdefs.h>
39170530Ssam__FBSDID("$FreeBSD: head/sys/netgraph/atm/ccatm/ng_ccatm.c 139823 2005-01-07 01:45:51Z imp $");
40170530Ssam
41170530Ssam#include <sys/param.h>
42170530Ssam#include <sys/systm.h>
43170530Ssam#include <sys/kernel.h>
44170530Ssam#include <sys/malloc.h>
45170530Ssam#include <sys/mbuf.h>
46170530Ssam#include <sys/errno.h>
47170530Ssam#include <sys/socket.h>
48170530Ssam#include <sys/socketvar.h>
49170530Ssam#include <sys/sbuf.h>
50195377Ssam#include <machine/stdarg.h>
51178354Ssam
52170530Ssam#include <netgraph/ng_message.h>
53170530Ssam#include <netgraph/netgraph.h>
54170530Ssam#include <netgraph/ng_parse.h>
55170530Ssam#include <netnatm/unimsg.h>
56170530Ssam#include <netnatm/msg/unistruct.h>
57219456Sbschmidt#include <netnatm/api/unisap.h>
58219456Sbschmidt#include <netnatm/sig/unidef.h>
59219456Sbschmidt#include <netgraph/atm/ngatmbase.h>
60219456Sbschmidt#include <netgraph/atm/ng_uni.h>
61219456Sbschmidt#include <netnatm/api/atmapi.h>
62219456Sbschmidt#include <netgraph/atm/ng_ccatm.h>
63219456Sbschmidt#include <netnatm/api/ccatm.h>
64219456Sbschmidt
65219456SbschmidtMODULE_DEPEND(ng_ccatm, ngatmbase, 1, 1, 1);
66219456Sbschmidt
67219456SbschmidtMALLOC_DEFINE(M_NG_CCATM, "ng_ccatm", "netgraph uni api node");
68219456Sbschmidt
69219456Sbschmidt/*
70219456Sbschmidt * Command structure parsing
71219456Sbschmidt */
72219456Sbschmidt
73219456Sbschmidt/* ESI */
74219456Sbschmidtstatic const struct ng_parse_fixedarray_info ng_ccatm_esi_type_info =
75219456Sbschmidt    NGM_CCATM_ESI_INFO;
76219456Sbschmidtstatic const struct ng_parse_type ng_ccatm_esi_type = {
77219456Sbschmidt	&ng_parse_fixedarray_type,
78219456Sbschmidt	&ng_ccatm_esi_type_info
79219456Sbschmidt};
80219456Sbschmidt
81219456Sbschmidt/* PORT PARAMETERS */
82219456Sbschmidtstatic const struct ng_parse_struct_field ng_ccatm_atm_port_type_info[] =
83219456Sbschmidt    NGM_CCATM_ATM_PORT_INFO;
84219456Sbschmidtstatic const struct ng_parse_type ng_ccatm_atm_port_type = {
85219456Sbschmidt	&ng_parse_struct_type,
86219456Sbschmidt	ng_ccatm_atm_port_type_info
87219456Sbschmidt};
88219456Sbschmidt
89219456Sbschmidt/* PORT structure */
90219456Sbschmidtstatic const struct ng_parse_struct_field ng_ccatm_port_type_info[] =
91219456Sbschmidt    NGM_CCATM_PORT_INFO;
92219456Sbschmidtstatic const struct ng_parse_type ng_ccatm_port_type = {
93219456Sbschmidt	&ng_parse_struct_type,
94219456Sbschmidt	ng_ccatm_port_type_info
95219456Sbschmidt};
96219456Sbschmidt
97219456Sbschmidt/* the ADDRESS array itself */
98219456Sbschmidtstatic const struct ng_parse_fixedarray_info ng_ccatm_addr_array_type_info =
99219456Sbschmidt    NGM_CCATM_ADDR_ARRAY_INFO;
100219456Sbschmidtstatic const struct ng_parse_type ng_ccatm_addr_array_type = {
101219456Sbschmidt	&ng_parse_fixedarray_type,
102219456Sbschmidt	&ng_ccatm_addr_array_type_info
103219456Sbschmidt};
104219456Sbschmidt
105219456Sbschmidt/* one ADDRESS */
106219456Sbschmidtstatic const struct ng_parse_struct_field ng_ccatm_uni_addr_type_info[] =
107219456Sbschmidt    NGM_CCATM_UNI_ADDR_INFO;
108219456Sbschmidtstatic const struct ng_parse_type ng_ccatm_uni_addr_type = {
109219456Sbschmidt	&ng_parse_struct_type,
110219456Sbschmidt	ng_ccatm_uni_addr_type_info
111219456Sbschmidt};
112219456Sbschmidt
113219456Sbschmidt/* ADDRESS request */
114219456Sbschmidtstatic const struct ng_parse_struct_field ng_ccatm_addr_req_type_info[] =
115219456Sbschmidt    NGM_CCATM_ADDR_REQ_INFO;
116219456Sbschmidtstatic const struct ng_parse_type ng_ccatm_addr_req_type = {
117219456Sbschmidt	&ng_parse_struct_type,
118219456Sbschmidt	ng_ccatm_addr_req_type_info
119219456Sbschmidt};
120219456Sbschmidt
121219456Sbschmidt/* ADDRESS var-array */
122219456Sbschmidtstatic int
123219456Sbschmidtng_ccatm_addr_req_array_getlen(const struct ng_parse_type *type,
124219456Sbschmidt    const u_char *start, const u_char *buf)
125219456Sbschmidt{
126219456Sbschmidt	const struct ngm_ccatm_get_addresses *p;
127219456Sbschmidt
128219456Sbschmidt	p = (const struct ngm_ccatm_get_addresses *)
129219456Sbschmidt	    (buf - offsetof(struct ngm_ccatm_get_addresses, addr));
130219456Sbschmidt	return (p->count);
131219456Sbschmidt}
132219456Sbschmidtstatic const struct ng_parse_array_info ng_ccatm_addr_req_array_type_info =
133219456Sbschmidt    NGM_CCATM_ADDR_REQ_ARRAY_INFO;
134219456Sbschmidtstatic const struct ng_parse_type ng_ccatm_addr_req_array_type = {
135170530Ssam	&ng_parse_array_type,
136170530Ssam	&ng_ccatm_addr_req_array_type_info
137173273Ssam};
138193115Ssam
139193115Ssam/* Outer get_ADDRESSes structure */
140193115Ssamstatic const struct ng_parse_struct_field ng_ccatm_get_addresses_type_info[] =
141193115Ssam    NGM_CCATM_GET_ADDRESSES_INFO;
142173273Ssamstatic const struct ng_parse_type ng_ccatm_get_addresses_type = {
143173273Ssam	&ng_parse_struct_type,
144193115Ssam	ng_ccatm_get_addresses_type_info
145193115Ssam};
146193115Ssam
147193115Ssam/* Port array */
148193115Ssamstatic int
149193115Ssamng_ccatm_port_array_getlen(const struct ng_parse_type *type,
150193115Ssam    const u_char *start, const u_char *buf)
151193115Ssam{
152193115Ssam	const struct ngm_ccatm_portlist *p;
153193115Ssam
154193115Ssam	p = (const struct ngm_ccatm_portlist *)
155193115Ssam	    (buf - offsetof(struct ngm_ccatm_portlist, ports));
156193115Ssam	return (p->nports);
157193115Ssam}
158193115Ssamstatic const struct ng_parse_array_info ng_ccatm_port_array_type_info =
159193115Ssam    NGM_CCATM_PORT_ARRAY_INFO;
160193115Ssamstatic const struct ng_parse_type ng_ccatm_port_array_type = {
161193115Ssam	&ng_parse_array_type,
162193115Ssam	&ng_ccatm_port_array_type_info
163195377Ssam};
164195377Ssam
165195377Ssam/* Portlist structure */
166195377Ssamstatic const struct ng_parse_struct_field ng_ccatm_portlist_type_info[] =
167195377Ssam    NGM_CCATM_PORTLIST_INFO;
168195377Ssamstatic const struct ng_parse_type ng_ccatm_portlist_type = {
169195377Ssam	&ng_parse_struct_type,
170195377Ssam	ng_ccatm_portlist_type_info
171195377Ssam};
172195377Ssam
173178354Ssam/*
174195377Ssam * Command list
175178354Ssam */
176195377Ssamstatic const struct ng_cmdlist ng_ccatm_cmdlist[] = {
177195377Ssam	{
178195377Ssam	  NGM_CCATM_COOKIE,
179178354Ssam	  NGM_CCATM_DUMP,
180178354Ssam	  "dump",
181178354Ssam	  NULL,
182178354Ssam	  NULL
183178354Ssam	},
184184280Ssam	{
185195377Ssam	  NGM_CCATM_COOKIE,
186195377Ssam	  NGM_CCATM_STOP,
187195377Ssam	  "stop",
188195377Ssam	  &ng_ccatm_port_type,
189195377Ssam	  NULL
190195377Ssam	},
191195377Ssam	{
192195377Ssam	  NGM_CCATM_COOKIE,
193195377Ssam	  NGM_CCATM_START,
194195377Ssam	  "start",
195195377Ssam	  &ng_ccatm_port_type,
196195377Ssam	  NULL
197195377Ssam	},
198195377Ssam	{
199195377Ssam	  NGM_CCATM_COOKIE,
200195377Ssam	  NGM_CCATM_GETSTATE,
201195377Ssam	  "getstate",
202195377Ssam	  &ng_ccatm_port_type,
203195377Ssam	  &ng_parse_uint32_type
204195377Ssam	},
205195377Ssam	{
206195377Ssam	  NGM_CCATM_COOKIE,
207178354Ssam	  NGM_CCATM_GET_ADDRESSES,
208195377Ssam	  "get_addresses",
209170530Ssam	  &ng_ccatm_port_type,
210178354Ssam	  &ng_ccatm_get_addresses_type
211178354Ssam	},
212170530Ssam	{
213170530Ssam	  NGM_CCATM_COOKIE,
214170530Ssam	  NGM_CCATM_CLEAR,
215170530Ssam	  "clear",
216170530Ssam	  &ng_ccatm_port_type,
217170530Ssam	  NULL
218170530Ssam	},
219170530Ssam	{
220184280Ssam	  NGM_CCATM_COOKIE,
221184280Ssam	  NGM_CCATM_ADDRESS_REGISTERED,
222184280Ssam	  "address_reg",
223184280Ssam	  &ng_ccatm_addr_req_type,
224191552Ssam	  NULL
225191552Ssam	},
226191552Ssam	{
227170530Ssam	  NGM_CCATM_COOKIE,
228170530Ssam	  NGM_CCATM_ADDRESS_UNREGISTERED,
229170530Ssam	  "address_unreg",
230170530Ssam	  &ng_ccatm_addr_req_type,
231170530Ssam	  NULL
232195377Ssam	},
233170530Ssam	{
234178354Ssam	  NGM_CCATM_COOKIE,
235170530Ssam	  NGM_CCATM_SET_PORT_PARAM,
236170530Ssam	  "set_port_param",
237170530Ssam	  &ng_ccatm_atm_port_type,
238184280Ssam	  NULL
239191552Ssam	},
240191552Ssam	{
241170530Ssam	  NGM_CCATM_COOKIE,
242173273Ssam	  NGM_CCATM_GET_PORT_PARAM,
243173273Ssam	  "get_port_param",
244178354Ssam	  &ng_ccatm_port_type,
245173273Ssam	  &ng_ccatm_atm_port_type,
246178354Ssam	},
247178354Ssam	{
248178354Ssam	  NGM_CCATM_COOKIE,
249178354Ssam	  NGM_CCATM_GET_PORTLIST,
250173273Ssam	  "get_portlist",
251178354Ssam	  NULL,
252178354Ssam	  &ng_ccatm_portlist_type,
253178354Ssam	},
254178354Ssam	{
255178354Ssam	  NGM_CCATM_COOKIE,
256178354Ssam	  NGM_CCATM_SETLOG,
257178354Ssam	  "setlog",
258178354Ssam	  &ng_parse_hint32_type,
259178354Ssam	  &ng_parse_hint32_type,
260178354Ssam	},
261178354Ssam	{
262178354Ssam	  NGM_CCATM_COOKIE,
263178354Ssam	  NGM_CCATM_RESET,
264178354Ssam	  "reset",
265178354Ssam	  NULL,
266178354Ssam	  NULL,
267170530Ssam	},
268173273Ssam	{ 0 }
269173273Ssam};
270170530Ssam
271170530Ssam/*
272193655Ssam * Module data
273193655Ssam */
274193655Ssamstatic ng_constructor_t		ng_ccatm_constructor;
275178354Ssamstatic ng_rcvmsg_t		ng_ccatm_rcvmsg;
276193655Ssamstatic ng_shutdown_t		ng_ccatm_shutdown;
277173273Ssamstatic ng_newhook_t		ng_ccatm_newhook;
278178354Ssamstatic ng_rcvdata_t		ng_ccatm_rcvdata;
279193655Ssamstatic ng_disconnect_t		ng_ccatm_disconnect;
280178354Ssamstatic int ng_ccatm_mod_event(module_t, int, void *);
281193655Ssam
282170530Ssamstatic struct ng_type ng_ccatm_typestruct = {
283183256Ssam	.version =	NG_ABI_VERSION,
284183256Ssam	.name =		NG_CCATM_NODE_TYPE,
285193655Ssam	.mod_event =	ng_ccatm_mod_event,
286183256Ssam	.constructor =	ng_ccatm_constructor,	/* Node constructor */
287170530Ssam	.rcvmsg =	ng_ccatm_rcvmsg,	/* Control messages */
288193655Ssam	.shutdown =	ng_ccatm_shutdown,	/* Node destructor */
289178354Ssam	.newhook =	ng_ccatm_newhook,	/* Arrival of new hook */
290193655Ssam	.rcvdata =	ng_ccatm_rcvdata,	/* receive data */
291193655Ssam	.disconnect =	ng_ccatm_disconnect,	/* disconnect a hook */
292178354Ssam	.cmdlist =	ng_ccatm_cmdlist,
293193655Ssam};
294170530SsamNETGRAPH_INIT(ccatm, &ng_ccatm_typestruct);
295178354Ssam
296178354Ssamstatic ng_rcvdata_t	ng_ccatm_rcvuni;
297193655Ssamstatic ng_rcvdata_t	ng_ccatm_rcvdump;
298170530Ssamstatic ng_rcvdata_t	ng_ccatm_rcvmanage;
299170530Ssam
300170530Ssam/*
301178354Ssam * Private node data.
302170530Ssam */
303170530Ssamstruct ccnode {
304170530Ssam	node_p	node;		/* the owning node */
305219598Sbschmidt	hook_p	dump;		/* dump hook */
306219598Sbschmidt	hook_p	manage;		/* hook to ILMI */
307219598Sbschmidt
308219598Sbschmidt	struct ccdata *data;
309219598Sbschmidt	struct mbuf *dump_first;
310219598Sbschmidt	struct mbuf *dump_last;	/* first and last mbuf when dumping */
311219598Sbschmidt
312219598Sbschmidt	u_int	hook_cnt;	/* count user and port hooks */
313219598Sbschmidt};
314219598Sbschmidt
315219598Sbschmidt/*
316219598Sbschmidt * Private UNI hook data
317219598Sbschmidt */
318219598Sbschmidtstruct cchook {
319219598Sbschmidt	int		is_uni;	/* true if uni hook, user otherwise */
320219598Sbschmidt	struct ccnode	*node;	/* the owning node */
321219598Sbschmidt	hook_p		hook;
322219598Sbschmidt	void		*inst;	/* port or user */
323219598Sbschmidt};
324219598Sbschmidt
325219598Sbschmidtstatic void ng_ccatm_send_user(struct ccuser *, void *, u_int, void *, size_t);
326219598Sbschmidtstatic void ng_ccatm_respond_user(struct ccuser *, void *, int, u_int,
327219598Sbschmidt    void *, size_t);
328219598Sbschmidtstatic void ng_ccatm_send_uni(struct ccconn *, void *, u_int, u_int,
329219598Sbschmidt    struct uni_msg *);
330219598Sbschmidtstatic void ng_ccatm_send_uni_glob(struct ccport *, void *, u_int, u_int,
331219598Sbschmidt    struct uni_msg *);
332219598Sbschmidtstatic void ng_ccatm_log(const char *, ...) __printflike(1, 2);
333219598Sbschmidt
334219598Sbschmidtstatic const struct cc_funcs cc_funcs = {
335219598Sbschmidt	.send_user =		ng_ccatm_send_user,
336219598Sbschmidt	.respond_user =		ng_ccatm_respond_user,
337219598Sbschmidt	.send_uni =		ng_ccatm_send_uni,
338219598Sbschmidt	.send_uni_glob =	ng_ccatm_send_uni_glob,
339219598Sbschmidt	.log =			ng_ccatm_log,
340219598Sbschmidt};
341219598Sbschmidt
342219598Sbschmidt/************************************************************
343219598Sbschmidt *
344219598Sbschmidt * Create a new node
345219598Sbschmidt */
346219598Sbschmidtstatic int
347219598Sbschmidtng_ccatm_constructor(node_p node)
348170530Ssam{
349219598Sbschmidt	struct ccnode *priv;
350170530Ssam
351219598Sbschmidt	priv = malloc(sizeof(*priv), M_NG_CCATM, M_NOWAIT | M_ZERO);
352219598Sbschmidt	if (priv == NULL)
353219598Sbschmidt		return (ENOMEM);
354170530Ssam
355219598Sbschmidt	priv->node = node;
356219598Sbschmidt	priv->data = cc_create(&cc_funcs);
357170530Ssam	if (priv->data == NULL) {
358219598Sbschmidt		free(priv, M_NG_CCATM);
359219598Sbschmidt		return (ENOMEM);
360219598Sbschmidt	}
361219598Sbschmidt
362219598Sbschmidt	NG_NODE_SET_PRIVATE(node, priv);
363219598Sbschmidt
364219598Sbschmidt	return (0);
365219598Sbschmidt}
366219598Sbschmidt
367219598Sbschmidt/*
368219598Sbschmidt * Destroy a node. The user list is empty here, because all hooks are
369219598Sbschmidt * previously disconnected. The connection lists may not be empty, because
370219598Sbschmidt * connections may be waiting for responses from the stack. This also means,
371219598Sbschmidt * that no orphaned connections will be made by the port_destroy routine.
372219598Sbschmidt */
373205277Srpaulostatic int
374170530Ssamng_ccatm_shutdown(node_p node)
375170530Ssam{
376170530Ssam	struct ccnode *priv = NG_NODE_PRIVATE(node);
377205277Srpaulo
378219598Sbschmidt	cc_destroy(priv->data);
379205277Srpaulo
380205277Srpaulo	free(priv, M_NG_CCATM);
381205277Srpaulo	NG_NODE_SET_PRIVATE(node, NULL);
382219598Sbschmidt
383219606Sbschmidt	NG_NODE_UNREF(node);
384219598Sbschmidt
385219598Sbschmidt	return (0);
386219606Sbschmidt}
387219598Sbschmidt
388219598Sbschmidt/*
389219598Sbschmidt * Retrieve the registered addresses for one port or all ports.
390219606Sbschmidt * Returns an error code or 0 on success.
391219598Sbschmidt */
392219598Sbschmidtstatic int
393219598Sbschmidtng_ccatm_get_addresses(node_p node, uint32_t portno, struct ng_mesg *msg,
394219598Sbschmidt    struct ng_mesg **resp)
395219606Sbschmidt{
396219598Sbschmidt	struct ccnode *priv = NG_NODE_PRIVATE(node);
397219598Sbschmidt	struct uni_addr *addrs;
398205277Srpaulo	u_int *ports;
399205277Srpaulo	struct ngm_ccatm_get_addresses *list;
400170530Ssam	u_int count, i;
401170530Ssam	size_t len;
402170530Ssam	int err;
403219598Sbschmidt
404219598Sbschmidt	err = cc_get_addrs(priv->data, portno, &addrs, &ports, &count);
405219598Sbschmidt	if (err != 0)
406219598Sbschmidt		return (err);
407219598Sbschmidt
408170530Ssam	len = sizeof(*list) + count * sizeof(list->addr[0]);
409219598Sbschmidt	NG_MKRESPONSE(*resp, msg, len, M_NOWAIT);
410170530Ssam	if (*resp == NULL) {
411219598Sbschmidt		free(addrs, M_NG_CCATM);
412170530Ssam		free(ports, M_NG_CCATM);
413170530Ssam		return (ENOMEM);
414219602Sbschmidt	}
415219602Sbschmidt	list = (struct ngm_ccatm_get_addresses *)(*resp)->data;
416170530Ssam
417170530Ssam	list->count = count;
418219602Sbschmidt	for (i = 0; i < count; i++) {
419170530Ssam		list->addr[i].port = ports[i];
420219602Sbschmidt		list->addr[i].addr = addrs[i];
421219602Sbschmidt	}
422219602Sbschmidt
423219602Sbschmidt	free(addrs, M_NG_CCATM);
424219602Sbschmidt	free(ports, M_NG_CCATM);
425219602Sbschmidt
426219602Sbschmidt	return (0);
427219602Sbschmidt}
428219602Sbschmidt
429219602Sbschmidt/*
430219602Sbschmidt * Dumper function. Pack the data into an mbuf chain.
431219602Sbschmidt */
432219602Sbschmidtstatic int
433219602Sbschmidtsend_dump(struct ccdata *data, void *uarg, const char *buf)
434219602Sbschmidt{
435219602Sbschmidt	struct mbuf *m;
436219602Sbschmidt	struct ccnode *priv = uarg;
437219602Sbschmidt
438219602Sbschmidt	if (priv->dump == NULL) {
439219602Sbschmidt		m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
440219602Sbschmidt		if (m == NULL)
441219602Sbschmidt			return (ENOBUFS);
442219602Sbschmidt		priv->dump_first = priv->dump_last = m;
443219602Sbschmidt		m->m_pkthdr.len = 0;
444219602Sbschmidt	} else {
445219602Sbschmidt		m = m_getcl(M_DONTWAIT, MT_DATA, 0);
446219602Sbschmidt		if (m == 0) {
447219602Sbschmidt			m_freem(priv->dump_first);
448170530Ssam			return (ENOBUFS);
449170530Ssam		}
450170530Ssam		priv->dump_last->m_next = m;
451170530Ssam		priv->dump_last = m;
452170530Ssam	}
453170530Ssam
454170530Ssam	strcpy(m->m_data, buf);
455170530Ssam	priv->dump_first->m_pkthdr.len += (m->m_len = strlen(buf));
456170530Ssam
457170530Ssam	return (0);
458170530Ssam}
459170530Ssam
460170530Ssam/*
461170530Ssam * Dump current status to dump hook
462178354Ssam */
463173462Ssamstatic int
464170530Ssamng_ccatm_dump(node_p node)
465170530Ssam{
466170530Ssam	struct ccnode *priv = NG_NODE_PRIVATE(node);
467170530Ssam	struct mbuf *m;
468170530Ssam	int error;
469178354Ssam
470170530Ssam	priv->dump_first = priv->dump_last = NULL;
471170530Ssam	error = cc_dump(priv->data, MCLBYTES, send_dump, priv);
472170530Ssam	if (error != 0)
473170530Ssam		return (error);
474170530Ssam
475170530Ssam	if ((m = priv->dump_first) != NULL) {
476170530Ssam		priv->dump_first = priv->dump_last = NULL;
477170530Ssam		NG_SEND_DATA_ONLY(error, priv->dump, m);
478170530Ssam		return (error);
479170530Ssam	}
480178354Ssam	return (0);
481173462Ssam}
482178354Ssam
483170530Ssam/*
484170530Ssam * Control message
485173462Ssam */
486170530Ssamstatic int
487170530Ssamng_ccatm_rcvmsg(node_p node, item_p item, hook_p lasthook)
488170530Ssam{
489178354Ssam	struct ng_mesg *resp = NULL;
490170530Ssam	struct ng_mesg *msg;
491170530Ssam	struct ccnode *priv = NG_NODE_PRIVATE(node);
492178354Ssam	int error = 0;
493170530Ssam
494170530Ssam	NGI_GET_MSG(item, msg);
495170530Ssam
496178354Ssam	switch (msg->header.typecookie) {
497170530Ssam
498170530Ssam	  case NGM_CCATM_COOKIE:
499170530Ssam		switch (msg->header.cmd) {
500170530Ssam
501170530Ssam		  case NGM_CCATM_DUMP:
502170530Ssam			if (priv->dump)
503170530Ssam				error = ng_ccatm_dump(node);
504170530Ssam			else
505170530Ssam				error = ENOTCONN;
506170530Ssam			break;
507170530Ssam
508170530Ssam		  case NGM_CCATM_STOP:
509170530Ssam		    {
510170530Ssam			struct ngm_ccatm_port *arg;
511170530Ssam
512170530Ssam			if (msg->header.arglen != sizeof(*arg)) {
513170530Ssam				error = EINVAL;
514170530Ssam				break;
515170530Ssam			}
516170530Ssam			arg = (struct ngm_ccatm_port *)msg->data;
517170530Ssam			error = cc_port_stop(priv->data, arg->port);
518170530Ssam			break;
519170530Ssam		    }
520170530Ssam
521170530Ssam		  case NGM_CCATM_START:
522170530Ssam		    {
523170530Ssam			struct ngm_ccatm_port *arg;
524170530Ssam
525170530Ssam			if (msg->header.arglen != sizeof(*arg)) {
526170530Ssam				error = EINVAL;
527170530Ssam				break;
528170530Ssam			}
529170530Ssam			arg = (struct ngm_ccatm_port *)msg->data;
530170530Ssam			error = cc_port_start(priv->data, arg->port);
531170530Ssam			break;
532170530Ssam		    }
533178354Ssam
534178354Ssam		  case NGM_CCATM_GETSTATE:
535191552Ssam		    {
536191552Ssam			struct ngm_ccatm_port *arg;
537191552Ssam			int state;
538178354Ssam
539191552Ssam			if (msg->header.arglen != sizeof(*arg)) {
540191552Ssam				error = EINVAL;
541178354Ssam				break;
542178354Ssam			}
543178354Ssam			arg = (struct ngm_ccatm_port *)msg->data;
544178354Ssam			error = cc_port_isrunning(priv->data, arg->port,
545178354Ssam			    &state);
546178354Ssam			if (error == 0) {
547178354Ssam				NG_MKRESPONSE(resp, msg, sizeof(uint32_t),
548178354Ssam				    M_NOWAIT);
549178354Ssam				if (resp == NULL) {
550178354Ssam					error = ENOMEM;
551191552Ssam					break;
552178354Ssam				}
553191552Ssam				*(uint32_t *)resp->data = state;
554191552Ssam			}
555178354Ssam			break;
556178354Ssam		    }
557178354Ssam
558170530Ssam		  case NGM_CCATM_GET_ADDRESSES:
559170530Ssam		   {
560170530Ssam			struct ngm_ccatm_port *arg;
561191552Ssam
562170530Ssam			if (msg->header.arglen != sizeof(*arg)) {
563205277Srpaulo				error = EINVAL;
564170530Ssam				break;
565178354Ssam			}
566170530Ssam			arg = (struct ngm_ccatm_port *)msg->data;
567170530Ssam			error = ng_ccatm_get_addresses(node, arg->port, msg,
568170530Ssam			    &resp);
569170530Ssam			break;
570170530Ssam		    }
571183247Ssam
572170530Ssam		  case NGM_CCATM_CLEAR:
573170530Ssam		    {
574170530Ssam			struct ngm_ccatm_port *arg;
575170530Ssam
576170530Ssam			if (msg->header.arglen != sizeof(*arg)) {
577183247Ssam				error = EINVAL;
578192468Ssam				break;
579192468Ssam			}
580170530Ssam			arg = (struct ngm_ccatm_port *)msg->data;
581170530Ssam			error = cc_port_clear(priv->data, arg->port);
582170530Ssam			break;
583170530Ssam		    }
584170530Ssam
585170530Ssam		  case NGM_CCATM_ADDRESS_REGISTERED:
586170530Ssam		    {
587170530Ssam			struct ngm_ccatm_addr_req *arg;
588170530Ssam
589170530Ssam			if (msg->header.arglen != sizeof(*arg)) {
590170530Ssam				error = EINVAL;
591170530Ssam				break;
592170530Ssam			}
593178354Ssam			arg = (struct ngm_ccatm_addr_req *)msg->data;
594170530Ssam			error = cc_addr_register(priv->data, arg->port,
595170530Ssam			    &arg->addr);
596170530Ssam			break;
597170530Ssam		    }
598170530Ssam
599170530Ssam		  case NGM_CCATM_ADDRESS_UNREGISTERED:
600170530Ssam		    {
601170530Ssam			struct ngm_ccatm_addr_req *arg;
602170530Ssam
603170530Ssam			if (msg->header.arglen != sizeof(*arg)) {
604170530Ssam				error = EINVAL;
605170530Ssam				break;
606170530Ssam			}
607170530Ssam			arg = (struct ngm_ccatm_addr_req *)msg->data;
608170530Ssam			error = cc_addr_unregister(priv->data, arg->port,
609170530Ssam			    &arg->addr);
610170530Ssam			break;
611170530Ssam		    }
612170530Ssam
613170530Ssam		  case NGM_CCATM_GET_PORT_PARAM:
614170530Ssam		    {
615170530Ssam			struct ngm_ccatm_port *arg;
616170530Ssam
617170530Ssam			if (msg->header.arglen != sizeof(*arg)) {
618170530Ssam				error = EINVAL;
619170530Ssam				break;
620170530Ssam			}
621170530Ssam			arg = (struct ngm_ccatm_port *)msg->data;
622170530Ssam			NG_MKRESPONSE(resp, msg, sizeof(struct atm_port_info),
623178354Ssam			    M_NOWAIT);
624170530Ssam			if (resp == NULL) {
625173273Ssam				error = ENOMEM;
626173273Ssam				break;
627173273Ssam			}
628173273Ssam			error = cc_port_get_param(priv->data, arg->port,
629173273Ssam			    (struct atm_port_info *)resp->data);
630178354Ssam			if (error != 0) {
631170530Ssam				free(resp, M_NETGRAPH_MSG);
632170530Ssam				resp = NULL;
633173273Ssam			}
634170530Ssam			break;
635173273Ssam		    }
636170530Ssam
637170530Ssam		  case NGM_CCATM_SET_PORT_PARAM:
638173273Ssam		    {
639170530Ssam			struct atm_port_info *arg;
640178354Ssam
641170530Ssam			if (msg->header.arglen != sizeof(*arg)) {
642170530Ssam				error = EINVAL;
643170530Ssam				break;
644173273Ssam			}
645170530Ssam			arg = (struct atm_port_info *)msg->data;
646170530Ssam			error = cc_port_set_param(priv->data, arg);
647170530Ssam			break;
648170530Ssam		    }
649170530Ssam
650173273Ssam		  case NGM_CCATM_GET_PORTLIST:
651178354Ssam		    {
652173273Ssam			struct ngm_ccatm_portlist *arg;
653170530Ssam			u_int n, *ports;
654173273Ssam
655170530Ssam			if (msg->header.arglen != 0) {
656170530Ssam				error = EINVAL;
657170530Ssam				break;
658173273Ssam			}
659170530Ssam			error = cc_port_getlist(priv->data, &n, &ports);
660170530Ssam			if (error != 0)
661173273Ssam				break;
662173273Ssam
663173273Ssam			NG_MKRESPONSE(resp, msg, sizeof(*arg) +
664173273Ssam			    n * sizeof(arg->ports[0]), M_NOWAIT);
665173273Ssam			if (resp == NULL) {
666173273Ssam				free(ports, M_NG_CCATM);
667173273Ssam				error = ENOMEM;
668173273Ssam				break;
669178354Ssam			}
670173273Ssam			arg = (struct ngm_ccatm_portlist *)resp->data;
671173273Ssam
672173273Ssam			arg->nports = 0;
673173273Ssam			for (arg->nports = 0; arg->nports < n; arg->nports++)
674173273Ssam				arg->ports[arg->nports] = ports[arg->nports];
675173273Ssam			free(ports, M_NG_CCATM);
676173273Ssam			break;
677173273Ssam		    }
678173273Ssam
679173273Ssam		  case NGM_CCATM_SETLOG:
680173273Ssam		    {
681173273Ssam			uint32_t log_level;
682173273Ssam
683173273Ssam			log_level = cc_get_log(priv->data);
684173273Ssam			if (msg->header.arglen != 0) {
685173273Ssam				if (msg->header.arglen != sizeof(log_level)) {
686173273Ssam					error = EINVAL;
687173273Ssam					break;
688178354Ssam				}
689173273Ssam				cc_set_log(priv->data, *(uint32_t *)msg->data);
690173273Ssam			}
691173273Ssam
692173273Ssam			NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
693173273Ssam			if (resp == NULL) {
694173273Ssam				error = ENOMEM;
695173273Ssam				if (msg->header.arglen != 0)
696173273Ssam					cc_set_log(priv->data, log_level);
697173273Ssam				break;
698173273Ssam			}
699173273Ssam			*(uint32_t *)resp->data = log_level;
700173273Ssam			break;
701173273Ssam		    }
702173273Ssam
703178354Ssam		  case NGM_CCATM_RESET:
704178354Ssam			if (msg->header.arglen != 0) {
705178354Ssam				error = EINVAL;
706178354Ssam				break;
707173273Ssam			}
708173273Ssam
709173273Ssam			if (priv->hook_cnt != 0) {
710173273Ssam				error = EBUSY;
711173273Ssam				break;
712173273Ssam			}
713173273Ssam			cc_reset(priv->data);
714173273Ssam			break;
715173273Ssam
716173273Ssam		  case NGM_CCATM_GET_EXSTAT:
717173273Ssam		    {
718173273Ssam			struct atm_exstatus s;
719173273Ssam			struct atm_exstatus_ep *eps;
720178354Ssam			struct atm_exstatus_port *ports;
721173273Ssam			struct atm_exstatus_conn *conns;
722173273Ssam			struct atm_exstatus_party *parties;
723173273Ssam			size_t offs;
724173273Ssam
725173273Ssam			if (msg->header.arglen != 0) {
726173273Ssam				error = EINVAL;
727173273Ssam				break;
728173273Ssam			}
729173273Ssam			error = cc_get_extended_status(priv->data,
730173273Ssam			    &s, &eps, &ports, &conns, &parties);
731173273Ssam			if (error != 0)
732170530Ssam				break;
733170530Ssam
734170530Ssam			offs = sizeof(s) + s.neps * sizeof(*eps) +
735173273Ssam			    s.nports * sizeof(*ports) +
736170530Ssam			    s.nconns * sizeof(*conns) +
737170530Ssam			    s.nparties * sizeof(*parties);
738170530Ssam
739170530Ssam			NG_MKRESPONSE(resp, msg, offs, M_NOWAIT);
740170530Ssam			if (resp == NULL) {
741170530Ssam				error = ENOMEM;
742170530Ssam				break;
743170530Ssam			}
744173273Ssam
745173273Ssam			memcpy(resp->data, &s, sizeof(s));
746178354Ssam			offs = sizeof(s);
747170530Ssam
748170530Ssam			memcpy(resp->data + offs, eps,
749170530Ssam			    sizeof(*eps) * s.neps);
750170530Ssam			offs += sizeof(*eps) * s.neps;
751170530Ssam
752170530Ssam			memcpy(resp->data + offs, ports,
753183247Ssam			    sizeof(*ports) * s.nports);
754183247Ssam			offs += sizeof(*ports) * s.nports;
755170530Ssam
756170530Ssam			memcpy(resp->data + offs, conns,
757170530Ssam			    sizeof(*conns) * s.nconns);
758170530Ssam			offs += sizeof(*conns) * s.nconns;
759183247Ssam
760183247Ssam			memcpy(resp->data + offs, parties,
761183247Ssam			    sizeof(*parties) * s.nparties);
762183247Ssam			offs += sizeof(*parties) * s.nparties;
763183247Ssam
764183247Ssam			free(eps, M_NG_CCATM);
765183247Ssam			free(ports, M_NG_CCATM);
766193840Ssam			free(conns, M_NG_CCATM);
767173273Ssam			free(parties, M_NG_CCATM);
768173273Ssam			break;
769173273Ssam		    }
770173273Ssam
771170530Ssam		  default:
772170530Ssam			error = EINVAL;
773170530Ssam			break;
774170530Ssam
775170530Ssam		}
776173273Ssam		break;
777170530Ssam
778182827Ssam	  default:
779182827Ssam		error = EINVAL;
780182827Ssam		break;
781182827Ssam
782182827Ssam	}
783182827Ssam
784182827Ssam	NG_RESPOND_MSG(error, node, item, resp);
785182827Ssam	NG_FREE_MSG(msg);
786182827Ssam	return (error);
787182827Ssam}
788182827Ssam
789182827Ssam/************************************************************
790182827Ssam *
791182827Ssam * New hook arrival
792182827Ssam */
793173273Ssamstatic int
794173273Ssamng_ccatm_newhook(node_p node, hook_p hook, const char *name)
795170530Ssam{
796170530Ssam	struct ccnode *priv = NG_NODE_PRIVATE(node);
797170530Ssam	struct ccport *port;
798170530Ssam	struct ccuser *user;
799170530Ssam	struct cchook *hd;
800170530Ssam	u_long lport;
801170530Ssam	char *end;
802170530Ssam
803170530Ssam	if (strncmp(name, "uni", 3) == 0) {
804170530Ssam		/*
805170530Ssam		 * This is a UNI hook. Should be a new port.
806173273Ssam		 */
807170530Ssam		if (name[3] == '\0')
808170530Ssam			return (EINVAL);
809170530Ssam		lport = strtoul(name + 3, &end, 10);
810170530Ssam		if (*end != '\0' || lport == 0 || lport > 0xffffffff)
811170530Ssam			return (EINVAL);
812170530Ssam
813173273Ssam		hd = malloc(sizeof(*hd), M_NG_CCATM, M_NOWAIT);
814170530Ssam		if (hd == NULL)
815170530Ssam			return (ENOMEM);
816170530Ssam		hd->is_uni = 1;
817173273Ssam		hd->node = priv;
818170530Ssam		hd->hook = hook;
819170530Ssam
820170530Ssam		port = cc_port_create(priv->data, hd, (u_int)lport);
821173273Ssam		if (port == NULL) {
822170530Ssam			free(hd, M_NG_CCATM);
823173273Ssam			return (ENOMEM);
824205277Srpaulo		}
825173273Ssam		hd->inst = port;
826173273Ssam
827173273Ssam		NG_HOOK_SET_PRIVATE(hook, hd);
828173273Ssam		NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvuni);
829173273Ssam		NG_HOOK_FORCE_QUEUE(hook);
830173273Ssam
831173273Ssam		priv->hook_cnt++;
832173273Ssam
833173273Ssam		return (0);
834173273Ssam	}
835173273Ssam
836173273Ssam	if (strcmp(name, "dump") == 0) {
837170530Ssam		priv->dump = hook;
838173273Ssam		NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvdump);
839173273Ssam		return (0);
840173273Ssam	}
841173273Ssam
842173273Ssam	if (strcmp(name, "manage") == 0) {
843170530Ssam		priv->manage = hook;
844173273Ssam		NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvmanage);
845173273Ssam		return (0);
846173273Ssam	}
847173273Ssam
848173273Ssam	/*
849173273Ssam	 * User hook
850173273Ssam	 */
851173273Ssam	hd = malloc(sizeof(*hd), M_NG_CCATM, M_NOWAIT);
852178354Ssam	if (hd == NULL)
853173273Ssam		return (ENOMEM);
854173273Ssam	hd->is_uni = 0;
855173273Ssam	hd->node = priv;
856173273Ssam	hd->hook = hook;
857173273Ssam
858173273Ssam	user = cc_user_create(priv->data, hd, NG_HOOK_NAME(hook));
859173273Ssam	if (user == NULL) {
860173273Ssam		free(hd, M_NG_CCATM);
861173273Ssam		return (ENOMEM);
862173273Ssam	}
863173273Ssam
864173273Ssam	hd->inst = user;
865173273Ssam	NG_HOOK_SET_PRIVATE(hook, hd);
866173273Ssam	NG_HOOK_FORCE_QUEUE(hook);
867173273Ssam
868173273Ssam	priv->hook_cnt++;
869173273Ssam
870173273Ssam	return (0);
871178354Ssam}
872173273Ssam
873178354Ssam/*
874173273Ssam * Disconnect a hook
875173273Ssam */
876173273Ssamstatic int
877173273Ssamng_ccatm_disconnect(hook_p hook)
878173273Ssam{
879178354Ssam	node_p node = NG_HOOK_NODE(hook);
880173273Ssam	struct ccnode *priv = NG_NODE_PRIVATE(node);
881173273Ssam	struct cchook *hd = NG_HOOK_PRIVATE(hook);
882173273Ssam
883173273Ssam	if (hook == priv->dump) {
884173273Ssam		priv->dump = NULL;
885173273Ssam
886173273Ssam	} else if (hook == priv->manage) {
887173273Ssam		priv->manage = NULL;
888173273Ssam		cc_unmanage(priv->data);
889205277Srpaulo
890173273Ssam	} else {
891178354Ssam		if (hd->is_uni)
892173273Ssam			cc_port_destroy(hd->inst, 0);
893170530Ssam		else
894173273Ssam			cc_user_destroy(hd->inst);
895170530Ssam
896178354Ssam		free(hd, M_NG_CCATM);
897170530Ssam		NG_HOOK_SET_PRIVATE(hook, NULL);
898173273Ssam
899173273Ssam		priv->hook_cnt--;
900173273Ssam
901173273Ssam		cc_work(hd->node->data);
902173273Ssam	}
903173273Ssam
904173273Ssam	/*
905173273Ssam	 * When the number of hooks drops to zero, delete the node.
906173273Ssam	 */
907173273Ssam	if (NG_NODE_NUMHOOKS(node) == 0 && NG_NODE_IS_VALID(node))
908173273Ssam		ng_rmnode_self(node);
909173273Ssam
910170530Ssam	return (0);
911170530Ssam}
912173273Ssam
913205277Srpaulo/************************************************************
914170530Ssam *
915178354Ssam * Receive data from user hook
916173273Ssam */
917178354Ssamstatic int
918173273Ssamng_ccatm_rcvdata(hook_p hook, item_p item)
919173273Ssam{
920173273Ssam	struct cchook *hd = NG_HOOK_PRIVATE(hook);
921173273Ssam	struct uni_msg *msg;
922178354Ssam	struct mbuf *m;
923173273Ssam	struct ccatm_op op;
924170530Ssam	int err;
925173273Ssam
926170530Ssam	NGI_GET_M(item, m);
927173273Ssam	NG_FREE_ITEM(item);
928173273Ssam
929170530Ssam	if ((err = uni_msg_unpack_mbuf(m, &msg)) != 0) {
930170530Ssam		m_freem(m);
931170530Ssam		return (err);
932170530Ssam	}
933170530Ssam	m_freem(m);
934170530Ssam
935173273Ssam	if (uni_msg_len(msg) < sizeof(op)) {
936170530Ssam		printf("%s: packet too short\n", __func__);
937170530Ssam		uni_msg_destroy(msg);
938170530Ssam		return (EINVAL);
939170530Ssam	}
940178354Ssam
941170530Ssam	bcopy(msg->b_rptr, &op, sizeof(op));
942170530Ssam	msg->b_rptr += sizeof(op);
943170530Ssam
944170530Ssam	err = cc_user_signal(hd->inst, op.op, msg);
945170530Ssam	cc_work(hd->node->data);
946173273Ssam	return (err);
947173273Ssam}
948178354Ssam
949173273Ssam/*
950173273Ssam * Pack a header and a data area into an mbuf chain
951178354Ssam */
952173273Ssamstatic struct mbuf *
953173273Ssampack_buf(void *h, size_t hlen, void *t, size_t tlen)
954170530Ssam{
955170530Ssam	struct mbuf *m, *m0, *last;
956170530Ssam	u_char *buf = (u_char *)t;
957170530Ssam	size_t n;
958170530Ssam
959170530Ssam	/* header should fit into a normal mbuf */
960170530Ssam	MGETHDR(m0, M_NOWAIT, MT_DATA);
961170530Ssam	if (m0 == NULL)
962178354Ssam		return NULL;
963170530Ssam
964170530Ssam	KASSERT(hlen <= MHLEN, ("hlen > MHLEN"));
965178354Ssam
966170530Ssam	bcopy(h, m0->m_data, hlen);
967170530Ssam	m0->m_len = hlen;
968178354Ssam	m0->m_pkthdr.len = hlen;
969170530Ssam
970173273Ssam	last = m0;
971173273Ssam	while ((n = tlen) != 0) {
972170530Ssam		if (n > MLEN) {
973170530Ssam			m = m_getcl(M_NOWAIT, MT_DATA, 0);
974173273Ssam			if (n > MCLBYTES)
975170530Ssam				n = MCLBYTES;
976173273Ssam		} else
977205277Srpaulo			MGET(m, M_NOWAIT, MT_DATA);
978170530Ssam
979178354Ssam		if(m == NULL)
980173273Ssam			goto drop;
981170530Ssam
982173273Ssam		last->m_next = m;
983173273Ssam		last = m;
984178354Ssam
985173273Ssam		bcopy(buf, m->m_data, n);
986173273Ssam		buf += n;
987173273Ssam		tlen -= n;
988173273Ssam		m->m_len = n;
989173273Ssam		m0->m_pkthdr.len += n;
990173273Ssam	}
991173273Ssam
992173273Ssam	return (m0);
993173273Ssam
994170530Ssam  drop:
995173273Ssam	m_freem(m0);
996170530Ssam	return NULL;
997173273Ssam}
998205277Srpaulo
999170530Ssam/*
1000178354Ssam * Send an indication to the user.
1001173273Ssam */
1002173273Ssamstatic void
1003173273Ssamng_ccatm_send_user(struct ccuser *user, void *uarg, u_int op,
1004173273Ssam    void *val, size_t len)
1005173273Ssam{
1006173273Ssam	struct cchook *hd = uarg;
1007178354Ssam	struct mbuf *m;
1008173273Ssam	struct ccatm_op	h;
1009170530Ssam	int error;
1010170530Ssam
1011170530Ssam	h.op = op;
1012170530Ssam	m = pack_buf(&h, sizeof(h), val, len);
1013170530Ssam	if (m == NULL)
1014170530Ssam		return;
1015170530Ssam
1016170530Ssam	NG_SEND_DATA_ONLY(error, hd->hook, m);
1017170530Ssam	if (error != 0)
1018183254Ssam		printf("%s: error=%d\n", __func__, error);
1019170530Ssam}
1020170530Ssam
1021170530Ssam/*
1022170530Ssam * Send a response to the user.
1023173273Ssam */
1024173273Ssamstatic void
1025173273Ssamng_ccatm_respond_user(struct ccuser *user, void *uarg, int err, u_int data,
1026173273Ssam    void *val, size_t len)
1027173273Ssam{
1028173273Ssam	struct cchook *hd = uarg;
1029173273Ssam	struct mbuf *m;
1030173273Ssam	struct {
1031170530Ssam		struct ccatm_op	op;
1032170530Ssam		struct atm_resp resp;
1033170530Ssam	} resp;
1034184280Ssam	int error;
1035173273Ssam
1036170530Ssam	resp.op.op = ATMOP_RESP;
1037173273Ssam	resp.resp.resp = err;
1038170530Ssam	resp.resp.data = data;
1039170530Ssam	m = pack_buf(&resp, sizeof(resp), val, len);
1040170530Ssam	if (m == NULL)
1041170530Ssam		return;
1042170530Ssam
1043170530Ssam	NG_SEND_DATA_ONLY(error, hd->hook, m);
1044170530Ssam	if (error != 0)
1045170530Ssam		printf("%s: error=%d\n", __func__, error);
1046170530Ssam}
1047191552Ssam
1048170530Ssam/*
1049170530Ssam * Receive data from UNI.
1050170530Ssam */
1051170530Ssamstatic int
1052170530Ssamng_ccatm_rcvuni(hook_p hook, item_p item)
1053170530Ssam{
1054170530Ssam	struct cchook *hd = NG_HOOK_PRIVATE(hook);
1055184280Ssam	struct uni_msg *msg;
1056184280Ssam	struct uni_arg arg;
1057170530Ssam	struct mbuf *m;
1058170530Ssam	int err;
1059191552Ssam
1060170530Ssam	NGI_GET_M(item, m);
1061170530Ssam	NG_FREE_ITEM(item);
1062182828Ssam
1063170530Ssam	if ((err = uni_msg_unpack_mbuf(m, &msg)) != 0) {
1064170530Ssam		m_freem(m);
1065178354Ssam		return (err);
1066178354Ssam	}
1067178354Ssam	m_freem(m);
1068178354Ssam
1069178354Ssam	if (uni_msg_len(msg) < sizeof(arg)) {
1070178354Ssam		printf("%s: packet too short\n", __func__);
1071178354Ssam		uni_msg_destroy(msg);
1072178354Ssam		return (EINVAL);
1073178354Ssam	}
1074178354Ssam
1075178354Ssam	bcopy(msg->b_rptr, &arg, sizeof(arg));
1076178354Ssam	msg->b_rptr += sizeof(arg);
1077178354Ssam
1078178354Ssam	if (arg.sig == UNIAPI_ERROR) {
1079178354Ssam		if (uni_msg_len(msg) != sizeof(struct uniapi_error)) {
1080178354Ssam			printf("%s: bad UNIAPI_ERROR size %zu\n", __func__,
1081178354Ssam			    uni_msg_len(msg));
1082178354Ssam			uni_msg_destroy(msg);
1083178354Ssam			return (EINVAL);
1084178354Ssam		}
1085178354Ssam		err = cc_uni_response(hd->inst, arg.cookie,
1086178354Ssam		    ((struct uniapi_error *)msg->b_rptr)->reason,
1087178354Ssam		    ((struct uniapi_error *)msg->b_rptr)->state);
1088178354Ssam		uni_msg_destroy(msg);
1089178354Ssam	} else
1090178354Ssam		err = cc_uni_signal(hd->inst, arg.cookie, arg.sig, msg);
1091178354Ssam
1092178354Ssam	cc_work(hd->node->data);
1093178354Ssam	return (err);
1094178354Ssam}
1095178354Ssam
1096178354Ssam/*
1097178354Ssam * Uarg is the port's uarg.
1098178354Ssam */
1099178354Ssamstatic void
1100178354Ssamng_ccatm_send_uni(struct ccconn *conn, void *uarg, u_int op, u_int cookie,
1101178354Ssam    struct uni_msg *msg)
1102178354Ssam{
1103178354Ssam	struct cchook *hd = uarg;
1104173273Ssam	struct uni_arg arg;
1105173273Ssam	struct mbuf *m;
1106173273Ssam	int error;
1107173273Ssam
1108173273Ssam	arg.sig = op;
1109173273Ssam	arg.cookie = cookie;
1110173273Ssam
1111173273Ssam	m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
1112173273Ssam	uni_msg_destroy(msg);
1113173273Ssam	if (m == NULL)
1114173273Ssam		return;
1115173273Ssam
1116173273Ssam	NG_SEND_DATA_ONLY(error, hd->hook, m);
1117173273Ssam	if (error != 0)
1118173273Ssam		printf("%s: error=%d\n", __func__, error);
1119173273Ssam}
1120193655Ssam
1121173273Ssam/*
1122193655Ssam * Send a global message to the UNI
1123173273Ssam */
1124173273Ssamstatic void
1125173273Ssamng_ccatm_send_uni_glob(struct ccport *port, void *uarg, u_int op, u_int cookie,
1126173273Ssam    struct uni_msg *msg)
1127173273Ssam{
1128173273Ssam	struct cchook *hd = uarg;
1129173273Ssam	struct uni_arg arg;
1130173273Ssam	struct mbuf *m;
1131173273Ssam	int error;
1132173273Ssam
1133173273Ssam	arg.sig = op;
1134173273Ssam	arg.cookie = cookie;
1135173273Ssam
1136173273Ssam	m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
1137173273Ssam	if (msg != NULL)
1138173273Ssam		uni_msg_destroy(msg);
1139173273Ssam	if (m == NULL)
1140173273Ssam		return;
1141173273Ssam
1142173273Ssam	NG_SEND_DATA_ONLY(error, hd->hook, m);
1143173273Ssam	if (error != 0)
1144173273Ssam		printf("%s: error=%d\n", __func__, error);
1145173273Ssam}
1146173273Ssam/*
1147173273Ssam * Receive from ILMID
1148173273Ssam */
1149173273Ssamstatic int
1150173273Ssamng_ccatm_rcvmanage(hook_p hook, item_p item)
1151173273Ssam{
1152173273Ssam	NG_FREE_ITEM(item);
1153173273Ssam	return (0);
1154173273Ssam}
1155173273Ssam
1156178354Ssamstatic int
1157173273Ssamng_ccatm_rcvdump(hook_p hook, item_p item)
1158173273Ssam{
1159173273Ssam	NG_FREE_ITEM(item);
1160193655Ssam	return (0);
1161173273Ssam}
1162173273Ssam
1163173273Ssamstatic void
1164173273Ssamng_ccatm_log(const char *fmt, ...)
1165173273Ssam{
1166173273Ssam	va_list ap;
1167173273Ssam
1168173273Ssam	va_start(ap, fmt);
1169178354Ssam	vprintf(fmt, ap);
1170178354Ssam	printf("\n");
1171173273Ssam	va_end(ap);
1172173273Ssam}
1173193655Ssam
1174173273Ssam/*
1175173273Ssam * Loading and unloading of node type
1176173273Ssam */
1177173273Ssamstatic int
1178173273Ssamng_ccatm_mod_event(module_t mod, int event, void *data)
1179173273Ssam{
1180173273Ssam	int s;
1181173273Ssam	int error = 0;
1182193655Ssam
1183173273Ssam	s = splnet();
1184173273Ssam	switch (event) {
1185173273Ssam
1186173273Ssam	  case MOD_LOAD:
1187173273Ssam		break;
1188173273Ssam
1189193655Ssam	  case MOD_UNLOAD:
1190183256Ssam		break;
1191183256Ssam
1192173273Ssam	  default:
1193173273Ssam		error = EOPNOTSUPP;
1194173273Ssam		break;
1195173273Ssam	}
1196173273Ssam	splx(s);
1197173273Ssam	return (error);
1198173273Ssam}
1199173273Ssam