diff --git a/share/man/man4/ng_ccatm.4 b/share/man/man4/ng_ccatm.4 index 3d6778fa25d5..02a5a5f011b5 100644 --- a/share/man/man4/ng_ccatm.4 +++ b/share/man/man4/ng_ccatm.4 @@ -1,323 +1,328 @@ .\" .\" Copyright (c) 2001-2004 .\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). .\" All rights reserved. .\" Copyright (c) 2005 .\" Hartmut Brandt. .\" All rights reserved. .\" .\" Author: Harti Brandt .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd March 10, 2005 +.Dd March 3, 2023 .Dt NG_CCATM 4 .Os .Sh NAME .Nm ng_ccatm .Nd "ATM Call Control netgraph node type" .Sh SYNOPSIS .In netnatm/unimsg.h .In netnatm/msg/unistruct.h .In netnatm/sig/unidef.h .In netnatm/api/unisap.h .In netnatm/api/atmapi.h .In netnatm/api/ccatm.h .In netgraph.h .In netgraph/ng_uni.h .In netgraph/ng_ccatm.h +.Sh DEPRECATION NOTICE +.Nm +is deprecated and may not be available in +.Fx 14.0 +and later. .Sh DESCRIPTION The .Nm node implements the API specified by the ATM Forum for access to ATM services (see ATM-Forum document .Pa af-saa-0108 ) . This document specifies the semantics of the API, not the exact language binding. For this reason, it is expected that this implementation is neither compile-time nor binary compatible with other implementations of this API. It should, however, be fairly straightforward to convert between different API implementations. .Pp This node is usually stacked on top of one or more UNI nodes (see .Xr ng_uni 4 ) . Each of these hooks appears as a .Dq port to the user of the node. It also has one hook connected to the ILMI daemon for management purposes. .Pp The node is removed when it receives a .Dv NGM_SHUTDOWN messages or when all hooks are disconnected. .Sh HOOKS The node understands a number of hooks with predefined names and an unlimited number of hooks for user connections. The predefined names are: .Bl -tag -width ".Va orphans" .It Va uni Ns Ar NNN These hooks stack the .Nm node on top of a UNI stack. The node expects the interface on these hooks to conform to the upper interface specified in .Xr ng_uni 4 . These hooks are forced into queuing mode, so that there are no circular calls from call control to UNI and UNI back to call control. The .Ar NNN in the hook name is the decimal port number and should not be zero. The port number is a 32-bit unsigned integer. .It Va manage This hook should be connected to the ILMI daemon. No data is ever sent on this hook and all received data is discarded. The hook is used to send control messages along. .It Va dump On receipt of a .Dv NGM_CCATM_DUMP command a textual description of the current state of the node is sent out of this hook. This text is sent as one large message consisting of more than one .Vt mbuf . .El .Pp All other hook names are taken to be user hooks and correspond to an ATM endpoint as specified in the ATM Forum document. The interface on these hooks is defined in .In atmapi.h and uses a structure .Bd -literal struct ccatm_op { uint32_t op; /* request code */ u_char data[]; /* optional data */ }; .Ed .Pp This structure is followed directly by the data for the operation. The opcode is one of the following: .Bd -literal enum atmop { ATMOP_RESP, ATMOP_ABORT_CONNECTION, ATMOP_ACCEPT_INCOMING_CALL, ATMOP_ADD_PARTY, ATMOP_ADD_PARTY_REJECT, ATMOP_ADD_PARTY_SUCCESS, ATMOP_ARRIVAL_OF_INCOMING_CALL, ATMOP_CALL_RELEASE, ATMOP_CONNECT_OUTGOING_CALL, ATMOP_DROP_PARTY, ATMOP_GET_LOCAL_PORT_INFO, ATMOP_P2MP_CALL_ACTIVE, ATMOP_P2P_CALL_ACTIVE, ATMOP_PREPARE_INCOMING_CALL, ATMOP_PREPARE_OUTGOING_CALL, ATMOP_QUERY_CONNECTION_ATTRIBUTES, ATMOP_REJECT_INCOMING_CALL, ATMOP_SET_CONNECTION_ATTRIBUTES, ATMOP_WAIT_ON_INCOMING_CALL, ATMOP_SET_CONNECTION_ATTRIBUTES_X, ATMOP_QUERY_CONNECTION_ATTRIBUTES_X, ATMOP_QUERY_STATE }; .Ed .Pp These codes correspond directly to the operations specified in the ATM Forum document with the following exceptions: .Bl -tag -width foo .It Dv ATMOP_RESP As discussed in .Xr ng_uni 4 , this is used to .Dq synchronify the interface. The argument is a .Bd -literal struct atm_resp { int32_t resp; uint32_t data; /* type of attached data */ }; .Ed .Pp If the response code .Va resp is zero, the node has accepted the user request. If something goes wrong, .Va resp contains an error code. For requests that return data, .Va data contains a code describing the type of data and the data itself starts immediately after the structure. .It Dv ATMOP_QUERY_CONNECTION_ATTRIBUTES_X This is the same as .Dv ATMOP_QUERY_CONNECTION_ATTRIBUTES except that it allows to query several attributes within one request. .It Dv ATMOP_SET_CONNECTION_ATTRIBUTES_X This is the same as .Dv ATMOP_SET_CONNECTION_ATTRIBUTES except that it allows to set several attributes within one request. The list of attributes is followed directly by the attributes in the same order as they appear in the list. .El .Pp If a user hook is disconnected, an active connection on that hook is released. Incoming connections waiting to be accepted are reoffered to other listening hooks or rejected. .Sh CONTROL MESSAGES Besides the generic messages the node understands the following special messages: .Bl -tag -width foo .It Dv NGM_CCATM_DUMP Pq Ic dump This causes the internal state of the node to be dumped in ASCII to the .Va dump hook. .It Dv NGM_CCATM_STOP Pq Ic stop This message causes all connections on that port to be aborted (not released!\&) and all ATM endpoints which are bound to that port to be closed. It stops processing of all messages from the UNI stack on that port UNI stack. The argument is a .Bd -literal struct ngm_ccatm_port { uint32_t port; }; .Ed .It Dv NGM_CCATM_START Pq Ic start Start processing on the port. The argument is a .Vt ngm_ccatm_port structure. .It Dv NGM_CCATM_CLEAR Pq Ic clear This message takes a .Vt ngm_ccatm_port structure and clears all prefixes and addresses on that port. If the port number is zero, all ports are cleared. .It Dv NGM_CCATM_GET_ADDRESSES Pq Ic get_addresses Get the list of all registered addresses on the given port. The argument is a .Vt ngm_ccatm_port structure and the result is a .Vt ngm_ccatm_get_addresses structure: .Bd -literal struct ngm_ccatm_get_addresses { uint32_t count; struct ngm_ccatm_address_req addr[0]; }; struct ngm_ccatm_address_req { uint32_t port; struct uni_addr addr; }; .Ed .Pp If the .Va port field is zero in the request, all addresses on all ports are returned. If it is not zero, only the addresses on that port are reported. The number of addresses is returned in the .Va count field. .It Dv NGM_CCATM_ADDRESS_REGISTERED Pq Ic address_reg This message is used by ILMI to inform the .Nm node that a previous address registration request was successful. This causes the node to activate that address. The argument to the message is a .Vt ngm_ccatm_address_req structure. .It Dv NGM_CCATM_ADDRESS_UNREGISTERED Pq Ic address_unreg This message is used by ILMI to inform the .Nm node that an address has been unregistered. The node clears that address from its tables. The argument is a .Vt ngm_ccatm_address_req structure. .It Dv NGM_CCATM_SET_PORT_PARAM Pq Ic set_port_param This request sets the parameters on the given port. The argument is a .Bd -literal struct ngm_ccatm_atm_port { uint32_t port; /* port for which to set parameters */ uint32_t pcr; /* port peak cell rate */ uint32_t max_vpi_bits; uint32_t max_vci_bits; uint32_t max_svpc_vpi; uint32_t max_svcc_vpi; uint32_t min_svcc_vci; uint8_t esi[6]; uint32_t num_addr; }; .Ed .Pp This should be used only by ILMI and when that port is stopped and the address and prefix tables of that port are empty. The .Va num_addr field is ignored. .It Dv NGM_CCATM_GET_PORT_PARAM Pq Ic get_port_param Retrieve the parameters of the given port. The argument is a .Vt ngm_ccatm_port and the result a .Vt ngm_ccatm_atm_port . .It Dv NGM_CCATM_GET_PORTLIST Pq Ic get_portlist Get a list of all available ports on that node. This is returned as a .Bd -literal struct ngm_ccatm_portlist { uint32_t nports; uint32_t ports[]; }; .Ed .It Dv NGM_CCATM_GETSTATE Pq Ic getstate Return the state of a port. The argument is a .Vt "struct ngm_ccatm_port" and the return values as a .Vt uint32_t . .It Dv NGM_CCATM_SETLOG Pq Ic setlog This requests sets a new logging level and returns the previous one. The argument is either a .Vt uint32_t in which case it specifies the new logging level, or may be empty in which case just the old level is returned as a .Vt uint32_t . .It Dv NGM_CCATM_RESET Pq Ic reset Reset the node. This is allowed only if the number of user hooks and connected UNI stacks is zero. .It Dv NGM_CCATM_GET_EXSTAT Return extended status information from the node. .El .Sh SEE ALSO .Xr netgraph 4 , .Xr ng_uni 4 , .Xr ngctl 8 .Sh AUTHORS .An Harti Brandt Aq Mt harti@FreeBSD.org diff --git a/share/man/man4/ng_sscfu.4 b/share/man/man4/ng_sscfu.4 index 2c444dacd589..6011deaeb2b3 100644 --- a/share/man/man4/ng_sscfu.4 +++ b/share/man/man4/ng_sscfu.4 @@ -1,161 +1,166 @@ .\" .\" Copyright (c) 2001-2003 .\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" Author: Hartmut Brandt .\" .\" $FreeBSD$ .\" .\" ng_sscfu(4) man page .\" -.Dd October 24, 2003 +.Dd March 3, 2023 .Dt NG_SSCFU 4 .Os .Sh NAME .Nm ng_sscfu .Nd netgraph SSCF at the UNI node type .Sh SYNOPSIS .In netnatm/saal/sscopdef.h .In netnatm/saal/sscfudef.h .In netgraph/atm/ng_sscfu.h +.Sh DEPRECATION NOTICE +.Nm +is deprecated and may not be available in +.Fx 14.0 +and later. .Sh DESCRIPTION The .Nm sscfu netgraph node type implements ITU-T recommendation Q.2130. This recommendation specifies the Service Specific Coordination Function at the UNI. This is a thin sub-layer between the SSCOP (see .Xr ng_sscop 4 ) and the UNI signalling. This node does not really implement a protocol but provides a mapping between the signals at the upper layer of the SSCOP and the signals the UNI expects at its lower layer. It also provides default values for the parameters of the SSCOP. .Pp After creation of the node, the SSCF instance must be created by sending an .Dq enable message to the node. If the node is enabled, default SSCOP parameters can be retrieved and set in the corresponding SSCOP instance. .Pp The node is shut down either by a .Dv NGM_SHUTDOWN message, or when all hooks are disconnected. .Sh HOOKS Each .Nm sscfu node has two hooks with fixed names: .Bl -tag -width ".Va upper" .It Va lower This hook is the interface to the SSCOP. The interface expected here is exactly that which is exported by the .Xr ng_sscop 4 node type. .It Va upper This is the interface to the UNI. It uses the following message format: .Bd -literal struct sscfu_arg { uint32_t sig; u_char data[]; }; .Ed .Pp The .Va sig field is one of the following signals: .Bd -literal enum saal_sig { SAAL_ESTABLISH_request, /* U -> SAAL: (UU) */ SAAL_ESTABLISH_indication, /* SAAL -> U: (UU) */ SAAL_ESTABLISH_confirm, /* SAAL -> U: (UU) */ SAAL_RELEASE_request, /* U -> SAAL: (UU) */ SAAL_RELEASE_confirm, /* SAAL -> U: */ SAAL_RELEASE_indication, /* SAAL -> U: (UU) */ SAAL_DATA_request, /* U -> SAAL: (DATA) */ SAAL_DATA_indication, /* SAAL -> U: (DATA) */ SAAL_UDATA_request, /* U -> SAAL: (UDATA) */ SAAL_UDATA_indication, /* SAAL -> U: (UDATA) */ }; .Ed .Pp The arrows in the comment show the direction of the signal, whether it is a signal that comes out of the node .Pq Ql -> , or is sent by the node user to the node .Pq Ql <- . The type of the data expected for the signal is specified in parentheses. This data starts at the .Va data field of the message structure. .El .Pp If the .Va lower hook is disconnected and the node is enabled, the protocol state is reset. .Sh CONTROL MESSAGES The .Nm sscfu node understands the generic messages plus the following: .Bl -tag -width foo .It Dv NGM_SSCFU_GETDEFPARAM Pq Ic getdefparam This message returns a .Vt sscop_param structure, which contains the default parameters for the SSCOP at the UNI. This structure should be used for a .Dv NGM_SSCOP_SETPARAM message to the SSCOP node below the SSCF. .It Dv NGM_SSCFU_ENABLE Pq Ic enable This message creates the actual SSCF instance and initializes it. Until this is done, parameters may neither be retrieved nor set, and all messages received on any hook are discarded. .It Dv NGM_SSCFU_DISABLE Pq Ic disable Destroy the SSCF instance. After this, all messages on any hooks are discarded. .It Dv NGM_SSCFU_GETDEBUG Pq Ic getdebug Retrieve the debugging flags in a .Vt uint32_t . .It Dv NGM_SSCFU_SETDEBUG Pq Ic setdebug Set debugging flags. The argument must be a .Vt uint32_t . .It Dv NGM_SSCFU_GETSTATE Pq Ic getstate Retrieve the current state of the SSCFU instance in a .Vt uint32_t . If the node has not been enabled, 0 is returned. .El .Sh SEE ALSO .Xr netgraph 4 , .Xr ng_atm 4 , .Xr ng_sscop 4 , .Xr ngctl 8 .Sh AUTHORS .An Harti Brandt Aq Mt harti@FreeBSD.org diff --git a/share/man/man4/ng_sscop.4 b/share/man/man4/ng_sscop.4 index c98a43462581..451edcc4aebf 100644 --- a/share/man/man4/ng_sscop.4 +++ b/share/man/man4/ng_sscop.4 @@ -1,403 +1,408 @@ .\" .\" Copyright (c) 2001-2003 .\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" Author: Hartmut Brandt .\" .\" $FreeBSD$ .\" .\" ng_sscop(4) man page .\" -.Dd October 24, 2003 +.Dd March 3, 2023 .Dt NG_SSCOP 4 .Os .Sh NAME .Nm ng_sscop .Nd netgraph SSCOP node type .Sh SYNOPSIS .In netnatm/saal/sscopdef.h .In netgraph/atm/ng_sscop.h +.Sh DEPRECATION NOTICE +.Nm +is deprecated and may not be available in +.Fx 14.0 +and later. .Sh DESCRIPTION The .Nm sscop netgraph node type implements the ITU-T standard Q.2110. This standard describes the so called Service Specific Connection Oriented Protocol (SSCOP) that is used to carry signalling messages over the private and public UNIs and the public NNI. This protocol is a transport protocol with selective acknowledgements, and can be tailored to the environment. This implementation is a full implementation of that standard. .Pp After creation of the node, the SSCOP instance must be created by sending an .Dq enable message to the node. If the node is enabled, the SSCOP parameters can be retrieved and modified and the protocol can be started. .Pp The node is shut down either by a .Dv NGM_SHUTDOWN message, or when all hooks are disconnected. .Sh HOOKS Each .Nm sscop node has three hooks with fixed names: .Bl -tag -width ".Va manage" .It Va lower This hook must be connected to a node that ensures transport of packets to and from the remote peer node. Normally this is a .Xr ng_atm 4 node with an AAL5 hook, but the .Nm sscop node is able to work on any packet-transporting layer, like, for example, IP or UDP. The node handles flow control messages received on this hook: if it receives a .Dv NGM_HIGH_WATER_PASSED message, it declares the .Dq "lower layer busy" state. If a .Dv NGM_LOW_WATER_PASSED message is received, the busy state is cleared. Note that the node does not look at the message contents of these flow control messages. .It Va upper This is the interface to the SSCOP user. This interface uses the following message format: .Bd -literal struct sscop_arg { uint32_t sig; uint32_t arg; /* opt. sequence number or clear-buff */ u_char data[]; }; .Ed .Pp The .Va sig field is one of the signals defined in the standard: .Bd -literal enum sscop_aasig { SSCOP_ESTABLISH_request, /* <- UU, BR */ SSCOP_ESTABLISH_indication, /* -> UU */ SSCOP_ESTABLISH_response, /* <- UU, BR */ SSCOP_ESTABLISH_confirm, /* -> UU */ SSCOP_RELEASE_request, /* <- UU */ SSCOP_RELEASE_indication, /* -> UU, SRC */ SSCOP_RELEASE_confirm, /* -> */ SSCOP_DATA_request, /* <- MU */ SSCOP_DATA_indication, /* -> MU, SN */ SSCOP_UDATA_request, /* <- MU */ SSCOP_UDATA_indication, /* -> MU */ SSCOP_RECOVER_indication, /* -> */ SSCOP_RECOVER_response, /* <- */ SSCOP_RESYNC_request, /* <- UU */ SSCOP_RESYNC_indication, /* -> UU */ SSCOP_RESYNC_response, /* <- */ SSCOP_RESYNC_confirm, /* -> */ SSCOP_RETRIEVE_request, /* <- RN */ SSCOP_RETRIEVE_indication, /* -> MU */ SSCOP_RETRIEVE_COMPL_indication,/* -> */ }; .Ed .Pp The arrows in the comment show the direction of the signal, whether it is a signal that comes out of the node .Pq Ql -> , or is sent by the node user to the node .Pq Ql <- . The .Va arg field contains the argument to some of the signals: it is either a PDU sequence number, or the .Dv CLEAR-BUFFER flag. There are a number of special sequence numbers for some operations: .Pp .Bl -tag -width ".Dv SSCOP_RETRIEVE_UNKNOWN" -offset indent -compact .It Dv SSCOP_MAXSEQNO maximum legal sequence number .It Dv SSCOP_RETRIEVE_UNKNOWN retrieve transmission queue .It Dv SSCOP_RETRIEVE_TOTAL retrieve transmission buffer and queue .El .Pp For signals that carry user data (as, for example, .Dv SSCOP_DATA_request ) these two fields are followed by the variable sized user data. .Pp If the .Va upper hook is disconnected and the SSCOP instance is not in the idle state, and the .Va lower hook is still connected, an .Dv SSCOP_RELEASE_request is executed to release the SSCOP connection. .It Va manage This is the management interface defined in the standard. The data structure used here is: .Bd -literal struct sscop_marg { uint32_t sig; u_char data[]; }; .Ed .Pp Here .Va sig is one of .Bd -literal enum sscop_maasig { SSCOP_MDATA_request, /* <- MU */ SSCOP_MDATA_indication, /* -> MU */ SSCOP_MERROR_indication, /* -> CODE, CNT */ }; .Ed .Pp The .Dv SSCOP_MDATA signals are followed by the actual management data, where the .Dv SSCOP_MERROR signal has the form: .Bd -literal struct sscop_merr { uint32_t sig; uint32_t err; /* error code */ uint32_t cnt; /* error count */ }; .Ed .El .Sh CONTROL MESSAGES The .Nm sscop node understands the generic control messages, plus the following: .Bl -tag -width foo .It Dv NGM_SSCOP_SETPARAM Pq Ic setparam Sets operational parameters of the SSCOP instance and takes the following structure: .Bd -literal struct ng_sscop_setparam { uint32_t mask; struct sscop_param param; }; .Ed .Pp The sub-structure .Va param contains the parameters to set, and the .Va mask field contains a bit mask, telling which of the parameters to set, and which to ignore. If a bit is set, the corresponding parameter is set. The parameters are: .Bd -literal struct sscop_param { uint32_t timer_cc; /* timer_cc in msec */ uint32_t timer_poll; /* timer_poll im msec */ uint32_t timer_keep_alive;/* timer_keep_alive in msec */ uint32_t timer_no_response;/*timer_no_response in msec */ uint32_t timer_idle; /* timer_idle in msec */ uint32_t maxk; /* maximum user data in bytes */ uint32_t maxj; /* maximum u-u info in bytes */ uint32_t maxcc; /* max. retransmissions for control packets */ uint32_t maxpd; /* max. vt(pd) before sending poll */ uint32_t maxstat; /* max. number of elements in stat list */ uint32_t mr; /* initial window */ uint32_t flags; /* flags */ }; .Ed .Pp The .Va flags field contains the following flags influencing SSCOP operation: .Pp .Bl -tag -width ".Dv SSCOP_POLLREX" -offset indent -compact .It Dv SSCOP_ROBUST enable atmf/97-0216 robustness enhancement .It Dv SSCOP_POLLREX send POLL after each retransmission .El .Pp The bitmap has the following bits: .Pp .Bl -tag -width ".Dv SSCOP_SET_POLLREX" -offset indent -compact .It Dv SSCOP_SET_TCC set .Va timer_cc .It Dv SSCOP_SET_TPOLL set .Va timer_poll .It Dv SSCOP_SET_TKA set .Va timer_keep_alive .It Dv SSCOP_SET_TNR set .Va timer_no_response .It Dv SSCOP_SET_TIDLE set .Va timer_idle .It Dv SSCOP_SET_MAXK set .Va maxk .It Dv SSCOP_SET_MAXJ set .Va maxj .It Dv SSCOP_SET_MAXCC set .Va maxcc .It Dv SSCOP_SET_MAXPD set .Va maxpd .It Dv SSCOP_SET_MAXSTAT set .Va maxstat .It Dv SSCOP_SET_MR set the initial window .It Dv SSCOP_SET_ROBUST set or clear .Dv SSCOP_ROBUST .It Dv SSCOP_SET_POLLREX set or clear .Dv SSCOP_POLLREX .El .Pp The node responds to the .Dv NGM_SSCOP_SETPARAM message with the following response: .Bd -literal struct ng_sscop_setparam_resp { uint32_t mask; int32_t error; }; .Ed .Pp Here .Va mask contains a bitmask of the parameters that the user requested to set, but that could not be set and .Va error is an .Xr errno 2 code describing why the parameter could not be set. .It Dv NGM_SSCOP_GETPARAM Pq Ic getparam This message returns the current operational parameters of the SSCOP instance in a .Vt sscop_param structure. .It Dv NGM_SSCOP_ENABLE Pq Ic enable This message creates the actual SSCOP instance and initializes it. Until this is done, parameters may neither be retrieved nor set, and all messages received on any hook are discarded. .It Dv NGM_SSCOP_DISABLE Pq Ic disable Destroy the SSCOP instance. After this, all messages on any hooks are discarded. .It Dv NGM_SSCOP_SETDEBUG Pq Ic setdebug Set debugging flags. The argument is a .Vt uint32_t . .It Dv NGM_SSCOP_GETDEBUG Pq Ic getdebug Retrieve the actual debugging flags. Needs no arguments and responds with a .Vt uint32_t . .It Dv NGM_SSCOP_GETSTATE Pq Ic getstate Responds with the current state of the SSCOP instance in a .Vt uint32_t . If the node is not enabled, the retrieved state is 0. .El .Sh FLOW CONTROL Flow control works on the upper and on the lower layer interface. At the lower layer interface, the two messages, .Dv NGM_HIGH_WATER_PASSED and .Dv NGM_LOW_WATER_PASSED , are used to declare or clear the .Dq "lower layer busy" state of the protocol. .Pp At the upper layer interface, the .Nm sscop node handles three types of flow control messages: .Bl -tag -width foo .It Dv NGM_HIGH_WATER_PASSED If this message is received, the SSCOP stops moving the receive window. Each time a data message is handed over to the upper layer, the receive window is moved by one message. Stopping these updates means that the window will start to close and if the peer has sent all messages allowed by the current window, it stops transmission. This means that the upper layer must be able to still receive a full window amount of messages. .It Dv NGM_LOW_WATER_PASSED This will re-enable the automatic window updates, and if the space indicated in the message is larger than the current window, the window will be opened by that amount. The space is computed as the difference of the .Va max_queuelen_packets and .Va current members of the .Vt ngm_queue_state structure. .It Dv NGM_SYNC_QUEUE_STATE If the upper layer buffer filling state, as indicated by .Va current , is equal to or greater than .Va high_watermark then the message is ignored. If this is not the case, the amount of receiver space is computed as the difference of .Va max_queuelen_packets and .Va current if automatic window updates are currently allowed, and as the difference of .Va high_water_mark and .Va current if window updates are disabled. If the resulting value is larger than the current window, the current window is opened up to this value. Automatic window updates are enabled if they were disabled. .El .Sh SEE ALSO .Xr netgraph 4 , .Xr ng_atm 4 , .Xr ng_sscfu 4 , .Xr ngctl 8 .Sh AUTHORS .An Harti Brandt Aq Mt harti@FreeBSD.org diff --git a/share/man/man4/ng_uni.4 b/share/man/man4/ng_uni.4 index da7028b0e015..993119d23c70 100644 --- a/share/man/man4/ng_uni.4 +++ b/share/man/man4/ng_uni.4 @@ -1,420 +1,425 @@ .\" .\" Copyright (c) 2001-2003 .\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). .\" All rights reserved. .\" .\" Author: Hartmut Brandt .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd October 6, 2003 +.Dd March 3, 2023 .Dt NG_UNI 4 .Os .Sh NAME .Nm ng_uni .Nd netgraph UNI node type .Sh SYNOPSIS .In netnatm/msg/unistruct.h .In netnatm/sig/unidef.h .In netgraph/atm/ng_uni.h +.Sh DEPRECATION NOTICE +.Nm +is deprecated and may not be available in +.Fx 14.0 +and later. .Sh DESCRIPTION The .Nm uni netgraph node type implements ATM Forum signalling 4.0. .Pp After creation of the node, the UNI instance must be created by sending an .Dq enable message to the node. If the node is enabled, the UNI parameters can be retrieved and modified, and the protocol can be started. .Pp The node is shut down either by an .Dv NGM_SHUTDOWN message, or when all hooks are disconnected. .Sh HOOKS Each .Nm uni node has three hooks with fixed names: .Bl -tag -width ".Va upper" .It Va lower This hook is the interface of the UNI protocol to the transport layer of the ATM control plane. The node expects the interface exported by .Xr ng_sscfu 4 at this hook. .It Va upper This hook is the .Dq user interface of the UNI protocol. Because there is no standardized interface at this point, this implementation follows more or less the interface specified by the SDL diagrams in ITU-T recommendations Q.2931 and Q.2971. Normally either a .Xr ng_ccatm 4 or a switch CAC should be stacked at this interface. The message format at the .Va upper hook is described below. Because .Xr netgraph 4 is functional, it makes sometimes sense to switch this hook to queueing mode from the peer node upon connection. .El .Pp The .Va upper interface of the .Nm uni node is loosely modelled after the interface specified in the ITU-T signalling standards. There is however one derivation from this: normally there exists four kinds of signals: requests, responses, indications and confirmations. These signals are usually triggered either by external events (receiving a message) or internal events (a timer or another signal). This scheme works fine for user APIs that are entirely asynchronous, and in cases where error handling is not taken into account. With synchronous APIs and error handling however, there is a problem. If, for example, the application issues a request to set up a connection, it may do it by sending a .Dv SETUP.request signal to the UNI. Normally, the UNI stack will send a SETUP message and receive a message from the switch (a RELEASE, CONNECT, CALL PROCEEDING or ALERTING), or a timer in the UNI stack will time out. In any of these cases, the UNI stack is supposed to report an event back to the application, and the application will unblock (in the case of a synchronous API) and handle the event. The problem occurs when an error happens. Suppose there is no memory to send the SETUP message and to start the timer. In this case, the application will block forever because no received message and no timer will wake it up. For this reason this implementation uses an additional message: for each signal sent from the application to the stack, the stack will respond with an error code. If this code is zero, the stack has accepted the signal and the application may block; if the code is non-zero, the signal is effectively ignored and the code describes what was wrong. This system makes it very easy to make a blocking interface out of the message based netgraph interface. .Pp The .Va upper interface uses the following structure: .Bd -literal struct uni_arg { uint32_t sig; uint32_t cookie; u_char data[]; }; .Ed The .Va sig field contains the actual signal that is sent from the user to UNI or from UNI to the user. The .Va cookie can be used by the user to correlate requests with events and responses. If an error response, a confirmation or an indication was triggered by a request or response, the cookie from that request or response is carried in the message from the stack to the user. The .Va cookie field is followed by the actual data for the signal. .Pp The signal is one of the following: .Bd -literal enum uni_sig { UNIAPI_ERROR, /* UNI -> API */ UNIAPI_CALL_CREATED, /* UNI -> API */ UNIAPI_CALL_DESTROYED, /* UNI -> API */ UNIAPI_PARTY_CREATED, /* UNI -> API */ UNIAPI_PARTY_DESTROYED, /* UNI -> API */ UNIAPI_LINK_ESTABLISH_request, /* API -> UNI */ UNIAPI_LINK_ESTABLISH_confirm, /* UNI -> API */ UNIAPI_LINK_RELEASE_request, /* API -> UNI */ UNIAPI_LINK_RELEASE_confirm, /* UNI -> API */ UNIAPI_RESET_request, /* API -> UNI */ UNIAPI_RESET_confirm, /* UNI -> API */ UNIAPI_RESET_indication, /* UNI -> API */ UNIAPI_RESET_ERROR_indication, /* UNI -> API */ UNIAPI_RESET_response, /* API -> UNI */ UNIAPI_RESET_ERROR_response, /* API -> UNI */ UNIAPI_RESET_STATUS_indication, /* UNI -> API */ UNIAPI_SETUP_request, /* API -> UNI */ UNIAPI_SETUP_indication, /* UNI -> API */ UNIAPI_SETUP_response, /* API -> UNI */ UNIAPI_SETUP_confirm, /* UNI -> API */ UNIAPI_SETUP_COMPLETE_indication, /* UNI -> API */ UNIAPI_ALERTING_request, /* API -> UNI */ UNIAPI_ALERTING_indication, /* UNI -> API */ UNIAPI_PROCEEDING_request, /* API -> UNI */ UNIAPI_PROCEEDING_indication, /* UNI -> API */ UNIAPI_RELEASE_request, /* API -> UNI */ UNIAPI_RELEASE_indication, /* UNI -> API */ UNIAPI_RELEASE_response, /* API -> UNI */ UNIAPI_RELEASE_confirm, /* UNI -> API */ UNIAPI_NOTIFY_request, /* API -> UNI */ UNIAPI_NOTIFY_indication, /* UNI -> API */ UNIAPI_STATUS_indication, /* UNI -> API */ UNIAPI_STATUS_ENQUIRY_request, /* API -> UNI */ UNIAPI_ADD_PARTY_request, /* API -> UNI */ UNIAPI_ADD_PARTY_indication, /* UNI -> API */ UNIAPI_PARTY_ALERTING_request, /* API -> UNI */ UNIAPI_PARTY_ALERTING_indication, /* UNI -> API */ UNIAPI_ADD_PARTY_ACK_request, /* API -> UNI */ UNIAPI_ADD_PARTY_ACK_indication, /* UNI -> API */ UNIAPI_ADD_PARTY_REJ_request, /* API -> UNI */ UNIAPI_ADD_PARTY_REJ_indication, /* UNI -> API */ UNIAPI_DROP_PARTY_request, /* API -> UNI */ UNIAPI_DROP_PARTY_indication, /* UNI -> API */ UNIAPI_DROP_PARTY_ACK_request, /* API -> UNI */ UNIAPI_DROP_PARTY_ACK_indication, /* UNI -> API */ UNIAPI_ABORT_CALL_request, /* API -> UNI */ UNIAPI_MAXSIG }; .Ed .Pp The meaning of most of the signals can be deduced from the ITU-T SDLs. A number of signals, however, is unique to this implementation: .Bl -tag -width foo .It Dv UNIAPI_ERROR This is the error response, mentioned earlier. It carries an error code or zero, if the signal was accepted by the stack. .It Dv UNIAPI_CALL_CREATED The UNI stack has created a call instance either from an incoming SETUP or from the user requesting an outgoing SETUP. This may be used to synchronize the creation and destroying of call data between the UNI stack and the user. .It Dv UNIAPI_CALL_DESTROYED A call instance has been destroyed and all resources have been freed. .It Dv UNIAPI_PARTY_CREATED A new party has been created for an existing point-to-multipoint call. This may be used to synchronize the creation and destroying of party data between the UNI stack and the user. .It Dv UNIAPI_PARTY_DESTROYED A party has been destroyed and all resources have been freed. .It Dv UNIAPI_ABORT_CALL_request This requests the stack to destroy the call instance and free all its resources, without sending any messages to the network. .It Dv UNIAPI_MAXSIG This is not a signal, but rather a definition to get the number of defined signals. .El .Pp Each of the signals is followed by a fixed size structure defined in .In netnatm/sig/unidef.h . .Sh CONTROL MESSAGES The .Nm uni node understands the standard control messages, plus the following: .Bl -tag -width foo .It Dv NGM_UNI_SETDEBUG Pq Ic setdebug Set debugging facility levels. The UNI stack defines a number of debugging facilities, each one associated with a debugging level. If the debugging level of a facility is non-zero, text output will be generated to the console. The message uses the following structure: .Bd -literal struct ngm_uni_debug { uint32_t level[UNI_MAXFACILITY]; }; .Ed .It Dv NGM_UNI_GETDEBUG Pq Ic getdebug Get debugging facility levels. This returns an .Vt ngm_uni_debug structure. .It Dv NGM_UNI_GET_CONFIG Pq Ic get_config Retrieve the current configuration of the UNI instance. This message returns a .Vt uni_config structure: .Bd -literal struct uni_config { uint32_t proto; /* which protocol */ uint32_t popt; /* protocol option */ uint32_t option; /* other options */ uint32_t timer301; /* T301 */ uint32_t timer303; /* T303 */ uint32_t init303; /* T303 retransmission count */ uint32_t timer308; /* T308 */ uint32_t init308; /* T308 retransmission count */ uint32_t timer309; /* T309 */ uint32_t timer310; /* T310 */ uint32_t timer313; /* T313 */ uint32_t timer316; /* T316 */ uint32_t init316; /* T316 retransmission count */ uint32_t timer317; /* T317 */ uint32_t timer322; /* T322 */ uint32_t init322; /* T322 retransmission count */ uint32_t timer397; /* T397 */ uint32_t timer398; /* T398 */ uint32_t timer399; /* T399 */ }; .Ed .Pp The field .Va proto specifies one of the following protocols: .Bd -literal enum uni_proto { UNIPROTO_UNI40U, /* UNI4.0 user side */ UNIPROTO_UNI40N, /* UNI4.0 network side */ UNIPROTO_PNNI10, /* PNNI1.0 */ }; .Ed .Pp Some protocols may have options which can be set in .Va popt : .Bd -literal enum uni_popt { UNIPROTO_GFP, /* enable GFP */ }; .Ed .Pp The .Va option field controls parsing and checking of messages: .Bd -literal enum uni_option { UNIOPT_GIT_HARD, /* harder check of GIT IE */ UNIOPT_BEARER_HARD, /* harder check of BEARER IE */ UNIOPT_CAUSE_HARD, /* harder check of CAUSE IE */ }; .Ed .Pp All timer values are given in milliseconds. Note, however, that the actual resolution of the timers depend on system configuration (see .Xr timeout 9 ) . .It Dv NGM_UNI_SET_CONFIG Pq Ic set_config Change the UNI configuration. This takes a .Bd -literal struct ngm_uni_set_config { struct uni_config config; struct ngm_uni_config_mask mask; }; struct ngm_uni_config_mask { uint32_t mask; uint32_t popt_mask; uint32_t option_mask; }; .Ed .Pp The fields of the .Vt ngm_uni_config_mask specify which configuration parameter to change. The .Va mask field contains bit definitions for all timers, retransmission counters and the .Va proto field, .Va popt_mask selects which of the protocol options to change, and .Va option_mask specifies which options should be changed. The following bits are defined: .Bd -literal enum uni_config_mask { UNICFG_PROTO, UNICFG_TIMER301, UNICFG_TIMER303, UNICFG_INIT303, UNICFG_TIMER308, UNICFG_INIT308, UNICFG_TIMER309, UNICFG_TIMER310, UNICFG_TIMER313, UNICFG_TIMER316, UNICFG_INIT316, UNICFG_TIMER317, UNICFG_TIMER322, UNICFG_INIT322, UNICFG_TIMER397, UNICFG_TIMER398, UNICFG_TIMER399, }; .Ed .Pp For .Va popt_mask and .Va option_mask , the definitions from .Vt "enum uni_popt" and .Vt "enum uni_option" should be used. .It Dv NGM_UNI_ENABLE Pq Ic enable Create the UNI instance and enable processing. Before the UNI is enabled parameters cannot be retrieved or set. .It Dv NGM_UNI_DISABLE Pq Ic disable Destroy the UNI instance and free all resources. Note, that connections are not released. .El .Sh SEE ALSO .Xr netgraph 4 , .Xr ng_atm 4 , .Xr ng_sscfu 4 , .Xr ng_sscop 4 , .Xr ngctl 8 .Sh AUTHORS The .Nm uni netgraph node and this manual page were written by .An Harti Brandt Aq Mt harti@FreeBSD.org .Sh BUGS .Bl -bullet -compact .It LIJ (leaf-initiated-join) is not implemented yet. .It GFP (generic functional protocol, Q.2932.1) is not yet implemented. .It More testing needed. .It PNNI not yet implemented. .It Need to implement connection modification and the Q.2931 amendments. .El diff --git a/share/man/man4/ngatmbase.4 b/share/man/man4/ngatmbase.4 index 0227b44347bd..6cdc3eb532fc 100644 --- a/share/man/man4/ngatmbase.4 +++ b/share/man/man4/ngatmbase.4 @@ -1,134 +1,139 @@ .\" .\" Copyright (c) 2004 .\" Hartmut Brandt. .\" All rights reserved. .\" .\" Author: Hartmut Brandt .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .\" ngatmbase(4) man page .\" -.Dd August 24, 2004 +.Dd March 3, 2023 .Dt NGATMBASE 4 .Os +.Sh DEPRECATION NOTICE +.Nm +is deprecated and may not be available in +.Fx 14.0 +and later. .Sh NAME .Nm ngatmbase .Nd netgraph ATM utility module .Sh SYNOPSIS .In netnatm/unimsg.h .In netgraph/atm/ngatmbase.h .Ft "struct mbuf *" .Fn uni_msg_pack_mbuf "struct uni_msg *msg" "void *hdr" "size_t len" .Ft "struct uni_msg *" .Fn uni_msg_alloc "size_t len" .Ft "struct uni_msg *" .Fn uni_msg_build "void *buf" ... .Ft void .Fn uni_msg_destroy "struct uni_msg *msg" .Ft int .Fn uni_msg_unpack_mbuf "struct mbuf *m" "struct uni_msg *msgp" .Sh DESCRIPTION This module provides utility functions for the handling of signalling messages to the NgATM modules. .Pp The .Fn uni_msg_pack_mbuf function packs a message into one or several .Vt mbuf Ns s optionally prepending a header. The header is given by its address .Fa hdr and length .Fa len . If .Fa hdr is .Dv NULL or .Fa len equals 0, no header is prepended. Either .Fa msg or .Fa hdr may be .Dv NULL but not both. The .Fn uni_msg_pack_mbuf function returns a pointer to the allocated .Vt mbuf chain or .Dv NULL in the case of an error. .Pp The .Fn uni_msg_alloc function allocates a new message with space for at least .Fa len bytes. In the case of an error .Dv NULL is returned. .Pp The .Fn uni_msg_build function constructs a message from pieces. Each piece is given by a pair of arguments, the first of type .Vt "void *" and the second a .Vt size_t . The list of pieces must be terminated by .Po Vt "void *" Pc Ns Dv NULL . .Pp The .Fn uni_msg_destroy function destroys the messages and frees all the messages's memory. .Pp The .Fn uni_msg_unpack_mbuf function unpacks an .Vt mbuf chain info a .Vt uni_msg . A pointer to the newly allocated message is stored in .Fa msgp and 0 is returned. In the case of an error (either when no packet header is found in the first mbuf or memory cannot be allocated) the function returns an appropriate error code. .Sh SEE ALSO .Xr ng_ccatm 4 , .Xr ng_sscfu 4 , .Xr ng_sscop 4 , .Xr ng_uni 4 .Sh AUTHORS .An Harti Brandt Aq Mt harti@FreeBSD.org diff --git a/sys/netgraph/atm/ccatm/ng_ccatm.c b/sys/netgraph/atm/ccatm/ng_ccatm.c index 6c27b6aacc0f..4a7af2c4579b 100644 --- a/sys/netgraph/atm/ccatm/ng_ccatm.c +++ b/sys/netgraph/atm/ccatm/ng_ccatm.c @@ -1,1191 +1,1193 @@ /*- * Copyright (c) 2001-2002 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). * All rights reserved. * Copyright (c) 2003-2004 * Hartmut Brandt * All rights reserved. * * Author: Harti Brandt * * Redistribution of this software and documentation and use in source and * binary forms, with or without modification, are permitted provided that * the following conditions are met: * * 1. Redistributions of source code or documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * * ATM call control and API */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include MODULE_DEPEND(ng_ccatm, ngatmbase, 1, 1, 1); MALLOC_DEFINE(M_NG_CCATM, "ng_ccatm", "netgraph uni api node"); /* * Command structure parsing */ /* ESI */ static const struct ng_parse_fixedarray_info ng_ccatm_esi_type_info = NGM_CCATM_ESI_INFO; static const struct ng_parse_type ng_ccatm_esi_type = { &ng_parse_fixedarray_type, &ng_ccatm_esi_type_info }; /* PORT PARAMETERS */ static const struct ng_parse_struct_field ng_ccatm_atm_port_type_info[] = NGM_CCATM_ATM_PORT_INFO; static const struct ng_parse_type ng_ccatm_atm_port_type = { &ng_parse_struct_type, ng_ccatm_atm_port_type_info }; /* PORT structure */ static const struct ng_parse_struct_field ng_ccatm_port_type_info[] = NGM_CCATM_PORT_INFO; static const struct ng_parse_type ng_ccatm_port_type = { &ng_parse_struct_type, ng_ccatm_port_type_info }; /* the ADDRESS array itself */ static const struct ng_parse_fixedarray_info ng_ccatm_addr_array_type_info = NGM_CCATM_ADDR_ARRAY_INFO; static const struct ng_parse_type ng_ccatm_addr_array_type = { &ng_parse_fixedarray_type, &ng_ccatm_addr_array_type_info }; /* one ADDRESS */ static const struct ng_parse_struct_field ng_ccatm_uni_addr_type_info[] = NGM_CCATM_UNI_ADDR_INFO; static const struct ng_parse_type ng_ccatm_uni_addr_type = { &ng_parse_struct_type, ng_ccatm_uni_addr_type_info }; /* ADDRESS request */ static const struct ng_parse_struct_field ng_ccatm_addr_req_type_info[] = NGM_CCATM_ADDR_REQ_INFO; static const struct ng_parse_type ng_ccatm_addr_req_type = { &ng_parse_struct_type, ng_ccatm_addr_req_type_info }; /* ADDRESS var-array */ static int ng_ccatm_addr_req_array_getlen(const struct ng_parse_type *type, const u_char *start, const u_char *buf) { const struct ngm_ccatm_get_addresses *p; p = (const struct ngm_ccatm_get_addresses *) (buf - offsetof(struct ngm_ccatm_get_addresses, addr)); return (p->count); } static const struct ng_parse_array_info ng_ccatm_addr_req_array_type_info = NGM_CCATM_ADDR_REQ_ARRAY_INFO; static const struct ng_parse_type ng_ccatm_addr_req_array_type = { &ng_parse_array_type, &ng_ccatm_addr_req_array_type_info }; /* Outer get_ADDRESSes structure */ static const struct ng_parse_struct_field ng_ccatm_get_addresses_type_info[] = NGM_CCATM_GET_ADDRESSES_INFO; static const struct ng_parse_type ng_ccatm_get_addresses_type = { &ng_parse_struct_type, ng_ccatm_get_addresses_type_info }; /* Port array */ static int ng_ccatm_port_array_getlen(const struct ng_parse_type *type, const u_char *start, const u_char *buf) { const struct ngm_ccatm_portlist *p; p = (const struct ngm_ccatm_portlist *) (buf - offsetof(struct ngm_ccatm_portlist, ports)); return (p->nports); } static const struct ng_parse_array_info ng_ccatm_port_array_type_info = NGM_CCATM_PORT_ARRAY_INFO; static const struct ng_parse_type ng_ccatm_port_array_type = { &ng_parse_array_type, &ng_ccatm_port_array_type_info }; /* Portlist structure */ static const struct ng_parse_struct_field ng_ccatm_portlist_type_info[] = NGM_CCATM_PORTLIST_INFO; static const struct ng_parse_type ng_ccatm_portlist_type = { &ng_parse_struct_type, ng_ccatm_portlist_type_info }; /* * Command list */ static const struct ng_cmdlist ng_ccatm_cmdlist[] = { { NGM_CCATM_COOKIE, NGM_CCATM_DUMP, "dump", NULL, NULL }, { NGM_CCATM_COOKIE, NGM_CCATM_STOP, "stop", &ng_ccatm_port_type, NULL }, { NGM_CCATM_COOKIE, NGM_CCATM_START, "start", &ng_ccatm_port_type, NULL }, { NGM_CCATM_COOKIE, NGM_CCATM_GETSTATE, "getstate", &ng_ccatm_port_type, &ng_parse_uint32_type }, { NGM_CCATM_COOKIE, NGM_CCATM_GET_ADDRESSES, "get_addresses", &ng_ccatm_port_type, &ng_ccatm_get_addresses_type }, { NGM_CCATM_COOKIE, NGM_CCATM_CLEAR, "clear", &ng_ccatm_port_type, NULL }, { NGM_CCATM_COOKIE, NGM_CCATM_ADDRESS_REGISTERED, "address_reg", &ng_ccatm_addr_req_type, NULL }, { NGM_CCATM_COOKIE, NGM_CCATM_ADDRESS_UNREGISTERED, "address_unreg", &ng_ccatm_addr_req_type, NULL }, { NGM_CCATM_COOKIE, NGM_CCATM_SET_PORT_PARAM, "set_port_param", &ng_ccatm_atm_port_type, NULL }, { NGM_CCATM_COOKIE, NGM_CCATM_GET_PORT_PARAM, "get_port_param", &ng_ccatm_port_type, &ng_ccatm_atm_port_type, }, { NGM_CCATM_COOKIE, NGM_CCATM_GET_PORTLIST, "get_portlist", NULL, &ng_ccatm_portlist_type, }, { NGM_CCATM_COOKIE, NGM_CCATM_SETLOG, "setlog", &ng_parse_hint32_type, &ng_parse_hint32_type, }, { NGM_CCATM_COOKIE, NGM_CCATM_RESET, "reset", NULL, NULL, }, { 0 } }; /* * Module data */ static ng_constructor_t ng_ccatm_constructor; static ng_rcvmsg_t ng_ccatm_rcvmsg; static ng_shutdown_t ng_ccatm_shutdown; static ng_newhook_t ng_ccatm_newhook; static ng_rcvdata_t ng_ccatm_rcvdata; static ng_disconnect_t ng_ccatm_disconnect; static int ng_ccatm_mod_event(module_t, int, void *); static struct ng_type ng_ccatm_typestruct = { .version = NG_ABI_VERSION, .name = NG_CCATM_NODE_TYPE, .mod_event = ng_ccatm_mod_event, .constructor = ng_ccatm_constructor, /* Node constructor */ .rcvmsg = ng_ccatm_rcvmsg, /* Control messages */ .shutdown = ng_ccatm_shutdown, /* Node destructor */ .newhook = ng_ccatm_newhook, /* Arrival of new hook */ .rcvdata = ng_ccatm_rcvdata, /* receive data */ .disconnect = ng_ccatm_disconnect, /* disconnect a hook */ .cmdlist = ng_ccatm_cmdlist, }; NETGRAPH_INIT(ccatm, &ng_ccatm_typestruct); static ng_rcvdata_t ng_ccatm_rcvuni; static ng_rcvdata_t ng_ccatm_rcvdump; static ng_rcvdata_t ng_ccatm_rcvmanage; /* * Private node data. */ struct ccnode { node_p node; /* the owning node */ hook_p dump; /* dump hook */ hook_p manage; /* hook to ILMI */ struct ccdata *data; struct mbuf *dump_first; struct mbuf *dump_last; /* first and last mbuf when dumping */ u_int hook_cnt; /* count user and port hooks */ }; /* * Private UNI hook data */ struct cchook { int is_uni; /* true if uni hook, user otherwise */ struct ccnode *node; /* the owning node */ hook_p hook; void *inst; /* port or user */ }; static void ng_ccatm_send_user(struct ccuser *, void *, u_int, void *, size_t); static void ng_ccatm_respond_user(struct ccuser *, void *, int, u_int, void *, size_t); static void ng_ccatm_send_uni(struct ccconn *, void *, u_int, u_int, struct uni_msg *); static void ng_ccatm_send_uni_glob(struct ccport *, void *, u_int, u_int, struct uni_msg *); static void ng_ccatm_log(const char *, ...) __printflike(1, 2); static const struct cc_funcs cc_funcs = { .send_user = ng_ccatm_send_user, .respond_user = ng_ccatm_respond_user, .send_uni = ng_ccatm_send_uni, .send_uni_glob = ng_ccatm_send_uni_glob, .log = ng_ccatm_log, }; /************************************************************ * * Create a new node */ static int ng_ccatm_constructor(node_p node) { struct ccnode *priv; + gone_in(14, "ng_ccatm: netgraph ATM modules"); + priv = malloc(sizeof(*priv), M_NG_CCATM, M_WAITOK | M_ZERO); priv->node = node; priv->data = cc_create(&cc_funcs); if (priv->data == NULL) { free(priv, M_NG_CCATM); return (ENOMEM); } NG_NODE_SET_PRIVATE(node, priv); return (0); } /* * Destroy a node. The user list is empty here, because all hooks are * previously disconnected. The connection lists may not be empty, because * connections may be waiting for responses from the stack. This also means, * that no orphaned connections will be made by the port_destroy routine. */ static int ng_ccatm_shutdown(node_p node) { struct ccnode *priv = NG_NODE_PRIVATE(node); cc_destroy(priv->data); free(priv, M_NG_CCATM); NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); return (0); } /* * Retrieve the registered addresses for one port or all ports. * Returns an error code or 0 on success. */ static int ng_ccatm_get_addresses(node_p node, uint32_t portno, struct ng_mesg *msg, struct ng_mesg **resp) { struct ccnode *priv = NG_NODE_PRIVATE(node); struct uni_addr *addrs; u_int *ports; struct ngm_ccatm_get_addresses *list; u_int count, i; size_t len; int err; err = cc_get_addrs(priv->data, portno, &addrs, &ports, &count); if (err != 0) return (err); len = sizeof(*list) + count * sizeof(list->addr[0]); NG_MKRESPONSE(*resp, msg, len, M_NOWAIT); if (*resp == NULL) { free(addrs, M_NG_CCATM); free(ports, M_NG_CCATM); return (ENOMEM); } list = (struct ngm_ccatm_get_addresses *)(*resp)->data; list->count = count; for (i = 0; i < count; i++) { list->addr[i].port = ports[i]; list->addr[i].addr = addrs[i]; } free(addrs, M_NG_CCATM); free(ports, M_NG_CCATM); return (0); } /* * Dumper function. Pack the data into an mbuf chain. */ static int send_dump(struct ccdata *data, void *uarg, const char *buf) { struct mbuf *m; struct ccnode *priv = uarg; if (priv->dump == NULL) { m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m == NULL) return (ENOBUFS); priv->dump_first = priv->dump_last = m; m->m_pkthdr.len = 0; } else { m = m_getcl(M_NOWAIT, MT_DATA, 0); if (m == NULL) { m_freem(priv->dump_first); return (ENOBUFS); } priv->dump_last->m_next = m; priv->dump_last = m; } strcpy(m->m_data, buf); priv->dump_first->m_pkthdr.len += (m->m_len = strlen(buf)); return (0); } /* * Dump current status to dump hook */ static int ng_ccatm_dump(node_p node) { struct ccnode *priv = NG_NODE_PRIVATE(node); struct mbuf *m; int error; priv->dump_first = priv->dump_last = NULL; error = cc_dump(priv->data, MCLBYTES, send_dump, priv); if (error != 0) return (error); if ((m = priv->dump_first) != NULL) { priv->dump_first = priv->dump_last = NULL; NG_SEND_DATA_ONLY(error, priv->dump, m); return (error); } return (0); } /* * Control message */ static int ng_ccatm_rcvmsg(node_p node, item_p item, hook_p lasthook) { struct ng_mesg *resp = NULL; struct ng_mesg *msg; struct ccnode *priv = NG_NODE_PRIVATE(node); int error = 0; NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_CCATM_COOKIE: switch (msg->header.cmd) { case NGM_CCATM_DUMP: if (priv->dump) error = ng_ccatm_dump(node); else error = ENOTCONN; break; case NGM_CCATM_STOP: { struct ngm_ccatm_port *arg; if (msg->header.arglen != sizeof(*arg)) { error = EINVAL; break; } arg = (struct ngm_ccatm_port *)msg->data; error = cc_port_stop(priv->data, arg->port); break; } case NGM_CCATM_START: { struct ngm_ccatm_port *arg; if (msg->header.arglen != sizeof(*arg)) { error = EINVAL; break; } arg = (struct ngm_ccatm_port *)msg->data; error = cc_port_start(priv->data, arg->port); break; } case NGM_CCATM_GETSTATE: { struct ngm_ccatm_port *arg; int state; if (msg->header.arglen != sizeof(*arg)) { error = EINVAL; break; } arg = (struct ngm_ccatm_port *)msg->data; error = cc_port_isrunning(priv->data, arg->port, &state); if (error == 0) { NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } *(uint32_t *)resp->data = state; } break; } case NGM_CCATM_GET_ADDRESSES: { struct ngm_ccatm_port *arg; if (msg->header.arglen != sizeof(*arg)) { error = EINVAL; break; } arg = (struct ngm_ccatm_port *)msg->data; error = ng_ccatm_get_addresses(node, arg->port, msg, &resp); break; } case NGM_CCATM_CLEAR: { struct ngm_ccatm_port *arg; if (msg->header.arglen != sizeof(*arg)) { error = EINVAL; break; } arg = (struct ngm_ccatm_port *)msg->data; error = cc_port_clear(priv->data, arg->port); break; } case NGM_CCATM_ADDRESS_REGISTERED: { struct ngm_ccatm_addr_req *arg; if (msg->header.arglen != sizeof(*arg)) { error = EINVAL; break; } arg = (struct ngm_ccatm_addr_req *)msg->data; error = cc_addr_register(priv->data, arg->port, &arg->addr); break; } case NGM_CCATM_ADDRESS_UNREGISTERED: { struct ngm_ccatm_addr_req *arg; if (msg->header.arglen != sizeof(*arg)) { error = EINVAL; break; } arg = (struct ngm_ccatm_addr_req *)msg->data; error = cc_addr_unregister(priv->data, arg->port, &arg->addr); break; } case NGM_CCATM_GET_PORT_PARAM: { struct ngm_ccatm_port *arg; if (msg->header.arglen != sizeof(*arg)) { error = EINVAL; break; } arg = (struct ngm_ccatm_port *)msg->data; NG_MKRESPONSE(resp, msg, sizeof(struct atm_port_info), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } error = cc_port_get_param(priv->data, arg->port, (struct atm_port_info *)resp->data); if (error != 0) { free(resp, M_NETGRAPH_MSG); resp = NULL; } break; } case NGM_CCATM_SET_PORT_PARAM: { struct atm_port_info *arg; if (msg->header.arglen != sizeof(*arg)) { error = EINVAL; break; } arg = (struct atm_port_info *)msg->data; error = cc_port_set_param(priv->data, arg); break; } case NGM_CCATM_GET_PORTLIST: { struct ngm_ccatm_portlist *arg; u_int n, *ports; if (msg->header.arglen != 0) { error = EINVAL; break; } error = cc_port_getlist(priv->data, &n, &ports); if (error != 0) break; NG_MKRESPONSE(resp, msg, sizeof(*arg) + n * sizeof(arg->ports[0]), M_NOWAIT); if (resp == NULL) { free(ports, M_NG_CCATM); error = ENOMEM; break; } arg = (struct ngm_ccatm_portlist *)resp->data; arg->nports = 0; for (arg->nports = 0; arg->nports < n; arg->nports++) arg->ports[arg->nports] = ports[arg->nports]; free(ports, M_NG_CCATM); break; } case NGM_CCATM_SETLOG: { uint32_t log_level; log_level = cc_get_log(priv->data); if (msg->header.arglen != 0) { if (msg->header.arglen != sizeof(log_level)) { error = EINVAL; break; } cc_set_log(priv->data, *(uint32_t *)msg->data); } NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); if (resp == NULL) { error = ENOMEM; if (msg->header.arglen != 0) cc_set_log(priv->data, log_level); break; } *(uint32_t *)resp->data = log_level; break; } case NGM_CCATM_RESET: if (msg->header.arglen != 0) { error = EINVAL; break; } if (priv->hook_cnt != 0) { error = EBUSY; break; } cc_reset(priv->data); break; case NGM_CCATM_GET_EXSTAT: { struct atm_exstatus s; struct atm_exstatus_ep *eps; struct atm_exstatus_port *ports; struct atm_exstatus_conn *conns; struct atm_exstatus_party *parties; size_t offs; if (msg->header.arglen != 0) { error = EINVAL; break; } error = cc_get_extended_status(priv->data, &s, &eps, &ports, &conns, &parties); if (error != 0) break; offs = sizeof(s) + s.neps * sizeof(*eps) + s.nports * sizeof(*ports) + s.nconns * sizeof(*conns) + s.nparties * sizeof(*parties); NG_MKRESPONSE(resp, msg, offs, M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } memcpy(resp->data, &s, sizeof(s)); offs = sizeof(s); memcpy(resp->data + offs, eps, sizeof(*eps) * s.neps); offs += sizeof(*eps) * s.neps; memcpy(resp->data + offs, ports, sizeof(*ports) * s.nports); offs += sizeof(*ports) * s.nports; memcpy(resp->data + offs, conns, sizeof(*conns) * s.nconns); offs += sizeof(*conns) * s.nconns; memcpy(resp->data + offs, parties, sizeof(*parties) * s.nparties); offs += sizeof(*parties) * s.nparties; free(eps, M_NG_CCATM); free(ports, M_NG_CCATM); free(conns, M_NG_CCATM); free(parties, M_NG_CCATM); break; } default: error = EINVAL; break; } break; default: error = EINVAL; break; } NG_RESPOND_MSG(error, node, item, resp); NG_FREE_MSG(msg); return (error); } /************************************************************ * * New hook arrival */ static int ng_ccatm_newhook(node_p node, hook_p hook, const char *name) { struct ccnode *priv = NG_NODE_PRIVATE(node); struct ccport *port; struct ccuser *user; struct cchook *hd; u_long lport; char *end; if (strncmp(name, "uni", 3) == 0) { /* * This is a UNI hook. Should be a new port. */ if (name[3] == '\0') return (EINVAL); lport = strtoul(name + 3, &end, 10); if (*end != '\0' || lport == 0 || lport > 0xffffffff) return (EINVAL); hd = malloc(sizeof(*hd), M_NG_CCATM, M_NOWAIT); if (hd == NULL) return (ENOMEM); hd->is_uni = 1; hd->node = priv; hd->hook = hook; port = cc_port_create(priv->data, hd, (u_int)lport); if (port == NULL) { free(hd, M_NG_CCATM); return (ENOMEM); } hd->inst = port; NG_HOOK_SET_PRIVATE(hook, hd); NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvuni); NG_HOOK_FORCE_QUEUE(hook); priv->hook_cnt++; return (0); } if (strcmp(name, "dump") == 0) { priv->dump = hook; NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvdump); return (0); } if (strcmp(name, "manage") == 0) { priv->manage = hook; NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvmanage); return (0); } /* * User hook */ hd = malloc(sizeof(*hd), M_NG_CCATM, M_NOWAIT); if (hd == NULL) return (ENOMEM); hd->is_uni = 0; hd->node = priv; hd->hook = hook; user = cc_user_create(priv->data, hd, NG_HOOK_NAME(hook)); if (user == NULL) { free(hd, M_NG_CCATM); return (ENOMEM); } hd->inst = user; NG_HOOK_SET_PRIVATE(hook, hd); NG_HOOK_FORCE_QUEUE(hook); priv->hook_cnt++; return (0); } /* * Disconnect a hook */ static int ng_ccatm_disconnect(hook_p hook) { node_p node = NG_HOOK_NODE(hook); struct ccnode *priv = NG_NODE_PRIVATE(node); struct cchook *hd = NG_HOOK_PRIVATE(hook); struct ccdata *cc; if (hook == priv->dump) { priv->dump = NULL; } else if (hook == priv->manage) { priv->manage = NULL; cc_unmanage(priv->data); } else { if (hd->is_uni) cc_port_destroy(hd->inst, 0); else cc_user_destroy(hd->inst); cc = hd->node->data; free(hd, M_NG_CCATM); NG_HOOK_SET_PRIVATE(hook, NULL); priv->hook_cnt--; cc_work(cc); } /* * When the number of hooks drops to zero, delete the node. */ if (NG_NODE_NUMHOOKS(node) == 0 && NG_NODE_IS_VALID(node)) ng_rmnode_self(node); return (0); } /************************************************************ * * Receive data from user hook */ static int ng_ccatm_rcvdata(hook_p hook, item_p item) { struct cchook *hd = NG_HOOK_PRIVATE(hook); struct uni_msg *msg; struct mbuf *m; struct ccatm_op op; int err; NGI_GET_M(item, m); NG_FREE_ITEM(item); if ((err = uni_msg_unpack_mbuf(m, &msg)) != 0) { m_freem(m); return (err); } m_freem(m); if (uni_msg_len(msg) < sizeof(op)) { printf("%s: packet too short\n", __func__); uni_msg_destroy(msg); return (EINVAL); } bcopy(msg->b_rptr, &op, sizeof(op)); msg->b_rptr += sizeof(op); err = cc_user_signal(hd->inst, op.op, msg); cc_work(hd->node->data); return (err); } /* * Pack a header and a data area into an mbuf chain */ static struct mbuf * pack_buf(void *h, size_t hlen, void *t, size_t tlen) { struct mbuf *m, *m0, *last; u_char *buf = (u_char *)t; size_t n; /* header should fit into a normal mbuf */ MGETHDR(m0, M_NOWAIT, MT_DATA); if (m0 == NULL) return NULL; KASSERT(hlen <= MHLEN, ("hlen > MHLEN")); bcopy(h, m0->m_data, hlen); m0->m_len = hlen; m0->m_pkthdr.len = hlen; last = m0; while ((n = tlen) != 0) { if (n > MLEN) { m = m_getcl(M_NOWAIT, MT_DATA, 0); if (n > MCLBYTES) n = MCLBYTES; } else MGET(m, M_NOWAIT, MT_DATA); if(m == NULL) goto drop; last->m_next = m; last = m; bcopy(buf, m->m_data, n); buf += n; tlen -= n; m->m_len = n; m0->m_pkthdr.len += n; } return (m0); drop: m_freem(m0); return NULL; } /* * Send an indication to the user. */ static void ng_ccatm_send_user(struct ccuser *user, void *uarg, u_int op, void *val, size_t len) { struct cchook *hd = uarg; struct mbuf *m; struct ccatm_op h; int error; h.op = op; m = pack_buf(&h, sizeof(h), val, len); if (m == NULL) return; NG_SEND_DATA_ONLY(error, hd->hook, m); if (error != 0) printf("%s: error=%d\n", __func__, error); } /* * Send a response to the user. */ static void ng_ccatm_respond_user(struct ccuser *user, void *uarg, int err, u_int data, void *val, size_t len) { struct cchook *hd = uarg; struct mbuf *m; struct { struct ccatm_op op; struct atm_resp resp; } resp; int error; resp.op.op = ATMOP_RESP; resp.resp.resp = err; resp.resp.data = data; m = pack_buf(&resp, sizeof(resp), val, len); if (m == NULL) return; NG_SEND_DATA_ONLY(error, hd->hook, m); if (error != 0) printf("%s: error=%d\n", __func__, error); } /* * Receive data from UNI. */ static int ng_ccatm_rcvuni(hook_p hook, item_p item) { struct cchook *hd = NG_HOOK_PRIVATE(hook); struct uni_msg *msg; struct uni_arg arg; struct mbuf *m; int err; NGI_GET_M(item, m); NG_FREE_ITEM(item); if ((err = uni_msg_unpack_mbuf(m, &msg)) != 0) { m_freem(m); return (err); } m_freem(m); if (uni_msg_len(msg) < sizeof(arg)) { printf("%s: packet too short\n", __func__); uni_msg_destroy(msg); return (EINVAL); } bcopy(msg->b_rptr, &arg, sizeof(arg)); msg->b_rptr += sizeof(arg); if (arg.sig == UNIAPI_ERROR) { if (uni_msg_len(msg) != sizeof(struct uniapi_error)) { printf("%s: bad UNIAPI_ERROR size %zu\n", __func__, uni_msg_len(msg)); uni_msg_destroy(msg); return (EINVAL); } err = cc_uni_response(hd->inst, arg.cookie, ((struct uniapi_error *)msg->b_rptr)->reason, ((struct uniapi_error *)msg->b_rptr)->state); uni_msg_destroy(msg); } else err = cc_uni_signal(hd->inst, arg.cookie, arg.sig, msg); cc_work(hd->node->data); return (err); } /* * Uarg is the port's uarg. */ static void ng_ccatm_send_uni(struct ccconn *conn, void *uarg, u_int op, u_int cookie, struct uni_msg *msg) { struct cchook *hd = uarg; struct uni_arg arg; struct mbuf *m; int error; arg.sig = op; arg.cookie = cookie; m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg)); uni_msg_destroy(msg); if (m == NULL) return; NG_SEND_DATA_ONLY(error, hd->hook, m); if (error != 0) printf("%s: error=%d\n", __func__, error); } /* * Send a global message to the UNI */ static void ng_ccatm_send_uni_glob(struct ccport *port, void *uarg, u_int op, u_int cookie, struct uni_msg *msg) { struct cchook *hd = uarg; struct uni_arg arg; struct mbuf *m; int error; arg.sig = op; arg.cookie = cookie; m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg)); if (msg != NULL) uni_msg_destroy(msg); if (m == NULL) return; NG_SEND_DATA_ONLY(error, hd->hook, m); if (error != 0) printf("%s: error=%d\n", __func__, error); } /* * Receive from ILMID */ static int ng_ccatm_rcvmanage(hook_p hook, item_p item) { NG_FREE_ITEM(item); return (0); } static int ng_ccatm_rcvdump(hook_p hook, item_p item) { NG_FREE_ITEM(item); return (0); } static void ng_ccatm_log(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vprintf(fmt, ap); printf("\n"); va_end(ap); } /* * Loading and unloading of node type */ static int ng_ccatm_mod_event(module_t mod, int event, void *data) { int error = 0; switch (event) { case MOD_LOAD: break; case MOD_UNLOAD: break; default: error = EOPNOTSUPP; break; } return (error); } diff --git a/sys/netgraph/atm/ngatmbase.c b/sys/netgraph/atm/ngatmbase.c index 785bbef26580..0e2d1597d696 100644 --- a/sys/netgraph/atm/ngatmbase.c +++ b/sys/netgraph/atm/ngatmbase.c @@ -1,500 +1,502 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2001-2003 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). * All rights reserved. * * Author: Hartmut Brandt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * In-kernel UNI stack message functions. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #define NGATMBASE_VERSION 1 static int ngatm_handler(module_t, int, void *); static moduledata_t ngatm_data = { "ngatmbase", ngatm_handler, 0 }; MODULE_VERSION(ngatmbase, NGATMBASE_VERSION); DECLARE_MODULE(ngatmbase, ngatm_data, SI_SUB_EXEC, SI_ORDER_ANY); /*********************************************************************/ /* * UNI Stack message handling functions */ static MALLOC_DEFINE(M_UNIMSG, "unimsg", "uni message buffers"); static MALLOC_DEFINE(M_UNIMSGHDR, "unimsghdr", "uni message headers"); #define EXTRA 128 /* mutex to protect the free list (and the used list if debugging) */ static struct mtx ngatm_unilist_mtx; /* * Initialize UNI message subsystem */ static void uni_msg_init(void) { + gone_in(14, "ngatmbase: netgraph ATM modules"); + mtx_init(&ngatm_unilist_mtx, "netgraph UNI msg header lists", NULL, MTX_DEF); } /* * Ensure, that the message can be extended by at least s bytes. * Re-allocate the message (not the header). If that fails, * free the entire message and return ENOMEM. Free space at the start of * the message is retained. */ int uni_msg_extend(struct uni_msg *m, size_t s) { u_char *b; size_t len, lead; lead = uni_msg_leading(m); len = uni_msg_len(m); s += lead + len + EXTRA; if ((b = malloc(s, M_UNIMSG, M_NOWAIT)) == NULL) { uni_msg_destroy(m); return (ENOMEM); } bcopy(m->b_rptr, b + lead, len); free(m->b_buf, M_UNIMSG); m->b_buf = b; m->b_rptr = m->b_buf + lead; m->b_wptr = m->b_rptr + len; m->b_lim = m->b_buf + s; return (0); } /* * Append a buffer to the message, making space if needed. * If reallocation files, ENOMEM is returned and the message freed. */ int uni_msg_append(struct uni_msg *m, void *buf, size_t size) { int error; if ((error = uni_msg_ensure(m, size))) return (error); bcopy(buf, m->b_wptr, size); m->b_wptr += size; return (0); } /* * Pack/unpack data from/into mbufs. Assume, that the (optional) header * fits into the first mbuf, ie. hdrlen < MHLEN. Note, that the message * can be NULL, but hdrlen should not be 0 in this case. */ struct mbuf * uni_msg_pack_mbuf(struct uni_msg *msg, void *hdr, size_t hdrlen) { struct mbuf *m, *m0, *last; size_t n; MGETHDR(m0, M_NOWAIT, MT_DATA); if (m0 == NULL) return (NULL); KASSERT(hdrlen <= MHLEN, ("uni_msg_pack_mbuf: hdrlen > MHLEN")); if (hdrlen != 0) { bcopy(hdr, m0->m_data, hdrlen); m0->m_len = hdrlen; m0->m_pkthdr.len = hdrlen; } else { if ((n = uni_msg_len(msg)) > MHLEN) { if (!(MCLGET(m0, M_NOWAIT))) goto drop; if (n > MCLBYTES) n = MCLBYTES; } bcopy(msg->b_rptr, m0->m_data, n); msg->b_rptr += n; m0->m_len = n; m0->m_pkthdr.len = n; } last = m0; while (msg != NULL && (n = uni_msg_len(msg)) != 0) { MGET(m, M_NOWAIT, MT_DATA); if (m == NULL) goto drop; last->m_next = m; last = m; if (n > MLEN) { if (!(MCLGET(m, M_NOWAIT))) goto drop; if (n > MCLBYTES) n = MCLBYTES; } bcopy(msg->b_rptr, m->m_data, n); msg->b_rptr += n; m->m_len = n; m0->m_pkthdr.len += n; } return (m0); drop: m_freem(m0); return (NULL); } #ifdef NGATM_DEBUG /* * Prepend a debugging header to each message */ struct ngatm_msg { LIST_ENTRY(ngatm_msg) link; const char *file; int line; struct uni_msg msg; }; /* * These are the lists of free and used message headers. */ static LIST_HEAD(, ngatm_msg) ngatm_freeuni = LIST_HEAD_INITIALIZER(ngatm_freeuni); static LIST_HEAD(, ngatm_msg) ngatm_useduni = LIST_HEAD_INITIALIZER(ngatm_useduni); /* * Clean-up UNI message subsystem */ static void uni_msg_fini(void) { struct ngatm_msg *h; /* free all free message headers */ while ((h = LIST_FIRST(&ngatm_freeuni)) != NULL) { LIST_REMOVE(h, link); free(h, M_UNIMSGHDR); } /* forget about still used messages */ LIST_FOREACH(h, &ngatm_useduni, link) printf("unimsg header in use: %p (%s, %d)\n", &h->msg, h->file, h->line); mtx_destroy(&ngatm_unilist_mtx); } /* * Allocate a message, that can hold at least s bytes. */ struct uni_msg * _uni_msg_alloc(size_t s, const char *file, int line) { struct ngatm_msg *m; mtx_lock(&ngatm_unilist_mtx); if ((m = LIST_FIRST(&ngatm_freeuni)) != NULL) LIST_REMOVE(m, link); mtx_unlock(&ngatm_unilist_mtx); if (m == NULL && (m = malloc(sizeof(*m), M_UNIMSGHDR, M_NOWAIT)) == NULL) return (NULL); s += EXTRA; if((m->msg.b_buf = malloc(s, M_UNIMSG, M_NOWAIT | M_ZERO)) == NULL) { mtx_lock(&ngatm_unilist_mtx); LIST_INSERT_HEAD(&ngatm_freeuni, m, link); mtx_unlock(&ngatm_unilist_mtx); return (NULL); } m->msg.b_rptr = m->msg.b_wptr = m->msg.b_buf; m->msg.b_lim = m->msg.b_buf + s; m->file = file; m->line = line; mtx_lock(&ngatm_unilist_mtx); LIST_INSERT_HEAD(&ngatm_useduni, m, link); mtx_unlock(&ngatm_unilist_mtx); return (&m->msg); } /* * Destroy a UNI message. * The header is inserted into the free header list. */ void _uni_msg_destroy(struct uni_msg *m, const char *file, int line) { struct ngatm_msg *h, *d; d = (struct ngatm_msg *)((char *)m - offsetof(struct ngatm_msg, msg)); mtx_lock(&ngatm_unilist_mtx); LIST_FOREACH(h, &ngatm_useduni, link) if (h == d) break; if (h == NULL) { /* * Not on used list. Ups. */ LIST_FOREACH(h, &ngatm_freeuni, link) if (h == d) break; if (h == NULL) printf("uni_msg %p was never allocated; found " "in %s:%u\n", m, file, line); else printf("uni_msg %p was already destroyed in %s,%d; " "found in %s:%u\n", m, h->file, h->line, file, line); } else { free(m->b_buf, M_UNIMSG); LIST_REMOVE(d, link); LIST_INSERT_HEAD(&ngatm_freeuni, d, link); d->file = file; d->line = line; } mtx_unlock(&ngatm_unilist_mtx); } #else /* !NGATM_DEBUG */ /* * This assumes, that sizeof(struct uni_msg) >= sizeof(struct ngatm_msg) * and the alignment requirements of are the same. */ struct ngatm_msg { LIST_ENTRY(ngatm_msg) link; }; /* Lists of free message headers. */ static LIST_HEAD(, ngatm_msg) ngatm_freeuni = LIST_HEAD_INITIALIZER(ngatm_freeuni); /* * Clean-up UNI message subsystem */ static void uni_msg_fini(void) { struct ngatm_msg *h; /* free all free message headers */ while ((h = LIST_FIRST(&ngatm_freeuni)) != NULL) { LIST_REMOVE(h, link); free(h, M_UNIMSGHDR); } mtx_destroy(&ngatm_unilist_mtx); } /* * Allocate a message, that can hold at least s bytes. */ struct uni_msg * uni_msg_alloc(size_t s) { struct ngatm_msg *a; struct uni_msg *m; mtx_lock(&ngatm_unilist_mtx); if ((a = LIST_FIRST(&ngatm_freeuni)) != NULL) LIST_REMOVE(a, link); mtx_unlock(&ngatm_unilist_mtx); if (a == NULL) { if ((m = malloc(sizeof(*m), M_UNIMSGHDR, M_NOWAIT)) == NULL) return (NULL); a = (struct ngatm_msg *)m; } else m = (struct uni_msg *)a; s += EXTRA; if((m->b_buf = malloc(s, M_UNIMSG, M_NOWAIT | M_ZERO)) == NULL) { mtx_lock(&ngatm_unilist_mtx); LIST_INSERT_HEAD(&ngatm_freeuni, a, link); mtx_unlock(&ngatm_unilist_mtx); return (NULL); } m->b_rptr = m->b_wptr = m->b_buf; m->b_lim = m->b_buf + s; return (m); } /* * Destroy a UNI message. * The header is inserted into the free header list. */ void uni_msg_destroy(struct uni_msg *m) { struct ngatm_msg *a; a = (struct ngatm_msg *)m; free(m->b_buf, M_UNIMSG); mtx_lock(&ngatm_unilist_mtx); LIST_INSERT_HEAD(&ngatm_freeuni, a, link); mtx_unlock(&ngatm_unilist_mtx); } #endif /* * Build a message from a number of buffers. Arguments are pairs * of (void *, size_t) ending with a NULL pointer. */ #ifdef NGATM_DEBUG struct uni_msg * _uni_msg_build(const char *file, int line, void *ptr, ...) #else struct uni_msg * uni_msg_build(void *ptr, ...) #endif { va_list ap; struct uni_msg *m; size_t len, n; void *p1; len = 0; va_start(ap, ptr); p1 = ptr; while (p1 != NULL) { n = va_arg(ap, size_t); len += n; p1 = va_arg(ap, void *); } va_end(ap); #ifdef NGATM_DEBUG if ((m = _uni_msg_alloc(len, file, line)) == NULL) #else if ((m = uni_msg_alloc(len)) == NULL) #endif return (NULL); va_start(ap, ptr); p1 = ptr; while (p1 != NULL) { n = va_arg(ap, size_t); bcopy(p1, m->b_wptr, n); m->b_wptr += n; p1 = va_arg(ap, void *); } va_end(ap); return (m); } /* * Unpack an mbuf chain into a uni_msg buffer. */ #ifdef NGATM_DEBUG int _uni_msg_unpack_mbuf(struct mbuf *m, struct uni_msg **pmsg, const char *file, int line) #else int uni_msg_unpack_mbuf(struct mbuf *m, struct uni_msg **pmsg) #endif { if (!(m->m_flags & M_PKTHDR)) { printf("%s: bogus packet %p\n", __func__, m); return (EINVAL); } #ifdef NGATM_DEBUG if ((*pmsg = _uni_msg_alloc(m->m_pkthdr.len, file, line)) == NULL) #else if ((*pmsg = uni_msg_alloc(m->m_pkthdr.len)) == NULL) #endif return (ENOMEM); m_copydata(m, 0, m->m_pkthdr.len, (*pmsg)->b_wptr); (*pmsg)->b_wptr += m->m_pkthdr.len; return (0); } /*********************************************************************/ static int ngatm_handler(module_t mod, int what, void *arg) { int error = 0; switch (what) { case MOD_LOAD: uni_msg_init(); break; case MOD_UNLOAD: uni_msg_fini(); break; default: error = EOPNOTSUPP; break; } return (error); } diff --git a/sys/netgraph/atm/sscfu/ng_sscfu.c b/sys/netgraph/atm/sscfu/ng_sscfu.c index 7fe3728b7eae..4811f576df0b 100644 --- a/sys/netgraph/atm/sscfu/ng_sscfu.c +++ b/sys/netgraph/atm/sscfu/ng_sscfu.c @@ -1,602 +1,604 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2001-2003 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Author: Hartmut Brandt * * Netgraph module for ITU-T Q.2120 UNI SSCF. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include MALLOC_DEFINE(M_NG_SSCFU, "netgraph_sscfu", "netgraph uni sscf node"); MODULE_DEPEND(ng_sscfu, ngatmbase, 1, 1, 1); /* * Private data */ struct priv { hook_p upper; /* SAAL interface */ hook_p lower; /* SSCOP interface */ struct sscfu *sscf; /* the instance */ int enabled; }; /* * PARSING */ /* * Parse PARAM type */ static const struct ng_parse_struct_field ng_sscop_param_type_info[] = NG_SSCOP_PARAM_INFO; static const struct ng_parse_type ng_sscop_param_type = { &ng_parse_struct_type, ng_sscop_param_type_info }; static const struct ng_parse_struct_field ng_sscfu_getdefparam_type_info[] = NG_SSCFU_GETDEFPARAM_INFO; static const struct ng_parse_type ng_sscfu_getdefparam_type = { &ng_parse_struct_type, ng_sscfu_getdefparam_type_info }; static const struct ng_cmdlist ng_sscfu_cmdlist[] = { { NGM_SSCFU_COOKIE, NGM_SSCFU_GETDEFPARAM, "getdefparam", NULL, &ng_sscfu_getdefparam_type }, { NGM_SSCFU_COOKIE, NGM_SSCFU_ENABLE, "enable", NULL, NULL }, { NGM_SSCFU_COOKIE, NGM_SSCFU_DISABLE, "disable", NULL, NULL }, { NGM_SSCFU_COOKIE, NGM_SSCFU_GETDEBUG, "getdebug", NULL, &ng_parse_hint32_type }, { NGM_SSCFU_COOKIE, NGM_SSCFU_SETDEBUG, "setdebug", &ng_parse_hint32_type, NULL }, { NGM_SSCFU_COOKIE, NGM_SSCFU_GETSTATE, "getstate", NULL, &ng_parse_uint32_type }, { 0 } }; static ng_constructor_t ng_sscfu_constructor; static ng_shutdown_t ng_sscfu_shutdown; static ng_rcvmsg_t ng_sscfu_rcvmsg; static ng_newhook_t ng_sscfu_newhook; static ng_disconnect_t ng_sscfu_disconnect; static ng_rcvdata_t ng_sscfu_rcvupper; static ng_rcvdata_t ng_sscfu_rcvlower; static int ng_sscfu_mod_event(module_t, int, void *); static struct ng_type ng_sscfu_typestruct = { .version = NG_ABI_VERSION, .name = NG_SSCFU_NODE_TYPE, .mod_event = ng_sscfu_mod_event, .constructor = ng_sscfu_constructor, .rcvmsg = ng_sscfu_rcvmsg, .shutdown = ng_sscfu_shutdown, .newhook = ng_sscfu_newhook, .rcvdata = ng_sscfu_rcvupper, .disconnect = ng_sscfu_disconnect, .cmdlist = ng_sscfu_cmdlist, }; NETGRAPH_INIT(sscfu, &ng_sscfu_typestruct); static void sscfu_send_upper(struct sscfu *, void *, enum saal_sig, struct mbuf *); static void sscfu_send_lower(struct sscfu *, void *, enum sscop_aasig, struct mbuf *, u_int); static void sscfu_window(struct sscfu *, void *, u_int); static void sscfu_verbose(struct sscfu *, void *, const char *, ...) __printflike(3, 4); static const struct sscfu_funcs sscfu_funcs = { sscfu_send_upper, sscfu_send_lower, sscfu_window, sscfu_verbose }; /************************************************************/ /* * CONTROL MESSAGES */ static int text_status(node_p node, struct priv *priv, char *arg, u_int len) { struct sbuf sbuf; sbuf_new(&sbuf, arg, len, 0); if (priv->upper) sbuf_printf(&sbuf, "upper hook: %s connected to %s:%s\n", NG_HOOK_NAME(priv->upper), NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))), NG_HOOK_NAME(NG_HOOK_PEER(priv->upper))); else sbuf_printf(&sbuf, "upper hook: \n"); if (priv->lower) sbuf_printf(&sbuf, "lower hook: %s connected to %s:%s\n", NG_HOOK_NAME(priv->lower), NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))), NG_HOOK_NAME(NG_HOOK_PEER(priv->lower))); else sbuf_printf(&sbuf, "lower hook: \n"); sbuf_printf(&sbuf, "sscf state: %s\n", priv->enabled == 0 ? "" : sscfu_statename(sscfu_getstate(priv->sscf))); sbuf_finish(&sbuf); return (sbuf_len(&sbuf)); } static int ng_sscfu_rcvmsg(node_p node, item_p item, hook_p lasthook) { struct priv *priv = NG_NODE_PRIVATE(node); struct ng_mesg *resp = NULL; struct ng_mesg *msg; int error = 0; NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_GENERIC_COOKIE: switch (msg->header.cmd) { case NGM_TEXT_STATUS: NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } resp->header.arglen = text_status(node, priv, (char *)resp->data, resp->header.arglen) + 1; break; default: error = EINVAL; break; } break; case NGM_SSCFU_COOKIE: switch (msg->header.cmd) { case NGM_SSCFU_GETDEFPARAM: { struct ng_sscfu_getdefparam *p; if (msg->header.arglen != 0) { error = EINVAL; break; } NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } p = (struct ng_sscfu_getdefparam *)resp->data; p->mask = sscfu_getdefparam(&p->param); break; } case NGM_SSCFU_ENABLE: if (msg->header.arglen != 0) { error = EINVAL; break; } if (priv->enabled) { error = EISCONN; break; } priv->enabled = 1; break; case NGM_SSCFU_DISABLE: if (msg->header.arglen != 0) { error = EINVAL; break; } if (!priv->enabled) { error = ENOTCONN; break; } priv->enabled = 0; sscfu_reset(priv->sscf); break; case NGM_SSCFU_GETSTATE: if (msg->header.arglen != 0) { error = EINVAL; break; } NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); if(resp == NULL) { error = ENOMEM; break; } *(uint32_t *)resp->data = priv->enabled ? (sscfu_getstate(priv->sscf) + 1) : 0; break; case NGM_SSCFU_GETDEBUG: if (msg->header.arglen != 0) { error = EINVAL; break; } NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); if(resp == NULL) { error = ENOMEM; break; } *(uint32_t *)resp->data = sscfu_getdebug(priv->sscf); break; case NGM_SSCFU_SETDEBUG: if (msg->header.arglen != sizeof(uint32_t)) { error = EINVAL; break; } sscfu_setdebug(priv->sscf, *(uint32_t *)msg->data); break; default: error = EINVAL; break; } break; default: error = EINVAL; break; } NG_RESPOND_MSG(error, node, item, resp); NG_FREE_MSG(msg); return (error); } /************************************************************/ /* * HOOK MANAGEMENT */ static int ng_sscfu_newhook(node_p node, hook_p hook, const char *name) { struct priv *priv = NG_NODE_PRIVATE(node); if (strcmp(name, "upper") == 0) priv->upper = hook; else if (strcmp(name, "lower") == 0) { priv->lower = hook; NG_HOOK_SET_RCVDATA(hook, ng_sscfu_rcvlower); } else return (EINVAL); return (0); } static int ng_sscfu_disconnect(hook_p hook) { node_p node = NG_HOOK_NODE(hook); struct priv *priv = NG_NODE_PRIVATE(node); if (hook == priv->upper) priv->upper = NULL; else if (hook == priv->lower) priv->lower = NULL; else { log(LOG_ERR, "bogus hook"); return (EINVAL); } if (NG_NODE_NUMHOOKS(node) == 0) { if (NG_NODE_IS_VALID(node)) ng_rmnode_self(node); } else { /* * Because there are no timeouts reset the protocol * if the lower layer is disconnected. */ if (priv->lower == NULL && priv->enabled && sscfu_getstate(priv->sscf) != SSCFU_RELEASED) sscfu_reset(priv->sscf); } return (0); } /************************************************************/ /* * DATA */ static int ng_sscfu_rcvupper(hook_p hook, item_p item) { node_p node = NG_HOOK_NODE(hook); struct priv *priv = NG_NODE_PRIVATE(node); struct mbuf *m; struct sscfu_arg a; if (!priv->enabled || priv->lower == NULL) { NG_FREE_ITEM(item); return (0); } NGI_GET_M(item, m); NG_FREE_ITEM(item); if (!(m->m_flags & M_PKTHDR)) { printf("no pkthdr\n"); m_freem(m); return (EINVAL); } if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL) return (ENOMEM); bcopy((caddr_t)mtod(m, struct sscfu_arg *), &a, sizeof(a)); m_adj(m, sizeof(a)); return (sscfu_saalsig(priv->sscf, a.sig, m)); } static void sscfu_send_upper(struct sscfu *sscf, void *p, enum saal_sig sig, struct mbuf *m) { node_p node = (node_p)p; struct priv *priv = NG_NODE_PRIVATE(node); int error; struct sscfu_arg *a; if (priv->upper == NULL) { if (m != NULL) m_freem(m); return; } if (m == NULL) { MGETHDR(m, M_NOWAIT, MT_DATA); if (m == NULL) return; m->m_len = sizeof(struct sscfu_arg); m->m_pkthdr.len = m->m_len; } else { M_PREPEND(m, sizeof(struct sscfu_arg), M_NOWAIT); if (m == NULL) return; } a = mtod(m, struct sscfu_arg *); a->sig = sig; NG_SEND_DATA_ONLY(error, priv->upper, m); } static int ng_sscfu_rcvlower(hook_p hook, item_p item) { node_p node = NG_HOOK_NODE(hook); struct priv *priv = NG_NODE_PRIVATE(node); struct mbuf *m; struct sscop_arg a; if (!priv->enabled || priv->upper == NULL) { NG_FREE_ITEM(item); return (0); } NGI_GET_M(item, m); NG_FREE_ITEM(item); if (!(m->m_flags & M_PKTHDR)) { printf("no pkthdr\n"); m_freem(m); return (EINVAL); } /* * Strip of the SSCOP header. */ if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL) return (ENOMEM); bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a)); m_adj(m, sizeof(a)); sscfu_input(priv->sscf, a.sig, m, a.arg); return (0); } static void sscfu_send_lower(struct sscfu *sscf, void *p, enum sscop_aasig sig, struct mbuf *m, u_int arg) { node_p node = (node_p)p; struct priv *priv = NG_NODE_PRIVATE(node); int error; struct sscop_arg *a; if (priv->lower == NULL) { if (m != NULL) m_freem(m); return; } if (m == NULL) { MGETHDR(m, M_NOWAIT, MT_DATA); if (m == NULL) return; m->m_len = sizeof(struct sscop_arg); m->m_pkthdr.len = m->m_len; } else { M_PREPEND(m, sizeof(struct sscop_arg), M_NOWAIT); if (m == NULL) return; } a = mtod(m, struct sscop_arg *); a->sig = sig; a->arg = arg; NG_SEND_DATA_ONLY(error, priv->lower, m); } /* * Window is handled by ng_sscop so make this a NOP. */ static void sscfu_window(struct sscfu *sscfu, void *arg, u_int w) { } /************************************************************/ /* * NODE MANAGEMENT */ static int ng_sscfu_constructor(node_p node) { struct priv *priv; + gone_in(14, "ng_sscfu: netgraph ATM modules"); + priv = malloc(sizeof(*priv), M_NG_SSCFU, M_WAITOK | M_ZERO); if ((priv->sscf = sscfu_create(node, &sscfu_funcs)) == NULL) { free(priv, M_NG_SSCFU); return (ENOMEM); } NG_NODE_SET_PRIVATE(node, priv); return (0); } static int ng_sscfu_shutdown(node_p node) { struct priv *priv = NG_NODE_PRIVATE(node); sscfu_destroy(priv->sscf); free(priv, M_NG_SSCFU); NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); return (0); } static void sscfu_verbose(struct sscfu *sscfu, void *arg, const char *fmt, ...) { va_list ap; va_start(ap, fmt); printf("sscfu(%p): ", sscfu); vprintf(fmt, ap); va_end(ap); printf("\n"); } /************************************************************/ /* * INITIALISATION */ /* * Loading and unloading of node type */ static int ng_sscfu_mod_event(module_t mod, int event, void *data) { int error = 0; switch (event) { case MOD_LOAD: break; case MOD_UNLOAD: break; default: error = EOPNOTSUPP; break; } return (error); } diff --git a/sys/netgraph/atm/sscop/ng_sscop.c b/sys/netgraph/atm/sscop/ng_sscop.c index b15ef5e258a1..ae60e7557978 100644 --- a/sys/netgraph/atm/sscop/ng_sscop.c +++ b/sys/netgraph/atm/sscop/ng_sscop.c @@ -1,872 +1,874 @@ /*- * Copyright (c) 2001-2003 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). * All rights reserved. * * Author: Harti Brandt * * Redistribution of this software and documentation and use in source and * binary forms, with or without modification, are permitted provided that * the following conditions are met: * * 1. Redistributions of source code or documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Netgraph module for ITU-T Q.2110 SSCOP. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DDD printf("%s: %d\n", __func__, __LINE__) #ifdef SSCOP_DEBUG #define VERBOSE(P,M,F) \ do { \ if (sscop_getdebug((P)->sscop) & (M)) \ sscop_verbose F ; \ } while(0) #else #define VERBOSE(P,M,F) #endif MALLOC_DEFINE(M_NG_SSCOP, "netgraph_sscop", "netgraph sscop node"); MODULE_DEPEND(ng_sscop, ngatmbase, 1, 1, 1); struct stats { uint64_t in_packets; uint64_t out_packets; uint64_t aa_signals; uint64_t errors; uint64_t data_delivered; uint64_t aa_dropped; uint64_t maa_dropped; uint64_t maa_signals; uint64_t in_dropped; uint64_t out_dropped; }; /* * Private data */ struct priv { hook_p upper; /* SAAL interface */ hook_p lower; /* AAL5 interface */ hook_p manage; /* management interface */ struct sscop *sscop; /* sscop state */ int enabled; /* whether the protocol is enabled */ int flow; /* flow control states */ struct stats stats; /* sadistics */ }; /* * Parse PARAM type */ static const struct ng_parse_struct_field ng_sscop_param_type_info[] = NG_SSCOP_PARAM_INFO; static const struct ng_parse_type ng_sscop_param_type = { &ng_parse_struct_type, ng_sscop_param_type_info }; /* * Parse a SET PARAM type. */ static const struct ng_parse_struct_field ng_sscop_setparam_type_info[] = NG_SSCOP_SETPARAM_INFO; static const struct ng_parse_type ng_sscop_setparam_type = { &ng_parse_struct_type, ng_sscop_setparam_type_info, }; /* * Parse a SET PARAM response */ static const struct ng_parse_struct_field ng_sscop_setparam_resp_type_info[] = NG_SSCOP_SETPARAM_RESP_INFO; static const struct ng_parse_type ng_sscop_setparam_resp_type = { &ng_parse_struct_type, ng_sscop_setparam_resp_type_info, }; static const struct ng_cmdlist ng_sscop_cmdlist[] = { { NGM_SSCOP_COOKIE, NGM_SSCOP_GETPARAM, "getparam", NULL, &ng_sscop_param_type }, { NGM_SSCOP_COOKIE, NGM_SSCOP_SETPARAM, "setparam", &ng_sscop_setparam_type, &ng_sscop_setparam_resp_type }, { NGM_SSCOP_COOKIE, NGM_SSCOP_ENABLE, "enable", NULL, NULL }, { NGM_SSCOP_COOKIE, NGM_SSCOP_DISABLE, "disable", NULL, NULL }, { NGM_SSCOP_COOKIE, NGM_SSCOP_GETDEBUG, "getdebug", NULL, &ng_parse_hint32_type }, { NGM_SSCOP_COOKIE, NGM_SSCOP_SETDEBUG, "setdebug", &ng_parse_hint32_type, NULL }, { NGM_SSCOP_COOKIE, NGM_SSCOP_GETSTATE, "getstate", NULL, &ng_parse_uint32_type }, { 0 } }; static ng_constructor_t ng_sscop_constructor; static ng_shutdown_t ng_sscop_shutdown; static ng_rcvmsg_t ng_sscop_rcvmsg; static ng_newhook_t ng_sscop_newhook; static ng_disconnect_t ng_sscop_disconnect; static ng_rcvdata_t ng_sscop_rcvlower; static ng_rcvdata_t ng_sscop_rcvupper; static ng_rcvdata_t ng_sscop_rcvmanage; static int ng_sscop_mod_event(module_t, int, void *); static struct ng_type ng_sscop_typestruct = { .version = NG_ABI_VERSION, .name = NG_SSCOP_NODE_TYPE, .mod_event = ng_sscop_mod_event, .constructor = ng_sscop_constructor, .rcvmsg = ng_sscop_rcvmsg, .shutdown = ng_sscop_shutdown, .newhook = ng_sscop_newhook, .rcvdata = ng_sscop_rcvlower, .disconnect = ng_sscop_disconnect, .cmdlist = ng_sscop_cmdlist, }; NETGRAPH_INIT(sscop, &ng_sscop_typestruct); static void sscop_send_manage(struct sscop *, void *, enum sscop_maasig, struct SSCOP_MBUF_T *, u_int, u_int); static void sscop_send_upper(struct sscop *, void *, enum sscop_aasig, struct SSCOP_MBUF_T *, u_int); static void sscop_send_lower(struct sscop *, void *, struct SSCOP_MBUF_T *); static void sscop_verbose(struct sscop *, void *, const char *, ...) __printflike(3, 4); static const struct sscop_funcs sscop_funcs = { sscop_send_manage, sscop_send_upper, sscop_send_lower, sscop_verbose }; static void sscop_verbose(struct sscop *sscop, void *arg, const char *fmt, ...) { va_list ap; va_start(ap, fmt); printf("sscop(%p): ", sscop); vprintf(fmt, ap); va_end(ap); printf("\n"); } /************************************************************/ /* * NODE MANAGEMENT */ static int ng_sscop_constructor(node_p node) { struct priv *p; + gone_in(14, "ng_sscop: netgraph ATM modules"); + p = malloc(sizeof(*p), M_NG_SSCOP, M_WAITOK | M_ZERO); if ((p->sscop = sscop_create(node, &sscop_funcs)) == NULL) { free(p, M_NG_SSCOP); return (ENOMEM); } NG_NODE_SET_PRIVATE(node, p); /* All data message received by the node are expected to change the * node's state. Therefor we must ensure, that we have a writer lock. */ NG_NODE_FORCE_WRITER(node); return (0); } static int ng_sscop_shutdown(node_p node) { struct priv *priv = NG_NODE_PRIVATE(node); sscop_destroy(priv->sscop); free(priv, M_NG_SSCOP); NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); return (0); } /************************************************************/ /* * CONTROL MESSAGES */ /* * Flow control message from upper layer. * This is very experimental: * If we get a message from the upper layer, that somebody has passed its * high water mark, we stop updating the receive window. * If we get a low watermark passed, then we raise the window up * to max - current. * If we get a queue status and it indicates a current below the * high watermark, we unstop window updates (if they are stopped) and * raise the window to highwater - current. */ static int flow_upper(node_p node, struct ng_mesg *msg) { struct ngm_queue_state *q; struct priv *priv = NG_NODE_PRIVATE(node); u_int window, space; if (msg->header.arglen != sizeof(struct ngm_queue_state)) return (EINVAL); q = (struct ngm_queue_state *)msg->data; switch (msg->header.cmd) { case NGM_HIGH_WATER_PASSED: if (priv->flow) { VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv, "flow control stopped")); priv->flow = 0; } break; case NGM_LOW_WATER_PASSED: window = sscop_window(priv->sscop, 0); space = q->max_queuelen_packets - q->current; if (space > window) { VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv, "flow control opened window by %u messages", space - window)); (void)sscop_window(priv->sscop, space - window); } priv->flow = 1; break; case NGM_SYNC_QUEUE_STATE: if (q->high_watermark <= q->current) break; window = sscop_window(priv->sscop, 0); if (priv->flow) space = q->max_queuelen_packets - q->current; else space = q->high_watermark - q->current; if (space > window) { VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv, "flow control opened window by %u messages", space - window)); (void)sscop_window(priv->sscop, space - window); } priv->flow = 1; break; default: return (EINVAL); } return (0); } static int flow_lower(node_p node, struct ng_mesg *msg) { struct priv *priv = NG_NODE_PRIVATE(node); if (msg->header.arglen != sizeof(struct ngm_queue_state)) return (EINVAL); switch (msg->header.cmd) { case NGM_HIGH_WATER_PASSED: sscop_setbusy(priv->sscop, 1); break; case NGM_LOW_WATER_PASSED: sscop_setbusy(priv->sscop, 1); break; default: return (EINVAL); } return (0); } /* * Produce a readable status description */ static int text_status(node_p node, struct priv *priv, char *arg, u_int len) { struct sbuf sbuf; sbuf_new(&sbuf, arg, len, 0); if (priv->upper) sbuf_printf(&sbuf, "upper hook: %s connected to %s:%s\n", NG_HOOK_NAME(priv->upper), NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))), NG_HOOK_NAME(NG_HOOK_PEER(priv->upper))); else sbuf_printf(&sbuf, "upper hook: \n"); if (priv->lower) sbuf_printf(&sbuf, "lower hook: %s connected to %s:%s\n", NG_HOOK_NAME(priv->lower), NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))), NG_HOOK_NAME(NG_HOOK_PEER(priv->lower))); else sbuf_printf(&sbuf, "lower hook: \n"); if (priv->manage) sbuf_printf(&sbuf, "manage hook: %s connected to %s:%s\n", NG_HOOK_NAME(priv->manage), NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->manage))), NG_HOOK_NAME(NG_HOOK_PEER(priv->manage))); else sbuf_printf(&sbuf, "manage hook: \n"); sbuf_printf(&sbuf, "sscop state: %s\n", !priv->enabled ? "" : sscop_statename(sscop_getstate(priv->sscop))); sbuf_printf(&sbuf, "input packets: %ju\n", (uintmax_t)priv->stats.in_packets); sbuf_printf(&sbuf, "input dropped: %ju\n", (uintmax_t)priv->stats.in_dropped); sbuf_printf(&sbuf, "output packets: %ju\n", (uintmax_t)priv->stats.out_packets); sbuf_printf(&sbuf, "output dropped: %ju\n", (uintmax_t)priv->stats.out_dropped); sbuf_printf(&sbuf, "aa signals: %ju\n", (uintmax_t)priv->stats.aa_signals); sbuf_printf(&sbuf, "aa dropped: %ju\n", (uintmax_t)priv->stats.aa_dropped); sbuf_printf(&sbuf, "maa signals: %ju\n", (uintmax_t)priv->stats.maa_signals); sbuf_printf(&sbuf, "maa dropped: %ju\n", (uintmax_t)priv->stats.maa_dropped); sbuf_printf(&sbuf, "errors: %ju\n", (uintmax_t)priv->stats.errors); sbuf_printf(&sbuf, "data delivered: %ju\n", (uintmax_t)priv->stats.data_delivered); sbuf_printf(&sbuf, "window: %u\n", sscop_window(priv->sscop, 0)); sbuf_finish(&sbuf); return (sbuf_len(&sbuf)); } /* * Control message received. */ static int ng_sscop_rcvmsg(node_p node, item_p item, hook_p lasthook) { struct priv *priv = NG_NODE_PRIVATE(node); struct ng_mesg *resp = NULL; struct ng_mesg *msg; int error = 0; NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_GENERIC_COOKIE: switch (msg->header.cmd) { case NGM_TEXT_STATUS: NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } resp->header.arglen = text_status(node, priv, (char *)resp->data, resp->header.arglen) + 1; break; default: error = EINVAL; break; } break; case NGM_FLOW_COOKIE: if (priv->enabled && lasthook != NULL) { if (lasthook == priv->upper) error = flow_upper(node, msg); else if (lasthook == priv->lower) error = flow_lower(node, msg); } break; case NGM_SSCOP_COOKIE: switch (msg->header.cmd) { case NGM_SSCOP_GETPARAM: { struct sscop_param *p; NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } p = (struct sscop_param *)resp->data; sscop_getparam(priv->sscop, p); break; } case NGM_SSCOP_SETPARAM: { struct ng_sscop_setparam *arg; struct ng_sscop_setparam_resp *p; if (msg->header.arglen != sizeof(*arg)) { error = EINVAL; break; } if (priv->enabled) { error = EISCONN; break; } arg = (struct ng_sscop_setparam *)msg->data; NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } p = (struct ng_sscop_setparam_resp *)resp->data; p->mask = arg->mask; p->error = sscop_setparam(priv->sscop, &arg->param, &p->mask); break; } case NGM_SSCOP_ENABLE: if (msg->header.arglen != 0) { error = EINVAL; break; } if (priv->enabled) { error = EBUSY; break; } priv->enabled = 1; priv->flow = 1; memset(&priv->stats, 0, sizeof(priv->stats)); break; case NGM_SSCOP_DISABLE: if (msg->header.arglen != 0) { error = EINVAL; break; } if (!priv->enabled) { error = ENOTCONN; break; } priv->enabled = 0; sscop_reset(priv->sscop); break; case NGM_SSCOP_GETDEBUG: if (msg->header.arglen != 0) { error = EINVAL; break; } NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); if(resp == NULL) { error = ENOMEM; break; } *(u_int32_t *)resp->data = sscop_getdebug(priv->sscop); break; case NGM_SSCOP_SETDEBUG: if (msg->header.arglen != sizeof(u_int32_t)) { error = EINVAL; break; } sscop_setdebug(priv->sscop, *(u_int32_t *)msg->data); break; case NGM_SSCOP_GETSTATE: if (msg->header.arglen != 0) { error = EINVAL; break; } NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); if(resp == NULL) { error = ENOMEM; break; } *(u_int32_t *)resp->data = priv->enabled ? (sscop_getstate(priv->sscop) + 1) : 0; break; default: error = EINVAL; break; } break; default: error = EINVAL; break; } NG_RESPOND_MSG(error, node, item, resp); NG_FREE_MSG(msg); return (error); } /************************************************************/ /* * HOOK MANAGEMENT */ static int ng_sscop_newhook(node_p node, hook_p hook, const char *name) { struct priv *priv = NG_NODE_PRIVATE(node); if(strcmp(name, "upper") == 0) { priv->upper = hook; NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvupper); } else if(strcmp(name, "lower") == 0) { priv->lower = hook; } else if(strcmp(name, "manage") == 0) { priv->manage = hook; NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvmanage); } else return EINVAL; return 0; } static int ng_sscop_disconnect(hook_p hook) { node_p node = NG_HOOK_NODE(hook); struct priv *priv = NG_NODE_PRIVATE(node); if(hook == priv->upper) priv->upper = NULL; else if(hook == priv->lower) priv->lower = NULL; else if(hook == priv->manage) priv->manage = NULL; if(NG_NODE_NUMHOOKS(node) == 0) { if(NG_NODE_IS_VALID(node)) ng_rmnode_self(node); } else { /* * Imply a release request, if the upper layer is * disconnected. */ if(priv->upper == NULL && priv->lower != NULL && priv->enabled && sscop_getstate(priv->sscop) != SSCOP_IDLE) { sscop_aasig(priv->sscop, SSCOP_RELEASE_request, NULL, 0); } } return 0; } /************************************************************/ /* * DATA */ static int ng_sscop_rcvlower(hook_p hook, item_p item) { struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct mbuf *m; if (!priv->enabled) { NG_FREE_ITEM(item); return EINVAL; } /* * If we are disconnected at the upper layer and in the IDLE * state, drop any incoming packet. */ if (priv->upper != NULL || sscop_getstate(priv->sscop) != SSCOP_IDLE) { NGI_GET_M(item, m); priv->stats.in_packets++; sscop_input(priv->sscop, m); } else { priv->stats.in_dropped++; } NG_FREE_ITEM(item); return (0); } static void sscop_send_lower(struct sscop *sscop, void *p, struct mbuf *m) { node_p node = (node_p)p; struct priv *priv = NG_NODE_PRIVATE(node); int error; if (priv->lower == NULL) { m_freem(m); priv->stats.out_dropped++; return; } priv->stats.out_packets++; NG_SEND_DATA_ONLY(error, priv->lower, m); } static int ng_sscop_rcvupper(hook_p hook, item_p item) { struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct sscop_arg a; struct mbuf *m; if (!priv->enabled) { NG_FREE_ITEM(item); return (EINVAL); } /* * If the lower layer is not connected allow to proceed. * The lower layer sending function will drop outgoing frames, * and the sscop will timeout any establish requests. */ NGI_GET_M(item, m); NG_FREE_ITEM(item); if (!(m->m_flags & M_PKTHDR)) { printf("no pkthdr\n"); m_freem(m); return (EINVAL); } if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL) return (ENOBUFS); bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a)); m_adj(m, sizeof(a)); return (sscop_aasig(priv->sscop, a.sig, m, a.arg)); } static void sscop_send_upper(struct sscop *sscop, void *p, enum sscop_aasig sig, struct SSCOP_MBUF_T *m, u_int arg) { node_p node = (node_p)p; struct priv *priv = NG_NODE_PRIVATE(node); int error; struct sscop_arg *a; if (sig == SSCOP_DATA_indication && priv->flow) sscop_window(priv->sscop, 1); if (priv->upper == NULL) { if (m != NULL) m_freem(m); priv->stats.aa_dropped++; return; } priv->stats.aa_signals++; if (sig == SSCOP_DATA_indication) priv->stats.data_delivered++; if (m == NULL) { MGETHDR(m, M_NOWAIT, MT_DATA); if (m == NULL) return; m->m_len = sizeof(struct sscop_arg); m->m_pkthdr.len = m->m_len; } else { M_PREPEND(m, sizeof(struct sscop_arg), M_NOWAIT); if (m == NULL) return; } a = mtod(m, struct sscop_arg *); a->sig = sig; a->arg = arg; NG_SEND_DATA_ONLY(error, priv->upper, m); } static int ng_sscop_rcvmanage(hook_p hook, item_p item) { struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct sscop_marg a; struct mbuf *m; if (!priv->enabled) { NG_FREE_ITEM(item); return (EINVAL); } NGI_GET_M(item, m); NG_FREE_ITEM(item); if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL) return (ENOBUFS); bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a)); m_adj(m, sizeof(a)); return (sscop_maasig(priv->sscop, a.sig, m)); } 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) { node_p node = (node_p)p; struct priv *priv = NG_NODE_PRIVATE(node); int error; struct sscop_merr *e; struct sscop_marg *a; if (priv->manage == NULL) { if (m != NULL) m_freem(m); priv->stats.maa_dropped++; return; } if (sig == SSCOP_MERROR_indication) { MGETHDR(m, M_NOWAIT, MT_DATA); if (m == NULL) return; m->m_len = sizeof(*e); m->m_pkthdr.len = m->m_len; e = mtod(m, struct sscop_merr *); e->sig = sig; e->err = err; e->cnt = cnt; priv->stats.errors++; } else if (m == NULL) { MGETHDR(m, M_NOWAIT, MT_DATA); if (m == NULL) return; m->m_len = sizeof(*a); m->m_pkthdr.len = m->m_len; a = mtod(m, struct sscop_marg *); a->sig = sig; priv->stats.maa_signals++; } else { M_PREPEND(m, sizeof(*a), M_NOWAIT); if (m == NULL) return; a = mtod(m, struct sscop_marg *); a->sig = sig; priv->stats.maa_signals++; } NG_SEND_DATA_ONLY(error, priv->manage, m); } /************************************************************/ /* * INITIALISATION */ /* * Loading and unloading of node type */ static int ng_sscop_mod_event(module_t mod, int event, void *data) { int error = 0; switch (event) { case MOD_LOAD: break; case MOD_UNLOAD: break; default: error = EOPNOTSUPP; break; } return (error); } diff --git a/sys/netgraph/atm/uni/ng_uni.c b/sys/netgraph/atm/uni/ng_uni.c index c4e1c2c523b5..1313bd062188 100644 --- a/sys/netgraph/atm/uni/ng_uni.c +++ b/sys/netgraph/atm/uni/ng_uni.c @@ -1,920 +1,922 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2001-2003 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). * All rights reserved. * * Author: Hartmut Brandt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Netgraph module for ATM-Forum UNI 4.0 signalling */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static MALLOC_DEFINE(M_NG_UNI, "netgraph_uni_node", "netgraph uni node"); static MALLOC_DEFINE(M_UNI, "netgraph_uni_data", "uni protocol data"); MODULE_DEPEND(ng_uni, ngatmbase, 1, 1, 1); /* * Private node data */ struct priv { hook_p upper; hook_p lower; struct uni *uni; int enabled; }; /* UNI CONFIG MASK */ static const struct ng_parse_struct_field ng_uni_config_mask_type_info[] = NGM_UNI_CONFIG_MASK_INFO; static const struct ng_parse_type ng_uni_config_mask_type = { &ng_parse_struct_type, ng_uni_config_mask_type_info }; /* UNI_CONFIG */ static const struct ng_parse_struct_field ng_uni_config_type_info[] = NGM_UNI_CONFIG_INFO; static const struct ng_parse_type ng_uni_config_type = { &ng_parse_struct_type, ng_uni_config_type_info }; /* SET CONFIG */ static const struct ng_parse_struct_field ng_uni_set_config_type_info[] = NGM_UNI_SET_CONFIG_INFO; static const struct ng_parse_type ng_uni_set_config_type = { &ng_parse_struct_type, ng_uni_set_config_type_info }; /* * Parse DEBUG */ static const struct ng_parse_fixedarray_info ng_uni_debuglevel_type_info = NGM_UNI_DEBUGLEVEL_INFO; static const struct ng_parse_type ng_uni_debuglevel_type = { &ng_parse_fixedarray_type, &ng_uni_debuglevel_type_info }; static const struct ng_parse_struct_field ng_uni_debug_type_info[] = NGM_UNI_DEBUG_INFO; static const struct ng_parse_type ng_uni_debug_type = { &ng_parse_struct_type, ng_uni_debug_type_info }; /* * Command list */ static const struct ng_cmdlist ng_uni_cmdlist[] = { { NGM_UNI_COOKIE, NGM_UNI_GETDEBUG, "getdebug", NULL, &ng_uni_debug_type }, { NGM_UNI_COOKIE, NGM_UNI_SETDEBUG, "setdebug", &ng_uni_debug_type, NULL }, { NGM_UNI_COOKIE, NGM_UNI_GET_CONFIG, "get_config", NULL, &ng_uni_config_type }, { NGM_UNI_COOKIE, NGM_UNI_SET_CONFIG, "set_config", &ng_uni_set_config_type, &ng_uni_config_mask_type, }, { NGM_UNI_COOKIE, NGM_UNI_ENABLE, "enable", NULL, NULL, }, { NGM_UNI_COOKIE, NGM_UNI_DISABLE, "disable", NULL, NULL, }, { NGM_UNI_COOKIE, NGM_UNI_GETSTATE, "getstate", NULL, &ng_parse_uint32_type }, { 0 } }; /* * Netgraph module data */ static ng_constructor_t ng_uni_constructor; static ng_shutdown_t ng_uni_shutdown; static ng_rcvmsg_t ng_uni_rcvmsg; static ng_newhook_t ng_uni_newhook; static ng_disconnect_t ng_uni_disconnect; static ng_rcvdata_t ng_uni_rcvlower; static ng_rcvdata_t ng_uni_rcvupper; static int ng_uni_mod_event(module_t, int, void *); static struct ng_type ng_uni_typestruct = { .version = NG_ABI_VERSION, .name = NG_UNI_NODE_TYPE, .mod_event = ng_uni_mod_event, .constructor = ng_uni_constructor, .rcvmsg = ng_uni_rcvmsg, .shutdown = ng_uni_shutdown, .newhook = ng_uni_newhook, .rcvdata = ng_uni_rcvlower, .disconnect = ng_uni_disconnect, .cmdlist = ng_uni_cmdlist, }; NETGRAPH_INIT(uni, &ng_uni_typestruct); static void uni_uni_output(struct uni *, void *, enum uni_sig, u_int32_t, struct uni_msg *); static void uni_saal_output(struct uni *, void *, enum saal_sig, struct uni_msg *); static void uni_verbose(struct uni *, void *, u_int, const char *, ...) __printflike(4, 5); static void uni_do_status(struct uni *, void *, void *, const char *, ...) __printflike(4, 5); static const struct uni_funcs uni_funcs = { uni_uni_output, uni_saal_output, uni_verbose, uni_do_status }; /************************************************************/ /* * NODE MANAGEMENT */ static int ng_uni_constructor(node_p node) { struct priv *priv; + gone_in(14, "ng_uni: netgraph ATM modules"); + priv = malloc(sizeof(*priv), M_NG_UNI, M_WAITOK | M_ZERO); if ((priv->uni = uni_create(node, &uni_funcs)) == NULL) { free(priv, M_NG_UNI); return (ENOMEM); } NG_NODE_SET_PRIVATE(node, priv); NG_NODE_FORCE_WRITER(node); return (0); } static int ng_uni_shutdown(node_p node) { struct priv *priv = NG_NODE_PRIVATE(node); uni_destroy(priv->uni); free(priv, M_NG_UNI); NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); return (0); } /************************************************************/ /* * CONTROL MESSAGES */ static void uni_do_status(struct uni *uni, void *uarg, void *sbuf, const char *fmt, ...) { va_list ap; va_start(ap, fmt); sbuf_printf(sbuf, fmt, ap); va_end(ap); } static int text_status(node_p node, struct priv *priv, char *buf, u_int len) { struct sbuf sbuf; u_int f; sbuf_new(&sbuf, buf, len, 0); if (priv->lower != NULL) sbuf_printf(&sbuf, "lower hook: connected to %s:%s\n", NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))), NG_HOOK_NAME(NG_HOOK_PEER(priv->lower))); else sbuf_printf(&sbuf, "lower hook: \n"); if (priv->upper != NULL) sbuf_printf(&sbuf, "upper hook: connected to %s:%s\n", NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))), NG_HOOK_NAME(NG_HOOK_PEER(priv->upper))); else sbuf_printf(&sbuf, "upper hook: \n"); sbuf_printf(&sbuf, "debugging:"); for (f = 0; f < UNI_MAXFACILITY; f++) if (uni_get_debug(priv->uni, f) != 0) sbuf_printf(&sbuf, " %s=%u", uni_facname(f), uni_get_debug(priv->uni, f)); sbuf_printf(&sbuf, "\n"); if (priv->uni) uni_status(priv->uni, &sbuf); sbuf_finish(&sbuf); return (sbuf_len(&sbuf)); } static int ng_uni_rcvmsg(node_p node, item_p item, hook_p lasthook) { struct priv *priv = NG_NODE_PRIVATE(node); struct ng_mesg *resp = NULL; struct ng_mesg *msg; int error = 0; u_int i; NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_GENERIC_COOKIE: switch (msg->header.cmd) { case NGM_TEXT_STATUS: NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } resp->header.arglen = text_status(node, priv, (char *)resp->data, resp->header.arglen) + 1; break; default: error = EINVAL; break; } break; case NGM_UNI_COOKIE: switch (msg->header.cmd) { case NGM_UNI_SETDEBUG: { struct ngm_uni_debug *arg; if (msg->header.arglen > sizeof(*arg)) { error = EINVAL; break; } arg = (struct ngm_uni_debug *)msg->data; for (i = 0; i < UNI_MAXFACILITY; i++) uni_set_debug(priv->uni, i, arg->level[i]); break; } case NGM_UNI_GETDEBUG: { struct ngm_uni_debug *arg; NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT); if(resp == NULL) { error = ENOMEM; break; } arg = (struct ngm_uni_debug *)resp->data; for (i = 0; i < UNI_MAXFACILITY; i++) arg->level[i] = uni_get_debug(priv->uni, i); break; } case NGM_UNI_GET_CONFIG: { struct uni_config *config; if (msg->header.arglen != 0) { error = EINVAL; break; } NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } config = (struct uni_config *)resp->data; uni_get_config(priv->uni, config); break; } case NGM_UNI_SET_CONFIG: { struct ngm_uni_set_config *arg; struct ngm_uni_config_mask *mask; if (msg->header.arglen != sizeof(*arg)) { error = EINVAL; break; } arg = (struct ngm_uni_set_config *)msg->data; NG_MKRESPONSE(resp, msg, sizeof(*mask), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } mask = (struct ngm_uni_config_mask *)resp->data; *mask = arg->mask; uni_set_config(priv->uni, &arg->config, &mask->mask, &mask->popt_mask, &mask->option_mask); break; } case NGM_UNI_ENABLE: if (msg->header.arglen != 0) { error = EINVAL; break; } if (priv->enabled) { error = EISCONN; break; } priv->enabled = 1; break; case NGM_UNI_DISABLE: if (msg->header.arglen != 0) { error = EINVAL; break; } if (!priv->enabled) { error = ENOTCONN; break; } priv->enabled = 0; uni_reset(priv->uni); break; case NGM_UNI_GETSTATE: if (msg->header.arglen != 0) { error = EINVAL; break; } NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); if(resp == NULL) { error = ENOMEM; break; } *(u_int32_t *)resp->data = priv->enabled ? (uni_getcustate(priv->uni) + 1) : 0; break; default: error = EINVAL; break; } break; default: error = EINVAL; break; } NG_RESPOND_MSG(error, node, item, resp); NG_FREE_MSG(msg); return (error); } /************************************************************/ /* * HOOK MANAGEMENT */ static int ng_uni_newhook(node_p node, hook_p hook, const char *name) { struct priv *priv = NG_NODE_PRIVATE(node); if (strcmp(name, "lower") == 0) { priv->lower = hook; } else if(strcmp(name, "upper") == 0) { priv->upper = hook; NG_HOOK_SET_RCVDATA(hook, ng_uni_rcvupper); } else return EINVAL; return 0; } static int ng_uni_disconnect(hook_p hook) { node_p node = NG_HOOK_NODE(hook); struct priv *priv = NG_NODE_PRIVATE(node); if(hook == priv->lower) priv->lower = NULL; else if(hook == priv->upper) priv->upper = NULL; else printf("%s: bogus hook %s\n", __func__, NG_HOOK_NAME(hook)); if (NG_NODE_NUMHOOKS(node) == 0) { if (NG_NODE_IS_VALID(node)) ng_rmnode_self(node); } return (0); } /************************************************************/ /* * DATA */ /* * Receive signal from USER. * * Repackage the data into one large buffer. */ static int ng_uni_rcvupper(hook_p hook, item_p item) { node_p node = NG_HOOK_NODE(hook); struct priv *priv = NG_NODE_PRIVATE(node); struct mbuf *m; struct uni_arg arg; struct uni_msg *msg; int error; if (!priv->enabled) { NG_FREE_ITEM(item); return (ENOTCONN); } NGI_GET_M(item, m); NG_FREE_ITEM(item); if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) { m_freem(m); return (error); } m_freem(m); if (uni_msg_len(msg) < sizeof(arg)) { printf("%s: packet too short\n", __func__); uni_msg_destroy(msg); return (EINVAL); } bcopy(msg->b_rptr, &arg, sizeof(arg)); msg->b_rptr += sizeof(arg); if (arg.sig >= UNIAPI_MAXSIG) { printf("%s: bogus signal\n", __func__); uni_msg_destroy(msg); return (EINVAL); } uni_uni_input(priv->uni, arg.sig, arg.cookie, msg); uni_work(priv->uni); return (0); } /* * Upper layer signal from UNI */ static void uni_uni_output(struct uni *uni, void *varg, enum uni_sig sig, u_int32_t cookie, struct uni_msg *msg) { node_p node = (node_p)varg; struct priv *priv = NG_NODE_PRIVATE(node); struct mbuf *m; struct uni_arg arg; int error; if (priv->upper == NULL) { if (msg != NULL) uni_msg_destroy(msg); return; } arg.sig = sig; arg.cookie = cookie; m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg)); if (msg != NULL) uni_msg_destroy(msg); if (m == NULL) return; NG_SEND_DATA_ONLY(error, priv->upper, m); } static void dump_uni_msg(struct uni_msg *msg) { u_int pos; for (pos = 0; pos < uni_msg_len(msg); pos++) { if (pos % 16 == 0) printf("%06o ", pos); if (pos % 16 == 8) printf(" "); printf(" %02x", msg->b_rptr[pos]); if (pos % 16 == 15) printf("\n"); } if (pos % 16 != 0) printf("\n"); } /* * Dump a SAAL signal in either direction */ static void dump_saal_signal(node_p node, enum saal_sig sig, struct uni_msg *msg, int to) { struct priv *priv = NG_NODE_PRIVATE(node); printf("signal %s SAAL: ", to ? "to" : "from"); switch (sig) { #define D(S) case S: printf("%s", #S); break D(SAAL_ESTABLISH_request); D(SAAL_ESTABLISH_indication); D(SAAL_ESTABLISH_confirm); D(SAAL_RELEASE_request); D(SAAL_RELEASE_confirm); D(SAAL_RELEASE_indication); D(SAAL_DATA_request); D(SAAL_DATA_indication); D(SAAL_UDATA_request); D(SAAL_UDATA_indication); #undef D default: printf("sig=%d", sig); break; } if (msg != NULL) { printf(" data=%zu\n", uni_msg_len(msg)); if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 1) dump_uni_msg(msg); } else printf("\n"); } /* * Receive signal from SSCOP. * * If this is a data signal, repackage the data into one large buffer. * UNI shouldn't be the bottleneck in a system and this greatly simplifies * parsing in UNI. */ static int ng_uni_rcvlower(hook_p hook __unused, item_p item) { node_p node = NG_HOOK_NODE(hook); struct priv *priv = NG_NODE_PRIVATE(node); struct mbuf *m; struct sscfu_arg arg; struct uni_msg *msg; int error; if (!priv->enabled) { NG_FREE_ITEM(item); return (ENOTCONN); } NGI_GET_M(item, m); NG_FREE_ITEM(item); if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) { m_freem(m); return (error); } m_freem(m); if (uni_msg_len(msg) < sizeof(arg)) { uni_msg_destroy(msg); printf("%s: packet too short\n", __func__); return (EINVAL); } bcopy(msg->b_rptr, &arg, sizeof(arg)); msg->b_rptr += sizeof(arg); if (arg.sig > SAAL_UDATA_indication) { uni_msg_destroy(msg); printf("%s: bogus signal\n", __func__); return (EINVAL); } if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0) dump_saal_signal(node, arg.sig, msg, 0); uni_saal_input(priv->uni, arg.sig, msg); uni_work(priv->uni); return (0); } /* * Send signal to sscop. * Pack the message into an mbuf chain. */ static void uni_saal_output(struct uni *uni, void *varg, enum saal_sig sig, struct uni_msg *msg) { node_p node = (node_p)varg; struct priv *priv = NG_NODE_PRIVATE(node); struct mbuf *m; struct sscfu_arg arg; int error; if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0) dump_saal_signal(node, sig, msg, 1); if (priv->lower == NULL) { if (msg != NULL) uni_msg_destroy(msg); return; } arg.sig = sig; m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg)); if (msg != NULL) uni_msg_destroy(msg); if (m == NULL) return; NG_SEND_DATA_ONLY(error, priv->lower, m); } static void uni_verbose(struct uni *uni, void *varg, u_int fac, const char *fmt, ...) { va_list ap; static char *facnames[] = { #define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] = #D, UNI_DEBUG_FACILITIES #undef UNI_DEBUG_DEFINE }; printf("%s: ", facnames[fac]); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); } /************************************************************/ /* * Memory debugging */ struct unimem_debug { const char *file; u_int lno; LIST_ENTRY(unimem_debug) link; char data[0]; }; LIST_HEAD(unimem_debug_list, unimem_debug); static struct unimem_debug_list nguni_freemem[UNIMEM_TYPES] = { LIST_HEAD_INITIALIZER(nguni_freemem[0]), LIST_HEAD_INITIALIZER(nguni_freemem[1]), LIST_HEAD_INITIALIZER(nguni_freemem[2]), LIST_HEAD_INITIALIZER(nguni_freemem[3]), LIST_HEAD_INITIALIZER(nguni_freemem[4]), }; static struct unimem_debug_list nguni_usedmem[UNIMEM_TYPES] = { LIST_HEAD_INITIALIZER(nguni_usedmem[0]), LIST_HEAD_INITIALIZER(nguni_usedmem[1]), LIST_HEAD_INITIALIZER(nguni_usedmem[2]), LIST_HEAD_INITIALIZER(nguni_usedmem[3]), LIST_HEAD_INITIALIZER(nguni_usedmem[4]), }; static struct mtx nguni_unilist_mtx; static const char *unimem_names[UNIMEM_TYPES] = { "instance", "all", "signal", "call", "party" }; static void uni_init(void) { mtx_init(&nguni_unilist_mtx, "netgraph UNI structure lists", NULL, MTX_DEF); } static void uni_fini(void) { u_int type; struct unimem_debug *h; for (type = 0; type < UNIMEM_TYPES; type++) { while ((h = LIST_FIRST(&nguni_freemem[type])) != NULL) { LIST_REMOVE(h, link); free(h, M_UNI); } while ((h = LIST_FIRST(&nguni_usedmem[type])) != NULL) { LIST_REMOVE(h, link); printf("ng_uni: %s in use: %p (%s,%u)\n", unimem_names[type], (caddr_t)h->data, h->file, h->lno); free(h, M_UNI); } } mtx_destroy(&nguni_unilist_mtx); } /* * Allocate a chunk of memory from a given type. */ void * ng_uni_malloc(enum unimem type, const char *file, u_int lno) { struct unimem_debug *d; size_t full; /* * Try to allocate */ mtx_lock(&nguni_unilist_mtx); if ((d = LIST_FIRST(&nguni_freemem[type])) != NULL) LIST_REMOVE(d, link); mtx_unlock(&nguni_unilist_mtx); if (d == NULL) { /* * allocate */ full = unimem_sizes[type] + offsetof(struct unimem_debug, data); if ((d = malloc(full, M_UNI, M_NOWAIT | M_ZERO)) == NULL) return (NULL); } else { bzero(d->data, unimem_sizes[type]); } d->file = file; d->lno = lno; mtx_lock(&nguni_unilist_mtx); LIST_INSERT_HEAD(&nguni_usedmem[type], d, link); mtx_unlock(&nguni_unilist_mtx); return (d->data); } void ng_uni_free(enum unimem type, void *ptr, const char *file, u_int lno) { struct unimem_debug *d, *h; d = (struct unimem_debug *) ((char *)ptr - offsetof(struct unimem_debug, data)); mtx_lock(&nguni_unilist_mtx); LIST_FOREACH(h, &nguni_usedmem[type], link) if (d == h) break; if (h != NULL) { LIST_REMOVE(d, link); LIST_INSERT_HEAD(&nguni_freemem[type], d, link); } else { /* * Not on used list - try free list. */ LIST_FOREACH(h, &nguni_freemem[type], link) if (d == h) break; if (h == NULL) printf("ng_uni: %s,%u: %p(%s) was never allocated\n", file, lno, ptr, unimem_names[type]); else printf("ng_uni: %s,%u: %p(%s) was already destroyed " "in %s,%u\n", file, lno, ptr, unimem_names[type], h->file, h->lno); } mtx_unlock(&nguni_unilist_mtx); } /************************************************************/ /* * INITIALISATION */ /* * Loading and unloading of node type */ static int ng_uni_mod_event(module_t mod, int event, void *data) { int error = 0; switch(event) { case MOD_LOAD: uni_init(); break; case MOD_UNLOAD: uni_fini(); break; default: error = EOPNOTSUPP; break; } return (error); }