aboutsummaryrefslogtreecommitdiff
path: root/sys/netatm/uni/uniarp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/uni/uniarp.c')
-rw-r--r--sys/netatm/uni/uniarp.c1231
1 files changed, 1231 insertions, 0 deletions
diff --git a/sys/netatm/uni/uniarp.c b/sys/netatm/uni/uniarp.c
new file mode 100644
index 000000000000..f316a7325a32
--- /dev/null
+++ b/sys/netatm/uni/uniarp.c
@@ -0,0 +1,1231 @@
+/*
+ *
+ * ===================================
+ * 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: uniarp.c,v 1.10 1998/07/20 18:58:45 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * UNI ATMARP support (RFC1577)
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: uniarp.c,v 1.10 1998/07/20 18:58:45 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/uniip_var.h>
+
+
+/*
+ * Global variables
+ */
+struct uniarp *uniarp_arptab[UNIARP_HASHSIZ] = {NULL};
+struct uniarp *uniarp_nomaptab = NULL;
+struct uniarp *uniarp_pvctab = NULL;
+struct atm_time uniarp_timer = {0, 0}; /* Aging timer */
+struct uniarp_stat uniarp_stat = {0};
+int uniarp_print = 0;
+
+Atm_endpoint uniarp_endpt = {
+ NULL,
+ ENDPT_ATMARP,
+ uniarp_ioctl,
+ uniarp_getname,
+ uniarp_connected,
+ uniarp_cleared,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ uniarp_cpcs_data,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+struct sp_info uniarp_pool = {
+ "uni arp pool", /* si_name */
+ sizeof(struct uniarp), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 200 /* si_maxallow */
+};
+
+
+/*
+ * Local variables
+ */
+static void uniarp_server_mode __P((struct uniip *));
+static void uniarp_client_mode __P((struct uniip *, Atm_addr *));
+
+
+/*
+ * Process module loading notification
+ *
+ * Called whenever the uni module is initializing.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 initialization successful
+ * errno initialization failed - reason indicated
+ *
+ */
+int
+uniarp_start()
+{
+ int err;
+
+ /*
+ * Register our endpoint
+ */
+ err = atm_endpoint_register(&uniarp_endpt);
+
+ return (err);
+}
+
+
+/*
+ * Process module unloading notification
+ *
+ * Called whenever the uni module is about to be unloaded. All signalling
+ * instances will have been previously detached. All uniarp resources
+ * must be freed now.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_stop()
+{
+ int i;
+
+ /*
+ * Make sure the arp table is empty
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ if (uniarp_arptab[i] != NULL)
+ panic("uniarp_stop: arp table not empty");
+ }
+
+ /*
+ * Cancel timers
+ */
+ (void) atm_untimeout(&uniarp_timer);
+
+ /*
+ * De-register ourselves
+ */
+ (void) atm_endpoint_deregister(&uniarp_endpt);
+
+ /*
+ * Free our storage pools
+ */
+ atm_release_pool(&uniarp_pool);
+}
+
+
+/*
+ * Process IP Network Interface Activation
+ *
+ * Called whenever an IP network interface becomes active.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * uip pointer to UNI IP interface
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_ipact(uip)
+ struct uniip *uip;
+{
+ struct unisig *usp;
+
+ ATM_DEBUG1("uniarp_ipact: uip=0x%x\n", (int)uip);
+
+ /*
+ * Set initial state
+ */
+ uip->uip_arpstate = UIAS_NOTCONF;
+ uip->uip_arpsvratm.address_format = T_ATM_ABSENT;
+ uip->uip_arpsvratm.address_length = 0;
+ uip->uip_arpsvrsub.address_format = T_ATM_ABSENT;
+ uip->uip_arpsvrsub.address_length = 0;
+
+ usp = (struct unisig *)uip->uip_ipnif->inf_nif->nif_pif->pif_siginst;
+ if (usp->us_addr.address_format != T_ATM_ABSENT)
+ uip->uip_flags |= UIF_IFADDR;
+
+ /*
+ * Make sure aging timer is running
+ */
+ if ((uniarp_timer.ti_flag & TIF_QUEUED) == 0)
+ atm_timeout(&uniarp_timer, UNIARP_AGING, uniarp_aging);
+
+ return;
+}
+
+
+/*
+ * Process IP Network Interface Deactivation
+ *
+ * Called whenever an IP network interface becomes inactive. All VCCs
+ * for this interface should already have been closed.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * uip pointer to UNI IP interface
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_ipdact(uip)
+ struct uniip *uip;
+{
+ struct ip_nif *inp = uip->uip_ipnif;
+ struct uniarp *uap, *unext;
+ int i;
+
+ ATM_DEBUG1("uniarp_ipdact: uip=0x%x\n", (int)uip);
+
+ /*
+ * Delete all interface entries
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (uap->ua_intf != uip)
+ continue;
+
+ /*
+ * All VCCs should (better) be gone by now
+ */
+ if (uap->ua_ivp)
+ panic("uniarp_ipdact: entry not empty");
+
+ /*
+ * Clean up any loose ends
+ */
+ UNIARP_CANCEL(uap);
+
+ /*
+ * Delete entry from arp table and free entry
+ */
+ UNIARP_DELETE(uap);
+ atm_free((caddr_t)uap);
+ }
+ }
+
+ /*
+ * Clean up 'nomap' table
+ */
+ for (uap = uniarp_nomaptab; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (uap->ua_intf != uip)
+ continue;
+
+ /*
+ * All VCCs should (better) be gone by now
+ */
+ if (uap->ua_ivp)
+ panic("uniarp_ipdact: entry not empty");
+
+ /*
+ * Clean up any loose ends
+ */
+ UNIARP_CANCEL(uap);
+
+ /*
+ * Delete entry from 'no map' table and free entry
+ */
+ UNLINK(uap, struct uniarp, uniarp_nomaptab, ua_next);
+ atm_free((caddr_t)uap);
+ }
+
+ /*
+ * Also clean up pvc table
+ */
+ for (uap = uniarp_pvctab; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (uap->ua_intf != uip)
+ continue;
+
+ /*
+ * All PVCs should (better) be gone by now
+ */
+ panic("uniarp_ipdact: pvc table not empty");
+ }
+
+ /*
+ * Cancel arp interface timer
+ */
+ UNIIP_ARP_CANCEL(uip);
+
+ /*
+ * Stop aging timer if this is the last active interface
+ */
+ if (uniip_head == uip && uip->uip_next == NULL)
+ (void) atm_untimeout(&uniarp_timer);
+}
+
+
+/*
+ * Process Interface ATM Address Change
+ *
+ * This function is called whenever the ATM address for a physical
+ * interface is set/changed.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * sip pointer to interface's UNI signalling instance
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_ifaddr(sip)
+ struct siginst *sip;
+{
+ struct atm_nif *nip;
+ struct uniip *uip;
+
+ ATM_DEBUG1("uniarp_ifaddr: sip=0x%x\n", (int)sip);
+
+ /*
+ * We've got to handle this for every network interface
+ */
+ for (nip = sip->si_pif->pif_nif; nip; nip = nip->nif_pnext) {
+
+ /*
+ * Find our control blocks
+ */
+ for (uip = uniip_head; uip; uip = uip->uip_next) {
+ if (uip->uip_ipnif->inf_nif == nip)
+ break;
+ }
+ if (uip == NULL)
+ continue;
+
+ /*
+ * We don't support changing prefix (yet)
+ */
+ if (uip->uip_flags & UIF_IFADDR) {
+ log(LOG_ERR, "uniarp_ifaddr: change not supported\n");
+ continue;
+ }
+
+ /*
+ * Note that address has been set and figure out what
+ * to do next
+ */
+ uip->uip_flags |= UIF_IFADDR;
+
+ if (uip->uip_arpstate == UIAS_CLIENT_PADDR) {
+ /*
+ * This is what we're waiting for
+ */
+ uniarp_client_mode(uip, NULL);
+ }
+ }
+
+ return;
+}
+
+
+/*
+ * Set ATMARP Server Mode
+ *
+ * This function is called to configure the local node to become the
+ * ATMARP server for the specified LIS.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * uip pointer to UNI IP interface
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+uniarp_server_mode(uip)
+ struct uniip *uip;
+{
+ struct ip_nif *inp;
+ struct atm_nif *nip;
+ struct siginst *sgp;
+ struct ipvcc *ivp, *inext;
+ struct uniarp *uap, *unext;
+ int i;
+
+ ATM_DEBUG1("uniarp_server_mode: uip=0x%x\n", (int)uip);
+
+ /*
+ * Handle client/server mode changes first
+ */
+ switch (uip->uip_arpstate) {
+
+ case UIAS_NOTCONF:
+ case UIAS_SERVER_ACTIVE:
+ case UIAS_CLIENT_PADDR:
+ /*
+ * Nothing to undo
+ */
+ break;
+
+ case UIAS_CLIENT_POPEN:
+ /*
+ * We're becoming the server, so kill the pending connection
+ */
+ UNIIP_ARP_CANCEL(uip);
+ if (ivp = uip->uip_arpsvrvcc) {
+ ivp->iv_flags &= ~IVF_NOIDLE;
+ uip->uip_arpsvrvcc = NULL;
+ (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED);
+ }
+ break;
+
+ case UIAS_CLIENT_REGISTER:
+ case UIAS_CLIENT_ACTIVE:
+ /*
+ * We're becoming the server, but leave existing VCC as a
+ * "normal" IP VCC
+ */
+ UNIIP_ARP_CANCEL(uip);
+ ivp = uip->uip_arpsvrvcc;
+ ivp->iv_flags &= ~IVF_NOIDLE;
+ uip->uip_arpsvrvcc = NULL;
+ break;
+ }
+
+ /*
+ * Revalidate status for all arp entries on this interface
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (uap->ua_intf != uip)
+ continue;
+
+ if (uap->ua_origin >= UAO_PERM)
+ continue;
+
+ if (uap->ua_origin >= UAO_SCSP) {
+ if (uniarp_validate_ip(uip, &uap->ua_dstip,
+ uap->ua_origin) == 0)
+ continue;
+ }
+
+ if (uap->ua_ivp == NULL) {
+ UNIARP_CANCEL(uap);
+ UNIARP_DELETE(uap);
+ atm_free((caddr_t)uap);
+ continue;
+ }
+
+ if (uap->ua_flags & UAF_VALID) {
+ uap->ua_flags |= UAF_LOCKED;
+ for (ivp = uap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*ivp->iv_ipnif->inf_arpnotify)
+ (ivp, MAP_INVALID);
+ }
+ uap->ua_flags &= ~(UAF_LOCKED | UAF_VALID);
+ }
+ uap->ua_aging = 1;
+ uap->ua_origin = 0;
+ }
+ }
+
+ /*
+ * OK, now let's make ourselves the server
+ */
+ inp = uip->uip_ipnif;
+ nip = inp->inf_nif;
+ sgp = nip->nif_pif->pif_siginst;
+ ATM_ADDR_SEL_COPY(&sgp->si_addr, nip->nif_sel, &uip->uip_arpsvratm);
+ uip->uip_arpsvrip = IA_SIN(inp->inf_addr)->sin_addr;
+ uip->uip_arpstate = UIAS_SERVER_ACTIVE;
+ return;
+}
+
+
+/*
+ * Set ATMARP Client Mode
+ *
+ * This function is called to configure the local node to be an ATMARP
+ * client on the specified LIS using the specified ATMARP server.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * uip pointer to UNI IP interface
+ * aap pointer to the ATMARP server's ATM address
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+uniarp_client_mode(uip, aap)
+ struct uniip *uip;
+ Atm_addr *aap;
+{
+ struct ip_nif *inp = uip->uip_ipnif;
+ struct uniarp *uap, *unext;
+ struct ipvcc *ivp, *inext;
+ int i;
+
+ ATM_DEBUG2("uniarp_client_mode: uip=0x%x, atm=(%s,-)\n",
+ (int)uip, aap ? unisig_addr_print(aap): "-");
+
+ /*
+ * Handle client/server mode changes first
+ */
+ switch (uip->uip_arpstate) {
+
+ case UIAS_NOTCONF:
+ case UIAS_CLIENT_PADDR:
+ /*
+ * Nothing to undo
+ */
+ break;
+
+ case UIAS_CLIENT_POPEN:
+ /*
+ * If this is this a timeout retry, just go do it
+ */
+ if (aap == NULL)
+ break;
+
+ /*
+ * If this isn't really a different arpserver, we're done
+ */
+ if (ATM_ADDR_EQUAL(aap, &uip->uip_arpsvratm))
+ return;
+
+ /*
+ * We're changing servers, so kill the pending connection
+ */
+ UNIIP_ARP_CANCEL(uip);
+ if (ivp = uip->uip_arpsvrvcc) {
+ ivp->iv_flags &= ~IVF_NOIDLE;
+ uip->uip_arpsvrvcc = NULL;
+ (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED);
+ }
+ break;
+
+ case UIAS_CLIENT_REGISTER:
+ case UIAS_CLIENT_ACTIVE:
+ /*
+ * If this isn't really a different arpserver, we're done
+ */
+ if (ATM_ADDR_EQUAL(aap, &uip->uip_arpsvratm))
+ return;
+
+ /*
+ * We're changing servers, but leave existing VCC as a
+ * "normal" IP VCC
+ */
+ UNIIP_ARP_CANCEL(uip);
+ ivp = uip->uip_arpsvrvcc;
+ ivp->iv_flags &= ~IVF_NOIDLE;
+ uip->uip_arpsvrvcc = NULL;
+ break;
+
+ case UIAS_SERVER_ACTIVE:
+ /*
+ * We're changing from server mode, so...
+ *
+ * Reset valid/authoritative status for all arp entries
+ * on this interface
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (uap->ua_intf != uip)
+ continue;
+
+ if (uap->ua_origin >= UAO_PERM)
+ continue;
+
+ if (uap->ua_ivp == NULL) {
+ UNIARP_CANCEL(uap);
+ UNIARP_DELETE(uap);
+ atm_free((caddr_t)uap);
+ continue;
+ }
+
+ if (uap->ua_flags & UAF_VALID) {
+ uap->ua_flags |= UAF_LOCKED;
+ for (ivp = uap->ua_ivp; ivp;
+ ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*ivp->iv_ipnif->inf_arpnotify)
+ (ivp, MAP_INVALID);
+ }
+ uap->ua_flags &=
+ ~(UAF_LOCKED | UAF_VALID);
+ }
+ uap->ua_aging = 1;
+ uap->ua_origin = 0;
+ }
+ }
+ uip->uip_arpsvratm.address_format = T_ATM_ABSENT;
+ uip->uip_arpsvratm.address_length = 0;
+ uip->uip_arpsvrsub.address_format = T_ATM_ABSENT;
+ uip->uip_arpsvrsub.address_length = 0;
+ uip->uip_arpsvrip.s_addr = 0;
+ break;
+ }
+
+ /*
+ * Save the arp server address, if supplied now
+ */
+ if (aap)
+ ATM_ADDR_COPY(aap, &uip->uip_arpsvratm);
+
+ /*
+ * If the interface's ATM address isn't set yet, then we
+ * can't do much until it is
+ */
+ if ((uip->uip_flags & UIF_IFADDR) == 0) {
+ uip->uip_arpstate = UIAS_CLIENT_PADDR;
+ return;
+ }
+
+ /*
+ * Just to keep things simple, if we already have (or are trying to
+ * setup) any SVCs to our new server, kill the connections so we can
+ * open a "fresh" SVC for the arpserver connection.
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (ATM_ADDR_EQUAL(&uip->uip_arpsvratm,
+ &uap->ua_dstatm) &&
+ ATM_ADDR_EQUAL(&uip->uip_arpsvrsub,
+ &uap->ua_dstatmsub)) {
+ uap->ua_flags &= ~UAF_VALID;
+ for (ivp = uap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*inp->inf_arpnotify)(ivp, MAP_FAILED);
+ }
+ }
+ }
+ }
+ for (uap = uniarp_nomaptab; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (ATM_ADDR_EQUAL(&uip->uip_arpsvratm, &uap->ua_dstatm) &&
+ ATM_ADDR_EQUAL(&uip->uip_arpsvrsub, &uap->ua_dstatmsub)) {
+ uap->ua_flags &= ~UAF_VALID;
+ for (ivp = uap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*inp->inf_arpnotify)(ivp, MAP_FAILED);
+ }
+ }
+ }
+
+ /*
+ * Now, get an arp entry for the server connection
+ */
+ uip->uip_arpstate = UIAS_CLIENT_POPEN;
+ uap = (struct uniarp *)atm_allocate(&uniarp_pool);
+ if (uap == NULL) {
+ UNIIP_ARP_TIMER(uip, 1 * ATM_HZ);
+ return;
+ }
+
+ /*
+ * Next, initiate an SVC to the server
+ */
+ if ((*inp->inf_createsvc)(&inp->inf_nif->nif_if, AF_ATM,
+ (caddr_t)&uip->uip_arpsvratm, &ivp)) {
+ atm_free((caddr_t)uap);
+ UNIIP_ARP_TIMER(uip, 1 * ATM_HZ);
+ return;
+ }
+
+ /*
+ * Finally, get everything set up and wait for the SVC
+ * connection to complete
+ */
+ uip->uip_arpsvrvcc = ivp;
+ ivp->iv_flags |= IVF_NOIDLE;
+
+ ATM_ADDR_COPY(&uip->uip_arpsvratm, &uap->ua_dstatm);
+ ATM_ADDR_COPY(&uip->uip_arpsvrsub, &uap->ua_dstatmsub);
+ uap->ua_intf = uip;
+
+ LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
+ ivp->iv_arpent = (struct arpmap *)uap;
+
+ LINK2TAIL(uap, struct uniarp, uniarp_nomaptab, ua_next);
+
+ return;
+}
+
+
+/*
+ * Process a UNI ARP interface timeout
+ *
+ * Called when a previously scheduled uniip arp interface timer expires.
+ * Processing will be based on the current uniip arp state.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to uniip arp timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_iftimeout(tip)
+ struct atm_time *tip;
+{
+ struct ip_nif *inp;
+ struct uniip *uip;
+
+
+ /*
+ * Back-off to uniip control block
+ */
+ uip = (struct uniip *)
+ ((caddr_t)tip - (int)(&((struct uniip *)0)->uip_arptime));
+
+ ATM_DEBUG2("uniarp_iftimeout: uip=0x%x, state=%d\n", (int)uip,
+ uip->uip_arpstate);
+
+ /*
+ * Process timeout based on protocol state
+ */
+ switch (uip->uip_arpstate) {
+
+ case UIAS_CLIENT_POPEN:
+ /*
+ * Retry opening arp server connection
+ */
+ uniarp_client_mode(uip, NULL);
+ break;
+
+ case UIAS_CLIENT_REGISTER:
+ /*
+ * Resend registration request
+ */
+ inp = uip->uip_ipnif;
+ (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr));
+
+ /*
+ * Restart timer
+ */
+ UNIIP_ARP_TIMER(uip, 2 * ATM_HZ);
+
+ break;
+
+ case UIAS_CLIENT_ACTIVE:
+ /*
+ * Refresh our registration
+ */
+ inp = uip->uip_ipnif;
+ (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr));
+
+ /*
+ * Restart timer
+ */
+ UNIIP_ARP_TIMER(uip, UNIARP_REGIS_RETRY);
+
+ break;
+
+ default:
+ log(LOG_ERR, "uniarp_iftimeout: invalid state %d\n",
+ uip->uip_arpstate);
+ }
+}
+
+
+/*
+ * UNI ARP IOCTL support
+ *
+ * Function will be 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
+uniarp_ioctl(code, data, arg1)
+ int code;
+ caddr_t data;
+ caddr_t arg1;
+{
+ struct atmaddreq *aap;
+ struct atmdelreq *adp;
+ struct atmsetreq *asp;
+ struct atminfreq *aip;
+ struct air_arp_rsp aar;
+ struct air_asrv_rsp asr;
+ struct atm_pif *pip;
+ struct atm_nif *nip;
+ struct ipvcc *ivp, *inext;
+ struct uniip *uip;
+ struct uniarp *uap;
+ struct unisig *usp;
+ struct in_addr ip;
+ Atm_addr atmsub;
+ u_long dst;
+ int err = 0, i, buf_len;
+ caddr_t buf_addr;
+
+ switch (code) {
+
+ case AIOCS_ADD_ARP:
+ /*
+ * Add a permanent ARP mapping
+ */
+ aap = (struct atmaddreq *)data;
+ uip = (struct uniip *)arg1;
+ if (aap->aar_arp_addr.address_format != T_ATM_ENDSYS_ADDR) {
+ err = EINVAL;
+ break;
+ }
+ atmsub.address_format = T_ATM_ABSENT;
+ atmsub.address_length = 0;
+ ip = SATOSIN(&aap->aar_arp_dst)->sin_addr;
+
+ /*
+ * Validate IP address
+ */
+ if (uniarp_validate_ip(uip, &ip, aap->aar_arp_origin) != 0) {
+ err = EADDRNOTAVAIL;
+ break;
+ }
+
+ /*
+ * Add an entry to the cache
+ */
+ err = uniarp_cache_svc(uip, &ip, &aap->aar_arp_addr,
+ &atmsub, aap->aar_arp_origin);
+ break;
+
+ case AIOCS_DEL_ARP:
+ /*
+ * Delete an ARP mapping
+ */
+ adp = (struct atmdelreq *)data;
+ uip = (struct uniip *)arg1;
+ ip = SATOSIN(&adp->adr_arp_dst)->sin_addr;
+
+ /*
+ * Now find the entry to be deleted
+ */
+ UNIARP_LOOKUP(ip.s_addr, uap);
+ if (uap == NULL) {
+ err = ENOENT;
+ break;
+ }
+
+ /*
+ * Notify all VCCs using this entry that they must finish
+ * up now.
+ */
+ uap->ua_flags |= UAF_LOCKED;
+ for (ivp = uap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED);
+ }
+
+ /*
+ * Now free up the entry
+ */
+ UNIARP_CANCEL(uap);
+ UNIARP_DELETE(uap);
+ atm_free((caddr_t)uap);
+ break;
+
+ case AIOCS_SET_ASV:
+ /*
+ * Set interface ARP server address
+ */
+ asp = (struct atmsetreq *)data;
+ for (uip = uniip_head; uip; uip = uip->uip_next) {
+ if (uip->uip_ipnif->inf_nif == (struct atm_nif *)arg1)
+ break;
+ }
+ if (uip == NULL) {
+ err = ENOPROTOOPT;
+ break;
+ }
+
+ /*
+ * Check for our own address
+ */
+ usp = (struct unisig *)
+ uip->uip_ipnif->inf_nif->nif_pif->pif_siginst;
+ if (ATM_ADDR_EQUAL(&asp->asr_arp_addr, &usp->us_addr)) {
+ asp->asr_arp_addr.address_format = T_ATM_ABSENT;
+ }
+
+ /*
+ * If we're going into server mode, make sure we can get
+ * the memory for the prefix list before continuing
+ */
+ if (asp->asr_arp_addr.address_format == T_ATM_ABSENT) {
+ i = asp->asr_arp_plen / sizeof(struct uniarp_prf);
+ if (i <= 0) {
+ err = EINVAL;
+ break;
+ }
+ buf_len = i * sizeof(struct uniarp_prf);
+ buf_addr = KM_ALLOC(buf_len, M_DEVBUF, M_NOWAIT);
+ if (buf_addr == NULL) {
+ err = ENOMEM;
+ break;
+ }
+ err = copyin(asp->asr_arp_pbuf, buf_addr, buf_len);
+ if (err) {
+ KM_FREE(buf_addr, buf_len, M_DEVBUF);
+ break;
+ }
+ } else {
+ /* Silence the compiler */
+ i = 0;
+ buf_addr = NULL;
+ }
+
+ /*
+ * Free any existing prefix address list
+ */
+ if (uip->uip_prefix != NULL) {
+ KM_FREE(uip->uip_prefix,
+ uip->uip_nprefix * sizeof(struct uniarp_prf),
+ M_DEVBUF);
+ uip->uip_prefix = NULL;
+ uip->uip_nprefix = 0;
+ }
+
+ if (asp->asr_arp_addr.address_format == T_ATM_ABSENT) {
+ /*
+ * Set ATMARP server mode
+ */
+ uip->uip_prefix = (struct uniarp_prf *)buf_addr;
+ uip->uip_nprefix = i;
+ uniarp_server_mode(uip);
+ } else
+ /*
+ * Set ATMARP client mode
+ */
+ uniarp_client_mode(uip, &asp->asr_arp_addr);
+ break;
+
+ case AIOCS_INF_ARP:
+ /*
+ * Get ARP table information
+ */
+ aip = (struct atminfreq *)data;
+
+ if (aip->air_arp_addr.sa_family != AF_INET)
+ break;
+ dst = SATOSIN(&aip->air_arp_addr)->sin_addr.s_addr;
+
+ buf_addr = aip->air_buf_addr;
+ buf_len = aip->air_buf_len;
+
+ pip = ((struct siginst *)arg1)->si_pif;
+
+ /*
+ * Run through entire arp table
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap; uap = uap->ua_next) {
+ /*
+ * We only want valid entries learned
+ * from the supplied interface.
+ */
+ nip = uap->ua_intf->uip_ipnif->inf_nif;
+ if (nip->nif_pif != pip)
+ continue;
+ if ((dst != INADDR_ANY) &&
+ (dst != uap->ua_dstip.s_addr))
+ continue;
+
+ /*
+ * Make sure there's room in the user's buffer
+ */
+ if (buf_len < sizeof(aar)) {
+ err = ENOSPC;
+ break;
+ }
+
+ /*
+ * Fill in info to be returned
+ */
+ SATOSIN(&aar.aap_arp_addr)->sin_family =
+ AF_INET;
+ SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr =
+ uap->ua_dstip.s_addr;
+ (void) sprintf(aar.aap_intf, "%s%d",
+ nip->nif_if.if_name,
+ nip->nif_if.if_unit);
+ aar.aap_flags = uap->ua_flags;
+ aar.aap_origin = uap->ua_origin;
+ if (uap->ua_flags & UAF_VALID)
+ aar.aap_age = uap->ua_aging +
+ uap->ua_retry * UNIARP_RETRY_AGE;
+ else
+ aar.aap_age = 0;
+ ATM_ADDR_COPY(&uap->ua_dstatm, &aar.aap_addr);
+ ATM_ADDR_COPY(&uap->ua_dstatmsub,
+ &aar.aap_subaddr);
+
+ /*
+ * Copy the response into the user's buffer
+ */
+ if (err = copyout((caddr_t)&aar, buf_addr,
+ sizeof(aar)))
+ break;
+ buf_addr += sizeof(aar);
+ buf_len -= sizeof(aar);
+ }
+ if (err)
+ break;
+ }
+
+ /*
+ * Now go through the 'nomap' table
+ */
+ if (err || (dst != INADDR_ANY))
+ goto updbuf;
+ for (uap = uniarp_nomaptab; uap; uap = uap->ua_next) {
+ /*
+ * We only want valid entries learned
+ * from the supplied interface.
+ */
+ nip = uap->ua_intf->uip_ipnif->inf_nif;
+ if (nip->nif_pif != pip)
+ continue;
+
+ /*
+ * Make sure there's room in the user's buffer
+ */
+ if (buf_len < sizeof(aar)) {
+ err = ENOSPC;
+ break;
+ }
+
+ /*
+ * Fill in info to be returned
+ */
+ SATOSIN(&aar.aap_arp_addr)->sin_family = AF_INET;
+ SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr = 0;
+ (void) sprintf(aar.aap_intf, "%s%d",
+ nip->nif_if.if_name, nip->nif_if.if_unit);
+ aar.aap_flags = 0;
+ aar.aap_origin = uap->ua_origin;
+ aar.aap_age = 0;
+ ATM_ADDR_COPY(&uap->ua_dstatm, &aar.aap_addr);
+ ATM_ADDR_COPY(&uap->ua_dstatmsub,
+ &aar.aap_subaddr);
+
+ /*
+ * Copy the response into the user's buffer
+ */
+ if (err = copyout((caddr_t)&aar, buf_addr,
+ sizeof(aar)))
+ break;
+ buf_addr += sizeof(aar);
+ buf_len -= sizeof(aar);
+ }
+
+updbuf:
+ /*
+ * Update the buffer pointer and length
+ */
+ aip->air_buf_addr = buf_addr;
+ aip->air_buf_len = buf_len;
+
+ /*
+ * If the user wants the refresh status reset and no
+ * errors have been encountered, then do the reset
+ */
+ if ((err == 0) && (aip->air_arp_flags & ARP_RESET_REF)) {
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap;
+ uap = uap->ua_next) {
+ /*
+ * We only want valid entries learned
+ * from the supplied interface.
+ */
+ nip = uap->ua_intf->uip_ipnif->inf_nif;
+ if (nip->nif_pif != pip)
+ continue;
+ if ((dst != INADDR_ANY) &&
+ (dst != uap->ua_dstip.s_addr))
+ continue;
+
+ /*
+ * Reset refresh flag
+ */
+ uap->ua_flags &= ~UAF_REFRESH;
+ }
+ }
+ }
+ break;
+
+ case AIOCS_INF_ASV:
+ /*
+ * Get ARP server information
+ */
+ aip = (struct atminfreq *)data;
+
+ buf_addr = aip->air_buf_addr;
+ buf_len = aip->air_buf_len;
+
+ for (uip = uniip_head; uip; uip = uip->uip_next) {
+
+ if ((arg1 != NULL) &&
+ (uip->uip_ipnif->inf_nif != (struct atm_nif *)arg1))
+ continue;
+
+ /*
+ * Make sure there's room in the user's buffer
+ */
+ if (buf_len < sizeof(asr)) {
+ err = ENOSPC;
+ break;
+ }
+
+ /*
+ * Fill in info to be returned
+ */
+ nip = uip->uip_ipnif->inf_nif;
+ (void) sprintf(asr.asp_intf, "%s%d",
+ nip->nif_if.if_name, nip->nif_if.if_unit);
+ asr.asp_state = uip->uip_arpstate;
+ if (uip->uip_arpstate == UIAS_SERVER_ACTIVE) {
+ asr.asp_addr.address_format = T_ATM_ABSENT;
+ asr.asp_addr.address_length = 0;
+ } else {
+ ATM_ADDR_COPY(&uip->uip_arpsvratm,
+ &asr.asp_addr);
+ }
+ asr.asp_subaddr.address_format = T_ATM_ABSENT;
+ asr.asp_subaddr.address_length = 0;
+ asr.asp_nprefix = uip->uip_nprefix;
+
+ /*
+ * Copy the response into the user's buffer
+ */
+ if (err = copyout((caddr_t)&asr, buf_addr, sizeof(asr)))
+ break;
+ buf_addr += sizeof(asr);
+ buf_len -= sizeof(asr);
+
+ /*
+ * Copy the prefix list into the user's buffer
+ */
+ if (uip->uip_nprefix) {
+ i = uip->uip_nprefix
+ * sizeof(struct uniarp_prf);
+ if (buf_len < i) {
+ err = ENOSPC;
+ break;
+ }
+ if (err = copyout(uip->uip_prefix, buf_addr, i))
+ break;
+ buf_addr += i;
+ buf_len -= i;
+ }
+ }
+
+ /*
+ * Update the buffer pointer and length
+ */
+ aip->air_buf_addr = buf_addr;
+ aip->air_buf_len = buf_len;
+ break;
+
+ default:
+ err = EOPNOTSUPP;
+ }
+
+ return (err);
+}
+
+
+/*
+ * Get Connection's Application/Owner Name
+ *
+ * Arguments:
+ * tok uniarp connection token (pointer to ipvcc)
+ *
+ * Returns:
+ * addr pointer to string containing our name
+ *
+ */
+caddr_t
+uniarp_getname(tok)
+ void *tok;
+{
+ return ("ATMARP");
+}
+