aboutsummaryrefslogtreecommitdiff
path: root/sys/netatm/ipatm
diff options
context:
space:
mode:
authorPoul-Henning Kamp <phk@FreeBSD.org>1998-09-15 08:23:17 +0000
committerPoul-Henning Kamp <phk@FreeBSD.org>1998-09-15 08:23:17 +0000
commit1820df7a2d615975e02b646f749fb05757e92f79 (patch)
treea7cd0079858aee749b0cbaadb313a655dee7765b /sys/netatm/ipatm
parent06915ea69a48dd223d1612cefc20795c2d38d359 (diff)
downloadsrc-1820df7a2d615975e02b646f749fb05757e92f79.tar.gz
src-1820df7a2d615975e02b646f749fb05757e92f79.zip
Add new files for HARP3
Host ATM Research Platform (HARP), Network Computing Services, Inc. This software was developed with the support of the Defense Advanced Research Projects Agency (DARPA).
Notes
Notes: svn path=/head/; revision=39232
Diffstat (limited to 'sys/netatm/ipatm')
-rw-r--r--sys/netatm/ipatm/ipatm.h55
-rw-r--r--sys/netatm/ipatm/ipatm_event.c454
-rw-r--r--sys/netatm/ipatm/ipatm_if.c335
-rw-r--r--sys/netatm/ipatm/ipatm_input.c210
-rw-r--r--sys/netatm/ipatm/ipatm_load.c878
-rw-r--r--sys/netatm/ipatm/ipatm_output.c216
-rw-r--r--sys/netatm/ipatm/ipatm_serv.h114
-rw-r--r--sys/netatm/ipatm/ipatm_usrreq.c394
-rw-r--r--sys/netatm/ipatm/ipatm_var.h215
-rw-r--r--sys/netatm/ipatm/ipatm_vcm.c1245
10 files changed, 4116 insertions, 0 deletions
diff --git a/sys/netatm/ipatm/ipatm.h b/sys/netatm/ipatm/ipatm.h
new file mode 100644
index 000000000000..b3ce348a285f
--- /dev/null
+++ b/sys/netatm/ipatm/ipatm.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * ===================================
+ * 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.h,v 1.5 1998/03/24 20:49:49 mks Exp $
+ *
+ */
+
+/*
+ * IP Over ATM Support
+ * -------------------
+ *
+ * Protocol definitions
+ *
+ */
+
+#ifndef _IPATM_IPATM_H
+#define _IPATM_IPATM_H
+
+/*
+ * Protocol Variables
+ */
+#define IPATM_VCIDLE 15 /* VCC idle time (minutes) */
+#define IPATM_ARP_TIME (60 * ATM_HZ) /* Wait for ARP answer */
+#define IPATM_SVC_TIME (60 * ATM_HZ) /* Wait for SVC open answer */
+#define IPATM_IDLE_TIME (60 * ATM_HZ) /* VCC idle timer tick */
+
+/*
+ * IP/ATM LLC/SNAP header
+ */
+#define IPATM_LLC_LEN 8
+#define IPATM_LLC_HDR {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00}
+
+#endif /* _IPATM_IPATM_H */
diff --git a/sys/netatm/ipatm/ipatm_event.c b/sys/netatm/ipatm/ipatm_event.c
new file mode 100644
index 000000000000..048edf951dfa
--- /dev/null
+++ b/sys/netatm/ipatm/ipatm_event.c
@@ -0,0 +1,454 @@
+/*
+ *
+ * ===================================
+ * 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_event.c,v 1.8 1998/08/06 18:21:13 mks Exp $
+ *
+ */
+
+/*
+ * IP Over ATM Support
+ * -------------------
+ *
+ * IP VCC event handler
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: ipatm_event.c,v 1.8 1998/08/06 18:21:13 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>
+
+
+/*
+ * Process an IP VCC timeout
+ *
+ * Called when a previously scheduled ipvcc control block timer expires.
+ * Processing will be based on the current ipvcc state.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to ipvcc timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+ipatm_timeout(tip)
+ struct atm_time *tip;
+{
+ struct ipvcc *ivp;
+
+ /*
+ * Back-off to ipvcc control block
+ */
+ ivp = (struct ipvcc *)
+ ((caddr_t)tip - (int)(&((struct ipvcc *)0)->iv_time));
+
+ /*
+ * Process timeout based on protocol state
+ */
+ switch (ivp->iv_state) {
+
+ case IPVCC_PMAP:
+ /*
+ * Give up waiting for arp response
+ */
+ (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE);
+ break;
+
+ case IPVCC_POPEN:
+ case IPVCC_PACCEPT:
+ /*
+ * Give up waiting for signalling manager response
+ */
+ (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE);
+ break;
+
+ case IPVCC_ACTPENT:
+ /*
+ * Try again to get an ARP entry
+ */
+ switch ((*ivp->iv_ipnif->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
+ */
+ IPVCC_TIMER(ivp, 5 * ATM_HZ);
+ break;
+
+ default:
+ panic("ipatm_timeout: invalid am_pvcopen return");
+ }
+ break;
+
+ default:
+ log(LOG_ERR, "ipatm: invalid timer state: ivp=0x%x, state=%d\n",
+ (int)ivp, ivp->iv_state);
+ }
+}
+
+
+/*
+ * Process IP VCC Connected Notification
+ *
+ * Arguments:
+ * toku owner's connection token (ipvcc protocol block)
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+ipatm_connected(toku)
+ void *toku;
+{
+ struct ipvcc *ivp = (struct ipvcc *)toku;
+
+ /*
+ * SVC is connected
+ */
+ if ((ivp->iv_state != IPVCC_POPEN) &&
+ (ivp->iv_state != IPVCC_PACCEPT)) {
+ log(LOG_ERR, "ipatm: invalid CALL_CONNECTED state=%d\n",
+ ivp->iv_state);
+ return;
+ }
+
+ /*
+ * Verify possible negotiated parameter values
+ */
+ if (ivp->iv_state == IPVCC_POPEN) {
+ Atm_attributes *ap = &ivp->iv_conn->co_connvc->cvc_attr;
+ int mtu = (ivp->iv_flags & IVF_LLC) ?
+ ATM_NIF_MTU + IPATM_LLC_LEN :
+ ATM_NIF_MTU;
+
+ /*
+ * Verify final 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)) {
+ (void) ipatm_closevc(ivp,
+ T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED);
+ return;
+ }
+ } else {
+ if ((ap->aal.v.aal4.forward_max_SDU_size < mtu) ||
+ (ap->aal.v.aal4.backward_max_SDU_size > mtu)) {
+ (void) ipatm_closevc(ivp,
+ T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED);
+ return;
+ }
+ }
+ }
+
+ /*
+ * Finish up VCC activation
+ */
+ ipatm_activate(ivp);
+}
+
+
+/*
+ * Process IP VCC Cleared Notification
+ *
+ * Arguments:
+ * toku owner's connection token (ipvcc protocol block)
+ * cause pointer to cause code
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+ipatm_cleared(toku, cause)
+ void *toku;
+ struct t_atm_cause *cause;
+{
+ struct ipvcc *ivp = (struct ipvcc *)toku;
+
+
+ /*
+ * VCC has been cleared, so figure out what's next
+ */
+ ivp->iv_conn = NULL;
+
+ switch (ivp->iv_state) {
+
+ case IPVCC_POPEN:
+ /*
+ * Call setup failed, see if there is another
+ * set of vcc parameters to try
+ */
+ ivp->iv_state = IPVCC_CLOSED;
+ if (ipatm_retrysvc(ivp)) {
+ (void) ipatm_closevc(ivp, cause->cause_value);
+ }
+ break;
+
+ case IPVCC_PACCEPT:
+ case IPVCC_ACTPENT:
+ case IPVCC_ACTIVE:
+ ivp->iv_state = IPVCC_CLOSED;
+ (void) ipatm_closevc(ivp, cause->cause_value);
+ break;
+ }
+}
+
+
+/*
+ * Process an ARP Event Notification
+ *
+ * Arguments:
+ * ivp pointer to IP VCC control block
+ * event ARP event type
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+ipatm_arpnotify(ivp, event)
+ struct ipvcc *ivp;
+ int event;
+{
+ struct sockaddr_in sin;
+ struct ifnet *ifp;
+
+ /*
+ * Process event
+ */
+ switch (event) {
+
+ case MAP_VALID:
+ switch (ivp->iv_state) {
+
+ case IPVCC_PMAP:
+ /*
+ * We've got our destination, however, first we'll
+ * check to make sure no other VCC to our destination
+ * has also had it's ARP table entry completed.
+ * If we don't find a better VCC to use, then we'll
+ * go ahead and open this SVC.
+ */
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = ivp->iv_dst.s_addr;
+ if (ipatm_iptovc(&sin, ivp->iv_ipnif->inf_nif) != ivp) {
+ /*
+ * We found a better VCC, so use it and
+ * get rid of this VCC
+ */
+ if (ivp->iv_queue) {
+ ifp = (struct ifnet *)
+ ivp->iv_ipnif->inf_nif;
+ (void) ipatm_ifoutput(ifp,
+ ivp->iv_queue,
+ (struct sockaddr *)&sin);
+ ivp->iv_queue = NULL;
+ }
+ (void) ipatm_closevc(ivp,
+ T_ATM_CAUSE_UNSPECIFIED_NORMAL);
+
+ } else {
+ /*
+ * We like this VCC...
+ */
+ ivp->iv_flags |= IVF_MAPOK;
+ if (ipatm_opensvc(ivp)) {
+ (void) ipatm_closevc(ivp,
+ T_ATM_CAUSE_TEMPORARY_FAILURE);
+ }
+ }
+ break;
+
+ case IPVCC_POPEN:
+ case IPVCC_PACCEPT:
+ case IPVCC_ACTIVE:
+ /*
+ * Everything looks good, so accept new mapping
+ */
+ ivp->iv_flags |= IVF_MAPOK;
+ ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr;
+
+ /*
+ * Send queued packet
+ */
+ if ((ivp->iv_state == IPVCC_ACTIVE) && ivp->iv_queue) {
+ 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;
+ }
+ break;
+ }
+ break;
+
+ case MAP_INVALID:
+ switch (ivp->iv_state) {
+
+ case IPVCC_POPEN:
+ case IPVCC_PACCEPT:
+ case IPVCC_ACTIVE:
+
+ /*
+ * Mapping has gone stale, so we cant use this VCC
+ * until the mapping is refreshed
+ */
+ ivp->iv_flags &= ~IVF_MAPOK;
+ break;
+ }
+ break;
+
+ case MAP_FAILED:
+ /*
+ * ARP lookup failed, just trash it all
+ */
+ (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE);
+ break;
+
+ case MAP_CHANGED:
+ /*
+ * ARP mapping has changed
+ */
+ if (ivp->iv_flags & IVF_PVC) {
+ /*
+ * For PVCs, just reset lookup cache if needed
+ */
+ if (last_map_ipvcc == ivp) {
+ last_map_ipdst = 0;
+ last_map_ipvcc = NULL;
+ }
+ } else {
+ /*
+ * Close SVC if it has already used this mapping
+ */
+ switch (ivp->iv_state) {
+
+ case IPVCC_POPEN:
+ case IPVCC_ACTIVE:
+ (void) ipatm_closevc(ivp,
+ T_ATM_CAUSE_UNSPECIFIED_NORMAL);
+ break;
+ }
+ }
+ break;
+
+ default:
+ log(LOG_ERR, "ipatm: unknown arp event %d, ivp=0x%x\n",
+ event, (int)ivp);
+ }
+}
+
+
+/*
+ * Process an IP VCC idle timer tick
+ *
+ * This function is called every IPATM_IDLE_TIME seconds, in order to
+ * scan for idle IP VCC's. If an active VCC reaches the idle time limit,
+ * then it will be closed.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to the VCC idle timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+ipatm_itimeout(tip)
+ struct atm_time *tip;
+{
+ struct ipvcc *ivp, *inext;
+ struct ip_nif *inp;
+
+
+ /*
+ * Schedule next timeout
+ */
+ atm_timeout(&ipatm_itimer, IPATM_IDLE_TIME, ipatm_itimeout);
+
+ /*
+ * Check for disabled idle timeout
+ */
+ if (ipatm_vcidle == 0)
+ return;
+
+ /*
+ * Check out all IP VCCs
+ */
+ for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
+ for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp;
+ ivp = inext) {
+
+ inext = Q_NEXT(ivp, struct ipvcc, iv_elem);
+
+ /*
+ * Looking for active, idle SVCs
+ */
+ if (ivp->iv_flags & (IVF_PVC | IVF_NOIDLE))
+ continue;
+ if (ivp->iv_state != IPVCC_ACTIVE)
+ continue;
+ if (++ivp->iv_idle < ipatm_vcidle)
+ continue;
+
+ /*
+ * OK, we found one - close the VCC
+ */
+ (void) ipatm_closevc(ivp,
+ T_ATM_CAUSE_UNSPECIFIED_NORMAL);
+ }
+ }
+}
+
diff --git a/sys/netatm/ipatm/ipatm_if.c b/sys/netatm/ipatm/ipatm_if.c
new file mode 100644
index 000000000000..ede2450ff8be
--- /dev/null
+++ b/sys/netatm/ipatm/ipatm_if.c
@@ -0,0 +1,335 @@
+/*
+ *
+ * ===================================
+ * 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_if.c,v 1.6 1998/03/24 20:51:47 mks Exp $
+ *
+ */
+
+/*
+ * IP Over ATM Support
+ * -------------------
+ *
+ * Interface Manager
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: ipatm_if.c,v 1.6 1998/03/24 20:51:47 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>
+
+
+/*
+ * Local functions
+ */
+static void ipatm_closenif __P((struct ip_nif *));
+
+
+/*
+ * Process Network Interface status change
+ *
+ * Called whenever a network interface status change is requested.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * cmd command code
+ * nip pointer to atm network interface control block
+ * arg command specific parameter
+ *
+ * Returns:
+ * 0 command successful
+ * errno command failed - reason indicated
+ *
+ */
+int
+ipatm_nifstat(cmd, nip, arg)
+ int cmd;
+ struct atm_nif *nip;
+ int arg;
+{
+ struct in_ifaddr *ia;
+ struct siginst *sip;
+ struct ip_nif *inp;
+ int err = 0;
+
+ /*
+ * Look for corresponding IP interface
+ */
+ for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
+ if (inp->inf_nif == nip)
+ break;
+ }
+
+ /*
+ * Process command
+ */
+ switch (cmd) {
+
+ case NCM_ATTACH:
+ /*
+ * Make sure i/f isn't already attached
+ */
+ if (inp != NULL) {
+ err = EEXIST;
+ break;
+ }
+
+ /*
+ * Get a new interface block
+ */
+ inp = (struct ip_nif *)atm_allocate(&ipatm_nifpool);
+ if (inp == NULL) {
+ err = ENOMEM;
+ break;
+ }
+ inp->inf_nif = nip;
+ inp->inf_state = IPNIF_ADDR;
+ inp->inf_arpnotify = ipatm_arpnotify;
+ inp->inf_ipinput = ipatm_ipinput;
+ inp->inf_createsvc = ipatm_createsvc;
+ LINK2TAIL(inp, struct ip_nif, ipatm_nif_head, inf_next);
+ break;
+
+ case NCM_DETACH:
+ /*
+ * Make sure i/f is attached
+ */
+ if (inp == NULL) {
+ err = ENODEV;
+ break;
+ }
+
+ /*
+ * Validate interface stuff
+ */
+ if (Q_HEAD(inp->inf_vcq, struct ipvcc))
+ panic("ipatm_nifstat: ipvcc queue not empty");
+
+ /*
+ * If we're active, close all our VCCs and tell the
+ * interface service about the deactivation
+ */
+ if (inp->inf_state == IPNIF_ACTIVE) {
+
+ ipatm_closenif(inp);
+
+ if (inp->inf_serv)
+ (void) (*inp->inf_serv->is_ifdact)(inp);
+ }
+
+ /*
+ * Clean up and free block
+ */
+ UNLINK(inp, struct ip_nif, ipatm_nif_head, inf_next);
+ atm_free((caddr_t)inp);
+ break;
+
+ case NCM_SETADDR:
+ /*
+ * We only care about IP addresses
+ */
+#if (defined(BSD) && (BSD >= 199103))
+ if (((struct ifaddr *)arg)->ifa_addr->sa_family != AF_INET)
+#else
+ if (((struct ifaddr *)arg)->ifa_addr.sa_family != AF_INET)
+#endif
+ break;
+
+ /*
+ * Make sure i/f is there
+ */
+ ia = (struct in_ifaddr *)arg;
+ if (inp == NULL)
+ panic("ipatm_nifstat: setaddr missing ip_nif");
+
+ /*
+ * Process new address
+ */
+ switch (inp->inf_state) {
+
+ case IPNIF_SIGMGR:
+ case IPNIF_ADDR:
+ inp->inf_addr = ia;
+
+ /*
+ * If signalling manager is not set, wait for it
+ */
+ sip = nip->nif_pif->pif_siginst;
+ if (sip == NULL) {
+ inp->inf_state = IPNIF_SIGMGR;
+ break;
+ }
+
+ /*
+ * Otherwise, everything's set
+ */
+ inp->inf_state = IPNIF_ACTIVE;
+
+ /*
+ * Tell interface service we're around
+ */
+ if (sip->si_ipserv) {
+ inp->inf_serv = sip->si_ipserv;
+ err = (*inp->inf_serv->is_ifact)(inp);
+ }
+
+ /*
+ * Reset state if there's been a problem
+ */
+ if (err) {
+ inp->inf_serv = NULL;
+ inp->inf_addr = NULL;
+ inp->inf_state = IPNIF_ADDR;
+ }
+ break;
+
+ case IPNIF_ACTIVE:
+ /*
+ * We dont support an address change
+ */
+ err = EEXIST;
+ break;
+ }
+ break;
+
+ case NCM_SIGATTACH:
+ /*
+ * Make sure i/f is attached
+ */
+ if (inp == NULL) {
+ err = ENODEV;
+ break;
+ }
+
+ /*
+ * Are we waiting for the sigmgr attach??
+ */
+ if (inp->inf_state != IPNIF_SIGMGR) {
+ /*
+ * No, nothing else to do
+ */
+ break;
+ }
+
+ /*
+ * OK, everything's set
+ */
+ inp->inf_state = IPNIF_ACTIVE;
+
+ /*
+ * Tell interface service we're around
+ */
+ sip = nip->nif_pif->pif_siginst;
+ if (sip->si_ipserv) {
+ inp->inf_serv = sip->si_ipserv;
+ err = (*inp->inf_serv->is_ifact)(inp);
+ }
+
+ /*
+ * Just report any problems, since a NCM_SIGDETACH will
+ * be coming down immediately
+ */
+ break;
+
+ case NCM_SIGDETACH:
+ /*
+ * Make sure i/f is attached
+ */
+ if (inp == NULL) {
+ err = ENODEV;
+ break;
+ }
+
+ /*
+ * Are we currently active??
+ */
+ if (inp->inf_state != IPNIF_ACTIVE) {
+ /*
+ * No, nothing else to do
+ */
+ break;
+ }
+
+ /*
+ * Close all the IP VCCs for this interface
+ */
+ ipatm_closenif(inp);
+
+ /*
+ * Tell interface service that i/f has gone down
+ */
+ if (inp->inf_serv)
+ (void) (*inp->inf_serv->is_ifdact)(inp);
+
+ /*
+ * Just have to wait for another sigattach
+ */
+ inp->inf_serv = NULL;
+ inp->inf_state = IPNIF_SIGMGR;
+ break;
+
+ default:
+ log(LOG_ERR, "ipatm_nifstat: unknown command %d\n", cmd);
+ }
+
+ return (err);
+}
+
+
+/*
+ * Close all VCCs on a Network Interface
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * inp pointer to IP network interface
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+ipatm_closenif(inp)
+ struct ip_nif *inp;
+{
+ struct ipvcc *ivp, *inext;
+
+ /*
+ * Close each IP VCC on this interface
+ */
+ for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; ivp = inext) {
+
+ inext = Q_NEXT(ivp, struct ipvcc, iv_elem);
+
+ (void) ipatm_closevc(ivp, T_ATM_CAUSE_UNSPECIFIED_NORMAL);
+ }
+}
+
diff --git a/sys/netatm/ipatm/ipatm_input.c b/sys/netatm/ipatm/ipatm_input.c
new file mode 100644
index 000000000000..ca3e3e75a34a
--- /dev/null
+++ b/sys/netatm/ipatm/ipatm_input.c
@@ -0,0 +1,210 @@
+/*
+ *
+ * ===================================
+ * 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_input.c,v 1.9 1998/04/07 23:03:52 mks Exp $
+ *
+ */
+
+/*
+ * IP Over ATM Support
+ * -------------------
+ *
+ * Process stack and data input
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: ipatm_input.c,v 1.9 1998/04/07 23:03:52 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>
+
+
+/*
+ * Process VCC Input Data
+ *
+ * Arguments:
+ * tok ipatm connection token (pointer to ipvcc)
+ * m pointer to input packet buffer chain
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+ipatm_cpcs_data(tok, m)
+ void *tok;
+ KBuffer *m;
+{
+ struct ipvcc *ivp = tok;
+
+#ifdef DIAGNOSTIC
+ if (ipatm_print) {
+ atm_pdu_print(m, "ipatm_input");
+ }
+#endif
+
+ /*
+ * Handle input packet
+ */
+ if (ivp->iv_state != IPVCC_ACTIVE) {
+ KB_FREEALL(m);
+ ipatm_stat.ias_rcvstate++;
+ return;
+ }
+
+ /*
+ * IP packet - reset idle timer
+ */
+ ivp->iv_idle = 0;
+
+ /*
+ * Pass packet to IP
+ */
+ (void) ipatm_ipinput(ivp->iv_ipnif, m);
+}
+
+
+/*
+ * IP Input Packet Handler
+ *
+ * All IP packets received from various ATM sources will be sent here
+ * for final queuing to the IP layer.
+ *
+ * Arguments:
+ * inp pointer to packet's receiving IP network interface
+ * m pointer to packet buffer chain
+ *
+ * Returns:
+ * 0 packet successfully queued to IP layer
+ * else error queuing packet, buffer chain freed
+ *
+ */
+int
+ipatm_ipinput(inp, m)
+ struct ip_nif *inp;
+ KBuffer *m;
+{
+ int s, space;
+
+#ifdef DIAGNOSTIC
+ if (ipatm_print) {
+ atm_pdu_print(m, "ipatm_ipinput");
+ }
+#endif
+
+#if defined(BSD)
+#if BSD >= 199103
+
+#ifdef DIAGNOSTIC
+ if (!KB_ISPKT(m)) {
+ panic("ipatm_ipinput: no packet header");
+ }
+ {
+ int cnt = 0;
+ KBuffer *m0 = m;
+
+ while (m0) {
+ cnt += KB_LEN(m0);
+ m0 = KB_NEXT(m0);
+ }
+ if (m->m_pkthdr.len != cnt) {
+ panic("ipatm_ipinput: packet length incorrect");
+ }
+ }
+#endif
+ /*
+ * Save the input ifnet pointer in the packet header
+ */
+ m->m_pkthdr.rcvif = (struct ifnet *)inp->inf_nif;
+
+#else /* ! BSD >= 199103 */
+ /*
+ * Stick ifnet pointer onto front of packet - hopefully
+ * there'll be room in the first buffer.
+ */
+ KB_HEADROOM(m, space);
+ if (space < sizeof(struct ifnet *)) {
+ KBuffer *n;
+
+ /*
+ * We have to allocate another buffer and tack it
+ * onto the front of the packet
+ */
+ KB_ALLOCPKT(n, sizeof(struct ifnet *),
+ KB_F_NOWAIT, KB_T_HEADER);
+ if (n == 0) {
+ KB_FREEALL(m);
+ ipatm_stat.ias_rcvnobuf++;
+ return (1);
+ }
+ KB_LEN(n) = sizeof(struct ifnet *);
+ KB_LINKHEAD(n, m);
+ m = n;
+ } else {
+ /*
+ * Header fits, just adjust buffer controls
+ */
+ KB_HEADADJ(m, sizeof(struct ifnet *));
+ }
+ {
+ struct ifnet **p;
+
+ KB_DATASTART(m, p, struct ifnet **);
+ *p = (struct ifnet *)inp->inf_nif;
+ }
+#endif /* ! BSD >= 199103 */
+
+ /*
+ * Finally, hand packet off to IP.
+ *
+ * NB: Since we're already in the softint kernel state, we
+ * just call IP directly to avoid the extra unnecessary
+ * kernel scheduling.
+ */
+ s = splimp();
+ if (IF_QFULL(&ipintrq)) {
+ IF_DROP(&ipintrq);
+ (void) splx(s);
+ KB_FREEALL(m);
+ return (1);
+ }
+
+ IF_ENQUEUE(&ipintrq, m);
+ (void) splx(s);
+#if BSD < 199506
+ ipintr();
+#else
+ schednetisr ( NETISR_IP );
+#endif /* BSD >= 199506 */
+#endif /* defined(BSD) */
+
+ return (0);
+}
+
diff --git a/sys/netatm/ipatm/ipatm_load.c b/sys/netatm/ipatm/ipatm_load.c
new file mode 100644
index 000000000000..8caa6354a4cb
--- /dev/null
+++ b/sys/netatm/ipatm/ipatm_load.c
@@ -0,0 +1,878 @@
+/*
+ *
+ * ===================================
+ * 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_load.c,v 1.12 1998/07/30 22:23:00 mks Exp $
+ *
+ */
+
+/*
+ * IP Over ATM Support
+ * -------------------
+ *
+ * Support for running as a loadable kernel module
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: ipatm_load.c,v 1.12 1998/07/30 22:23:00 mks Exp $";
+#endif
+
+#ifndef ATM_IP_MODULE
+#include "opt_atm.h"
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm.h>
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+
+
+/*
+ * Global variables
+ */
+int ipatm_vccnt = 0;
+int ipatm_vcidle = IPATM_VCIDLE;
+int ipatm_print = 0;
+u_long last_map_ipdst = 0;
+struct ipvcc* last_map_ipvcc = NULL;
+
+struct ip_nif *ipatm_nif_head = NULL;
+
+struct ipatm_stat ipatm_stat = {0};
+
+struct atm_time ipatm_itimer = {0, 0}; /* VCC idle timer */
+
+Atm_endpoint ipatm_endpt = {
+ NULL,
+ ENDPT_IP,
+ ipatm_ioctl,
+ ipatm_getname,
+ ipatm_connected,
+ ipatm_cleared,
+ ipatm_incoming,
+ NULL,
+ NULL,
+ NULL,
+ ipatm_cpcs_data,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+struct sp_info ipatm_vcpool = {
+ "ipatm vcc pool", /* si_name */
+ sizeof(struct ipvcc), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 100 /* si_maxallow */
+};
+
+struct sp_info ipatm_nifpool = {
+ "ipatm nif pool", /* si_name */
+ sizeof(struct ip_nif), /* si_blksiz */
+ 5, /* si_blkcnt */
+ 20 /* si_maxallow */
+};
+
+
+/*
+ * Local functions
+ */
+static int ipatm_start __P((void));
+static int ipatm_stop __P((void));
+
+
+/*
+ * Local variables
+ */
+static struct atm_ncm ipatm_ncm = {
+ NULL,
+ AF_INET,
+ ipatm_ifoutput,
+ ipatm_nifstat
+};
+
+static struct ipatm_listener {
+ Atm_attributes attr;
+ Atm_connection *conn;
+} ipatm_listeners[] = {
+{
+ { 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_ANY
+ },
+ { /* 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_ANY
+ },
+ { /* calling */
+ T_ATM_ANY
+ },
+ { /* qos */
+ T_ATM_PRESENT,
+ {
+ T_ATM_NETWORK_CODING,
+ {
+ T_ATM_QOS_CLASS_0,
+ },
+ {
+ T_ATM_QOS_CLASS_0
+ }
+ }
+ },
+ { /* transit */
+ T_ATM_ANY
+ },
+ { /* cause */
+ T_ATM_ABSENT
+ },
+ },
+ NULL
+},
+{
+ { 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_ANY
+ },
+ { /* bhli */
+ T_ATM_ABSENT
+ },
+ { /* blli */
+ T_ATM_ABSENT,
+ T_ATM_ABSENT
+ },
+ { /* llc */
+ T_ATM_ABSENT
+ },
+ { /* called */
+ T_ATM_ANY
+ },
+ { /* calling */
+ T_ATM_ANY
+ },
+ { /* qos */
+ T_ATM_PRESENT,
+ {
+ T_ATM_NETWORK_CODING,
+ {
+ T_ATM_QOS_CLASS_0,
+ },
+ {
+ T_ATM_QOS_CLASS_0
+ }
+ }
+ },
+ { /* transit */
+ T_ATM_ANY
+ },
+ { /* cause */
+ T_ATM_ABSENT
+ },
+ },
+ NULL
+},
+{
+ { NULL, /* nif */
+ CMAPI_CPCS, /* api */
+ 0, /* api_init */
+ 0, /* 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_ANY
+ },
+ { /* bhli */
+ T_ATM_ABSENT
+ },
+ { /* blli */
+ T_ATM_ABSENT,
+ T_ATM_ABSENT
+ },
+ { /* llc */
+ T_ATM_ABSENT
+ },
+ { /* called */
+ T_ATM_ANY
+ },
+ { /* calling */
+ T_ATM_ANY
+ },
+ { /* qos */
+ T_ATM_PRESENT,
+ {
+ T_ATM_NETWORK_CODING,
+ {
+ T_ATM_QOS_CLASS_0,
+ },
+ {
+ T_ATM_QOS_CLASS_0
+ }
+ }
+ },
+ { /* transit */
+ T_ATM_ANY
+ },
+ { /* cause */
+ T_ATM_ABSENT
+ },
+ },
+ NULL
+},
+};
+
+static struct t_atm_cause ipatm_cause = {
+ T_ATM_ITU_CODING,
+ T_ATM_LOC_USER,
+ T_ATM_CAUSE_UNSPECIFIED_NORMAL,
+ {0, 0, 0, 0}
+};
+
+
+/*
+ * Initialize ipatm processing
+ *
+ * This will be called during module loading. We'll just register
+ * ourselves and wait for the packets to start flying.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 startup was successful
+ * errno startup failed - reason indicated
+ *
+ */
+static int
+ipatm_start()
+{
+ struct atm_pif *pip;
+ struct atm_nif *nip;
+ int err, s, i;
+
+ /*
+ * Verify software version
+ */
+ if (atm_version != ATM_VERSION) {
+ log(LOG_ERR, "version mismatch: ipatm=%d.%d kernel=%d.%d\n",
+ ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION),
+ ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version));
+ return (EINVAL);
+ }
+
+ /*
+ * Register ourselves as a network convergence module
+ */
+ err = atm_netconv_register(&ipatm_ncm);
+ if (err)
+ goto done;
+
+ /*
+ * Register ourselves as an ATM endpoint
+ */
+ err = atm_endpoint_register(&ipatm_endpt);
+ if (err)
+ goto done;
+
+ /*
+ * Get current system configuration
+ */
+ s = splnet();
+ for (pip = atm_interface_head; pip; pip = pip->pif_next) {
+ /*
+ * Process each network interface
+ */
+ for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
+ struct ifnet *ifp = (struct ifnet *)nip;
+ struct in_ifaddr *ia;
+
+ /*
+ * Attach interface
+ */
+ err = ipatm_nifstat(NCM_ATTACH, nip, 0);
+ if (err) {
+ (void) splx(s);
+ goto done;
+ }
+
+ /*
+ * If IP address has been set, register it
+ */
+ TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
+ if (ia->ia_ifp == ifp)
+ break;
+ }
+ if (ia) {
+ err = ipatm_nifstat(NCM_SETADDR, nip, (int)ia);
+ if (err) {
+ (void) splx(s);
+ goto done;
+ }
+ }
+ }
+ }
+ (void) splx(s);
+
+ /*
+ * Fill in union fields
+ */
+ ipatm_aal5llc.aal.v.aal5.forward_max_SDU_size =
+ ATM_NIF_MTU + IPATM_LLC_LEN;
+ ipatm_aal5llc.aal.v.aal5.backward_max_SDU_size =
+ ATM_NIF_MTU + IPATM_LLC_LEN;
+ ipatm_aal5llc.aal.v.aal5.SSCS_type = T_ATM_NULL;
+ ipatm_aal5llc.blli.v.layer_2_protocol.ID.simple_ID = T_ATM_BLLI2_I8802;
+
+ ipatm_aal5null.aal.v.aal5.forward_max_SDU_size = ATM_NIF_MTU;
+ ipatm_aal5null.aal.v.aal5.backward_max_SDU_size = ATM_NIF_MTU;
+ ipatm_aal5null.aal.v.aal5.SSCS_type = T_ATM_NULL;
+
+ ipatm_aal4null.aal.v.aal4.forward_max_SDU_size = ATM_NIF_MTU;
+ ipatm_aal4null.aal.v.aal4.backward_max_SDU_size = ATM_NIF_MTU;
+ ipatm_aal4null.aal.v.aal4.SSCS_type = T_ATM_NULL;
+ ipatm_aal4null.aal.v.aal4.mid_low = 0;
+ ipatm_aal4null.aal.v.aal4.mid_high = 1023;
+
+ /*
+ * Listen for incoming calls
+ */
+ for (i = 0;
+ i < (sizeof(ipatm_listeners) / sizeof(struct ipatm_listener));
+ i++) {
+ struct attr_aal *aalp = &ipatm_listeners[i].attr.aal;
+ int maxsdu = ATM_NIF_MTU;
+
+ /*
+ * Fill in union fields
+ */
+ if (ipatm_listeners[i].attr.blli.tag_l2 == T_ATM_PRESENT) {
+ struct t_atm_blli *bp = &ipatm_listeners[i].attr.blli.v;
+
+ bp->layer_2_protocol.ID.simple_ID = T_ATM_BLLI2_I8802;
+ maxsdu += IPATM_LLC_LEN;
+ }
+ if (aalp->type == ATM_AAL5) {
+ aalp->v.aal5.forward_max_SDU_size = maxsdu;
+ aalp->v.aal5.backward_max_SDU_size = maxsdu;
+ aalp->v.aal5.SSCS_type = T_ATM_NULL;
+ } else {
+ aalp->v.aal4.forward_max_SDU_size = maxsdu;
+ aalp->v.aal4.backward_max_SDU_size = maxsdu;
+ aalp->v.aal4.SSCS_type = T_ATM_NULL;
+ aalp->v.aal4.mid_low = 0;
+ aalp->v.aal4.mid_high = 1023;
+ }
+
+ /*
+ * Now start listening
+ */
+ if (err = atm_cm_listen(&ipatm_endpt, (void *)i,
+ &ipatm_listeners[i].attr,
+ &ipatm_listeners[i].conn))
+ goto done;
+ }
+
+ /*
+ * Start background VCC idle timer
+ */
+ atm_timeout(&ipatm_itimer, IPATM_IDLE_TIME, ipatm_itimeout);
+
+done:
+ return (err);
+}
+
+
+/*
+ * Halt ipatm processing
+ *
+ * This will be called just prior to unloading the module from
+ * memory. All IP VCCs must be terminated before the protocol can
+ * be shutdown.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 shutdown was successful
+ * errno shutdown failed - reason indicated
+ *
+ */
+static int
+ipatm_stop()
+{
+ struct ip_nif *inp;
+ int err = 0, i;
+ int s = splnet();
+
+ /*
+ * Any VCCs still open??
+ */
+ if (ipatm_vccnt) {
+
+ /* Yes, can't stop now */
+ err = EBUSY;
+ goto done;
+ }
+
+ /*
+ * Kill VCC idle timer
+ */
+ (void) atm_untimeout(&ipatm_itimer);
+
+ /*
+ * Stop listening for incoming calls
+ */
+ for (i = 0;
+ i < (sizeof(ipatm_listeners) / sizeof(struct ipatm_listener));
+ i++) {
+ if (ipatm_listeners[i].conn != NULL) {
+ (void) atm_cm_release(ipatm_listeners[i].conn,
+ &ipatm_cause);
+ }
+ }
+
+ /*
+ * Detach all our interfaces
+ */
+ while (inp = ipatm_nif_head) {
+ (void) ipatm_nifstat(NCM_DETACH, inp->inf_nif, 0);
+ }
+
+ /*
+ * De-register from system
+ */
+ (void) atm_netconv_deregister(&ipatm_ncm);
+ (void) atm_endpoint_deregister(&ipatm_endpt);
+
+ /*
+ * Free up our storage pools
+ */
+ atm_release_pool(&ipatm_vcpool);
+ atm_release_pool(&ipatm_nifpool);
+
+done:
+ (void) splx(s);
+ return (err);
+}
+
+
+#ifdef ATM_IP_MODULE
+/*
+ *******************************************************************
+ *
+ * Loadable Module Support
+ *
+ *******************************************************************
+ */
+static int ipatm_doload __P((void));
+static int ipatm_dounload __P((void));
+
+/*
+ * Generic module load processing
+ *
+ * This function is called by an OS-specific function when this
+ * module is being loaded.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 load was successful
+ * errno load failed - reason indicated
+ *
+ */
+static int
+ipatm_doload()
+{
+ int err = 0;
+
+ /*
+ * Start us up
+ */
+ err = ipatm_start();
+ if (err)
+ /* Problems, clean up */
+ (void)ipatm_stop();
+
+ return (err);
+}
+
+
+/*
+ * Generic module unload processing
+ *
+ * This function is called by an OS-specific function when this
+ * module is being unloaded.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 unload was successful
+ * errno unload failed - reason indicated
+ *
+ */
+static int
+ipatm_dounload()
+{
+ int err = 0;
+
+ /*
+ * OK, try to clean up our mess
+ */
+ err = ipatm_stop();
+
+ return (err);
+}
+
+
+#ifdef sun
+/*
+ * Loadable driver description
+ */
+struct vdldrv ipatm_drv = {
+ VDMAGIC_PSEUDO, /* Pseudo Driver */
+ "ipatm_mod", /* name */
+ NULL, /* dev_ops */
+ NULL, /* bdevsw */
+ NULL, /* cdevsw */
+ 0, /* blockmajor */
+ 0 /* charmajor */
+};
+
+
+/*
+ * Loadable module support entry point
+ *
+ * This is the routine called by the vd driver for all loadable module
+ * functions for this pseudo driver. This routine name must be specified
+ * on the modload(1) command. This routine will be called whenever the
+ * modload(1), modunload(1) or modstat(1) commands are issued for this
+ * module.
+ *
+ * Arguments:
+ * cmd vd command code
+ * vdp pointer to vd driver's structure
+ * vdi pointer to command-specific vdioctl_* structure
+ * vds pointer to status structure (VDSTAT only)
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+int
+ipatm_mod(cmd, vdp, vdi, vds)
+ int cmd;
+ struct vddrv *vdp;
+ caddr_t vdi;
+ struct vdstat *vds;
+{
+ int err = 0;
+
+ switch (cmd) {
+
+ case VDLOAD:
+ /*
+ * Module Load
+ *
+ * We dont support any user configuration
+ */
+ err = ipatm_doload();
+ if (err == 0)
+ /* Let vd driver know about us */
+ vdp->vdd_vdtab = (struct vdlinkage *)&ipatm_drv;
+ break;
+
+ case VDUNLOAD:
+ /*
+ * Module Unload
+ */
+ err = ipatm_dounload();
+ break;
+
+ case VDSTAT:
+ /*
+ * Module Status
+ */
+
+ /* Not much to say at the moment */
+
+ break;
+
+ default:
+ log(LOG_ERR, "ipatm_mod: Unknown vd command 0x%x\n", cmd);
+ err = EINVAL;
+ }
+
+ return (err);
+}
+#endif /* sun */
+
+#ifdef __FreeBSD__
+
+#include <sys/exec.h>
+#include <sys/sysent.h>
+#include <sys/lkm.h>
+
+/*
+ * Loadable miscellaneous module description
+ */
+MOD_MISC(ipatm);
+
+
+/*
+ * Loadable module support "load" entry point
+ *
+ * This is the routine called by the lkm driver whenever the
+ * modload(1) command is issued for this module.
+ *
+ * Arguments:
+ * lkmtp pointer to lkm drivers's structure
+ * cmd lkm command code
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+static int
+ipatm_load(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ return(ipatm_doload());
+}
+
+
+/*
+ * Loadable module support "unload" entry point
+ *
+ * This is the routine called by the lkm driver whenever the
+ * modunload(1) command is issued for this module.
+ *
+ * Arguments:
+ * lkmtp pointer to lkm drivers's structure
+ * cmd lkm command code
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+static int
+ipatm_unload(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ return(ipatm_dounload());
+}
+
+
+/*
+ * Loadable module support entry point
+ *
+ * This is the routine called by the lkm driver for all loadable module
+ * functions for this driver. This routine name must be specified
+ * on the modload(1) command. This routine will be called whenever the
+ * modload(1), modunload(1) or modstat(1) commands are issued for this
+ * module.
+ *
+ * Arguments:
+ * lkmtp pointer to lkm drivers's structure
+ * cmd lkm command code
+ * ver lkm version
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+int
+ipatm_mod(lkmtp, cmd, ver)
+ struct lkm_table *lkmtp;
+ int cmd;
+ int ver;
+{
+ MOD_DISPATCH(ipatm, lkmtp, cmd, ver,
+ ipatm_load, ipatm_unload, lkm_nullcmd);
+}
+#endif /* __FreeBSD__ */
+
+#else /* !ATM_IP_MODULE */
+
+/*
+ *******************************************************************
+ *
+ * Kernel Compiled Module Support
+ *
+ *******************************************************************
+ */
+static void ipatm_doload __P((void *));
+
+SYSINIT(atmipatm, SI_SUB_PROTO_END, SI_ORDER_ANY, ipatm_doload, NULL)
+
+/*
+ * Kernel initialization
+ *
+ * Arguments:
+ * arg Not used
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+ipatm_doload(void *arg)
+{
+ int err = 0;
+
+ /*
+ * Start us up
+ */
+ err = ipatm_start();
+ if (err) {
+ /* Problems, clean up */
+ (void)ipatm_stop();
+
+ log(LOG_ERR, "IP over ATM unable to initialize (%d)!!\n", err);
+ }
+ return;
+}
+#endif /* ATM_IP_MODULE */
+
diff --git a/sys/netatm/ipatm/ipatm_output.c b/sys/netatm/ipatm/ipatm_output.c
new file mode 100644
index 000000000000..7f02f28c8505
--- /dev/null
+++ b/sys/netatm/ipatm/ipatm_output.c
@@ -0,0 +1,216 @@
+/*
+ *
+ * ===================================
+ * 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_output.c,v 1.6 1998/02/19 20:14:17 mks Exp $
+ *
+ */
+
+/*
+ * IP Over ATM Support
+ * -------------------
+ *
+ * Output IP packets across an ATM VCC
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: ipatm_output.c,v 1.6 1998/02/19 20:14:17 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>
+
+
+/*
+ * Output an IP Packet
+ *
+ * All IP packets output to an ATM interface will be directed here via
+ * the atm_ifoutput() function. If there is an ATM VCC already setup for
+ * the destination IP address, then we'll just send the packet to that VCC.
+ * Otherwise we will have to setup a new VCC, ARPing for the corresponding
+ * destination ATM hardware address along the way.
+ *
+ * Arguments:
+ * ifp pointer to ifnet structure
+ * m pointer to packet buffer chain to be output
+ * dst pointer to packet's IP destination address
+ *
+ * Returns:
+ * 0 packet "output" was successful
+ * errno output failed - reason indicated
+ *
+ */
+int
+ipatm_ifoutput(ifp, m, dst)
+ struct ifnet *ifp;
+ KBuffer *m;
+ struct sockaddr *dst;
+{
+ struct ipvcc *ivp;
+ int err = 0;
+
+#ifdef DIAGNOSTIC
+ if (ipatm_print) {
+ atm_pdu_print(m, "ipatm_ifoutput");
+ }
+#endif
+
+ /*
+ * See if we've already got an appropriate VCC
+ */
+ ivp = ipatm_iptovc((struct sockaddr_in *)dst, (struct atm_nif *)ifp);
+ if (ivp) {
+
+ /*
+ * Reset idle timer
+ */
+ ivp->iv_idle = 0;
+
+ /*
+ * Can we use this VCC now??
+ */
+ if ((ivp->iv_state == IPVCC_ACTIVE) &&
+ (ivp->iv_flags & IVF_MAPOK)) {
+
+ /*
+ * OK, now send packet
+ */
+ err = atm_cm_cpcs_data(ivp->iv_conn, m);
+ if (err) {
+ /*
+ * Output problem, drop packet
+ */
+ KB_FREEALL(m);
+ }
+ } else {
+
+ /*
+ * VCC is unavailable for data packets. Queue packet
+ * for now, but only maintain a queue length of one.
+ */
+ if (ivp->iv_queue)
+ KB_FREEALL(ivp->iv_queue);
+
+ ivp->iv_queue = m;
+ }
+ } else {
+ struct in_ifaddr *ia;
+#if (defined(BSD) && (BSD < 199306))
+ extern struct ifnet loif;
+#endif
+
+ /*
+ * No VCC to destination
+ */
+
+ /*
+ * Is packet for our interface address?
+ */
+ TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
+ if (ia->ia_ifp != ifp)
+ continue;
+ if (((struct sockaddr_in *)dst)->sin_addr.s_addr ==
+ IA_SIN(ia)->sin_addr.s_addr) {
+
+ /*
+ * It's for us - hand packet to loopback driver
+ */
+ (void) if_simloop(ifp, m, dst, 0);
+ goto done;
+ }
+ }
+
+ /*
+ * Is this a broadcast packet ??
+ */
+#if (defined(BSD) && (BSD >= 199306))
+ if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr, ifp)) {
+#else
+ if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr)) {
+#endif
+ struct ip_nif *inp;
+ int s;
+
+ /*
+ * If interface server exists and provides broadcast
+ * services, then let it deal with this packet
+ */
+ s = splnet();
+ for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
+ if (inp->inf_nif == (struct atm_nif *)ifp)
+ break;
+ }
+ (void) splx(s);
+
+ if ((inp == NULL) ||
+ (inp->inf_serv == NULL) ||
+ (inp->inf_serv->is_bcast_output == NULL)) {
+ KB_FREEALL(m);
+ err = EADDRNOTAVAIL;
+ goto done;
+ }
+
+ err = (*inp->inf_serv->is_bcast_output)(inp, m);
+ goto done;
+ }
+
+ /*
+ * How about a multicast packet ??
+ */
+ if (IN_MULTICAST(ntohl(SATOSIN(dst)->sin_addr.s_addr))) {
+ /*
+ * Multicast isn't currently supported
+ */
+ KB_FREEALL(m);
+ err = EADDRNOTAVAIL;
+ goto done;
+ }
+
+ /*
+ * Well, I guess we need to create an SVC to the destination
+ */
+ if ((err = ipatm_createsvc(ifp, AF_INET,
+ (caddr_t)&((struct sockaddr_in *)dst)->sin_addr,
+ &ivp)) == 0) {
+ /*
+ * SVC open is proceeding, queue packet
+ */
+ ivp->iv_queue = m;
+
+ } else {
+ /*
+ * SVC open failed, release buffers and return
+ */
+ KB_FREEALL(m);
+ }
+ }
+
+done:
+ return (err);
+}
+
diff --git a/sys/netatm/ipatm/ipatm_serv.h b/sys/netatm/ipatm/ipatm_serv.h
new file mode 100644
index 000000000000..20462137968f
--- /dev/null
+++ b/sys/netatm/ipatm/ipatm_serv.h
@@ -0,0 +1,114 @@
+/*
+ *
+ * ===================================
+ * 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_serv.h,v 1.6 1998/02/19 20:14:21 mks Exp $
+ *
+ */
+
+/*
+ * IP Over ATM Support
+ * -------------------
+ *
+ * IP/ATM service interface definitions
+ *
+ */
+
+#ifndef _IPATM_IPATM_SERV_H
+#define _IPATM_IPATM_SERV_H
+
+
+/*
+ * Structures specifying VCC parameters and pointers to all of the IP
+ * services offered by an external IP interface service provider.
+ */
+struct ip_vccparm {
+ Aal_t ivc_aal; /* AAL type */
+ Encaps_t ivc_encaps; /* VCC encapsulation */
+};
+
+#define IPATM_VCCPARMS 4 /* Number of parameter lists */
+
+struct ip_serv {
+/* Interfaces to IP/ATM interface services */
+ int (*is_ifact) /* Interface activation */
+ __P((struct ip_nif *));
+ int (*is_ifdact) /* Interface deactivation */
+ __P((struct ip_nif *));
+ int (*is_ioctl) /* Interface ioctl */
+ __P((int, caddr_t, caddr_t));
+
+/* Interfaces to IP/ATM ARP services */
+ int (*is_arp_pvcopen) /* IP creating dynamic PVC */
+ __P((struct ipvcc *));
+ int (*is_arp_svcout) /* IP creating outgoing SVC */
+ __P((struct ipvcc *, struct in_addr *));
+ int (*is_arp_svcin) /* IP creating incoming SVC */
+ __P((struct ipvcc *, Atm_addr *, Atm_addr *));
+ int (*is_arp_svcact) /* IP SVC is active */
+ __P((struct ipvcc *));
+ void (*is_arp_close) /* IP closing VCC */
+ __P((struct ipvcc *));
+
+/* Interfaces to IP/ATM broadcast services */
+ int (*is_bcast_output) /* IP broadcast packet output */
+ __P((struct ip_nif *, KBuffer *));
+
+/* Interfaces to IP/ATM multicast services */
+
+/* Ordered list of parameters to try for IP/ATM VCC connections */
+ struct ip_vccparm is_vccparm[IPATM_VCCPARMS]; /* List of vcc params */
+};
+
+
+/*
+ * ARP Interface
+ * ----------------
+ */
+
+/*
+ * Common header for IP/ATM ARP mappings. For each IP VCC created, the
+ * appropriate IP/ATM ARP server must assign one of these structures to
+ * indicate the address mapping. This is the only IP-visible ARP structure.
+ * The servers may embed this structure at the beginning of their
+ * module-specific mappings.
+ */
+struct arpmap {
+ struct in_addr am_dstip; /* Destination IP address */
+ Atm_addr am_dstatm; /* Destination ATM address */
+ Atm_addr am_dstatmsub; /* Destination ATM subaddress */
+};
+
+
+/*
+ * is_arp_[ps]open() return codes and ipatm_arpnotify() event types
+ */
+#define MAP_PROCEEDING 1 /* Lookup is proceeding (open only) */
+#define MAP_VALID 2 /* Mapping is valid */
+#define MAP_INVALID 3 /* Mapping is invalid */
+#define MAP_CHANGED 4 /* Mapping has changed */
+#define MAP_FAILED 5 /* Mapping request has failed */
+
+
+#endif /* _IPATM_IPATM_SERV_H */
diff --git a/sys/netatm/ipatm/ipatm_usrreq.c b/sys/netatm/ipatm/ipatm_usrreq.c
new file mode 100644
index 000000000000..1f1751c703d5
--- /dev/null
+++ b/sys/netatm/ipatm/ipatm_usrreq.c
@@ -0,0 +1,394 @@
+/*
+ *
+ * ===================================
+ * 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_usrreq.c,v 1.6 1998/05/18 19:14:04 mks Exp $
+ *
+ */
+
+/*
+ * IP Over ATM Support
+ * -------------------
+ *
+ * Process user requests
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: ipatm_usrreq.c,v 1.6 1998/05/18 19:14:04 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>
+
+
+/*
+ * Process IP PF_ATM ioctls
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * code PF_ATM sub-operation code
+ * data pointer to code specific parameter data area
+ * arg1 pointer to code specific argument
+ *
+ * Returns:
+ * 0 request procesed
+ * errno error processing request - reason indicated
+ *
+ */
+int
+ipatm_ioctl(code, data, arg1)
+ int code;
+ caddr_t data;
+ caddr_t arg1;
+{
+ struct atmaddreq *aap;
+ struct atmdelreq *adp;
+ struct atminfreq *aip;
+ struct air_ip_vcc_rsp aivr;
+ struct atm_nif *nip;
+ struct ip_nif *inp;
+ struct ipvcc *ivp;
+ struct vccb *vcp;
+ struct ipatmpvc pv;
+ caddr_t cp;
+ struct in_addr ip;
+ int space, err = 0;
+
+
+ switch (code) {
+
+ case AIOCS_ADD_PVC:
+ /*
+ * Add an IP PVC
+ */
+ aap = (struct atmaddreq *)data;
+
+ /*
+ * Find the IP network interface
+ */
+ if ((nip = atm_nifname(aap->aar_pvc_intf)) == NULL) {
+ err = ENXIO;
+ break;
+ }
+
+ for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
+ if (inp->inf_nif == nip)
+ break;
+ }
+ if (inp == NULL) {
+ err = ENXIO;
+ break;
+ }
+
+ /*
+ * Validate PVC params
+ */
+ if (aap->aar_pvc_aal == ATM_AAL5) {
+ if ((aap->aar_pvc_encaps != ATM_ENC_LLC) &&
+ (aap->aar_pvc_encaps != ATM_ENC_NULL)) {
+ err = EINVAL;
+ break;
+ }
+ } else if (aap->aar_pvc_aal == ATM_AAL3_4) {
+ if (aap->aar_pvc_encaps != ATM_ENC_NULL) {
+ err = EINVAL;
+ break;
+ }
+ } else {
+ err = EINVAL;
+ break;
+ }
+
+ if (aap->aar_pvc_flags & PVC_DYN) {
+ /*
+ * For dynamic PVC destination addressing, the
+ * network interface must have support for this
+ */
+ if ((inp->inf_serv == NULL) ||
+ (inp->inf_serv->is_arp_pvcopen == NULL)) {
+ err = EDESTADDRREQ;
+ break;
+ }
+ } else {
+ u_long dst = ((struct sockaddr_in *)&aap->aar_pvc_dst)
+ ->sin_addr.s_addr;
+
+ if (dst == INADDR_ANY) {
+ err = EINVAL;
+ break;
+ }
+ }
+
+ /*
+ * Build connection request
+ */
+ pv.ipp_ipnif = inp;
+ pv.ipp_vpi = aap->aar_pvc_vpi;
+ pv.ipp_vci = aap->aar_pvc_vci;
+ pv.ipp_encaps = aap->aar_pvc_encaps;
+ pv.ipp_aal = aap->aar_pvc_aal;
+ if (aap->aar_pvc_flags & PVC_DYN) {
+ pv.ipp_dst.sin_addr.s_addr = INADDR_ANY;
+ } else
+ pv.ipp_dst = *(struct sockaddr_in *)&aap->aar_pvc_dst;
+
+ /*
+ * Open a new VCC
+ */
+ err = ipatm_openpvc(&pv, &ivp);
+ break;
+
+ case AIOCS_ADD_ARP:
+ /*
+ * Add an ARP mapping
+ */
+ aap = (struct atmaddreq *)data;
+
+ /*
+ * Validate IP address
+ */
+ if (aap->aar_arp_dst.sa_family != AF_INET) {
+ err = EAFNOSUPPORT;
+ break;
+ }
+ ip = SATOSIN(&aap->aar_arp_dst)->sin_addr;
+
+ if (aap->aar_arp_intf[0] == '\0') {
+ /*
+ * Find the IP network interface associated with
+ * the supplied IP address
+ */
+ for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
+ if (ipatm_chknif(ip, inp) == 0)
+ break;
+ }
+ if (inp == NULL) {
+ err = EADDRNOTAVAIL;
+ break;
+ }
+ } else {
+ /*
+ * Find the specified IP network interface
+ */
+ if ((nip = atm_nifname(aap->aar_arp_intf)) == NULL) {
+ err = ENXIO;
+ break;
+ }
+ for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
+ if (inp->inf_nif == nip)
+ break;
+ }
+ if (inp == NULL) {
+ err = ENXIO;
+ break;
+ }
+ }
+
+ if ((ip.s_addr == INADDR_ANY) ||
+#if (defined(BSD) && (BSD >= 199306))
+ in_broadcast(ip, &inp->inf_nif->nif_if) ||
+#else
+ in_broadcast(ip) ||
+#endif
+ IN_MULTICAST(ntohl(ip.s_addr))) {
+ err = EADDRNOTAVAIL;
+ break;
+ }
+
+ /*
+ * Notify the responsible ARP service
+ */
+ err = (*inp->inf_serv->is_ioctl)(code, data, inp->inf_isintf);
+ break;
+
+ case AIOCS_DEL_ARP:
+ /*
+ * Delete an ARP mapping
+ */
+ adp = (struct atmdelreq *)data;
+
+ /*
+ * Validate IP address
+ */
+ if (adp->adr_arp_dst.sa_family != AF_INET) {
+ err = EAFNOSUPPORT;
+ break;
+ }
+ ip = SATOSIN(&adp->adr_arp_dst)->sin_addr;
+
+ if (adp->adr_arp_intf[0] == '\0') {
+ /*
+ * Find the IP network interface associated with
+ * the supplied IP address
+ */
+ for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
+ if (ipatm_chknif(ip, inp) == 0)
+ break;
+ }
+ if (inp == NULL) {
+ err = EADDRNOTAVAIL;
+ break;
+ }
+ } else {
+ /*
+ * Find the specified IP network interface
+ */
+ if ((nip = atm_nifname(adp->adr_arp_intf)) == NULL) {
+ err = ENXIO;
+ break;
+ }
+ for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
+ if (inp->inf_nif == nip)
+ break;
+ }
+ if (inp == NULL) {
+ err = ENXIO;
+ break;
+ }
+ }
+
+ if ((ip.s_addr == INADDR_ANY) ||
+#if (defined(BSD) && (BSD >= 199306))
+ in_broadcast(ip, &inp->inf_nif->nif_if) ||
+#else
+ in_broadcast(ip) ||
+#endif
+ IN_MULTICAST(ntohl(ip.s_addr))) {
+ err = EADDRNOTAVAIL;
+ break;
+ }
+
+ /*
+ * Notify the responsible ARP service
+ */
+ err = (*inp->inf_serv->is_ioctl)(code, data, inp->inf_isintf);
+ break;
+
+ case AIOCS_INF_IPM:
+ /*
+ * Get IP VCC information
+ */
+ aip = (struct atminfreq *)data;
+
+ if (aip->air_ip_addr.sa_family != AF_INET)
+ break;
+ ip = SATOSIN(&aip->air_ip_addr)->sin_addr;
+
+ cp = aip->air_buf_addr;
+ space = aip->air_buf_len;
+
+ /*
+ * Loop through all our interfaces
+ */
+ for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
+ /*
+ * Check out each VCC
+ */
+ for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp;
+ ivp = Q_NEXT(ivp, struct ipvcc, iv_elem)) {
+
+ if ((ip.s_addr != INADDR_ANY) &&
+ (ip.s_addr != ivp->iv_dst.s_addr))
+ continue;
+
+ /*
+ * Make sure there's room in user buffer
+ */
+ if (space < sizeof(aivr)) {
+ err = ENOSPC;
+ break;
+ }
+
+ /*
+ * Fill in info to be returned
+ */
+ KM_ZERO((caddr_t)&aivr, sizeof(aivr));
+ SATOSIN(&aivr.aip_dst_addr)->sin_family =
+ AF_INET;
+ SATOSIN(&aivr.aip_dst_addr)->sin_addr.s_addr =
+ ivp->iv_dst.s_addr;
+ (void) sprintf(aivr.aip_intf, "%s%d",
+ inp->inf_nif->nif_if.if_name,
+ inp->inf_nif->nif_if.if_unit);
+ if ((ivp->iv_conn) &&
+ (ivp->iv_conn->co_connvc) &&
+ (vcp = ivp->iv_conn->co_connvc->cvc_vcc)) {
+ aivr.aip_vpi = vcp->vc_vpi;
+ aivr.aip_vci = vcp->vc_vci;
+ aivr.aip_sig_proto = vcp->vc_proto;
+ }
+ aivr.aip_flags = ivp->iv_flags;
+ aivr.aip_state = ivp->iv_state;
+
+ /*
+ * Copy data to user buffer and
+ * update buffer controls
+ */
+ err = copyout((caddr_t)&aivr, cp, sizeof(aivr));
+ if (err)
+ break;
+ cp += sizeof(aivr);
+ space -= sizeof(aivr);
+ }
+ if (err)
+ break;
+ }
+
+ /*
+ * Update buffer pointer/count
+ */
+ aip->air_buf_addr = cp;
+ aip->air_buf_len = space;
+ break;
+
+ default:
+ err = EOPNOTSUPP;
+ }
+
+ return (err);
+}
+
+
+/*
+ * Get Connection's Application/Owner Name
+ *
+ * Arguments:
+ * tok ipatm connection token (pointer to ipvcc)
+ *
+ * Returns:
+ * addr pointer to string containing our name
+ *
+ */
+caddr_t
+ipatm_getname(tok)
+ void *tok;
+{
+ return ("IP");
+}
+
diff --git a/sys/netatm/ipatm/ipatm_var.h b/sys/netatm/ipatm/ipatm_var.h
new file mode 100644
index 000000000000..6048284b4d75
--- /dev/null
+++ b/sys/netatm/ipatm/ipatm_var.h
@@ -0,0 +1,215 @@
+/*
+ *
+ * ===================================
+ * 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_var.h,v 1.8 1998/03/24 20:56:57 mks Exp $
+ *
+ */
+
+/*
+ * IP Over ATM Support
+ * -------------------
+ *
+ * Protocol control blocks
+ *
+ */
+
+#ifndef _IPATM_IPATM_VAR_H
+#define _IPATM_IPATM_VAR_H
+
+#ifdef ATM_KERNEL
+/*
+ * Structure containing information for each VCC, both SVC and PVC, which
+ * supports IP traffic.
+ */
+struct ipvcc {
+ Qelem_t iv_elem; /* ip_nif queueing links */
+ u_short iv_flags; /* VCC flags (see below) */
+ u_char iv_state; /* VCC state (see below) */
+ Atm_connection *iv_conn; /* Connection manager token */
+ struct in_addr iv_dst; /* Peer's IP address */
+ struct ip_nif *iv_ipnif; /* IP network interface */
+ struct atm_time iv_time; /* Timer controls */
+ short iv_idle; /* VCC idle timer */
+ u_char iv_parmx; /* Index into provider's vcc params */
+ KBuffer *iv_queue; /* Packet waiting for VCC */
+ struct arpmap *iv_arpent; /* ARP entry for VCC */
+ struct ipvcc *iv_arpnext; /* ARP link field */
+ Atm_connection *iv_arpconn; /* ARP connection manager token */
+};
+#define iv_forw iv_elem.q_forw
+#define iv_back iv_elem.q_back
+#endif /* ATM_KERNEL */
+
+/*
+ * VCC Flags
+ */
+#define IVF_PVC 0x0001 /* PVC */
+#define IVF_SVC 0x0002 /* SVC */
+#define IVF_LLC 0x0004 /* VCC uses LLC/SNAP encapsulation */
+#define IVF_MAPOK 0x0008 /* VCC ARP mapping is valid */
+#define IVF_NOIDLE 0x0010 /* Do not idle-timeout this VCC */
+
+/*
+ * VCC States
+ */
+#define IPVCC_FREE 0 /* No VCC associated with entry */
+#define IPVCC_PMAP 1 /* SVC waiting for ARP mapping */
+#define IPVCC_POPEN 2 /* Pending SVC open completion */
+#define IPVCC_PACCEPT 3 /* Pending SVC accept completion */
+#define IPVCC_ACTPENT 4 /* PVC open - waiting for ARP entry */
+#define IPVCC_ACTIVE 5 /* VCC open - available */
+#define IPVCC_CLOSED 6 /* VCC has been closed */
+
+
+#ifdef ATM_KERNEL
+/*
+ * Structure containing IP-specific information for each ATM network
+ * interface in the system.
+ */
+struct ip_nif {
+ struct ip_nif *inf_next; /* Next on interface chain */
+ struct atm_nif *inf_nif; /* ATM network interface */
+ u_short inf_state; /* Interface state (see below) */
+ struct in_ifaddr *inf_addr; /* Interface's IP address */
+ Queue_t inf_vcq; /* VCC connections queue */
+ struct ip_serv *inf_serv; /* Interface service provider */
+
+/* For use by IP interface service provider (ie signalling manager) */
+ caddr_t inf_isintf; /* Interface control block */
+
+/* IP/ATM provided interface services */
+ void (*inf_arpnotify)/* ARP event notification */
+ __P((struct ipvcc *, int));
+ int (*inf_ipinput) /* IP packet input */
+ __P((struct ip_nif *, KBuffer *));
+ int (*inf_createsvc)/* Create an IP SVC */
+ __P((struct ifnet *, u_short, caddr_t,
+ struct ipvcc **));
+};
+
+/*
+ * Network Interface States
+ */
+#define IPNIF_ADDR 1 /* Waiting for i/f address */
+#define IPNIF_SIGMGR 2 /* Waiting for sigmgr attach */
+#define IPNIF_ACTIVE 3 /* Active */
+
+
+/*
+ * Global IP/ATM Statistics
+ */
+struct ipatm_stat {
+ u_long ias_rcvstate; /* Packets received, bad vcc state */
+ u_long ias_rcvnobuf; /* Packets received, no buf avail */
+};
+
+
+/*
+ * Structure to pass parameters for ipatm_openpvc()
+ */
+struct ipatmpvc {
+ struct ip_nif *ipp_ipnif; /* PVC's IP network interface */
+ u_short ipp_vpi; /* VPI value */
+ u_short ipp_vci; /* VCI value */
+ Aal_t ipp_aal; /* AAL type */
+ Encaps_t ipp_encaps; /* VCC encapsulation */
+ struct sockaddr_in ipp_dst; /* Destination's IP address */
+};
+
+
+/*
+ * Timer macros
+ */
+#define IPVCC_TIMER(s, t) atm_timeout(&(s)->iv_time, (t), ipatm_timeout)
+#define IPVCC_CANCEL(s) atm_untimeout(&(s)->iv_time)
+
+/*
+ * Misc useful macros
+ */
+#define SATOSIN(sa) ((struct sockaddr_in *)(sa))
+
+
+/*
+ * Global function declarations
+ */
+ /* ipatm_event.c */
+void ipatm_timeout __P((struct atm_time *));
+void ipatm_connected __P((void *));
+void ipatm_cleared __P((void *, struct t_atm_cause *));
+void ipatm_arpnotify __P((struct ipvcc *, int));
+void ipatm_itimeout __P((struct atm_time *));
+
+ /* ipatm_if.c */
+int ipatm_nifstat __P((int, struct atm_nif *, int));
+
+ /* ipatm_input.c */
+void ipatm_cpcs_data __P((void *, KBuffer *));
+int ipatm_ipinput __P((struct ip_nif *, KBuffer *));
+
+ /* ipatm_load.c */
+
+ /* ipatm_output.c */
+int ipatm_ifoutput __P((struct ifnet *, KBuffer *,
+ struct sockaddr *));
+
+ /* ipatm_usrreq.c */
+int ipatm_ioctl __P((int, caddr_t, caddr_t));
+caddr_t ipatm_getname __P((void *));
+
+ /* ipatm_vcm.c */
+int ipatm_openpvc __P((struct ipatmpvc *, struct ipvcc **));
+int ipatm_createsvc __P((struct ifnet *, u_short, caddr_t,
+ struct ipvcc **));
+int ipatm_opensvc __P((struct ipvcc *));
+int ipatm_retrysvc __P((struct ipvcc *));
+void ipatm_activate __P((struct ipvcc *));
+int ipatm_incoming __P((void *, Atm_connection *, Atm_attributes *,
+ void **));
+int ipatm_closevc __P((struct ipvcc *, int));
+int ipatm_chknif __P((struct in_addr, struct ip_nif *));
+struct ipvcc *ipatm_iptovc __P((struct sockaddr_in *, struct atm_nif *));
+
+
+/*
+ * External variables
+ */
+extern int ipatm_vccnt;
+extern int ipatm_vcidle;
+extern int ipatm_print;
+extern u_long last_map_ipdst;
+extern struct ipvcc *last_map_ipvcc;
+extern struct ip_nif *ipatm_nif_head;
+extern struct sp_info ipatm_vcpool;
+extern struct sp_info ipatm_nifpool;
+extern struct ipatm_stat ipatm_stat;
+extern struct atm_time ipatm_itimer;
+extern Atm_endpoint ipatm_endpt;
+extern Atm_attributes ipatm_aal5llc;
+extern Atm_attributes ipatm_aal5null;
+extern Atm_attributes ipatm_aal4null;
+
+#endif /* ATM_KERNEL */
+
+#endif /* _IPATM_IPATM_VAR_H */
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);
+}
+