aboutsummaryrefslogtreecommitdiff
path: root/sys/netatm/ipatm/ipatm_vcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/ipatm/ipatm_vcm.c')
-rw-r--r--sys/netatm/ipatm/ipatm_vcm.c1245
1 files changed, 1245 insertions, 0 deletions
diff --git a/sys/netatm/ipatm/ipatm_vcm.c b/sys/netatm/ipatm/ipatm_vcm.c
new file mode 100644
index 000000000000..5d6a7fc7cfb4
--- /dev/null
+++ b/sys/netatm/ipatm/ipatm_vcm.c
@@ -0,0 +1,1245 @@
+/*
+ *
+ * ===================================
+ * 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: ipatm_vcm.c,v 1.13 1998/08/06 18:21:14 mks Exp $
+ *
+ */
+
+/*
+ * IP Over ATM Support
+ * -------------------
+ *
+ * Virtual Channel Manager
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: ipatm_vcm.c,v 1.13 1998/08/06 18:21:14 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm.h>
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+
+
+Atm_attributes ipatm_aal5llc = {
+ NULL, /* nif */
+ CMAPI_CPCS, /* api */
+ 0, /* api_init */
+ 0, /* headin */
+ 0, /* headout */
+ { /* aal */
+ T_ATM_PRESENT,
+ ATM_AAL5
+ },
+ { /* traffic */
+ T_ATM_PRESENT,
+ {
+ {
+ T_ATM_ABSENT,
+ 0,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_NO
+ },
+ {
+ T_ATM_ABSENT,
+ 0,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_NO
+ },
+ T_YES
+ },
+ },
+ { /* bearer */
+ T_ATM_PRESENT,
+ {
+ T_ATM_CLASS_X,
+ T_ATM_NULL,
+ T_ATM_NULL,
+ T_NO,
+ T_ATM_1_TO_1
+ }
+ },
+ { /* bhli */
+ T_ATM_ABSENT
+ },
+ { /* blli */
+ T_ATM_PRESENT,
+ T_ATM_ABSENT,
+ {
+ {
+ T_ATM_SIMPLE_ID,
+ },
+ {
+ T_ATM_ABSENT
+ }
+ }
+ },
+ { /* llc */
+ T_ATM_PRESENT,
+ {
+ T_ATM_LLC_SHARING,
+ IPATM_LLC_LEN,
+ IPATM_LLC_HDR
+ }
+ },
+ { /* called */
+ T_ATM_PRESENT,
+ },
+ { /* calling */
+ T_ATM_ABSENT
+ },
+ { /* qos */
+ T_ATM_PRESENT,
+ {
+ T_ATM_NETWORK_CODING,
+ {
+ T_ATM_QOS_CLASS_0,
+ },
+ {
+ T_ATM_QOS_CLASS_0
+ }
+ }
+ },
+ { /* transit */
+ T_ATM_ABSENT
+ },
+ { /* cause */
+ T_ATM_ABSENT
+ }
+};
+
+Atm_attributes ipatm_aal5null = {
+ NULL, /* nif */
+ CMAPI_CPCS, /* api */
+ 0, /* api_init */
+ sizeof(struct ifnet *), /* headin */
+ 0, /* headout */
+ { /* aal */
+ T_ATM_PRESENT,
+ ATM_AAL5
+ },
+ { /* traffic */
+ T_ATM_PRESENT,
+ {
+ {
+ T_ATM_ABSENT,
+ 0,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_NO
+ },
+ {
+ T_ATM_ABSENT,
+ 0,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_NO
+ },
+ T_YES
+ },
+ },
+ { /* bearer */
+ T_ATM_PRESENT,
+ {
+ T_ATM_CLASS_X,
+ T_ATM_NULL,
+ T_ATM_NULL,
+ T_NO,
+ T_ATM_1_TO_1
+ }
+ },
+ { /* bhli */
+ T_ATM_ABSENT
+ },
+ { /* blli */
+ T_ATM_ABSENT,
+ T_ATM_ABSENT
+ },
+ { /* llc */
+ T_ATM_ABSENT
+ },
+ { /* called */
+ T_ATM_PRESENT,
+ },
+ { /* calling */
+ T_ATM_ABSENT
+ },
+ { /* qos */
+ T_ATM_PRESENT,
+ {
+ T_ATM_NETWORK_CODING,
+ {
+ T_ATM_QOS_CLASS_0,
+ },
+ {
+ T_ATM_QOS_CLASS_0
+ }
+ }
+ },
+ { /* transit */
+ T_ATM_ABSENT
+ },
+ { /* cause */
+ T_ATM_ABSENT
+ }
+};
+
+Atm_attributes ipatm_aal4null = {
+ NULL, /* nif */
+ CMAPI_CPCS, /* api */
+ 0, /* api_init */
+ sizeof(struct ifnet *), /* headin */
+ 0, /* headout */
+ { /* aal */
+ T_ATM_PRESENT,
+ ATM_AAL3_4
+ },
+ { /* traffic */
+ T_ATM_PRESENT,
+ {
+ {
+ T_ATM_ABSENT,
+ 0,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_NO
+ },
+ {
+ T_ATM_ABSENT,
+ 0,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_NO
+ },
+ T_YES
+ },
+ },
+ { /* bearer */
+ T_ATM_PRESENT,
+ {
+ T_ATM_CLASS_X,
+ T_ATM_NULL,
+ T_ATM_NULL,
+ T_NO,
+ T_ATM_1_TO_1
+ }
+ },
+ { /* bhli */
+ T_ATM_ABSENT
+ },
+ { /* blli */
+ T_ATM_ABSENT,
+ T_ATM_ABSENT
+ },
+ { /* llc */
+ T_ATM_ABSENT
+ },
+ { /* called */
+ T_ATM_PRESENT,
+ },
+ { /* calling */
+ T_ATM_ABSENT
+ },
+ { /* qos */
+ T_ATM_PRESENT,
+ {
+ T_ATM_NETWORK_CODING,
+ {
+ T_ATM_QOS_CLASS_0,
+ },
+ {
+ T_ATM_QOS_CLASS_0
+ }
+ }
+ },
+ { /* transit */
+ T_ATM_ABSENT
+ },
+ { /* cause */
+ T_ATM_ABSENT
+ }
+};
+
+static struct t_atm_cause ipatm_cause = {
+ T_ATM_ITU_CODING,
+ T_ATM_LOC_USER,
+ 0,
+ {0, 0, 0, 0}
+};
+
+
+/*
+ * Open an IP PVC
+ *
+ * This function will perform all actions necessary to activate a
+ * PVC for IP usage. In particular, it will allocate control blocks,
+ * open the PVC, initialize PVC stack, and initiate whatever ARP
+ * procedures are required.
+ *
+ * Arguments:
+ * pvp pointer to PVC parameter structure
+ * sivp address to return pointer to IP PVC control block
+ *
+ * Returns:
+ * 0 PVC was successfully opened
+ * errno open failed - reason indicated
+ *
+ */
+int
+ipatm_openpvc(pvp, sivp)
+ struct ipatmpvc *pvp;
+ struct ipvcc **sivp;
+{
+ struct ipvcc *ivp;
+ Atm_attributes *ap;
+ Atm_addr_pvc *pvcp;
+ struct atm_nif *nip;
+ struct ip_nif *inp;
+ int s, err = 0;
+
+ inp = pvp->ipp_ipnif;
+ nip = inp->inf_nif;
+
+ /*
+ * Make sure interface is ready to go
+ */
+ if (inp->inf_state != IPNIF_ACTIVE) {
+ err = ENETDOWN;
+ goto done;
+ }
+
+ /*
+ * Validate fixed destination IP address
+ */
+ if (pvp->ipp_dst.sin_addr.s_addr != INADDR_ANY) {
+#if (defined(BSD) && (BSD >= 199306))
+ if (in_broadcast(pvp->ipp_dst.sin_addr, &nip->nif_if) ||
+#else
+ if (in_broadcast(pvp->ipp_dst.sin_addr) ||
+#endif
+ IN_MULTICAST(ntohl(pvp->ipp_dst.sin_addr.s_addr)) ||
+ ipatm_chknif(pvp->ipp_dst.sin_addr, inp)) {
+ err = EINVAL;
+ goto done;
+ }
+ }
+
+ /*
+ * Allocate IP VCC block
+ */
+ ivp = (struct ipvcc *)atm_allocate(&ipatm_vcpool);
+ if (ivp == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+
+ /*
+ * Initialize the PVC
+ */
+ ivp->iv_flags = IVF_PVC;
+ if (pvp->ipp_encaps == ATM_ENC_LLC)
+ ivp->iv_flags |= IVF_LLC;
+
+ /*
+ * Fill out connection attributes
+ */
+ if (pvp->ipp_aal == ATM_AAL5) {
+ if (pvp->ipp_encaps == ATM_ENC_LLC)
+ ap = &ipatm_aal5llc;
+ else
+ ap = &ipatm_aal5null;
+ } else {
+ ap = &ipatm_aal4null;
+ }
+
+ ap->nif = nip;
+ ap->traffic.v.forward.PCR_all_traffic = nip->nif_pif->pif_pcr;
+ ap->traffic.v.backward.PCR_all_traffic = nip->nif_pif->pif_pcr;
+ ap->called.addr.address_format = T_ATM_PVC_ADDR;
+ ap->called.addr.address_length = sizeof(Atm_addr_pvc);
+ pvcp = (Atm_addr_pvc *)ap->called.addr.address;
+ ATM_PVC_SET_VPI(pvcp, pvp->ipp_vpi);
+ ATM_PVC_SET_VCI(pvcp, pvp->ipp_vci);
+ ap->called.subaddr.address_format = T_ATM_ABSENT;
+ ap->called.subaddr.address_length = 0;
+
+ /*
+ * Create PVC
+ */
+ err = atm_cm_connect(&ipatm_endpt, ivp, ap, &ivp->iv_conn);
+ if (err) {
+ atm_free((caddr_t)ivp);
+ goto done;
+ }
+
+ /*
+ * Save PVC information and link in VCC
+ */
+ /* ivp->iv_ = ap->headout; */
+
+ /*
+ * Queue VCC onto its network interface
+ */
+ s = splnet();
+ ipatm_vccnt++;
+ ENQUEUE(ivp, struct ipvcc, iv_elem, inp->inf_vcq);
+ ivp->iv_ipnif = inp;
+ (void) splx(s);
+
+ /*
+ * Set destination IP address and IPVCC state
+ */
+ if (pvp->ipp_dst.sin_addr.s_addr == INADDR_ANY) {
+ /*
+ * Initiate ARP processing
+ */
+ switch ((*inp->inf_serv->is_arp_pvcopen)(ivp)) {
+
+ case MAP_PROCEEDING:
+ /*
+ * Wait for answer
+ */
+ ivp->iv_state = IPVCC_ACTIVE;
+ break;
+
+ case MAP_VALID:
+ /*
+ * We've got our answer already
+ */
+ ivp->iv_state = IPVCC_ACTIVE;
+ ivp->iv_flags |= IVF_MAPOK;
+ ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr;
+ break;
+
+ case MAP_FAILED:
+ /*
+ * Try again later
+ */
+ ivp->iv_state = IPVCC_ACTPENT;
+ IPVCC_TIMER(ivp, 1 * ATM_HZ);
+ break;
+
+ default:
+ panic("ipatm_openpvc: invalid arp_pvcopen return");
+ }
+
+ } else {
+ /*
+ * Use configured IP destination
+ */
+ ivp->iv_dst.s_addr = pvp->ipp_dst.sin_addr.s_addr;
+ ivp->iv_state = IPVCC_ACTIVE;
+ ivp->iv_flags |= IVF_MAPOK;
+ }
+
+done:
+ if (err)
+ *sivp = NULL;
+ else
+ *sivp = ivp;
+ return (err);
+}
+
+
+/*
+ * Create an IP SVC
+ *
+ * This function will initiate the creation of an IP SVC. The IP VCC
+ * control block will be initialized and, if required, we will initiate
+ * ARP processing in order to resolve the destination's ATM address. Once
+ * the destination ATM address is known, ipatm_opensvc() will be called.
+ *
+ * Arguments:
+ * ifp pointer to destination ifnet structure
+ * daf destination address family type
+ * dst pointer to destination address
+ * sivp address to return pointer to IP SVC control block
+ *
+ * Returns:
+ * 0 SVC creation was successfully initiated
+ * errno creation failed - reason indicated
+ *
+ */
+int
+ipatm_createsvc(ifp, daf, dst, sivp)
+ struct ifnet *ifp;
+ u_short daf;
+ caddr_t dst;
+ struct ipvcc **sivp;
+{
+ struct atm_nif *nip = (struct atm_nif *)ifp;
+ struct ip_nif *inp;
+ struct ipvcc *ivp;
+ struct in_addr *ip;
+ Atm_addr *atm;
+ int s, err = 0;
+
+ /*
+ * Get IP interface and make sure its ready
+ */
+ for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
+ if (inp->inf_nif == nip)
+ break;
+ }
+ if (inp == NULL) {
+ err = ENXIO;
+ goto done;
+ }
+ if (inp->inf_state != IPNIF_ACTIVE) {
+ err = ENETDOWN;
+ goto done;
+ }
+
+ /*
+ * Validate destination address
+ */
+ if (daf == AF_INET) {
+ /*
+ * Destination is IP address
+ */
+ ip = (struct in_addr *)dst;
+ atm = NULL;
+ if (ip->s_addr == INADDR_ANY) {
+ err = EADDRNOTAVAIL;
+ goto done;
+ }
+ } else if (daf == AF_ATM) {
+ /*
+ * Destination is ATM address
+ */
+ atm = (Atm_addr *)dst;
+ ip = NULL;
+ if (atm->address_format == T_ATM_ABSENT) {
+ err = EINVAL;
+ goto done;
+ }
+ } else {
+ err = EINVAL;
+ goto done;
+ }
+
+ /*
+ * Make sure we have services provider and ARP support
+ */
+ if ((inp->inf_serv == NULL) ||
+ (inp->inf_serv->is_arp_svcout == NULL)) {
+ err = ENETDOWN;
+ goto done;
+ }
+
+ /*
+ * Allocate IP VCC
+ */
+ ivp = (struct ipvcc *)atm_allocate(&ipatm_vcpool);
+ if (ivp == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+
+ /*
+ * Initialize SVC
+ */
+ ivp->iv_flags = IVF_SVC;
+ ivp->iv_ipnif = inp;
+
+ /*
+ * Get destination ATM address
+ */
+ if (daf == AF_INET) {
+ /*
+ * ARP is the way...
+ */
+ ivp->iv_dst.s_addr = ip->s_addr;
+
+ switch ((*inp->inf_serv->is_arp_svcout)(ivp, ip)) {
+
+ case MAP_PROCEEDING:
+ /*
+ * Wait for answer
+ */
+ ivp->iv_state = IPVCC_PMAP;
+ IPVCC_TIMER(ivp, IPATM_ARP_TIME);
+ break;
+
+ case MAP_VALID:
+ /*
+ * We've got our answer already, so open SVC
+ */
+ ivp->iv_flags |= IVF_MAPOK;
+ err = ipatm_opensvc(ivp);
+ if (err) {
+ (*inp->inf_serv->is_arp_close)(ivp);
+ atm_free((caddr_t)ivp);
+ goto done;
+ }
+ break;
+
+ case MAP_FAILED:
+ /*
+ * So sorry...come again
+ */
+ atm_free((caddr_t)ivp);
+ err = ENETDOWN;
+ goto done;
+
+ default:
+ panic("ipatm_createsvc: invalid arp_svcout return");
+ }
+ } else {
+ /*
+ * We were given the ATM address, so open the SVC
+ *
+ * Create temporary arp map entry so that opensvc() works.
+ * Caller must set up a permanent entry immediately! (yuk)
+ */
+ struct arpmap map;
+
+ ATM_ADDR_COPY(atm, &map.am_dstatm);
+ map.am_dstatmsub.address_format = T_ATM_ABSENT;
+ map.am_dstatmsub.address_length = 0;
+ ivp->iv_arpent = &map;
+ err = ipatm_opensvc(ivp);
+ if (err) {
+ atm_free((caddr_t)ivp);
+ goto done;
+ }
+ ivp->iv_arpent = NULL;
+ }
+
+ /*
+ * Queue VCC onto its network interface
+ */
+ s = splnet();
+ ipatm_vccnt++;
+ ENQUEUE(ivp, struct ipvcc, iv_elem, inp->inf_vcq);
+ (void) splx(s);
+
+done:
+ if (err)
+ *sivp = NULL;
+ else
+ *sivp = ivp;
+ return (err);
+}
+
+
+/*
+ * Open an IP SVC
+ *
+ * This function will continue the IP SVC creation process. Here, we
+ * will issue an SVC open to the signalling manager and then wait for
+ * the final SVC setup results.
+ *
+ * Arguments:
+ * ivp pointer to IP SVC to open
+ *
+ * Returns:
+ * 0 SVC open was successfully initiated
+ * errno open failed - reason indicated
+ *
+ */
+int
+ipatm_opensvc(ivp)
+ struct ipvcc *ivp;
+{
+ struct ip_nif *inp = ivp->iv_ipnif;
+ Atm_attributes *ap;
+ int err = 0, i;
+
+ /*
+ * Cancel possible arp timeout
+ */
+ IPVCC_CANCEL(ivp);
+
+ /*
+ * Fill out connection attributes
+ */
+ i = ivp->iv_parmx;
+ if (inp->inf_serv->is_vccparm[i].ivc_aal == ATM_AAL5) {
+ if (inp->inf_serv->is_vccparm[i].ivc_encaps == ATM_ENC_LLC) {
+ ap = &ipatm_aal5llc;
+ ivp->iv_flags |= IVF_LLC;
+ } else {
+ ap = &ipatm_aal5null;
+ ivp->iv_flags &= ~IVF_LLC;
+ }
+ } else {
+ ap = &ipatm_aal4null;
+ ivp->iv_flags &= ~IVF_LLC;
+ }
+
+ ap->nif = inp->inf_nif;
+ ap->traffic.v.forward.PCR_all_traffic = inp->inf_nif->nif_pif->pif_pcr;
+ ap->traffic.v.backward.PCR_all_traffic = inp->inf_nif->nif_pif->pif_pcr;
+
+ ATM_ADDR_COPY(&ivp->iv_arpent->am_dstatm, &ap->called.addr);
+ ATM_ADDR_COPY(&ivp->iv_arpent->am_dstatmsub, &ap->called.subaddr);
+
+ /*
+ * Initiate SVC open
+ */
+ err = atm_cm_connect(&ipatm_endpt, ivp, ap, &ivp->iv_conn);
+ switch (err) {
+
+ case EINPROGRESS:
+ /*
+ * Call is progressing
+ */
+ /* ivp->iv_ = ap->headout; */
+
+ /*
+ * Now we just wait for a CALL_CONNECTED event
+ */
+ ivp->iv_state = IPVCC_POPEN;
+ IPVCC_TIMER(ivp, IPATM_SVC_TIME);
+ err = 0;
+ break;
+
+ case 0:
+ /*
+ * We've been hooked up with a shared VCC
+ */
+ /* ivp->iv_ = ap->headout; */
+ ipatm_activate(ivp);
+ break;
+ }
+
+ return (err);
+}
+
+
+/*
+ * Retry an IP SVC Open
+ *
+ * This function will attempt to retry a failed SVC open request. The IP
+ * interface service provider specifies a list of possible VCC parameters
+ * for IP to use. We will try each set of parameters in turn until either
+ * an open succeeds or we reach the end of the list.
+ *
+ * Arguments:
+ * ivp pointer to IP SVC
+ *
+ * Returns:
+ * 0 SVC (re)open was successfully initiated
+ * else retry failed
+ *
+ */
+int
+ipatm_retrysvc(ivp)
+ struct ipvcc *ivp;
+{
+ struct ip_nif *inp = ivp->iv_ipnif;
+
+ /*
+ * If there isn't another set of vcc parameters to try, return
+ */
+ if ((++ivp->iv_parmx >= IPATM_VCCPARMS) ||
+ (inp->inf_serv->is_vccparm[ivp->iv_parmx].ivc_aal == 0))
+ return (1);
+
+ /*
+ * Okay, now initiate open with a new set of parameters
+ */
+ return (ipatm_opensvc(ivp));
+}
+
+
+/*
+ * Finish IP SVC Activation
+ *
+ * Arguments:
+ * ivp pointer to IP SVC
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+ipatm_activate(ivp)
+ struct ipvcc *ivp;
+{
+
+ /*
+ * Connection is now active
+ */
+ ivp->iv_state = IPVCC_ACTIVE;
+ IPVCC_CANCEL(ivp);
+
+ /*
+ * Tell ARP module that connection is active
+ */
+ if ((*ivp->iv_ipnif->inf_serv->is_arp_svcact)(ivp)) {
+ (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE);
+ return;
+ }
+
+ /*
+ * Send any queued packet
+ */
+ if ((ivp->iv_flags & IVF_MAPOK) && ivp->iv_queue) {
+ struct sockaddr_in sin;
+ struct ifnet *ifp;
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = ivp->iv_dst.s_addr;
+ ifp = (struct ifnet *)ivp->iv_ipnif->inf_nif;
+ (void) ipatm_ifoutput(ifp, ivp->iv_queue,
+ (struct sockaddr *)&sin);
+ ivp->iv_queue = NULL;
+ }
+}
+
+
+/*
+ * Process Incoming Calls
+ *
+ * This function will receive control when an incoming call has been matched
+ * to one of our registered listen parameter blocks. Assuming the call passes
+ * acceptance criteria and all required resources are available, we will
+ * create an IP SVC and notify the connection manager of our decision. We
+ * will then await notification of the final SVC setup results. If any
+ * problems are encountered, we will just tell the connection manager to
+ * reject the call.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tok owner's matched listening token
+ * cop pointer to incoming call's connection block
+ * ap pointer to incoming call's attributes
+ * tokp pointer to location to store our connection token
+ *
+ * Returns:
+ * 0 call is accepted
+ * errno call rejected - reason indicated
+ *
+ */
+int
+ipatm_incoming(tok, cop, ap, tokp)
+ void *tok;
+ Atm_connection *cop;
+ Atm_attributes *ap;
+ void **tokp;
+{
+ struct atm_nif *nip = ap->nif;
+ struct ip_nif *inp;
+ struct ipvcc *ivp = NULL;
+ int err, cause;
+ int usellc = 0, mtu = ATM_NIF_MTU;
+
+ /*
+ * Get IP interface and make sure its ready
+ */
+ for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
+ if (inp->inf_nif == nip)
+ break;
+ }
+ if ((inp == NULL) || (inp->inf_state != IPNIF_ACTIVE)) {
+ err = ENETUNREACH;
+ cause = T_ATM_CAUSE_SERVICE_OR_OPTION_UNAVAILABLE;
+ goto reject;
+ }
+
+ /*
+ * Make sure we have services provider and ARP support
+ */
+ if ((inp->inf_serv == NULL) ||
+ (inp->inf_serv->is_arp_svcin == NULL)) {
+ err = ENETUNREACH;
+ cause = T_ATM_CAUSE_SERVICE_OR_OPTION_UNAVAILABLE;
+ goto reject;
+ }
+
+ /*
+ * Check for LLC encapsulation
+ */
+ if ((ap->blli.tag_l2 == T_ATM_PRESENT) &&
+ (ap->blli.v.layer_2_protocol.ID_type == T_ATM_SIMPLE_ID) &&
+ (ap->blli.v.layer_2_protocol.ID.simple_ID == T_ATM_BLLI2_I8802)) {
+ usellc = 1;
+ mtu += IPATM_LLC_LEN;
+ }
+
+ /*
+ * Verify requested MTU
+ */
+ if (ap->aal.type == ATM_AAL5) {
+ if ((ap->aal.v.aal5.forward_max_SDU_size > mtu) ||
+ (ap->aal.v.aal5.backward_max_SDU_size < mtu)) {
+ err = ENETUNREACH;
+ cause = T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED;
+ goto reject;
+ }
+ } else {
+ if ((ap->aal.v.aal4.forward_max_SDU_size > mtu) ||
+ (ap->aal.v.aal4.backward_max_SDU_size < mtu)) {
+ err = ENETUNREACH;
+ cause = T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED;
+ goto reject;
+ }
+ }
+
+ /*
+ * Allocate IP VCC
+ */
+ ivp = (struct ipvcc *)atm_allocate(&ipatm_vcpool);
+ if (ivp == NULL) {
+ err = ENOMEM;
+ cause = T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE;
+ goto reject;
+ }
+
+ /*
+ * Initialize SVC
+ */
+ ivp->iv_flags = IVF_SVC;
+ ivp->iv_ipnif = inp;
+ if (usellc)
+ ivp->iv_flags |= IVF_LLC;
+
+ /*
+ * Lookup ARP entry for destination
+ */
+ switch ((*inp->inf_serv->is_arp_svcin)
+ (ivp, &ap->calling.addr, &ap->calling.subaddr)) {
+
+ case MAP_PROCEEDING:
+ /*
+ * We'll be (hopefully) notified later
+ */
+ break;
+
+ case MAP_VALID:
+ /*
+ * We've got our answer already
+ */
+ ivp->iv_flags |= IVF_MAPOK;
+ ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr;
+ break;
+
+ case MAP_FAILED:
+ /*
+ * So sorry...come again
+ */
+ err = ENETUNREACH;
+ cause = T_ATM_CAUSE_SERVICE_OR_OPTION_UNAVAILABLE;
+ goto reject;
+
+ default:
+ panic("ipatm_incoming: invalid arp_svcin return");
+ }
+
+ /*
+ * Accept SVC connection
+ */
+ ivp->iv_state = IPVCC_PACCEPT;
+
+ /*
+ * Save VCC information
+ */
+ ivp->iv_conn = cop;
+ *tokp = ivp;
+ /* ivp->iv_ = ap->headout; */
+
+ /*
+ * Queue VCC onto its network interface
+ */
+ ipatm_vccnt++;
+ ENQUEUE(ivp, struct ipvcc, iv_elem, inp->inf_vcq);
+
+ /*
+ * Wait for a CALL_CONNECTED event
+ */
+ IPVCC_TIMER(ivp, IPATM_SVC_TIME);
+
+ return (0);
+
+reject:
+ /*
+ * Clean up after call failure
+ */
+ if (ivp) {
+ (*inp->inf_serv->is_arp_close)(ivp);
+ atm_free((caddr_t)ivp);
+ }
+ ap->cause.tag = T_ATM_PRESENT;
+ ap->cause.v = ipatm_cause;
+ ap->cause.v.cause_value = cause;
+ return (err);
+}
+
+
+/*
+ * Close an IP VCC
+ *
+ * This function will close an IP VCC (PVC or SVC), including notifying
+ * the signalling and ARP subsystems of the VCC's demise and cleaning
+ * up memory after ourselves.
+ *
+ * Arguments:
+ * ivp pointer to VCC
+ * code cause code
+ *
+ * Returns:
+ * 0 VCC successfully closed
+ * errno close failed - reason indicated
+ *
+ */
+int
+ipatm_closevc(ivp, code)
+ struct ipvcc *ivp;
+ int code;
+{
+ struct ip_nif *inp = ivp->iv_ipnif;
+ int s, err;
+
+ /*
+ * Make sure VCC hasn't been through here already
+ */
+ switch (ivp->iv_state) {
+
+ case IPVCC_FREE:
+ return (EALREADY);
+ }
+
+ /*
+ * Reset lookup cache
+ */
+ if (last_map_ipvcc == ivp) {
+ last_map_ipvcc = NULL;
+ last_map_ipdst = 0;
+ }
+
+ /*
+ * Tell ARP about SVCs and dynamic PVCs
+ */
+ if (inp->inf_serv &&
+ ((ivp->iv_flags & IVF_SVC) || inp->inf_serv->is_arp_pvcopen)) {
+ (*inp->inf_serv->is_arp_close)(ivp);
+ }
+
+ /*
+ * Free queued packets
+ */
+ if (ivp->iv_queue)
+ KB_FREEALL(ivp->iv_queue);
+
+ /*
+ * Cancel any timers
+ */
+ IPVCC_CANCEL(ivp);
+
+ /*
+ * Close VCC
+ */
+ switch (ivp->iv_state) {
+
+ case IPVCC_PMAP:
+ break;
+
+ case IPVCC_POPEN:
+ case IPVCC_PACCEPT:
+ case IPVCC_ACTPENT:
+ case IPVCC_ACTIVE:
+ ipatm_cause.cause_value = code;
+ err = atm_cm_release(ivp->iv_conn, &ipatm_cause);
+ if (err) {
+ log(LOG_ERR,
+ "ipatm_closevc: release fail: err=%d\n", err);
+ }
+ break;
+
+ case IPVCC_CLOSED:
+ break;
+
+ default:
+ log(LOG_ERR,
+ "ipatm_closevc: unknown state: ivp=0x%x, state=%d\n",
+ (int)ivp, ivp->iv_state);
+ }
+
+ /*
+ * Remove VCC from network i/f
+ */
+ s = splnet();
+ DEQUEUE(ivp, struct ipvcc, iv_elem, inp->inf_vcq);
+
+ /*
+ * Reset state just to be sure
+ */
+ ivp->iv_state = IPVCC_FREE;
+
+ /*
+ * If ARP module is done with VCC too, then free it
+ */
+ if (ivp->iv_arpconn == NULL)
+ atm_free((caddr_t)ivp);
+ ipatm_vccnt--;
+ (void) splx(s);
+
+ return (0);
+}
+
+
+/*
+ * Check if IP address is valid on a Network Interface
+ *
+ * Checks whether the supplied IP address is allowed to be assigned to
+ * the supplied IP network interface.
+ *
+ * Arguments:
+ * in IP address
+ * inp pointer to IP network interface
+ *
+ * Returns:
+ * 0 - OK to assign
+ * 1 - not valid to assign
+ *
+ */
+int
+ipatm_chknif(in, inp)
+ struct in_addr in;
+ struct ip_nif *inp;
+{
+ struct in_ifaddr *ia;
+ u_long i;
+
+ /*
+ * Make sure there's an interface requested
+ */
+ if (inp == NULL)
+ return (1);
+
+ /*
+ * Make sure we have an IP address
+ */
+ i = ntohl(in.s_addr);
+ if (i == 0)
+ return (1);
+
+ /*
+ * Make sure an interface address is set
+ */
+ ia = inp->inf_addr;
+ if (ia == NULL)
+ return (1);
+
+ /*
+ * Make sure we're on the right subnet
+ */
+ if ((i & ia->ia_subnetmask) != ia->ia_subnet)
+ return (1);
+
+ return (0);
+}
+
+
+/*
+ * Map an IP Address to an IP VCC
+ *
+ * Given a destination IP address, this function will return a pointer
+ * to the appropriate output IP VCC to which to send the packet.
+ * This is currently implemented using a one-behind cache containing the
+ * last successful mapping result. If the cache lookup fails, then a
+ * simple linear search of all IP VCCs on the destination network interface
+ * is performed. This is obviously an area to look at for performance
+ * improvements.
+ *
+ * Arguments:
+ * dst pointer to destination IP address
+ * nip pointer to destination network interface
+ *
+ * Returns:
+ * addr pointer to located IP VCC
+ * 0 no such mapping exists
+ *
+ */
+struct ipvcc *
+ipatm_iptovc(dst, nip)
+ struct sockaddr_in *dst;
+ struct atm_nif *nip;
+{
+ struct ip_nif *inp;
+ struct ipvcc *ivp;
+ u_long dstip = dst->sin_addr.s_addr;
+ int s;
+
+ /*
+ * Look in cache first
+ */
+ if (last_map_ipdst == dstip)
+ return (last_map_ipvcc);
+
+ /*
+ * Oh well, we've got to search for it...first find the interface
+ */
+ s = splnet();
+ for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
+ if (inp->inf_nif == nip)
+ break;
+ }
+ if (inp == NULL) {
+ (void) splx(s);
+ return (NULL);
+ }
+
+ /*
+ * Now home in on the VCC
+ */
+ for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp;
+ ivp = Q_NEXT(ivp, struct ipvcc, iv_elem)) {
+ if (ivp->iv_dst.s_addr == dstip)
+ break;
+ }
+
+ /*
+ * Update lookup cache
+ */
+ if (ivp) {
+ last_map_ipdst = dstip;
+ last_map_ipvcc = ivp;
+ }
+ (void) splx(s);
+
+ return (ivp);
+}
+