freebsd-skq/sys/netatm/ipatm/ipatm_load.c
1999-05-10 23:02:29 +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.3 1999/01/27 22:42:20 dillon Exp $
*
*/
/*
* IP Over ATM Support
* -------------------
*
* Support for running as a loadable kernel module
*
*/
#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>
#ifndef lint
__RCSID("@(#) $Id: ipatm_load.c,v 1.3 1999/01/27 22:42:20 dillon Exp $");
#endif
/*
* 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 */
52 /* 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)) != 0)
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) != NULL) {
(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 */