/* * Process a SPANS ARP retry timer tick * * This function is called every SPANSARP_RETRY seconds, in order to retry * awaiting arp resolution requests. We will retry requests indefinitely, * assuming that IP will set a timeout to close the VCC(s) requesting the * failing address resolution. * * Called from a critical section. * * Arguments: * tip pointer to spansarp retry timer control block * * Returns: * none * */ static void spansarp_retry(struct atm_time *tip) { struct spansarp *sap; /* * See if there's work to do */ if (spansarp_retry_head == NULL) { return; } /* * Schedule next timeout */ atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry); /* * Run through retry chain, (re)issuing arp requests. */ for (sap = spansarp_retry_head; sap; sap = sap->sa_next) { /* * Send another arp request */ spansarp_request(sap); } }
/* * Initialize driver processing * * This will be called during module loading. Not much to do here, as * we must wait for our identify/attach routines to get called before * we know what we're in for. * * Arguments: * none * * Returns: * 0 startup was successful * errno startup failed - reason indicated * */ static int fore_start() { /* * Verify software version */ if (atm_version != ATM_VERSION) { log(LOG_ERR, "version mismatch: fore=%d.%d kernel=%d.%d\n", ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION), ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version)); return (EINVAL); } /* * Initialize DMA mapping */ DMA_INIT(); /* * Start up watchdog timer */ atm_timeout(&fore_timer, ATM_HZ * FORE_TIME_TICK, fore_timeout); fore_inited = 1; return (0); }
/* * Initialize ATM kernel * * Performs any initialization required before things really get underway. * Called from ATM domain initialization or from first registration function * which gets called. * * Arguments: * none * * Returns: * none * */ void atm_initialize(void) { /* * Never called from interrupts, so no locking needed */ if (atm_init) return; atm_init = 1; atm_intrq.ifq_maxlen = ATM_INTRQ_MAX; netisr_register(NETISR_ATM, atm_intr, NULL); /* * Initialize subsystems */ atm_aal5_init(); /* * Prime the timer */ callout_init(&atm_timexp_ch); callout_reset(&atm_timexp_ch, hz / ATM_HZ, atm_timexp, NULL); /* * Start the compaction timer */ atm_timeout(&atm_compactimer, SPOOL_COMPACT, atm_compact); }
/* * Process IP Network Interface Activation * * Called whenever an IP network interface becomes active. * * Called from a critical section. * * Arguments: * clp pointer to CLS interface * * Returns: * none * */ void spansarp_ipact(struct spanscls *clp) { /* * Make sure aging timer is running */ if ((spansarp_timer.ti_flag & TIF_QUEUED) == 0) atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging); }
/* * Initialize ATM kernel * * Performs any initialization required before things really get underway. * Called from ATM domain initialization or from first registration function * which gets called. * * Arguments: * none * * Returns: * none * */ void atm_initialize() { /* * Never called from interrupts, so no locking needed */ if (atm_init) return; atm_init = 1; #ifndef __FreeBSD__ /* * Add ATM protocol family */ (void) protocol_family(&atmdomain, NULL, NULL); #endif atm_intrq.ifq_maxlen = ATM_INTRQ_MAX; #ifdef sgi atm_intr_index = register_isr(atm_intr); #endif /* * Initialize subsystems */ atm_aal5_init(); /* * Prime the timer */ (void) timeout(atm_timexp, (void *)0, hz/ATM_HZ); /* * Start the compaction timer */ atm_timeout(&atm_compactimer, SPOOL_COMPACT, atm_compact); }
/* * Process a new outgoing SVC requiring SPANS ARP support * * This function is called by an endpoint wishing 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 spansarp_svcout(struct ipvcc *ivp, struct in_addr *dst) { struct spanscls *clp; struct spansarp *sap; ivp->iv_arpent = NULL; /* * Lookup destination address */ crit_enter(); SPANSARP_LOOKUP(dst->s_addr, sap); if (sap) { /* * Link this vcc to entry queue */ LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext); /* * If entry is valid, we're done */ if (sap->sa_flags & SAF_VALID) { ivp->iv_arpent = (struct arpmap *)sap; crit_exit(); return (MAP_VALID); } /* * We're already looking for this address */ crit_exit(); return (MAP_PROCEEDING); } /* * Need a new arp entry - first, find the cls instance * corresponding to the requestor's IP interface. */ for (clp = spanscls_head; clp; clp = clp->cls_next) { if (clp->cls_ipnif == ivp->iv_ipnif) break; } if (clp == NULL) { crit_exit(); return (MAP_FAILED); } /* * Now get the new arp entry */ sap = (struct spansarp *)atm_allocate(&spansarp_pool); if (sap == NULL) { crit_exit(); return (MAP_FAILED); } /* * Get entry set up */ sap->sa_dstip.s_addr = dst->s_addr; sap->sa_dstatm.address_format = T_ATM_ABSENT; sap->sa_dstatm.address_length = 0; sap->sa_dstatmsub.address_format = T_ATM_ABSENT; sap->sa_dstatmsub.address_length = 0; sap->sa_cls = clp; sap->sa_origin = SAO_LOOKUP; /* * Link ipvcc to arp entry for later notification */ LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext); /* * Add arp entry to table */ SPANSARP_ADD(sap); /* * Add arp entry to retry list and start retry timer if needed */ LINK2TAIL(sap, struct spansarp, spansarp_retry_head, sa_rnext); if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0) atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry); /* * Issue arp request for this address */ spansarp_request(sap); crit_exit(); return (MAP_PROCEEDING); }
/* * Process a SPANS ARP aging timer tick * * This function is called every SPANSARP_AGING seconds, in order to age * all the arp table entries. * * Called from a critical section. * * Arguments: * tip pointer to spansarp aging timer control block * * Returns: * none * */ static void spansarp_aging(struct atm_time *tip) { struct spansarp *sap, *snext; struct ipvcc *ivp, *inext; int i; /* * Schedule next timeout */ atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging); /* * Run through arp table bumping each entry's aging timer. */ for (i = 0; i < SPANSARP_HASHSIZ; i++) { for (sap = spansarp_arptab[i]; sap; sap = snext) { snext = sap->sa_next; /* * Permanent (manually installed) entries aren't aged */ if (sap->sa_origin == SAO_PERM) continue; /* * See if entry is valid and over-aged */ if ((sap->sa_flags & SAF_VALID) == 0) continue; if (++sap->sa_reftime < SPANSARP_MAXAGE) continue; /* * Entry is now invalid, tell IP/ATM about it */ sap->sa_flags |= SAF_LOCKED; for (ivp = sap->sa_ivp; ivp; ivp = inext) { inext = ivp->iv_arpnext; (*ivp->iv_ipnif->inf_arpnotify) (ivp, MAP_INVALID); } sap->sa_flags &= ~(SAF_LOCKED | SAF_VALID); if (sap->sa_ivp != NULL) { /* * Somebody still cares, so add the arp * entry to the retry list. */ LINK2TAIL(sap, struct spansarp, spansarp_retry_head, sa_rnext); if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0) atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry); /* * Issue arp request for this address */ spansarp_request(sap); } else { /* * Delete unused entry */ SPANSARP_DELETE(sap); atm_free((caddr_t)sap); } } } }
/* * Process an SSCOP timer tick * * This function is called SSCOP_HZ times a second in order to update * all of the sscop connection timers. The sscop expiration function * will be called to process all timer expirations. * * Called at splnet. * * Arguments: * tip pointer to sscop timer control block * * Returns: * none * */ void sscop_timeout(struct atm_time *tip) { struct sscop *sop, **sprev; int i; /* * Schedule next timeout */ atm_timeout(&sscop_timer, ATM_HZ/SSCOP_HZ, sscop_timeout); /* * Run through all connections, updating each active timer. * If an expired timer is found, notify that entry. */ sprev = &sscop_head; while ((sop = *sprev) != NULL) { /* * Check out each timer */ for (i =0; i < SSCOP_T_NUM; i++) { /* * Decrement timer if it's active */ if (sop->so_timer[i] && (--sop->so_timer[i] == 0)) { #ifdef DIAGNOSTIC { static char *tn[] = { "POLL", "NORESPONSE", "CC", "IDLE" }; ATM_DEBUG3("sscop_timer: %s expired, sop=%p, state=%d\n", tn[i], sop, sop->so_state); } #endif /* * Expired timer - process it */ (*sscop_expired[i])(sop); /* * Make sure connection still exists */ if (*sprev != sop) break; } } /* * Update previous pointer if current control * block wasn't deleted */ if (*sprev == sop) sprev = &sop->so_next; } }
/* * Storage Pool Compaction * * Called periodically in order to perform compaction of the * storage pools. Each pool will be checked to see if any chunks * can be freed, taking some care to avoid freeing too many chunks * in order to avoid memory thrashing. * * Called from a critical section. * * Arguments: * tip pointer to timer control block (atm_compactimer) * * Returns: * none * */ static void atm_compact(struct atm_time *tip) { struct sp_info *sip; struct sp_chunk *scp; int i; struct sp_chunk *scp_prev; /* * Check out all storage pools */ for (sip = atm_pool_head; sip; sip = sip->si_next) { /* * Always keep a minimum number of chunks around */ if (sip->si_chunks <= SPOOL_MIN_CHUNK) continue; /* * Maximum chunks to free at one time will leave * pool with at least 50% utilization, but never * go below minimum chunk count. */ i = ((sip->si_free * 2) - sip->si_total) / sip->si_blkcnt; i = MIN(i, sip->si_chunks - SPOOL_MIN_CHUNK); /* * Look for chunks to free */ scp_prev = NULL; for (scp = sip->si_poolh; scp && i > 0; ) { if (scp->sc_used == 0) { /* * Found a chunk to free, so do it */ if (scp_prev) { scp_prev->sc_next = scp->sc_next; if (sip->si_poolt == scp) sip->si_poolt = scp_prev; } else sip->si_poolh = scp->sc_next; KM_FREE((caddr_t)scp, sip->si_chunksiz, M_DEVBUF); /* * Update pool controls */ sip->si_chunks--; sip->si_total -= sip->si_blkcnt; sip->si_free -= sip->si_blkcnt; i--; if (scp_prev) scp = scp_prev->sc_next; else scp = sip->si_poolh; } else { scp_prev = scp; scp = scp->sc_next; } } } /* * Restart the compaction timer */ atm_timeout(&atm_compactimer, SPOOL_COMPACT, atm_compact); return; }