freebsd-dev/sys/netatm/ipatm/ipatm_event.c
Poul-Henning Kamp 1820df7a2d Add new files for HARP3
Host ATM Research Platform (HARP), Network Computing Services, Inc.
This software was developed with the support of the Defense Advanced
Research Projects Agency (DARPA).
1998-09-15 08:23:17 +00:00

455 lines
8.9 KiB
C

/*
*
* ===================================
* 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);
}
}
}