summaryrefslogtreecommitdiffstats
path: root/sys/netatm/atm_socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/atm_socket.c')
-rw-r--r--sys/netatm/atm_socket.c1311
1 files changed, 1311 insertions, 0 deletions
diff --git a/sys/netatm/atm_socket.c b/sys/netatm/atm_socket.c
new file mode 100644
index 0000000..2370a15
--- /dev/null
+++ b/sys/netatm/atm_socket.c
@@ -0,0 +1,1311 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: atm_socket.c,v 1.3 1998/07/30 22:30:53 mks Exp $
+ *
+ */
+
+/*
+ * Core ATM Services
+ * -----------------
+ *
+ * ATM common socket protocol processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: atm_socket.c,v 1.3 1998/07/30 22:30:53 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+
+/*
+ * Local functions
+ */
+
+
+/*
+ * Local variables
+ */
+static struct sp_info atm_pcb_pool = {
+ "atm pcb pool", /* si_name */
+ sizeof(Atm_pcb), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 100 /* si_maxallow */
+};
+
+static struct t_atm_cause atm_sock_cause = {
+ T_ATM_ITU_CODING,
+ T_ATM_LOC_USER,
+ T_ATM_CAUSE_UNSPECIFIED_NORMAL,
+ {0, 0, 0, 0}
+};
+
+
+/*
+ * Allocate resources for a new ATM socket
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * so pointer to socket
+ * send socket send buffer maximum
+ * recv socket receive buffer maximum
+ *
+ * Returns:
+ * 0 attach successful
+ * errno attach failed - reason indicated
+ *
+ */
+int
+atm_sock_attach(so, send, recv)
+ struct socket *so;
+ u_long send;
+ u_long recv;
+{
+ Atm_pcb *atp = sotoatmpcb(so);
+ int err;
+
+ /*
+ * Make sure initialization has happened
+ */
+ if (!atm_init)
+ atm_initialize();
+
+ /*
+ * Make sure we're not already attached
+ */
+ if (atp)
+ return (EISCONN);
+
+ /*
+ * Reserve socket buffer space, if not already done
+ */
+ if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) {
+ err = soreserve(so, send, recv);
+ if (err)
+ return (err);
+ }
+
+ /*
+ * Allocate and initialize our control block
+ */
+ atp = (Atm_pcb *)atm_allocate(&atm_pcb_pool);
+ if (atp == NULL)
+ return (ENOMEM);
+
+ atp->atp_socket = so;
+ so->so_pcb = (caddr_t)atp;
+ return (0);
+}
+
+
+/*
+ * Detach from socket and free resources
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * so pointer to socket
+ *
+ * Returns:
+ * 0 detach successful
+ * errno detach failed - reason indicated
+ *
+ */
+int
+atm_sock_detach(so)
+ struct socket *so;
+{
+ Atm_pcb *atp = sotoatmpcb(so);
+
+ /*
+ * Make sure we're still attached
+ */
+ if (atp == NULL)
+ return (ENOTCONN);
+
+ /*
+ * Terminate any (possibly pending) connection
+ */
+ if (atp->atp_conn) {
+ (void) atm_sock_disconnect(so);
+ }
+
+ /*
+ * Break links and free control blocks
+ */
+ so->so_pcb = NULL;
+ sofree(so);
+
+ atm_free((caddr_t)atp);
+
+ return (0);
+}
+
+
+/*
+ * Bind local address to socket
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * so pointer to socket
+ * addr pointer to protocol address
+ *
+ * Returns:
+ * 0 request processed
+ * errno error processing request - reason indicated
+ *
+ */
+int
+atm_sock_bind(so, addr)
+ struct socket *so;
+ struct sockaddr *addr;
+{
+ Atm_pcb *atp = sotoatmpcb(so);
+ Atm_attributes attr;
+ struct sockaddr_atm *satm;
+ struct t_atm_sap_addr *sapadr;
+ struct t_atm_sap_layer2 *sapl2;
+ struct t_atm_sap_layer3 *sapl3;
+ struct t_atm_sap_appl *sapapl;
+
+ /*
+ * Make sure we're still attached
+ */
+ if (atp == NULL)
+ return (ENOTCONN);
+
+ /*
+ * Can't change local address once we've started connection process
+ */
+ if (atp->atp_conn != NULL)
+ return (EADDRNOTAVAIL);
+
+ /*
+ * Validate requested local address
+ */
+ satm = (struct sockaddr_atm *)addr;
+ if (satm->satm_family != AF_ATM)
+ return (EAFNOSUPPORT);
+
+ sapadr = &satm->satm_addr.t_atm_sap_addr;
+ if (sapadr->SVE_tag_addr == T_ATM_PRESENT) {
+ if (sapadr->address_format == T_ATM_ENDSYS_ADDR) {
+ if (sapadr->SVE_tag_selector != T_ATM_PRESENT)
+ return (EINVAL);
+ } else if (sapadr->address_format == T_ATM_E164_ADDR) {
+ if (sapadr->SVE_tag_selector != T_ATM_ABSENT)
+ return (EINVAL);
+ } else
+ return (EINVAL);
+ } else if ((sapadr->SVE_tag_addr != T_ATM_ABSENT) &&
+ (sapadr->SVE_tag_addr != T_ATM_ANY))
+ return (EINVAL);
+ if (sapadr->address_length > ATM_ADDR_LEN)
+ return (EINVAL);
+
+ sapl2 = &satm->satm_addr.t_atm_sap_layer2;
+ if (sapl2->SVE_tag == T_ATM_PRESENT) {
+ if ((sapl2->ID_type != T_ATM_SIMPLE_ID) &&
+ (sapl2->ID_type != T_ATM_USER_ID))
+ return (EINVAL);
+ } else if ((sapl2->SVE_tag != T_ATM_ABSENT) &&
+ (sapl2->SVE_tag != T_ATM_ANY))
+ return (EINVAL);
+
+ sapl3 = &satm->satm_addr.t_atm_sap_layer3;
+ if (sapl3->SVE_tag == T_ATM_PRESENT) {
+ if ((sapl3->ID_type != T_ATM_SIMPLE_ID) &&
+ (sapl3->ID_type != T_ATM_IPI_ID) &&
+ (sapl3->ID_type != T_ATM_SNAP_ID) &&
+ (sapl3->ID_type != T_ATM_USER_ID))
+ return (EINVAL);
+ } else if ((sapl3->SVE_tag != T_ATM_ABSENT) &&
+ (sapl3->SVE_tag != T_ATM_ANY))
+ return (EINVAL);
+
+ sapapl = &satm->satm_addr.t_atm_sap_appl;
+ if (sapapl->SVE_tag == T_ATM_PRESENT) {
+ if ((sapapl->ID_type != T_ATM_ISO_APP_ID) &&
+ (sapapl->ID_type != T_ATM_USER_APP_ID) &&
+ (sapapl->ID_type != T_ATM_VENDOR_APP_ID))
+ return (EINVAL);
+ } else if ((sapapl->SVE_tag != T_ATM_ABSENT) &&
+ (sapapl->SVE_tag != T_ATM_ANY))
+ return (EINVAL);
+
+ /*
+ * Create temporary attributes list so that we can check out the
+ * new bind parameters before we modify the socket's values;
+ */
+ attr = atp->atp_attr;
+ attr.called.tag = sapadr->SVE_tag_addr;
+ KM_COPY(&sapadr->address_format, &attr.called.addr, sizeof(Atm_addr));
+
+ attr.blli.tag_l2 = sapl2->SVE_tag;
+ if (sapl2->SVE_tag == T_ATM_PRESENT) {
+ attr.blli.v.layer_2_protocol.ID_type = sapl2->ID_type;
+ KM_COPY(&sapl2->ID, &attr.blli.v.layer_2_protocol.ID,
+ sizeof(attr.blli.v.layer_2_protocol.ID));
+ }
+
+ attr.blli.tag_l3 = sapl3->SVE_tag;
+ if (sapl3->SVE_tag == T_ATM_PRESENT) {
+ attr.blli.v.layer_3_protocol.ID_type = sapl3->ID_type;
+ KM_COPY(&sapl3->ID, &attr.blli.v.layer_3_protocol.ID,
+ sizeof(attr.blli.v.layer_3_protocol.ID));
+ }
+
+ attr.bhli.tag = sapapl->SVE_tag;
+ if (sapapl->SVE_tag == T_ATM_PRESENT) {
+ attr.bhli.v.ID_type = sapapl->ID_type;
+ KM_COPY(&sapapl->ID, &attr.bhli.v.ID,
+ sizeof(attr.bhli.v.ID));
+ }
+
+ /*
+ * Make sure we have unique listening attributes
+ */
+ if (atm_cm_match(&attr, NULL) != NULL)
+ return (EADDRINUSE);
+
+ /*
+ * Looks good, save new attributes
+ */
+ atp->atp_attr = attr;
+
+ return (0);
+}
+
+
+/*
+ * Listen for incoming connections
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * so pointer to socket
+ * epp pointer to endpoint definition structure
+ *
+ * Returns:
+ * 0 request processed
+ * errno error processing request - reason indicated
+ *
+ */
+int
+atm_sock_listen(so, epp)
+ struct socket *so;
+ Atm_endpoint *epp;
+{
+ Atm_pcb *atp = sotoatmpcb(so);
+
+ /*
+ * Make sure we're still attached
+ */
+ if (atp == NULL)
+ return (ENOTCONN);
+
+ /*
+ * Start listening for incoming calls
+ */
+ return (atm_cm_listen(epp, atp, &atp->atp_attr, &atp->atp_conn));
+}
+
+
+/*
+ * Connect socket to peer
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * so pointer to socket
+ * addr pointer to protocol address
+ * epp pointer to endpoint definition structure
+ *
+ * Returns:
+ * 0 request processed
+ * errno error processing request - reason indicated
+ *
+ */
+int
+atm_sock_connect(so, addr, epp)
+ struct socket *so;
+ struct sockaddr *addr;
+ Atm_endpoint *epp;
+{
+ Atm_pcb *atp = sotoatmpcb(so);
+ struct sockaddr_atm *satm;
+ struct t_atm_sap_addr *sapadr;
+ struct t_atm_sap_layer2 *sapl2;
+ struct t_atm_sap_layer3 *sapl3;
+ struct t_atm_sap_appl *sapapl;
+ int err;
+
+ /*
+ * Make sure we're still attached
+ */
+ if (atp == NULL)
+ return (ENOTCONN);
+
+ /*
+ * Validate requested peer address
+ */
+ satm = (struct sockaddr_atm *)addr;
+ if (satm->satm_family != AF_ATM)
+ return (EAFNOSUPPORT);
+
+ sapadr = &satm->satm_addr.t_atm_sap_addr;
+ if (sapadr->SVE_tag_addr != T_ATM_PRESENT)
+ return (EINVAL);
+ if (sapadr->address_format == T_ATM_ENDSYS_ADDR) {
+ if (sapadr->SVE_tag_selector != T_ATM_PRESENT)
+ return (EINVAL);
+ } else if (sapadr->address_format == T_ATM_E164_ADDR) {
+ if (sapadr->SVE_tag_selector != T_ATM_ABSENT)
+ return (EINVAL);
+ } else if (sapadr->address_format == T_ATM_PVC_ADDR) {
+ if (sapadr->SVE_tag_selector != T_ATM_ABSENT)
+ return (EINVAL);
+ } else
+ return (EINVAL);
+ if (sapadr->address_length > ATM_ADDR_LEN)
+ return (EINVAL);
+
+ sapl2 = &satm->satm_addr.t_atm_sap_layer2;
+ if (sapl2->SVE_tag == T_ATM_PRESENT) {
+ if ((sapl2->ID_type != T_ATM_SIMPLE_ID) &&
+ (sapl2->ID_type != T_ATM_USER_ID))
+ return (EINVAL);
+ } else if (sapl2->SVE_tag != T_ATM_ABSENT)
+ return (EINVAL);
+
+ sapl3 = &satm->satm_addr.t_atm_sap_layer3;
+ if (sapl3->SVE_tag == T_ATM_PRESENT) {
+ if ((sapl3->ID_type != T_ATM_SIMPLE_ID) &&
+ (sapl3->ID_type != T_ATM_IPI_ID) &&
+ (sapl3->ID_type != T_ATM_SNAP_ID) &&
+ (sapl3->ID_type != T_ATM_USER_ID))
+ return (EINVAL);
+ } else if (sapl3->SVE_tag != T_ATM_ABSENT)
+ return (EINVAL);
+
+ sapapl = &satm->satm_addr.t_atm_sap_appl;
+ if (sapapl->SVE_tag == T_ATM_PRESENT) {
+ if ((sapapl->ID_type != T_ATM_ISO_APP_ID) &&
+ (sapapl->ID_type != T_ATM_USER_APP_ID) &&
+ (sapapl->ID_type != T_ATM_VENDOR_APP_ID))
+ return (EINVAL);
+ } else if (sapapl->SVE_tag != T_ATM_ABSENT)
+ return (EINVAL);
+
+ /*
+ * Select an outgoing network interface
+ */
+ if (atp->atp_attr.nif == NULL) {
+ struct atm_pif *pip;
+
+ for (pip = atm_interface_head; pip != NULL;
+ pip = pip->pif_next) {
+ if (pip->pif_nif != NULL) {
+ atp->atp_attr.nif = pip->pif_nif;
+ break;
+ }
+ }
+ if (atp->atp_attr.nif == NULL)
+ return (ENXIO);
+ }
+
+ /*
+ * Set supplied connection attributes
+ */
+ atp->atp_attr.called.tag = T_ATM_PRESENT;
+ KM_COPY(&sapadr->address_format, &atp->atp_attr.called.addr,
+ sizeof(Atm_addr));
+
+ atp->atp_attr.blli.tag_l2 = sapl2->SVE_tag;
+ if (sapl2->SVE_tag == T_ATM_PRESENT) {
+ atp->atp_attr.blli.v.layer_2_protocol.ID_type = sapl2->ID_type;
+ KM_COPY(&sapl2->ID, &atp->atp_attr.blli.v.layer_2_protocol.ID,
+ sizeof(atp->atp_attr.blli.v.layer_2_protocol.ID));
+ }
+
+ atp->atp_attr.blli.tag_l3 = sapl3->SVE_tag;
+ if (sapl3->SVE_tag == T_ATM_PRESENT) {
+ atp->atp_attr.blli.v.layer_3_protocol.ID_type = sapl3->ID_type;
+ KM_COPY(&sapl3->ID, &atp->atp_attr.blli.v.layer_3_protocol.ID,
+ sizeof(atp->atp_attr.blli.v.layer_3_protocol.ID));
+ }
+
+ atp->atp_attr.bhli.tag = sapapl->SVE_tag;
+ if (sapapl->SVE_tag == T_ATM_PRESENT) {
+ atp->atp_attr.bhli.v.ID_type = sapapl->ID_type;
+ KM_COPY(&sapapl->ID, &atp->atp_attr.bhli.v.ID,
+ sizeof(atp->atp_attr.bhli.v.ID));
+ }
+
+ /*
+ * We're finally ready to initiate the ATM connection
+ */
+ soisconnecting(so);
+ atm_sock_stat.as_connreq[atp->atp_type]++;
+ err = atm_cm_connect(epp, atp, &atp->atp_attr, &atp->atp_conn);
+ if (err == 0) {
+ /*
+ * Connection is setup
+ */
+ atm_sock_stat.as_conncomp[atp->atp_type]++;
+ soisconnected(so);
+
+ } else if (err == EINPROGRESS) {
+ /*
+ * We've got to wait for a connected event
+ */
+ err = 0;
+
+ } else {
+ /*
+ * Call failed...
+ */
+ atm_sock_stat.as_connfail[atp->atp_type]++;
+ soisdisconnected(so);
+ }
+
+ return (err);
+}
+
+
+/*
+ * Disconnect connected socket
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * so pointer to socket
+ *
+ * Returns:
+ * 0 request processed
+ * errno error processing request - reason indicated
+ *
+ */
+int
+atm_sock_disconnect(so)
+ struct socket *so;
+{
+ Atm_pcb *atp = sotoatmpcb(so);
+ struct t_atm_cause *cause;
+ int err;
+
+ /*
+ * Make sure we're still attached
+ */
+ if (atp == NULL)
+ return (ENOTCONN);
+
+ /*
+ * Release the ATM connection
+ */
+ if (atp->atp_conn) {
+ if (atp->atp_attr.cause.tag == T_ATM_PRESENT)
+ cause = &atp->atp_attr.cause.v;
+ else
+ cause = &atm_sock_cause;
+ err = atm_cm_release(atp->atp_conn, cause);
+ if (err)
+ log(LOG_ERR, "atm_sock_disconnect: release fail (%d)\n",
+ err);
+ atm_sock_stat.as_connrel[atp->atp_type]++;
+ atp->atp_conn = NULL;
+ }
+
+ soisdisconnected(so);
+
+ return (0);
+}
+
+
+/*
+ * Retrieve local socket address
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * so pointer to socket
+ * addr pointer to pointer to contain protocol address
+ *
+ * Returns:
+ * 0 request processed
+ * errno error processing request - reason indicated
+ *
+ */
+int
+atm_sock_sockaddr(so, addr)
+ struct socket *so;
+ struct sockaddr **addr;
+{
+ struct sockaddr_atm *satm;
+ struct t_atm_sap_addr *saddr;
+ Atm_pcb *atp = sotoatmpcb(so);
+
+ /*
+ * Return local interface address, if known
+ */
+ satm = KM_ALLOC(sizeof *satm, M_SONAME, M_WAITOK);
+ if (satm == NULL)
+ return (ENOMEM);
+
+ KM_ZERO(satm, sizeof(*satm));
+ satm->satm_family = AF_ATM;
+#if (defined(BSD) && (BSD >= 199103))
+ satm->satm_len = sizeof(*satm);
+#endif
+
+ saddr = &satm->satm_addr.t_atm_sap_addr;
+ if (atp->atp_attr.nif && atp->atp_attr.nif->nif_pif->pif_siginst) {
+ saddr->SVE_tag_addr = T_ATM_PRESENT;
+ ATM_ADDR_SEL_COPY(
+ &atp->atp_attr.nif->nif_pif->pif_siginst->si_addr,
+ atp->atp_attr.nif->nif_sel, saddr);
+ if (saddr->address_format == T_ATM_ENDSYS_ADDR)
+ saddr->SVE_tag_selector = T_ATM_PRESENT;
+ else
+ saddr->SVE_tag_selector = T_ATM_ABSENT;
+ } else {
+ saddr->SVE_tag_addr = T_ATM_ABSENT;
+ saddr->SVE_tag_selector = T_ATM_ABSENT;
+ saddr->address_format = T_ATM_ABSENT;
+ }
+ satm->satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_ABSENT;
+ satm->satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
+ satm->satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
+
+ *addr = (struct sockaddr *)satm;
+ return (0);
+}
+
+
+/*
+ * Retrieve peer socket address
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * so pointer to socket
+ * addr pointer to pointer to contain protocol address
+ *
+ * Returns:
+ * 0 request processed
+ * errno error processing request - reason indicated
+ *
+ */
+int
+atm_sock_peeraddr(so, addr)
+ struct socket *so;
+ struct sockaddr **addr;
+{
+ struct sockaddr_atm *satm;
+ struct t_atm_sap_addr *saddr;
+ Atm_pcb *atp = sotoatmpcb(so);
+ Atm_connvc *cvp;
+
+ /*
+ * Return remote address, if known
+ */
+ satm = KM_ALLOC(sizeof *satm, M_SONAME, M_WAITOK);
+ if (satm == NULL)
+ return (ENOMEM);
+
+ KM_ZERO(satm, sizeof(*satm));
+ satm->satm_family = AF_ATM;
+#if (defined(BSD) && (BSD >= 199103))
+ satm->satm_len = sizeof(*satm);
+#endif
+
+ saddr = &satm->satm_addr.t_atm_sap_addr;
+ if (so->so_state & SS_ISCONNECTED) {
+ cvp = atp->atp_conn->co_connvc;
+ saddr->SVE_tag_addr = T_ATM_PRESENT;
+ if (cvp->cvc_flags & CVCF_CALLER) {
+ ATM_ADDR_COPY(&cvp->cvc_attr.called.addr, saddr);
+ } else {
+ if (cvp->cvc_attr.calling.tag == T_ATM_PRESENT) {
+ ATM_ADDR_COPY(&cvp->cvc_attr.calling.addr,
+ saddr);
+ } else {
+ saddr->SVE_tag_addr = T_ATM_ABSENT;
+ saddr->address_format = T_ATM_ABSENT;
+ }
+ }
+ if (saddr->address_format == T_ATM_ENDSYS_ADDR)
+ saddr->SVE_tag_selector = T_ATM_PRESENT;
+ else
+ saddr->SVE_tag_selector = T_ATM_ABSENT;
+ } else {
+ saddr->SVE_tag_addr = T_ATM_ABSENT;
+ saddr->SVE_tag_selector = T_ATM_ABSENT;
+ saddr->address_format = T_ATM_ABSENT;
+ }
+ satm->satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_ABSENT;
+ satm->satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
+ satm->satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
+
+ *addr = (struct sockaddr *)satm;
+ return (0);
+}
+
+
+/*
+ * Common setsockopt processing
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * so pointer to socket
+ * sopt pointer to socket option info
+ * atp pointer to ATM PCB
+ *
+ * Returns:
+ * 0 request processed
+ * errno error processing request - reason indicated
+ *
+ */
+int
+atm_sock_setopt(so, sopt, atp)
+ struct socket *so;
+ struct sockopt *sopt;
+ Atm_pcb *atp;
+{
+ int err = 0;
+ union {
+ struct t_atm_aal5 aal5;
+ struct t_atm_traffic trf;
+ struct t_atm_bearer brr;
+ struct t_atm_bhli bhl;
+ struct t_atm_blli bll;
+ Atm_addr addr;
+ struct t_atm_cause cau;
+ struct t_atm_qos qos;
+ struct t_atm_transit trn;
+ struct t_atm_net_intf nif;
+ struct t_atm_llc llc;
+ struct t_atm_app_name appn;
+ } p;
+
+#define MAXVAL(bits) ((1 << bits) - 1)
+#define MAXMASK(bits) (~MAXVAL(bits))
+
+ switch (sopt->sopt_name) {
+
+ case T_ATM_AAL5:
+ err = sooptcopyin(sopt, &p.aal5, sizeof p.aal5, sizeof p.aal5);
+ if (err)
+ break;
+ if ((p.aal5.forward_max_SDU_size != T_ATM_ABSENT) &&
+ (p.aal5.forward_max_SDU_size & MAXMASK(16)))
+ return (EINVAL);
+ if ((p.aal5.backward_max_SDU_size != T_ATM_ABSENT) &&
+ (p.aal5.backward_max_SDU_size & MAXMASK(16)))
+ return (EINVAL);
+ if ((p.aal5.SSCS_type != T_ATM_ABSENT) &&
+ (p.aal5.SSCS_type != T_ATM_NULL) &&
+ (p.aal5.SSCS_type != T_ATM_SSCS_SSCOP_REL) &&
+ (p.aal5.SSCS_type != T_ATM_SSCS_SSCOP_UNREL) &&
+ (p.aal5.SSCS_type != T_ATM_SSCS_FR))
+ return (EINVAL);
+
+ if ((p.aal5.forward_max_SDU_size == T_ATM_ABSENT) &&
+ (p.aal5.backward_max_SDU_size == T_ATM_ABSENT) &&
+ (p.aal5.SSCS_type == T_ATM_ABSENT))
+ atp->atp_attr.aal.tag = T_ATM_ABSENT;
+ else {
+ atp->atp_attr.aal.tag = T_ATM_PRESENT;
+ atp->atp_attr.aal.type = ATM_AAL5;
+ atp->atp_attr.aal.v.aal5 = p.aal5;
+ }
+ break;
+
+ case T_ATM_TRAFFIC:
+ err = sooptcopyin(sopt, &p.trf, sizeof p.trf, sizeof p.trf);
+ if (err)
+ break;
+ if ((p.trf.forward.PCR_high_priority != T_ATM_ABSENT) &&
+ (p.trf.forward.PCR_high_priority & MAXMASK(24)))
+ return (EINVAL);
+ if (p.trf.forward.PCR_all_traffic & MAXMASK(24))
+ return (EINVAL);
+ if ((p.trf.forward.SCR_high_priority != T_ATM_ABSENT) &&
+ (p.trf.forward.SCR_high_priority & MAXMASK(24)))
+ return (EINVAL);
+ if ((p.trf.forward.SCR_all_traffic != T_ATM_ABSENT) &&
+ (p.trf.forward.SCR_all_traffic & MAXMASK(24)))
+ return (EINVAL);
+ if ((p.trf.forward.MBS_high_priority != T_ATM_ABSENT) &&
+ (p.trf.forward.MBS_high_priority & MAXMASK(24)))
+ return (EINVAL);
+ if ((p.trf.forward.MBS_all_traffic != T_ATM_ABSENT) &&
+ (p.trf.forward.MBS_all_traffic & MAXMASK(24)))
+ return (EINVAL);
+ if ((p.trf.forward.tagging != T_YES) &&
+ (p.trf.forward.tagging != T_NO))
+ return (EINVAL);
+
+ if ((p.trf.backward.PCR_high_priority != T_ATM_ABSENT) &&
+ (p.trf.backward.PCR_high_priority & MAXMASK(24)))
+ return (EINVAL);
+ if (p.trf.backward.PCR_all_traffic & MAXMASK(24))
+ return (EINVAL);
+ if ((p.trf.backward.SCR_high_priority != T_ATM_ABSENT) &&
+ (p.trf.backward.SCR_high_priority & MAXMASK(24)))
+ return (EINVAL);
+ if ((p.trf.backward.SCR_all_traffic != T_ATM_ABSENT) &&
+ (p.trf.backward.SCR_all_traffic & MAXMASK(24)))
+ return (EINVAL);
+ if ((p.trf.backward.MBS_high_priority != T_ATM_ABSENT) &&
+ (p.trf.backward.MBS_high_priority & MAXMASK(24)))
+ return (EINVAL);
+ if ((p.trf.backward.MBS_all_traffic != T_ATM_ABSENT) &&
+ (p.trf.backward.MBS_all_traffic & MAXMASK(24)))
+ return (EINVAL);
+ if ((p.trf.backward.tagging != T_YES) &&
+ (p.trf.backward.tagging != T_NO))
+ return (EINVAL);
+ if ((p.trf.best_effort != T_YES) &&
+ (p.trf.best_effort != T_NO))
+ return (EINVAL);
+
+ atp->atp_attr.traffic.tag = T_ATM_PRESENT;
+ atp->atp_attr.traffic.v = p.trf;
+ break;
+
+ case T_ATM_BEARER_CAP:
+ err = sooptcopyin(sopt, &p.brr, sizeof p.brr, sizeof p.brr);
+ if (err)
+ break;
+ if ((p.brr.bearer_class != T_ATM_CLASS_A) &&
+ (p.brr.bearer_class != T_ATM_CLASS_C) &&
+ (p.brr.bearer_class != T_ATM_CLASS_X))
+ return (EINVAL);
+ if ((p.brr.traffic_type != T_ATM_NULL) &&
+ (p.brr.traffic_type != T_ATM_CBR) &&
+ (p.brr.traffic_type != T_ATM_VBR))
+ return (EINVAL);
+ if ((p.brr.timing_requirements != T_ATM_NULL) &&
+ (p.brr.timing_requirements != T_ATM_END_TO_END) &&
+ (p.brr.timing_requirements != T_ATM_NO_END_TO_END))
+ return (EINVAL);
+ if ((p.brr.clipping_susceptibility != T_NO) &&
+ (p.brr.clipping_susceptibility != T_YES))
+ return (EINVAL);
+ if ((p.brr.connection_configuration != T_ATM_1_TO_1) &&
+ (p.brr.connection_configuration != T_ATM_1_TO_MANY))
+ return (EINVAL);
+
+ atp->atp_attr.bearer.tag = T_ATM_PRESENT;
+ atp->atp_attr.bearer.v = p.brr;
+ break;
+
+ case T_ATM_BHLI:
+ err = sooptcopyin(sopt, &p.bhl, sizeof p.bhl, sizeof p.bhl);
+ if (err)
+ break;
+ if ((p.bhl.ID_type != T_ATM_ABSENT) &&
+ (p.bhl.ID_type != T_ATM_ISO_APP_ID) &&
+ (p.bhl.ID_type != T_ATM_USER_APP_ID) &&
+ (p.bhl.ID_type != T_ATM_VENDOR_APP_ID))
+ return (EINVAL);
+
+ if (p.bhl.ID_type == T_ATM_ABSENT)
+ atp->atp_attr.bhli.tag = T_ATM_ABSENT;
+ else {
+ atp->atp_attr.bhli.tag = T_ATM_PRESENT;
+ atp->atp_attr.bhli.v = p.bhl;
+ }
+ break;
+
+ case T_ATM_BLLI:
+ err = sooptcopyin(sopt, &p.bll, sizeof p.bll, sizeof p.bll);
+ if (err)
+ break;
+ if ((p.bll.layer_2_protocol.ID_type != T_ATM_ABSENT) &&
+ (p.bll.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) &&
+ (p.bll.layer_2_protocol.ID_type != T_ATM_USER_ID))
+ return (EINVAL);
+ if ((p.bll.layer_2_protocol.mode != T_ATM_ABSENT) &&
+ (p.bll.layer_2_protocol.mode != T_ATM_BLLI_NORMAL_MODE) &&
+ (p.bll.layer_2_protocol.mode != T_ATM_BLLI_EXTENDED_MODE))
+ return (EINVAL);
+ if ((p.bll.layer_2_protocol.window_size != T_ATM_ABSENT) &&
+ (p.bll.layer_2_protocol.window_size < 1))
+ return (EINVAL);
+
+ if ((p.bll.layer_3_protocol.ID_type != T_ATM_ABSENT) &&
+ (p.bll.layer_3_protocol.ID_type != T_ATM_SIMPLE_ID) &&
+ (p.bll.layer_3_protocol.ID_type != T_ATM_IPI_ID) &&
+ (p.bll.layer_3_protocol.ID_type != T_ATM_SNAP_ID) &&
+ (p.bll.layer_3_protocol.ID_type != T_ATM_USER_ID))
+ return (EINVAL);
+ if ((p.bll.layer_3_protocol.mode != T_ATM_ABSENT) &&
+ (p.bll.layer_3_protocol.mode != T_ATM_BLLI_NORMAL_MODE) &&
+ (p.bll.layer_3_protocol.mode != T_ATM_BLLI_EXTENDED_MODE))
+ return (EINVAL);
+ if ((p.bll.layer_3_protocol.packet_size != T_ATM_ABSENT) &&
+ (p.bll.layer_3_protocol.packet_size & MAXMASK(4)))
+ return (EINVAL);
+ if ((p.bll.layer_3_protocol.window_size != T_ATM_ABSENT) &&
+ (p.bll.layer_3_protocol.window_size < 1))
+ return (EINVAL);
+
+ if (p.bll.layer_2_protocol.ID_type == T_ATM_ABSENT)
+ atp->atp_attr.blli.tag_l2 = T_ATM_ABSENT;
+ else
+ atp->atp_attr.blli.tag_l2 = T_ATM_PRESENT;
+
+ if (p.bll.layer_3_protocol.ID_type == T_ATM_ABSENT)
+ atp->atp_attr.blli.tag_l3 = T_ATM_ABSENT;
+ else
+ atp->atp_attr.blli.tag_l3 = T_ATM_PRESENT;
+
+ if ((atp->atp_attr.blli.tag_l2 == T_ATM_PRESENT) ||
+ (atp->atp_attr.blli.tag_l3 == T_ATM_PRESENT))
+ atp->atp_attr.blli.v = p.bll;
+ break;
+
+ case T_ATM_DEST_ADDR:
+ err = sooptcopyin(sopt, &p.addr, sizeof p.addr, sizeof p.addr);
+ if (err)
+ break;
+ if ((p.addr.address_format != T_ATM_ENDSYS_ADDR) &&
+ (p.addr.address_format != T_ATM_E164_ADDR))
+ return (EINVAL);
+ if (p.addr.address_length > ATM_ADDR_LEN)
+ return (EINVAL);
+
+ atp->atp_attr.called.tag = T_ATM_PRESENT;
+ atp->atp_attr.called.addr = p.addr;
+ break;
+
+ case T_ATM_DEST_SUB:
+ err = sooptcopyin(sopt, &p.addr, sizeof p.addr, sizeof p.addr);
+ if (err)
+ break;
+ if ((p.addr.address_format != T_ATM_ABSENT) &&
+ (p.addr.address_format != T_ATM_NSAP_ADDR))
+ return (EINVAL);
+ if (p.addr.address_length > ATM_ADDR_LEN)
+ return (EINVAL);
+
+ /* T_ATM_DEST_ADDR controls tag */
+ atp->atp_attr.called.subaddr = p.addr;
+ break;
+
+ case T_ATM_ORIG_ADDR:
+ return (EACCES);
+
+ case T_ATM_ORIG_SUB:
+ return (EACCES);
+
+ case T_ATM_CALLER_ID:
+ return (EACCES);
+
+ case T_ATM_CAUSE:
+ err = sooptcopyin(sopt, &p.cau, sizeof p.cau, sizeof p.cau);
+ if (err)
+ break;
+ if ((p.cau.coding_standard != T_ATM_ABSENT) &&
+ (p.cau.coding_standard != T_ATM_ITU_CODING) &&
+ (p.cau.coding_standard != T_ATM_NETWORK_CODING))
+ return (EINVAL);
+ if ((p.cau.location != T_ATM_LOC_USER) &&
+ (p.cau.location != T_ATM_LOC_LOCAL_PRIVATE_NET) &&
+ (p.cau.location != T_ATM_LOC_LOCAL_PUBLIC_NET) &&
+ (p.cau.location != T_ATM_LOC_TRANSIT_NET) &&
+ (p.cau.location != T_ATM_LOC_REMOTE_PUBLIC_NET) &&
+ (p.cau.location != T_ATM_LOC_REMOTE_PRIVATE_NET) &&
+ (p.cau.location != T_ATM_LOC_INTERNATIONAL_NET) &&
+ (p.cau.location != T_ATM_LOC_BEYOND_INTERWORKING))
+ return (EINVAL);
+
+ if (p.cau.coding_standard == T_ATM_ABSENT)
+ atp->atp_attr.cause.tag = T_ATM_ABSENT;
+ else {
+ atp->atp_attr.cause.tag = T_ATM_PRESENT;
+ atp->atp_attr.cause.v = p.cau;
+ }
+ break;
+
+ case T_ATM_QOS:
+ err = sooptcopyin(sopt, &p.qos, sizeof p.qos, sizeof p.qos);
+ if (err)
+ break;
+ if ((p.qos.coding_standard != T_ATM_ABSENT) &&
+ (p.qos.coding_standard != T_ATM_ITU_CODING) &&
+ (p.qos.coding_standard != T_ATM_NETWORK_CODING))
+ return (EINVAL);
+ if ((p.qos.forward.qos_class != T_ATM_QOS_CLASS_0) &&
+ (p.qos.forward.qos_class != T_ATM_QOS_CLASS_1) &&
+ (p.qos.forward.qos_class != T_ATM_QOS_CLASS_2) &&
+ (p.qos.forward.qos_class != T_ATM_QOS_CLASS_3) &&
+ (p.qos.forward.qos_class != T_ATM_QOS_CLASS_4))
+ return (EINVAL);
+ if ((p.qos.backward.qos_class != T_ATM_QOS_CLASS_0) &&
+ (p.qos.backward.qos_class != T_ATM_QOS_CLASS_1) &&
+ (p.qos.backward.qos_class != T_ATM_QOS_CLASS_2) &&
+ (p.qos.backward.qos_class != T_ATM_QOS_CLASS_3) &&
+ (p.qos.backward.qos_class != T_ATM_QOS_CLASS_4))
+ return (EINVAL);
+
+ if (p.qos.coding_standard == T_ATM_ABSENT)
+ atp->atp_attr.qos.tag = T_ATM_ABSENT;
+ else {
+ atp->atp_attr.qos.tag = T_ATM_PRESENT;
+ atp->atp_attr.qos.v = p.qos;
+ }
+ break;
+
+ case T_ATM_TRANSIT:
+ err = sooptcopyin(sopt, &p.trn, sizeof p.trn, sizeof p.trn);
+ if (err)
+ break;
+ if (p.trn.length > T_ATM_MAX_NET_ID)
+ return (EINVAL);
+
+ if (p.trn.length == 0)
+ atp->atp_attr.transit.tag = T_ATM_ABSENT;
+ else {
+ atp->atp_attr.transit.tag = T_ATM_PRESENT;
+ atp->atp_attr.transit.v = p.trn;
+ }
+ break;
+
+ case T_ATM_ADD_LEAF:
+ return (EPROTONOSUPPORT); /* XXX */
+
+ case T_ATM_DROP_LEAF:
+ return (EPROTONOSUPPORT); /* XXX */
+
+ case T_ATM_NET_INTF:
+ err = sooptcopyin(sopt, &p.nif, sizeof p.nif, sizeof p.nif);
+ if (err)
+ break;
+
+ atp->atp_attr.nif = atm_nifname(p.nif.net_intf);
+ if (atp->atp_attr.nif == NULL)
+ return (ENXIO);
+ break;
+
+ case T_ATM_LLC:
+ err = sooptcopyin(sopt, &p.llc, sizeof p.llc, sizeof p.llc);
+ if (err)
+ break;
+ if ((p.llc.llc_len < T_ATM_LLC_MIN_LEN) ||
+ (p.llc.llc_len > T_ATM_LLC_MAX_LEN))
+ return (EINVAL);
+
+ atp->atp_attr.llc.tag = T_ATM_PRESENT;
+ atp->atp_attr.llc.v = p.llc;
+ break;
+
+ case T_ATM_APP_NAME:
+ err = sooptcopyin(sopt, &p.appn, sizeof p.appn, sizeof p.appn);
+ if (err)
+ break;
+
+ strncpy(atp->atp_name, p.appn.app_name, T_ATM_APP_NAME_LEN);
+ break;
+
+ default:
+ return (ENOPROTOOPT);
+ }
+
+ return (err);
+}
+
+
+/*
+ * Common getsockopt processing
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * so pointer to socket
+ * sopt pointer to socket option info
+ * atp pointer to ATM PCB
+ *
+ * Returns:
+ * 0 request processed
+ * errno error processing request - reason indicated
+ *
+ */
+int
+atm_sock_getopt(so, sopt, atp)
+ struct socket *so;
+ struct sockopt *sopt;
+ Atm_pcb *atp;
+{
+ Atm_attributes *ap;
+
+ /*
+ * If socket is connected, return attributes for the VCC in use,
+ * otherwise just return what the user has setup so far.
+ */
+ if (so->so_state & SS_ISCONNECTED)
+ ap = &atp->atp_conn->co_connvc->cvc_attr;
+ else
+ ap = &atp->atp_attr;
+
+ switch (sopt->sopt_name) {
+
+ case T_ATM_AAL5:
+ if ((ap->aal.tag == T_ATM_PRESENT) &&
+ (ap->aal.type == ATM_AAL5)) {
+ return (sooptcopyout(sopt, &ap->aal.v.aal5,
+ sizeof ap->aal.v.aal5));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_TRAFFIC:
+ if (ap->traffic.tag == T_ATM_PRESENT) {
+ return (sooptcopyout(sopt, &ap->traffic.v,
+ sizeof ap->traffic.v));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_BEARER_CAP:
+ if (ap->bearer.tag == T_ATM_PRESENT) {
+ return (sooptcopyout(sopt, &ap->bearer.v,
+ sizeof ap->bearer.v));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_BHLI:
+ if (ap->bhli.tag == T_ATM_PRESENT) {
+ return (sooptcopyout(sopt, &ap->bhli.v,
+ sizeof ap->bhli.v));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_BLLI:
+ if ((ap->blli.tag_l2 == T_ATM_PRESENT) ||
+ (ap->blli.tag_l3 == T_ATM_PRESENT)) {
+ return (sooptcopyout(sopt, &ap->blli.v,
+ sizeof ap->blli.v));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_DEST_ADDR:
+ if (ap->called.tag == T_ATM_PRESENT) {
+ return (sooptcopyout(sopt, &ap->called.addr,
+ sizeof ap->called.addr));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_DEST_SUB:
+ if (ap->called.tag == T_ATM_PRESENT) {
+ return (sooptcopyout(sopt, &ap->called.subaddr,
+ sizeof ap->called.subaddr));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_ORIG_ADDR:
+ if (ap->calling.tag == T_ATM_PRESENT) {
+ return (sooptcopyout(sopt, &ap->calling.addr,
+ sizeof ap->calling.addr));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_ORIG_SUB:
+ if (ap->calling.tag == T_ATM_PRESENT) {
+ return (sooptcopyout(sopt, &ap->calling.subaddr,
+ sizeof ap->calling.subaddr));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_CALLER_ID:
+ if (ap->calling.tag == T_ATM_PRESENT) {
+ return (sooptcopyout(sopt, &ap->calling.cid,
+ sizeof ap->calling.cid));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_CAUSE:
+ if (ap->cause.tag == T_ATM_PRESENT) {
+ return (sooptcopyout(sopt, &ap->cause.v,
+ sizeof ap->cause.v));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_QOS:
+ if (ap->qos.tag == T_ATM_PRESENT) {
+ return (sooptcopyout(sopt, &ap->qos.v,
+ sizeof ap->qos.v));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_TRANSIT:
+ if (ap->transit.tag == T_ATM_PRESENT) {
+ return (sooptcopyout(sopt, &ap->transit.v,
+ sizeof ap->transit.v));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_LEAF_IND:
+ return (EPROTONOSUPPORT); /* XXX */
+
+ case T_ATM_NET_INTF:
+ if (ap->nif) {
+ struct t_atm_net_intf netif;
+ struct ifnet *ifp;
+
+ ifp = &ap->nif->nif_if;
+ (void) sprintf(netif.net_intf, "%s%d",
+ ifp->if_name, ifp->if_unit);
+ return (sooptcopyout(sopt, &netif,
+ sizeof netif));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ case T_ATM_LLC:
+ if (ap->llc.tag == T_ATM_PRESENT) {
+ return (sooptcopyout(sopt, &ap->llc.v,
+ sizeof ap->llc.v));
+ } else {
+ return (ENOENT);
+ }
+ break;
+
+ default:
+ return (ENOPROTOOPT);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Process Socket VCC Connected Notification
+ *
+ * Arguments:
+ * toku owner's connection token (atm_pcb protocol block)
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+atm_sock_connected(toku)
+ void *toku;
+{
+ Atm_pcb *atp = (Atm_pcb *)toku;
+
+ /*
+ * Connection is setup
+ */
+ atm_sock_stat.as_conncomp[atp->atp_type]++;
+ soisconnected(atp->atp_socket);
+}
+
+
+/*
+ * Process Socket VCC Cleared Notification
+ *
+ * Arguments:
+ * toku owner's connection token (atm_pcb protocol block)
+ * cause pointer to cause code
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+atm_sock_cleared(toku, cause)
+ void *toku;
+ struct t_atm_cause *cause;
+{
+ Atm_pcb *atp = (Atm_pcb *)toku;
+ struct socket *so;
+
+ so = atp->atp_socket;
+
+ /*
+ * Save call clearing cause
+ */
+ atp->atp_attr.cause.tag = T_ATM_PRESENT;
+ atp->atp_attr.cause.v = *cause;
+
+ /*
+ * Set user error code
+ */
+ if (so->so_state & SS_ISCONNECTED) {
+ so->so_error = ECONNRESET;
+ atm_sock_stat.as_connclr[atp->atp_type]++;
+ } else {
+ so->so_error = ECONNREFUSED;
+ atm_sock_stat.as_connfail[atp->atp_type]++;
+ }
+
+ /*
+ * Connection is gone
+ */
+ atp->atp_conn = NULL;
+ soisdisconnected(so);
+
+ /*
+ * Cleanup failed incoming connection setup
+ */
+ if (so->so_state & SS_NOFDREF) {
+ (void) atm_sock_detach(so);
+ }
+}
+
OpenPOWER on IntegriCloud