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

879 lines
15 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_load.c,v 1.12 1998/07/30 22:23:00 mks Exp $
*
*/
/*
* IP Over ATM Support
* -------------------
*
* Support for running as a loadable kernel module
*
*/
#ifndef lint
static char *RCSid = "@(#) $Id: ipatm_load.c,v 1.12 1998/07/30 22:23:00 mks Exp $";
#endif
#ifndef ATM_IP_MODULE
#include "opt_atm.h"
#endif
#include <netatm/kern_include.h>
#include <netatm/ipatm/ipatm.h>
#include <netatm/ipatm/ipatm_var.h>
#include <netatm/ipatm/ipatm_serv.h>
/*
* Global variables
*/
int ipatm_vccnt = 0;
int ipatm_vcidle = IPATM_VCIDLE;
int ipatm_print = 0;
u_long last_map_ipdst = 0;
struct ipvcc* last_map_ipvcc = NULL;
struct ip_nif *ipatm_nif_head = NULL;
struct ipatm_stat ipatm_stat = {0};
struct atm_time ipatm_itimer = {0, 0}; /* VCC idle timer */
Atm_endpoint ipatm_endpt = {
NULL,
ENDPT_IP,
ipatm_ioctl,
ipatm_getname,
ipatm_connected,
ipatm_cleared,
ipatm_incoming,
NULL,
NULL,
NULL,
ipatm_cpcs_data,
NULL,
NULL,
NULL,
NULL
};
struct sp_info ipatm_vcpool = {
"ipatm vcc pool", /* si_name */
sizeof(struct ipvcc), /* si_blksiz */
10, /* si_blkcnt */
100 /* si_maxallow */
};
struct sp_info ipatm_nifpool = {
"ipatm nif pool", /* si_name */
sizeof(struct ip_nif), /* si_blksiz */
5, /* si_blkcnt */
20 /* si_maxallow */
};
/*
* Local functions
*/
static int ipatm_start __P((void));
static int ipatm_stop __P((void));
/*
* Local variables
*/
static struct atm_ncm ipatm_ncm = {
NULL,
AF_INET,
ipatm_ifoutput,
ipatm_nifstat
};
static struct ipatm_listener {
Atm_attributes attr;
Atm_connection *conn;
} ipatm_listeners[] = {
{
{ NULL, /* nif */
CMAPI_CPCS, /* api */
0, /* api_init */
0, /* headin */
0, /* headout */
{ /* aal */
T_ATM_PRESENT,
ATM_AAL5
},
{ /* traffic */
T_ATM_PRESENT,
{
{
T_ATM_ABSENT,
0,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_NO
},
{
T_ATM_ABSENT,
0,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_NO
},
T_YES
},
},
{ /* bearer */
T_ATM_ANY
},
{ /* bhli */
T_ATM_ABSENT
},
{ /* blli */
T_ATM_PRESENT,
T_ATM_ABSENT,
{
{
T_ATM_SIMPLE_ID,
},
{
T_ATM_ABSENT
}
}
},
{ /* llc */
T_ATM_PRESENT,
{
T_ATM_LLC_SHARING,
IPATM_LLC_LEN,
IPATM_LLC_HDR
}
},
{ /* called */
T_ATM_ANY
},
{ /* calling */
T_ATM_ANY
},
{ /* qos */
T_ATM_PRESENT,
{
T_ATM_NETWORK_CODING,
{
T_ATM_QOS_CLASS_0,
},
{
T_ATM_QOS_CLASS_0
}
}
},
{ /* transit */
T_ATM_ANY
},
{ /* cause */
T_ATM_ABSENT
},
},
NULL
},
{
{ NULL, /* nif */
CMAPI_CPCS, /* api */
0, /* api_init */
0, /* headin */
0, /* headout */
{ /* aal */
T_ATM_PRESENT,
ATM_AAL5
},
{ /* traffic */
T_ATM_PRESENT,
{
{
T_ATM_ABSENT,
0,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_NO
},
{
T_ATM_ABSENT,
0,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_NO
},
T_YES
},
},
{ /* bearer */
T_ATM_ANY
},
{ /* bhli */
T_ATM_ABSENT
},
{ /* blli */
T_ATM_ABSENT,
T_ATM_ABSENT
},
{ /* llc */
T_ATM_ABSENT
},
{ /* called */
T_ATM_ANY
},
{ /* calling */
T_ATM_ANY
},
{ /* qos */
T_ATM_PRESENT,
{
T_ATM_NETWORK_CODING,
{
T_ATM_QOS_CLASS_0,
},
{
T_ATM_QOS_CLASS_0
}
}
},
{ /* transit */
T_ATM_ANY
},
{ /* cause */
T_ATM_ABSENT
},
},
NULL
},
{
{ NULL, /* nif */
CMAPI_CPCS, /* api */
0, /* api_init */
0, /* headin */
0, /* headout */
{ /* aal */
T_ATM_PRESENT,
ATM_AAL3_4
},
{ /* traffic */
T_ATM_PRESENT,
{
{
T_ATM_ABSENT,
0,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_NO
},
{
T_ATM_ABSENT,
0,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_ATM_ABSENT,
T_NO
},
T_YES
},
},
{ /* bearer */
T_ATM_ANY
},
{ /* bhli */
T_ATM_ABSENT
},
{ /* blli */
T_ATM_ABSENT,
T_ATM_ABSENT
},
{ /* llc */
T_ATM_ABSENT
},
{ /* called */
T_ATM_ANY
},
{ /* calling */
T_ATM_ANY
},
{ /* qos */
T_ATM_PRESENT,
{
T_ATM_NETWORK_CODING,
{
T_ATM_QOS_CLASS_0,
},
{
T_ATM_QOS_CLASS_0
}
}
},
{ /* transit */
T_ATM_ANY
},
{ /* cause */
T_ATM_ABSENT
},
},
NULL
},
};
static struct t_atm_cause ipatm_cause = {
T_ATM_ITU_CODING,
T_ATM_LOC_USER,
T_ATM_CAUSE_UNSPECIFIED_NORMAL,
{0, 0, 0, 0}
};
/*
* Initialize ipatm processing
*
* This will be called during module loading. We'll just register
* ourselves and wait for the packets to start flying.
*
* Arguments:
* none
*
* Returns:
* 0 startup was successful
* errno startup failed - reason indicated
*
*/
static int
ipatm_start()
{
struct atm_pif *pip;
struct atm_nif *nip;
int err, s, i;
/*
* Verify software version
*/
if (atm_version != ATM_VERSION) {
log(LOG_ERR, "version mismatch: ipatm=%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);
}
/*
* Register ourselves as a network convergence module
*/
err = atm_netconv_register(&ipatm_ncm);
if (err)
goto done;
/*
* Register ourselves as an ATM endpoint
*/
err = atm_endpoint_register(&ipatm_endpt);
if (err)
goto done;
/*
* Get current system configuration
*/
s = splnet();
for (pip = atm_interface_head; pip; pip = pip->pif_next) {
/*
* Process each network interface
*/
for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
struct ifnet *ifp = (struct ifnet *)nip;
struct in_ifaddr *ia;
/*
* Attach interface
*/
err = ipatm_nifstat(NCM_ATTACH, nip, 0);
if (err) {
(void) splx(s);
goto done;
}
/*
* If IP address has been set, register it
*/
TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
if (ia->ia_ifp == ifp)
break;
}
if (ia) {
err = ipatm_nifstat(NCM_SETADDR, nip, (int)ia);
if (err) {
(void) splx(s);
goto done;
}
}
}
}
(void) splx(s);
/*
* Fill in union fields
*/
ipatm_aal5llc.aal.v.aal5.forward_max_SDU_size =
ATM_NIF_MTU + IPATM_LLC_LEN;
ipatm_aal5llc.aal.v.aal5.backward_max_SDU_size =
ATM_NIF_MTU + IPATM_LLC_LEN;
ipatm_aal5llc.aal.v.aal5.SSCS_type = T_ATM_NULL;
ipatm_aal5llc.blli.v.layer_2_protocol.ID.simple_ID = T_ATM_BLLI2_I8802;
ipatm_aal5null.aal.v.aal5.forward_max_SDU_size = ATM_NIF_MTU;
ipatm_aal5null.aal.v.aal5.backward_max_SDU_size = ATM_NIF_MTU;
ipatm_aal5null.aal.v.aal5.SSCS_type = T_ATM_NULL;
ipatm_aal4null.aal.v.aal4.forward_max_SDU_size = ATM_NIF_MTU;
ipatm_aal4null.aal.v.aal4.backward_max_SDU_size = ATM_NIF_MTU;
ipatm_aal4null.aal.v.aal4.SSCS_type = T_ATM_NULL;
ipatm_aal4null.aal.v.aal4.mid_low = 0;
ipatm_aal4null.aal.v.aal4.mid_high = 1023;
/*
* Listen for incoming calls
*/
for (i = 0;
i < (sizeof(ipatm_listeners) / sizeof(struct ipatm_listener));
i++) {
struct attr_aal *aalp = &ipatm_listeners[i].attr.aal;
int maxsdu = ATM_NIF_MTU;
/*
* Fill in union fields
*/
if (ipatm_listeners[i].attr.blli.tag_l2 == T_ATM_PRESENT) {
struct t_atm_blli *bp = &ipatm_listeners[i].attr.blli.v;
bp->layer_2_protocol.ID.simple_ID = T_ATM_BLLI2_I8802;
maxsdu += IPATM_LLC_LEN;
}
if (aalp->type == ATM_AAL5) {
aalp->v.aal5.forward_max_SDU_size = maxsdu;
aalp->v.aal5.backward_max_SDU_size = maxsdu;
aalp->v.aal5.SSCS_type = T_ATM_NULL;
} else {
aalp->v.aal4.forward_max_SDU_size = maxsdu;
aalp->v.aal4.backward_max_SDU_size = maxsdu;
aalp->v.aal4.SSCS_type = T_ATM_NULL;
aalp->v.aal4.mid_low = 0;
aalp->v.aal4.mid_high = 1023;
}
/*
* Now start listening
*/
if (err = atm_cm_listen(&ipatm_endpt, (void *)i,
&ipatm_listeners[i].attr,
&ipatm_listeners[i].conn))
goto done;
}
/*
* Start background VCC idle timer
*/
atm_timeout(&ipatm_itimer, IPATM_IDLE_TIME, ipatm_itimeout);
done:
return (err);
}
/*
* Halt ipatm processing
*
* This will be called just prior to unloading the module from
* memory. All IP VCCs must be terminated before the protocol can
* be shutdown.
*
* Arguments:
* none
*
* Returns:
* 0 shutdown was successful
* errno shutdown failed - reason indicated
*
*/
static int
ipatm_stop()
{
struct ip_nif *inp;
int err = 0, i;
int s = splnet();
/*
* Any VCCs still open??
*/
if (ipatm_vccnt) {
/* Yes, can't stop now */
err = EBUSY;
goto done;
}
/*
* Kill VCC idle timer
*/
(void) atm_untimeout(&ipatm_itimer);
/*
* Stop listening for incoming calls
*/
for (i = 0;
i < (sizeof(ipatm_listeners) / sizeof(struct ipatm_listener));
i++) {
if (ipatm_listeners[i].conn != NULL) {
(void) atm_cm_release(ipatm_listeners[i].conn,
&ipatm_cause);
}
}
/*
* Detach all our interfaces
*/
while (inp = ipatm_nif_head) {
(void) ipatm_nifstat(NCM_DETACH, inp->inf_nif, 0);
}
/*
* De-register from system
*/
(void) atm_netconv_deregister(&ipatm_ncm);
(void) atm_endpoint_deregister(&ipatm_endpt);
/*
* Free up our storage pools
*/
atm_release_pool(&ipatm_vcpool);
atm_release_pool(&ipatm_nifpool);
done:
(void) splx(s);
return (err);
}
#ifdef ATM_IP_MODULE
/*
*******************************************************************
*
* Loadable Module Support
*
*******************************************************************
*/
static int ipatm_doload __P((void));
static int ipatm_dounload __P((void));
/*
* Generic module load processing
*
* This function is called by an OS-specific function when this
* module is being loaded.
*
* Arguments:
* none
*
* Returns:
* 0 load was successful
* errno load failed - reason indicated
*
*/
static int
ipatm_doload()
{
int err = 0;
/*
* Start us up
*/
err = ipatm_start();
if (err)
/* Problems, clean up */
(void)ipatm_stop();
return (err);
}
/*
* Generic module unload processing
*
* This function is called by an OS-specific function when this
* module is being unloaded.
*
* Arguments:
* none
*
* Returns:
* 0 unload was successful
* errno unload failed - reason indicated
*
*/
static int
ipatm_dounload()
{
int err = 0;
/*
* OK, try to clean up our mess
*/
err = ipatm_stop();
return (err);
}
#ifdef sun
/*
* Loadable driver description
*/
struct vdldrv ipatm_drv = {
VDMAGIC_PSEUDO, /* Pseudo Driver */
"ipatm_mod", /* name */
NULL, /* dev_ops */
NULL, /* bdevsw */
NULL, /* cdevsw */
0, /* blockmajor */
0 /* charmajor */
};
/*
* Loadable module support entry point
*
* This is the routine called by the vd driver for all loadable module
* functions for this pseudo driver. This routine name must be specified
* on the modload(1) command. This routine will be called whenever the
* modload(1), modunload(1) or modstat(1) commands are issued for this
* module.
*
* Arguments:
* cmd vd command code
* vdp pointer to vd driver's structure
* vdi pointer to command-specific vdioctl_* structure
* vds pointer to status structure (VDSTAT only)
*
* Returns:
* 0 command was successful
* errno command failed - reason indicated
*
*/
int
ipatm_mod(cmd, vdp, vdi, vds)
int cmd;
struct vddrv *vdp;
caddr_t vdi;
struct vdstat *vds;
{
int err = 0;
switch (cmd) {
case VDLOAD:
/*
* Module Load
*
* We dont support any user configuration
*/
err = ipatm_doload();
if (err == 0)
/* Let vd driver know about us */
vdp->vdd_vdtab = (struct vdlinkage *)&ipatm_drv;
break;
case VDUNLOAD:
/*
* Module Unload
*/
err = ipatm_dounload();
break;
case VDSTAT:
/*
* Module Status
*/
/* Not much to say at the moment */
break;
default:
log(LOG_ERR, "ipatm_mod: Unknown vd command 0x%x\n", cmd);
err = EINVAL;
}
return (err);
}
#endif /* sun */
#ifdef __FreeBSD__
#include <sys/exec.h>
#include <sys/sysent.h>
#include <sys/lkm.h>
/*
* Loadable miscellaneous module description
*/
MOD_MISC(ipatm);
/*
* Loadable module support "load" entry point
*
* This is the routine called by the lkm driver whenever the
* modload(1) command is issued for this module.
*
* Arguments:
* lkmtp pointer to lkm drivers's structure
* cmd lkm command code
*
* Returns:
* 0 command was successful
* errno command failed - reason indicated
*
*/
static int
ipatm_load(lkmtp, cmd)
struct lkm_table *lkmtp;
int cmd;
{
return(ipatm_doload());
}
/*
* Loadable module support "unload" entry point
*
* This is the routine called by the lkm driver whenever the
* modunload(1) command is issued for this module.
*
* Arguments:
* lkmtp pointer to lkm drivers's structure
* cmd lkm command code
*
* Returns:
* 0 command was successful
* errno command failed - reason indicated
*
*/
static int
ipatm_unload(lkmtp, cmd)
struct lkm_table *lkmtp;
int cmd;
{
return(ipatm_dounload());
}
/*
* Loadable module support entry point
*
* This is the routine called by the lkm driver for all loadable module
* functions for this driver. This routine name must be specified
* on the modload(1) command. This routine will be called whenever the
* modload(1), modunload(1) or modstat(1) commands are issued for this
* module.
*
* Arguments:
* lkmtp pointer to lkm drivers's structure
* cmd lkm command code
* ver lkm version
*
* Returns:
* 0 command was successful
* errno command failed - reason indicated
*
*/
int
ipatm_mod(lkmtp, cmd, ver)
struct lkm_table *lkmtp;
int cmd;
int ver;
{
MOD_DISPATCH(ipatm, lkmtp, cmd, ver,
ipatm_load, ipatm_unload, lkm_nullcmd);
}
#endif /* __FreeBSD__ */
#else /* !ATM_IP_MODULE */
/*
*******************************************************************
*
* Kernel Compiled Module Support
*
*******************************************************************
*/
static void ipatm_doload __P((void *));
SYSINIT(atmipatm, SI_SUB_PROTO_END, SI_ORDER_ANY, ipatm_doload, NULL)
/*
* Kernel initialization
*
* Arguments:
* arg Not used
*
* Returns:
* none
*
*/
static void
ipatm_doload(void *arg)
{
int err = 0;
/*
* Start us up
*/
err = ipatm_start();
if (err) {
/* Problems, clean up */
(void)ipatm_stop();
log(LOG_ERR, "IP over ATM unable to initialize (%d)!!\n", err);
}
return;
}
#endif /* ATM_IP_MODULE */