/* * * =================================== * 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. * * @(#) $FreeBSD: src/sys/netatm/ipatm/ipatm_event.c,v 1.4 1999/08/28 00:48:43 peter Exp $ * @(#) $DragonFly: src/sys/netproto/atm/ipatm/ipatm_event.c,v 1.4 2003/08/07 21:54:33 dillon Exp $ */ /* * IP Over ATM Support * ------------------- * * IP VCC event handler * */ #include #include "ipatm.h" #include "ipatm_var.h" #include "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=%p, state=%d\n", 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=%p\n", event, 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); } } }