diff options
Diffstat (limited to 'sys/netatm/uni/uniarp_vcm.c')
-rw-r--r-- | sys/netatm/uni/uniarp_vcm.c | 708 |
1 files changed, 708 insertions, 0 deletions
diff --git a/sys/netatm/uni/uniarp_vcm.c b/sys/netatm/uni/uniarp_vcm.c new file mode 100644 index 0000000..9b1f211 --- /dev/null +++ b/sys/netatm/uni/uniarp_vcm.c @@ -0,0 +1,708 @@ +/* + * + * =================================== + * 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_vcm.c,v 1.10 1998/06/29 22:15:46 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) - Virtual Channel Management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp_vcm.c,v 1.10 1998/06/29 22:15:46 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> + + +/* + * Local variables + */ +static struct attr_llc uniarp_llc = { + T_ATM_PRESENT, + { + T_ATM_LLC_SHARING, + 8, + {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06} + } +}; + +static struct t_atm_cause uniarp_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_TEMPORARY_FAILURE, + {0, 0, 0, 0} +}; + + +/* + * Process a new PVC requiring ATMARP support + * + * This function is called after IP/ATM has successfully opened a PVC which + * requires ATMARP support. We will send an InATMARP request over the PVC + * to elicit a response from the PVC's ATMARP peer informing us of its + * network address. This information will also be used by IP/ATM in order + * to complete its address-to-VC mapping table. + * + * Arguments: + * ivp pointer to PVC's IPVCC control block + * + * Returns: + * MAP_PROCEEDING - OK so far, querying for peer's mapping + * MAP_FAILED - error, unable to allocate resources + * + */ +int +uniarp_pvcopen(ivp) + struct ipvcc *ivp; +{ + struct uniip *uip; + struct uniarp *uap; + int s, err; + + ATM_DEBUG1("uniarp_pvcopen: ivp=0x%x\n", (int)ivp); + + ivp->iv_arpent = NULL; + + /* + * Check things out + */ + if ((ivp->iv_flags & IVF_LLC) == 0) + return (MAP_FAILED); + + /* + * Get uni interface + */ + uip = (struct uniip *)ivp->iv_ipnif->inf_isintf; + if (uip == NULL) + return (MAP_FAILED); + + /* + * Get an arp map entry + */ + uap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (uap == NULL) + return (MAP_FAILED); + + /* + * Create our CM connection + */ + err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc, + ivp->iv_conn, &ivp->iv_arpconn); + if (err) { + /* + * We don't take no (or maybe) for an answer + */ + if (ivp->iv_arpconn) { + (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause); + ivp->iv_arpconn = NULL; + } + atm_free((caddr_t)uap); + return (MAP_FAILED); + } + + /* + * Get map entry set up + */ + s = splnet(); + uap->ua_dstatm.address_format = T_ATM_ABSENT; + uap->ua_dstatmsub.address_format = T_ATM_ABSENT; + uap->ua_intf = uip; + + /* + * Put ivp on arp entry chain + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + + /* + * Put arp entry on pvc chain + */ + LINK2TAIL(uap, struct uniarp, uniarp_pvctab, ua_next); + + /* + * Send Inverse ATMARP request + */ + (void) uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp); + + /* + * Start resend timer + */ + uap->ua_aging = UNIARP_REVALID_AGE; + + (void) splx(s); + return (MAP_PROCEEDING); +} + + +/* + * Process a new outgoing SVC requiring ATMARP support + * + * This function is called by the IP/ATM module to resolve a destination + * IP address to an ATM address in order to open an SVC to that destination. + * If a valid mapping is already in our cache, then we just tell the caller + * about it and that's that. Otherwise, we have to allocate a new arp entry + * and issue a query for the mapping. + * + * Arguments: + * ivp pointer to SVC's IPVCC control block + * dst pointer to destination IP address + * + * Returns: + * MAP_VALID - Got the answer, returned via iv_arpent field. + * MAP_PROCEEDING - OK so far, querying for peer's mapping + * MAP_FAILED - error, unable to allocate resources + * + */ +int +uniarp_svcout(ivp, dst) + struct ipvcc *ivp; + struct in_addr *dst; +{ + struct uniip *uip; + struct uniarp *uap; + int s = splnet(); + + ATM_DEBUG2("uniarp_svcout: ivp=0x%x,dst=0x%x\n", (int)ivp, dst->s_addr); + + ivp->iv_arpent = NULL; + + /* + * Get uni interface + */ + uip = (struct uniip *)ivp->iv_ipnif->inf_isintf; + if (uip == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Lookup IP destination address + */ + UNIARP_LOOKUP(dst->s_addr, uap); + + if (uap) { + /* + * We've got an entry, verify interface + */ + if (uap->ua_intf != uip) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Chain this vcc onto entry + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + uap->ua_flags |= UAF_USED; + + if (uap->ua_flags & UAF_VALID) { + /* + * Entry is valid, we're done + */ + (void) splx(s); + return (MAP_VALID); + } else { + /* + * We're already looking for this address + */ + (void) splx(s); + return (MAP_PROCEEDING); + } + } + + /* + * No info in the cache. If we're the server, then + * we're already authoritative, so just deny request. + * If we're a client but the server VCC isn't open we + * also deny the request. + */ + if (uip->uip_arpstate != UIAS_CLIENT_ACTIVE) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * We're a client with an open VCC to the server, get a new arp entry + */ + uap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (uap == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Get entry set up + */ + uap->ua_dstip.s_addr = dst->s_addr; + uap->ua_dstatm.address_format = T_ATM_ABSENT; + uap->ua_dstatm.address_length = 0; + uap->ua_dstatmsub.address_format = T_ATM_ABSENT; + uap->ua_dstatmsub.address_length = 0; + uap->ua_intf = uip; + + /* + * Link ipvcc to arp entry for later notification + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + uap->ua_flags |= UAF_USED; + + /* + * Add arp entry to table + */ + UNIARP_ADD(uap); + + /* + * Issue arp request for this address + */ + (void) uniarp_arp_req(uip, dst); + + /* + * Start retry timer + */ + UNIARP_TIMER(uap, UNIARP_ARP_RETRY); + + (void) splx(s); + return (MAP_PROCEEDING); +} + + +/* + * Process a new incoming SVC requiring ATMARP support + * + * This function is called by the IP/ATM module to resolve a caller's ATM + * address to its IP address for an incoming call in order to allow a + * bi-directional flow of IP packets on the SVC. If a valid mapping is + * already in our cache, then we will use it. Otherwise, we have to allocate + * a new arp entry and wait for the SVC to become active so that we can issue + * an InATMARP to the peer. + * + * Arguments: + * ivp pointer to SVC's IPVCC control block + * dst pointer to caller's ATM address + * dstsub pointer to caller's ATM subaddress + * + * Returns: + * MAP_VALID - Got the answer, returned via iv_arpent field. + * MAP_PROCEEDING - OK so far, querying for peer's mapping + * MAP_FAILED - error, unable to allocate resources + * + */ +int +uniarp_svcin(ivp, dst, dstsub) + struct ipvcc *ivp; + Atm_addr *dst; + Atm_addr *dstsub; +{ + struct uniip *uip; + struct uniarp *uap; + int found = 0, i, s = splnet(); + + ATM_DEBUG1("uniarp_svcin: ivp=0x%x\n", (int)ivp); + + /* + * Clear ARP entry field + */ + ivp->iv_arpent = NULL; + + /* + * Check things out + */ + if ((ivp->iv_flags & IVF_LLC) == 0) + return (MAP_FAILED); + + /* + * Get uni interface + */ + uip = (struct uniip *)ivp->iv_ipnif->inf_isintf; + if (uip == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Make sure we're configured as a client or server + */ + if (uip->uip_arpstate == UIAS_NOTCONF) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * If we know the caller's ATM address, look it up + */ + uap = NULL; + if (dst->address_format != T_ATM_ABSENT) { + for (i = 0; (i < UNIARP_HASHSIZ) && (found == 0); i++) { + for (uap = uniarp_arptab[i]; uap; uap = uap->ua_next) { + if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) && + ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub)){ + found = 1; + break; + } + } + } + if (uap == NULL) { + for (uap = uniarp_nomaptab; uap; uap = uap->ua_next) { + if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) && + ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub)) + break; + } + } + } + + if (uap) { + /* + * We've got an entry, verify interface + */ + if (uap->ua_intf != uip) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Chain the vcc onto this entry + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + uap->ua_flags |= UAF_USED; + + if (uap->ua_flags & UAF_VALID) { + /* + * Entry is valid, we're done + */ + (void) splx(s); + return (MAP_VALID); + } else { + /* + * We're already looking for this address + */ + (void) splx(s); + return (MAP_PROCEEDING); + } + } + + /* + * No info in the cache - get a new arp entry + */ + uap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (uap == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Get entry set up + */ + ATM_ADDR_COPY(dst, &uap->ua_dstatm); + ATM_ADDR_COPY(dstsub, &uap->ua_dstatmsub); + uap->ua_intf = uip; + + /* + * Link ipvcc to arp entry for later notification + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + uap->ua_flags |= UAF_USED; + + /* + * Add arp entry to 'nomap' table + */ + LINK2TAIL(uap, struct uniarp, uniarp_nomaptab, ua_next); + + (void) splx(s); + + /* + * Now we just wait for SVC to become active + */ + return (MAP_PROCEEDING); +} + + +/* + * Process ARP SVC activation notification + * + * This function is called by the IP/ATM module whenever a previously + * opened SVC has successfully been connected. + * + * Arguments: + * ivp pointer to SVC's IPVCC control block + * + * Returns: + * 0 activation processing successful + * errno activation failed - reason indicated + * + */ +int +uniarp_svcactive(ivp) + struct ipvcc *ivp; +{ + struct ip_nif *inp; + struct uniip *uip; + struct uniarp *uap; + int err, s = splnet(); + + ATM_DEBUG1("uniarp_svcactive: ivp=0x%x\n", (int)ivp); + + inp = ivp->iv_ipnif; + uip = (struct uniip *)inp->inf_isintf; + uap = (struct uniarp *)ivp->iv_arpent; + + /* + * First, we need to create our CM connection + */ + err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc, + ivp->iv_conn, &ivp->iv_arpconn); + if (err) { + /* + * We don't take no (or maybe) for an answer + */ + if (ivp->iv_arpconn) { + (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause); + ivp->iv_arpconn = NULL; + } + return (err); + } + + /* + * Is this the client->server vcc?? + */ + if (uip->uip_arpsvrvcc == ivp) { + + /* + * Yep, go into the client registration phase + */ + uip->uip_arpstate = UIAS_CLIENT_REGISTER; + + /* + * To register ourselves, RFC1577 says we should wait + * around for the server to send us an InATMARP_Request. + * However, draft-1577+ just has us send an ATMARP_Request + * for our own address. To keep everyone happy, we'll go + * with both and see what works! + */ + (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr)); + + /* + * Start retry timer + */ + UNIIP_ARP_TIMER(uip, 1 * ATM_HZ); + + (void) splx(s); + return (0); + } + + /* + * Send an InATMARP_Request on this VCC to find out/notify who's at + * the other end. If we're the server, this will start off the + * RFC1577 registration procedure. If we're a client, then this + * SVC is for user data and it's pretty likely that both ends are + * going to be sending packets. So, if we're the caller, we'll be + * nice and let the callee know right away who we are. If we're the + * callee, let's find out asap the caller's IP address. + */ + (void) uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp); + + /* + * Start retry timer if entry isn't valid yet + */ + if (((uap->ua_flags & UAF_VALID) == 0) && + ((uap->ua_time.ti_flag & TIF_QUEUED) == 0)) + UNIARP_TIMER(uap, UNIARP_ARP_RETRY); + + (void) splx(s); + return (0); +} + + +/* + * Process VCC close + * + * This function is called just prior to IP/ATM closing a VCC which + * supports ATMARP. We'll sever our links to the VCC and then + * figure out how much more cleanup we need to do for now. + * + * Arguments: + * ivp pointer to VCC's IPVCC control block + * + * Returns: + * none + * + */ +void +uniarp_vcclose(ivp) + struct ipvcc *ivp; +{ + struct uniip *uip; + struct uniarp *uap; + int s; + + ATM_DEBUG1("uniarp_vcclose: ivp=0x%x\n", (int)ivp); + + /* + * Close our CM connection + */ + if (ivp->iv_arpconn) { + (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause); + ivp->iv_arpconn = NULL; + } + + /* + * Get atmarp entry + */ + if ((uap = (struct uniarp *)ivp->iv_arpent) == NULL) + return; + uip = uap->ua_intf; + + s = splnet(); + + /* + * If this is the arpserver VCC, then schedule ourselves to + * reopen the connection soon + */ + if (uip->uip_arpsvrvcc == ivp) { + uip->uip_arpsvrvcc = NULL; + uip->uip_arpstate = UIAS_CLIENT_POPEN; + UNIIP_ARP_CANCEL(uip); + UNIIP_ARP_TIMER(uip, 5 * ATM_HZ); + } + + /* + * Remove IP VCC from chain + */ + UNLINK(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + + /* + * SVCs and PVCs are handled separately + */ + if (ivp->iv_flags & IVF_SVC) { + /* + * If the mapping is currently valid or in use, or if there + * are other VCCs still using this mapping, we're done for now + */ + if ((uap->ua_flags & (UAF_VALID | UAF_LOCKED)) || + (uap->ua_origin >= UAO_PERM) || + (uap->ua_ivp != NULL)) { + (void) splx(s); + return; + } + + /* + * Unlink the entry + */ + if (uap->ua_dstip.s_addr == 0) { + UNLINK(uap, struct uniarp, uniarp_nomaptab, ua_next); + } else { + UNIARP_DELETE(uap); + } + } else { + /* + * Remove entry from pvc table + */ + UNLINK(uap, struct uniarp, uniarp_pvctab, ua_next); + } + + UNIARP_CANCEL(uap); + + /* + * Finally, free the entry + */ + atm_free((caddr_t)uap); + + (void) splx(s); + return; +} + + +/* + * Process ATMARP VCC Connected Notification + * + * Arguments: + * toku owner's connection token (ipvcc protocol block) + * + * Returns: + * none + * + */ +void +uniarp_connected(toku) + void *toku; +{ + + /* + * Since we only do atm_cm_addllc()'s on active connections, + * we should never get called here... + */ + panic("uniarp_connected"); +} + + +/* + * Process ATMARP VCC Cleared Notification + * + * Arguments: + * toku owner's connection token (ipvcc protocol block) + * cause pointer to cause code + * + * Returns: + * none + * + */ +void +uniarp_cleared(toku, cause) + void *toku; + struct t_atm_cause *cause; +{ + struct ipvcc *ivp = toku; + int s; + + s = splnet(); + + /* + * We're done with VCC + */ + ivp->iv_arpconn = NULL; + + /* + * If IP is finished with VCC, then we'll free it + */ + if (ivp->iv_state == IPVCC_FREE) + atm_free((caddr_t)ivp); + + (void) splx(s); +} + |