Files
Arquivotheca.AIX-4.1.3/bos/kernel/net/aix_misc.c
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

730 lines
18 KiB
C

static char sccsid[] = "@(#)03 1.8 src/bos/kernel/net/aix_misc.c, sysnet, bos412, 9443A412c 10/20/94 15:51:48";
/*
* COMPONENT_NAME: SYSNET
*
* FUNCTIONS: add_input_type
* add_netisr
* add_netoption
* aix_netinit
* del_input_type
* del_netisr
* delete_netopt
* find_input_type
* net_sleep
* net_tap
* net_wakeup
* netsleepinit
* netsqhash
* splhi
* splimp
* splnet
* splx
*
* ORIGINS: 27
*
*
* (C) COPYRIGHT International Business Machines Corp. 1989,1993
* All Rights Reserved
* Licensed Materials - Property of IBM
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
#include "net/net_globals.h"
#include "sys/param.h"
#include "sys/types.h"
#include "sys/systm.h"
#include "sys/sleep.h"
#include "sys/errno.h"
#include "sys/socket.h"
#include "sys/socketvar.h"
#include "sys/intr.h"
#include "sys/pri.h"
#include "sys/ioctl.h"
#include "sys/nettrace.h"
#include <sys/mbuf.h>
#include <net/netisr.h>
#include <sys/cdli.h>
#include <net/nd_lan.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/spl.h>
#include <net/netopt.h>
#include <aixif/net_if.h>
#include <netinet/if_ether.h>
void netsleepinit(); /* initialize network sleep stuff */
/* sb_max option settable by no cmd limits the socketbuffer size. */
struct netopt sb_max_opt;
extern u_long sb_max;
extern u_long sb_max_dflt;
/* tcp retransmission exponential backoff options settable by no cmd */
int rto_low = RTO_DFLT_LOW;
int rto_low_dflt = RTO_DFLT_LOW;
int rto_high = RTO_DFLT_HIGH;
int rto_high_dflt = RTO_DFLT_HIGH;
int rto_limit = RTO_DFLT_LIMIT;
int rto_limit_dflt = RTO_DFLT_LIMIT;
int rto_length = RTO_DFLT_LENGTH;
int rto_length_dflt = RTO_DFLT_LENGTH;
/* confurable arp table size options settable by no cmd */
int arptab_bsiz = ARPTAB_BSIZ;
int arptab_bsiz_dflt = ARPTAB_BSIZ;
int arptab_nb = ARPTAB_NB;
int arptab_nb_dflt = ARPTAB_NB;
/* non-configurable arp table size variables used internaly. */
/* these had to be put here because of io/dumpdd_pg.c */
int arptabbsiz = ARPTAB_BSIZ;
int arptabnb = ARPTAB_NB;
int arptabsize = (ARPTAB_BSIZ * ARPTAB_NB);
struct arptab *arptabp;
/* configurable tcp debug table size option settable by no cmd */
int tcp_ndebug = TCP_NDEBUG;
int tcp_ndebug_dflt = TCP_NDEBUG;
/* configurable ifnet softc's option settable by the no cmd */
int ifsize = IF_SIZE;
int ifsize_dflt = IF_SIZE;
int wildcard_in_table = 0; /* wildcard present flag */
struct nit_ent nit_table[MAX_NITS]; /* Network Input Table (NIT) */
simple_lock_data_t nit_lock;
#define NIT_LOCK_DECL() int _nits;
#define NIT_LOCK(l) _nits = disable_lock(PL_IMP, l);
#define NIT_UNLOCK(l) unlock_enable(_nits, l);
#define THEMAX (2 * AF_MAX)
struct af_ent af_table[THEMAX];
extern int net_malloc_police_station();
NETOPTINT(dog_ticks);
NETOPTINT(thewall); /* see mbuf.c */
NETOPTINT(rto_low); /* see tcp_timer.c */
NETOPTINT(rto_high);
NETOPTINT(rto_limit);
NETOPTINT(rto_length);
NETOPTINT(arptab_bsiz);
NETOPTINT(arptab_nb);
NETOPTINT(tcp_ndebug);
NETOPTINT(ifsize);
NETOPTINT(net_malloc_police);
#define DEFAULT_HOSTNAME "localhost"
extern int hostnamelen;
extern char hostname[];
/***************************************************************************
*
* aix_netinit() - init the network kproc
*
* RETURNS : none
*
***************************************************************************/
void
aix_netinit()
{
extern int net_queued_write();
lock_alloc(&nit_lock, LOCK_ALLOC_PIN, NETISR_LOCK_FAMILY, -1);
simple_lock_init(&nit_lock);
netsleepinit();
ns_init();
arptabp = (struct arptab *)NULL;
hostnamelen = strlen(DEFAULT_HOSTNAME);
bcopy(DEFAULT_HOSTNAME, hostname, hostnamelen);
/* Add user modifiable kernel options here */
ADD_NETOPT(sb_max, "%d");
ADD_NETOPT(net_malloc_police, "%d");
net_malloc_police_opt.init = net_malloc_police_station;
ADD_NETOPT(rto_low, "%d");
ADD_NETOPT(rto_high, "%d");
ADD_NETOPT(rto_limit, "%d");
ADD_NETOPT(rto_length, "%d");
ADD_NETOPT(arptab_bsiz, "%d");
ADD_NETOPT(arptab_nb, "%d");
ADD_NETOPT(tcp_ndebug, "%d");
ADD_NETOPT(ifsize, "%d");
(void) netisr_add(NETISR_WRITE, net_queued_write,
(struct ifqueue *)0, (struct domain *)0);
}
#ifdef _MOVE_TO_INTF
/***************************************************************************
*
*
* RETURNS :
* 0 - no errors
*
***************************************************************************/
void
net_tap(nddp, m, macp, ifp)
struct ndd *nddp; /* network interface */
struct mbuf *m; /* input packet */
caddr_t macp;
u_char dir_flag; /* transmit or receive pkt */
{
struct mbuf *n; /* copy of m. It's passed up */
struct mbuf *n0; /* control header */
struct packet_trace_header *pth;
static struct sockaddr rawdst = { sizeof(rawdst), AF_INTF };
static struct sockaddr rawsrc = { sizeof(rawsrc), AF_INTF };
static struct sockproto intfproto = { PF_INTF };
n0 = m_gethdr(M_DONTWAIT, MT_HEADER);
if (!n0)
goto out;
pth = mtod(n0, struct packet_trace_header *);
n = m_copy...
if (!n) {
m_freem(n0);
return;
}
n0->m_next = n;
n0->m_len = sizeof(struct packet_trace_header);
n0->m_pkthdr.rcvif = ifp;
n0->m_pkthdr.len = n0->m_len + n->m_pkthdr.len;
n->m_flags &= ~M_PKTHDR;
bcopy((caddr_t)nddp->ndd_name, (caddr_t)pth->ifname,
sizeof(pth->ifname));
pth->unit = (u_char)nddp->ndd_unit;
pth->iftype = nddp->ndd_type;
pth->xmit_pkt = (u_char)xmit_flag;
n0 = m_pullup(n0, MIN(max_hdr, n->m_pkthdr.len));
if (!n0)
return;
raw_input(n0, &intfproto, (struct sockaddr *)&rawsrc,
(struct sockaddr *)&rawdst);
return;
}
#endif
int nethsque[NETNHSQUE];
/*****************************************************************************
* NAME: netsleepinit
*
* FUNCTION: Initialize nethsque
*
* EXECUTION ENVIRONMENT:
* This procedure can only be called by a process.
*
* NOTES: This routine initializes each element of the event-list anchor
* array to EVENT_NULL.
*****************************************************************************/
void
netsleepinit()
{
register int i;
for (i = 0; i < NETNHSQUE; i++)
nethsque[i] = EVENT_NULL;
}
/***************************************************************************
*
* net_sleep() - sleep (the network way!)
* liberally adapted from sleep.c
*
* EXECUTION ENVIRONMENT:
* This procedure can only be called by a process.
*
* RETURNS: 1 if signalled, 0 otherwise
*
***************************************************************************/
net_sleep(chan, flags)
int chan; /* wait channel */
int flags; /* signal control flags */
{
register rc; /* e_sleepl return code */
register sflags; /* e_sleepl flags */
if (flags & PCATCH | ((flags & PMASK) > PZERO) )
sflags = EVENT_SIGRET;
else
sflags = EVENT_SHORT;
rc = e_sleep(netsqhash(chan), sflags);
if (rc == EVENT_SIG)
return(EINTR);
else
return(0);
}
/***************************************************************************
*
* net_wakeup() - wakeup sleeping network processes
* wakes everyone on hash
*
* EXECUTION ENVIRONMENT:
* This procedure can be called by a process or interrupt handler.
*
***************************************************************************/
net_wakeup(chan)
int chan;
{
e_wakeup(netsqhash(chan));
}
/*
* NAME: add_netoption
*
* FUNCTION: to add a netopt struct to end of list of 'netopts'
*
* RETURNS: nothing.
*/
add_netoption(newopt)
struct netopt *newopt;
{
struct netopt *np = netopts;
if (np) {
while (np->next) np = np->next;
np->next = newopt;
} else
netopts = newopt;
}
/*
*
* FUNCTION: removes a network option from the linked list of options.
*
* RETURNS: nothing.
*/
void
delete_netopt(optaddr)
struct netopt *optaddr;
{
struct netopt **prevp = &netopts, *np = netopts;
/* look for option in chain of network options */
while (np && np != optaddr) {
prevp = &np->next;
np = np->next;
}
/* and if option was found, then remove it */
if (np)
*prevp = np->next;
}
#undef splnet
#undef splimp
#undef splhi
#undef splhigh
#undef splx
/***************************************************************************
*
* splnet() -
*
* EXECUTION ENVIRONMENT:
* This procedure can be called by a process or interrupt handler.
*
***************************************************************************/
splnet()
{
return(i_disable(PL_NET));
}
/***************************************************************************
*
* splimp() -
*
* EXECUTION ENVIRONMENT:
* This procedure can be called by a process or interrupt handler.
*
***************************************************************************/
splimp()
{
return(i_disable(PL_IMP));
}
/***************************************************************************
*
* splhi() -
*
* EXECUTION ENVIRONMENT:
* This procedure can be called by a process or interrupt handler.
*
***************************************************************************/
splhi()
{
return(i_disable(PL_HI));
}
splhigh()
{
return(i_disable(PL_HI));
}
/***************************************************************************
*
* splx() -
*
* EXECUTION ENVIRONMENT:
* This procedure can be called by a process or interrupt handler.
*
***************************************************************************/
splx(x)
int x;
{
i_enable(x);
}
/***************************************************************************
*
* find_input_type() - Searches for a packet type in the Network
* Input Table (NIT). If the type is found
* the mbuf is either ENQUEUEd or a function
* is called directly with the mbuf.
*
* RETURNS :
* 0 - no errors
* ENOENT - type not found
*
***************************************************************************/
find_input_type(type, m, ac, hp)
u_short type; /* type from packet */
struct mbuf *m; /* input packet */
struct arpcom *ac; /* interface common portion */
caddr_t *hp; /* pointer to link-level header */
{
int i = 0;
IFQ_LOCK_DECL()
NIT_LOCK_DECL()
if (wildcard_in_table)
wild_type_dispatch(type, m, &ac->ac_if, hp, 0);
NIT_LOCK(&nit_lock);
while ( i != MAX_NITS && !(nit_table[i].type == type &&
nit_table[i].used) ) {
i++;
}
if (i >= MAX_NITS) { /* type nowhere to be found */
m_freem(m);
ac->ac_if.if_noproto++;
NIT_UNLOCK(&nit_lock);
return(ENOENT);
}
if (nit_table[i].ifq_addr == NULL) {
(*(nit_table[i].handler))(ac, m, hp);
}
else {
IFQ_LOCK(nit_table[i].ifq_addr);
/* if not full, enqueue and schednetisr */
if (IF_QFULL(nit_table[i].ifq_addr)) {
IF_DROP(nit_table[i].ifq_addr);
m_freem(m);
} else {
IF_ENQUEUE_NOLOCK(nit_table[i].ifq_addr, m);
}
IFQ_UNLOCK(nit_table[i].ifq_addr);
schednetisr(nit_table[i].af);
}
NIT_UNLOCK(&nit_lock);
return(0);
}
/***************************************************************************
*
* add_input_type() - Adds a packet type to the Network Input Table(NIT).
*
* RETURNS :
* 0 - no errors
* EEXIST - type already in table with different isr
* ENOSPC - no room in NIT table
*
***************************************************************************/
add_input_type(type, service_level, isr, ifq_addr, af)
u_short type; /* type of packet, e.g. IP, arp... */
u_short service_level; /* call direct or schedule */
int (*isr)(); /* input handler for this type */
struct ifqueue *ifq_addr; /* ^queue, if pkt is to be enqueued */
u_short af; /* address family number of caller */
{
int rc, i, x;
int free = -1; /* first free slot found in table */
int error;
struct ifnet *ifp;
NIT_LOCK_DECL()
if ((ifq_addr == NULL) && (service_level == NET_KPROC))
return(EINVAL);
if ((type == NET_WILD_TYPE) && (service_level != NET_KPROC))
return(EINVAL);
if ((service_level != NET_OFF_LEVEL) && (service_level != NET_KPROC))
return(EINVAL);
if (isr == NULL)
return(EINVAL);
if ((af < 0) || (af >= NETISR_MAX))
return(EINVAL);
NIT_LOCK(&nit_lock);
for ( i = 0 ; i < MAX_NITS ; i++ ) {
if ((nit_table[i].used == 0) && (free == -1))
free = i;
if (nit_table[i].type == type) { /* already in */
if ( (nit_table[i].ifq_addr == NULL) &&
(nit_table[i].handler == isr) ) {
NIT_UNLOCK(&nit_lock);
return(EEXIST);
}
if ( (error = add_netisr(af, service_level, isr)) ) {
NIT_UNLOCK(&nit_lock);
return(error);
}
nit_table[i].ref_cnt++;
NIT_UNLOCK(&nit_lock);
return(0);
}
}
if (free == -1) { /* won't fit */
NIT_UNLOCK(&nit_lock);
return(ENOSPC);
}
/* fill out the slot */
if (ifq_addr != NULL) {
error = netisr_add(af, isr, NULL, NULL);
if (error) {
NIT_UNLOCK(&nit_lock);
return(error);
}
}
nit_table[free].handler = isr;
nit_table[free].used = 1;
nit_table[free].ref_cnt = 1;
nit_table[free].type = type;
nit_table[free].ifq_addr = ifq_addr;
nit_table[free].af = af;
if (type == NET_WILD_TYPE) {
wildcard_in_table = 1;
NIT_UNLOCK(&nit_lock);
return(0);
}
NIT_UNLOCK(&nit_lock);
for (ifp = ifnet; ifp; ifp = ifp->if_next) {
if (ifp->if_ioctl)
if (rc = (*ifp->if_ioctl)(ifp, SIOCADDNETID, &type))
if (rc != EINVAL)
return (rc);
}
return(0);
}
/***************************************************************************
*
* del_input_type() - Deletes a type from the Network Input Table(NIT).
*
* RETURNS :
* 0 - no errors
* ENOENT - the type was not found
*
***************************************************************************/
del_input_type(type)
u_short type; /* input packet type */
{
int i = 0, x;
NIT_LOCK_DECL()
NIT_LOCK(&nit_lock);
while ( (i < MAX_NITS) && (nit_table[i].type != type) )
i++;
if (i >= MAX_NITS) {
NIT_UNLOCK(&nit_lock);
return(ENOENT); /* type not found */
}
/* Since more than one protocol may register the same type
* (as long as the input handler is the same), a reference
* count is kept to keep track of the number of users. The
* entry is removed only when the reference count goes to
* zero.
*/
nit_table[i].ref_cnt--;
if (nit_table[i].ref_cnt <= 0) {
nit_table[i].used = 0;
nit_table[i].ref_cnt = 0;
nit_table[i].type = 0;
nit_table[i].handler = NULL;
if (nit_table[i].ifq_addr != NULL)
netisr_del(nit_table[i].af);
nit_table[i].ifq_addr = NULL;
if (type == NET_WILD_TYPE)
wildcard_in_table = 0;
}
NIT_UNLOCK(&nit_lock);
return(0);
}
wild_type_dispatch(type, m, ifp, hp, xmit_flag)
u_short type; /* type from packet */
struct mbuf *m; /* input packet */
struct ifnet *ifp; /* network interface */
caddr_t *hp; /* physical header */
u_char xmit_flag; /* transmit or receive pkt */
{
int i = 0, x;
struct mbuf *n; /* copy of m. It's passed up */
struct mbuf *n0; /* control header */
struct packet_trace_header *pth;
IFQ_LOCK_DECL()
NIT_LOCK_DECL()
NIT_LOCK(&nit_lock);
while ((i < MAX_NITS) && (nit_table[i].type != NET_WILD_TYPE))
i++;
if (i >= MAX_NITS) {
NIT_UNLOCK(&nit_lock);
return(0);
}
n0 = m_gethdr(M_DONTWAIT, MT_HEADER);
if (!n0) {
NIT_UNLOCK(&nit_lock);
return(0);
}
pth = mtod(n0, struct packet_trace_header *);
pth->type = type;
if (hp != NULL)
pth->hlen = (int) (mtod(m, caddr_t) - hp);
else
pth->hlen = 0;
/* XXX - fake out. make sure headers are copied */
m->m_data -= pth->hlen;
m->m_len += pth->hlen;
n = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
/* XXX - now put them back where they should be */
m->m_data += pth->hlen;
m->m_len -= pth->hlen;
if (!n) {
NIT_UNLOCK(&nit_lock);
m_freem(n0);
return(0);
}
n0->m_next = n;
n0->m_len = sizeof(struct packet_trace_header);
n0->m_pkthdr.rcvif = ifp;
n0->m_pkthdr.len = n0->m_len + n->m_pkthdr.len;
n->m_flags &= ~M_PKTHDR;
bcopy((caddr_t)ifp->if_name, (caddr_t)pth->ifname, IFNAMSIZ);
pth->unit = (u_char)ifp->if_unit;
if ((ifp->if_type == IFT_ETHER) || (ifp->if_type == IFT_ISO88023))
/* boy oh'boy */
if (mtod(m, struct ether_header *)->ether_type <= ETHERMTU) {
pth->iftype = IFT_ISO88023;
pth->ifname[1] = 't';
} else {
pth->iftype = IFT_ETHER;
pth->ifname[1] = 'n';
}
else
pth->iftype = ifp->if_type;
pth->xmit_pkt = (u_char)xmit_flag;
n0 = m_pullup(n0, MIN(max_hdr, n->m_pkthdr.len));
if (!n0) {
NIT_UNLOCK(&nit_lock);
return(0);
}
/* if not full, enqueue and schednetisr */
IFQ_LOCK(nit_table[i].ifq_addr);
if (IF_QFULL(nit_table[i].ifq_addr)) {
IF_DROP(nit_table[i].ifq_addr);
m_freem(n0);
} else {
IF_ENQUEUE_NOLOCK(nit_table[i].ifq_addr, n0);
schednetisr(nit_table[i].af);
}
IFQ_UNLOCK(nit_table[i].ifq_addr);
NIT_UNLOCK(&nit_lock);
}
/***************************************************************************
*
* add_netisr() - Adds a network software interrupt service routine to
* the Network Software Interrupt Table.
*
* RETURNS :
* 0 - no errors
* EEXIST - interrupt level already in table
* EINVAL - parameters error
*
*
***************************************************************************/
add_netisr(soft_intr_level, service_level, isr)
u_short soft_intr_level; /* software interrupt number */
u_short service_level; /* call direct or schedule */
int (*isr)(); /* interrupt service routine */
{
if ((service_level != NET_OFF_LEVEL) && (service_level != NET_KPROC))
return(EINVAL);
return(netisr_add(soft_intr_level, isr, NULL, NULL));
}
/***************************************************************************
*
* del_netisr() - Deletes a network software interrupt service routine
* from the Network Software Interrupt Table.
*
* RETURNS :
* 0 - no errors
* EINVAL - soft_intr_level out of range
*
*
***************************************************************************/
del_netisr(soft_intr_level)
u_short soft_intr_level; /* software interrupt number */
{
return(netisr_del(soft_intr_level));
}