aboutsummaryrefslogtreecommitdiff
path: root/sys/netatm/ipatm/ipatm_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/ipatm/ipatm_event.c')
-rw-r--r--sys/netatm/ipatm/ipatm_event.c454
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);
+ }
+ }
+}
+