freebsd-nq/sys/netatm/ipatm/ipatm_if.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

336 lines
6.2 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_if.c,v 1.6 1998/03/24 20:51:47 mks Exp $
*
*/
/*
* IP Over ATM Support
* -------------------
*
* Interface Manager
*
*/
#ifndef lint
static char *RCSid = "@(#) $Id: ipatm_if.c,v 1.6 1998/03/24 20:51:47 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>
/*
* Local functions
*/
static void ipatm_closenif __P((struct ip_nif *));
/*
* Process Network Interface status change
*
* Called whenever a network interface status change is requested.
*
* Called at splnet.
*
* Arguments:
* cmd command code
* nip pointer to atm network interface control block
* arg command specific parameter
*
* Returns:
* 0 command successful
* errno command failed - reason indicated
*
*/
int
ipatm_nifstat(cmd, nip, arg)
int cmd;
struct atm_nif *nip;
int arg;
{
struct in_ifaddr *ia;
struct siginst *sip;
struct ip_nif *inp;
int err = 0;
/*
* Look for corresponding IP interface
*/
for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
if (inp->inf_nif == nip)
break;
}
/*
* Process command
*/
switch (cmd) {
case NCM_ATTACH:
/*
* Make sure i/f isn't already attached
*/
if (inp != NULL) {
err = EEXIST;
break;
}
/*
* Get a new interface block
*/
inp = (struct ip_nif *)atm_allocate(&ipatm_nifpool);
if (inp == NULL) {
err = ENOMEM;
break;
}
inp->inf_nif = nip;
inp->inf_state = IPNIF_ADDR;
inp->inf_arpnotify = ipatm_arpnotify;
inp->inf_ipinput = ipatm_ipinput;
inp->inf_createsvc = ipatm_createsvc;
LINK2TAIL(inp, struct ip_nif, ipatm_nif_head, inf_next);
break;
case NCM_DETACH:
/*
* Make sure i/f is attached
*/
if (inp == NULL) {
err = ENODEV;
break;
}
/*
* Validate interface stuff
*/
if (Q_HEAD(inp->inf_vcq, struct ipvcc))
panic("ipatm_nifstat: ipvcc queue not empty");
/*
* If we're active, close all our VCCs and tell the
* interface service about the deactivation
*/
if (inp->inf_state == IPNIF_ACTIVE) {
ipatm_closenif(inp);
if (inp->inf_serv)
(void) (*inp->inf_serv->is_ifdact)(inp);
}
/*
* Clean up and free block
*/
UNLINK(inp, struct ip_nif, ipatm_nif_head, inf_next);
atm_free((caddr_t)inp);
break;
case NCM_SETADDR:
/*
* We only care about IP addresses
*/
#if (defined(BSD) && (BSD >= 199103))
if (((struct ifaddr *)arg)->ifa_addr->sa_family != AF_INET)
#else
if (((struct ifaddr *)arg)->ifa_addr.sa_family != AF_INET)
#endif
break;
/*
* Make sure i/f is there
*/
ia = (struct in_ifaddr *)arg;
if (inp == NULL)
panic("ipatm_nifstat: setaddr missing ip_nif");
/*
* Process new address
*/
switch (inp->inf_state) {
case IPNIF_SIGMGR:
case IPNIF_ADDR:
inp->inf_addr = ia;
/*
* If signalling manager is not set, wait for it
*/
sip = nip->nif_pif->pif_siginst;
if (sip == NULL) {
inp->inf_state = IPNIF_SIGMGR;
break;
}
/*
* Otherwise, everything's set
*/
inp->inf_state = IPNIF_ACTIVE;
/*
* Tell interface service we're around
*/
if (sip->si_ipserv) {
inp->inf_serv = sip->si_ipserv;
err = (*inp->inf_serv->is_ifact)(inp);
}
/*
* Reset state if there's been a problem
*/
if (err) {
inp->inf_serv = NULL;
inp->inf_addr = NULL;
inp->inf_state = IPNIF_ADDR;
}
break;
case IPNIF_ACTIVE:
/*
* We dont support an address change
*/
err = EEXIST;
break;
}
break;
case NCM_SIGATTACH:
/*
* Make sure i/f is attached
*/
if (inp == NULL) {
err = ENODEV;
break;
}
/*
* Are we waiting for the sigmgr attach??
*/
if (inp->inf_state != IPNIF_SIGMGR) {
/*
* No, nothing else to do
*/
break;
}
/*
* OK, everything's set
*/
inp->inf_state = IPNIF_ACTIVE;
/*
* Tell interface service we're around
*/
sip = nip->nif_pif->pif_siginst;
if (sip->si_ipserv) {
inp->inf_serv = sip->si_ipserv;
err = (*inp->inf_serv->is_ifact)(inp);
}
/*
* Just report any problems, since a NCM_SIGDETACH will
* be coming down immediately
*/
break;
case NCM_SIGDETACH:
/*
* Make sure i/f is attached
*/
if (inp == NULL) {
err = ENODEV;
break;
}
/*
* Are we currently active??
*/
if (inp->inf_state != IPNIF_ACTIVE) {
/*
* No, nothing else to do
*/
break;
}
/*
* Close all the IP VCCs for this interface
*/
ipatm_closenif(inp);
/*
* Tell interface service that i/f has gone down
*/
if (inp->inf_serv)
(void) (*inp->inf_serv->is_ifdact)(inp);
/*
* Just have to wait for another sigattach
*/
inp->inf_serv = NULL;
inp->inf_state = IPNIF_SIGMGR;
break;
default:
log(LOG_ERR, "ipatm_nifstat: unknown command %d\n", cmd);
}
return (err);
}
/*
* Close all VCCs on a Network Interface
*
* Called at splnet.
*
* Arguments:
* inp pointer to IP network interface
*
* Returns:
* none
*
*/
static void
ipatm_closenif(inp)
struct ip_nif *inp;
{
struct ipvcc *ivp, *inext;
/*
* Close each IP VCC on this interface
*/
for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; ivp = inext) {
inext = Q_NEXT(ivp, struct ipvcc, iv_elem);
(void) ipatm_closevc(ivp, T_ATM_CAUSE_UNSPECIFIED_NORMAL);
}
}