diff options
Diffstat (limited to 'sys/netatm/ipatm/ipatm_event.c')
-rw-r--r-- | sys/netatm/ipatm/ipatm_event.c | 454 |
1 files changed, 454 insertions, 0 deletions
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); + } + } +} + |