diff options
Diffstat (limited to 'sys/netatm/atm_socket.c')
-rw-r--r-- | sys/netatm/atm_socket.c | 1311 |
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); + } +} + |