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

524 lines
13 KiB
C

static char sccsid[] = "@(#)11 1.10 src/bos/kernel/net/nd_lan.c, sysnet, bos411, 9428A410j 4/21/94 11:05:28";
/*
* COMPONENT_NAME: SYSNET
*
* FUNCTIONS: dmx_8022_add_filter
* dmx_8022_del_filter
* dmx_8022_get_user
* dmx_8022_receive
* dmx_add_status
* dmx_del_status
* dmx_init
* dmx_non_ui
* dmx_status
* dmx_term
*
* ORIGINS: 27
*
*
* (C) COPYRIGHT International Business Machines Corp. 1988,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 <sys/errno.h>
#include <sys/types.h>
#include <sys/syspest.h>
#include <sys/syslog.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/cdli.h>
#include <net/nd_lan.h>
#include <sys/ndd.h>
#include <net/netisr.h>
#include <net/if.h>
struct ns_8022_user * dmx_8022_get_user();
#define THEMAX (2 * AF_MAX)
struct af_ent af_table[THEMAX];
/***************************************************************************
*
* Process incoming 802.2 packets. Look for user and distribute packets.
*
***************************************************************************/
void
dmx_8022_receive(nddp, m, llcoffset, extp)
struct ndd *nddp;
struct mbuf *m; /* input packet */
int llcoffset;
struct isr_data_ext *extp;
{
struct ns_8022_user *ns_8022_user;
caddr_t macp; /* pointer to mac header */
struct ie2_llc_snaphdr *llcp;
int headerlen = 0; /* length of header the
isr doesn't care about */
int pullup_len; /* len to pull up in 1st mbuf */
assert(nddp->ndd_nsdemux != (struct ns_dmx_ctl *) NULL);
if (m->m_flags & M_BCAST) {
nddp->ndd_nsdemux->nd_dmxstats.nd_bcast++;
} else {
if (m->m_flags & M_MCAST)
nddp->ndd_nsdemux->nd_dmxstats.nd_mcast++;
}
/*
* Make sure enough of the header is contiguous
*/
macp = mtod(m, caddr_t);
llcp = (struct ie2_llc_snaphdr *) (macp + llcoffset);
/*
* Pull up at least the maclen and a ie2 hdr. If possible
* pull up a snap header too...
*/
if (m->m_pkthdr.len < (llcoffset + sizeof(struct ie2_llc_snaphdr)))
pullup_len = llcoffset + sizeof(struct ie2_llc_hdr);
else
pullup_len = llcoffset + sizeof(struct ie2_llc_snaphdr);
if (m->m_len < pullup_len) {
m = m_pullup(m, pullup_len);
if (m == (struct mbuf *) NULL) {
nddp->ndd_nsdemux->nd_dmxstats.nd_nobufs++;
return;
}
}
/*
* Locate user that's done an ns_add_filter for this packet.
*
* If we don't have a snap header's worth of llc data, then
* pass null values for type and protid to DMX_8022_GET_USER...
*/
if (m->m_pkthdr.len < (llcoffset + sizeof(struct ie2_llc_snaphdr))) {
DMX_8022_GET_USER(ns_8022_user, llcp->dsap, 0, 0,
nddp->ndd_nsdemux);
} else {
DMX_8022_GET_USER(ns_8022_user, llcp->dsap, llcp->type,
llcp->prot_id, nddp->ndd_nsdemux);
}
if (ns_8022_user == NULL) {
/*
* Handle null sap non ui frames with no user.
* We must still respond to these...
*/
if ((llcp->ctrl != CTRL_UI) && (llcp->dsap == NULL)) {
dmx_non_ui(nddp, m, llcoffset);
return;
}
nddp->ndd_nsdemux->nd_dmxstats.nd_nofilter++;
m_freem(m);
return;
}
/*
* If it's not a UI packet, see what user wants done.
*/
if ( (llcp->ctrl != CTRL_UI) &&
(ns_8022_user->user.pkt_format & NS_HANDLE_NON_UI) ) {
dmx_non_ui(nddp, m, llcoffset);
return;
}
/*
* Fix up headers as requested.
*/
switch (ns_8022_user->user.pkt_format & 0xFF) {
case NS_PROTO:
headerlen = llcoffset + sizeof(struct ie2_llc_hdr);
break;
case NS_PROTO_SNAP:
headerlen = llcoffset + sizeof(struct ie2_llc_snaphdr);
break;
case NS_INCLUDE_LLC:
headerlen = llcoffset;
break;
case NS_INCLUDE_MAC:
default:
break;
}
if (headerlen) {
m->m_pkthdr.len -= headerlen;
m->m_len -= headerlen;
m->m_data += headerlen;
}
if (ns_8022_user->user.pkt_format & NS_HANDLE_HEADERS) {
/*
* Set llclen in extp.
*/
extp->llcp = (caddr_t)llcp;
if (ns_8022_user->filter.filtertype == NS_8022_LLC_DSAP)
extp->llclen = sizeof(struct ie2_llc_hdr);
else
extp->llclen = sizeof(struct ie2_llc_snaphdr);
extp->isr_data = ns_8022_user->user.isr_data;
} else
extp = (struct isr_data_ext *)ns_8022_user->user.isr_data;
IFSTUFF_AND_DELIVER(ns_8022_user, nddp, m, macp, extp);
return;
}
/***************************************************************************
*
* Respond to non-ui (ie XID and TEST) requests.
* DA/SA swapping is done in demuxer's nd_response()
*
***************************************************************************/
dmx_non_ui(nddp, m, llcoffset)
struct ndd *nddp;
struct mbuf *m;
int llcoffset;
{
caddr_t macp;
struct ie2_xid_ifield *llcp;
unsigned char t;
macp = mtod(m, caddr_t);
llcp = (struct ie2_xid_ifield *) (macp + llcoffset);
if (llcp->ssap & SSAP_RESP) { /* rcv Response */
m_freem(m);
return;
}
/*
* swap DSAP/SSAP
*/
t = llcp->dsap;
llcp->dsap = llcp->ssap;
llcp->ssap = t | SSAP_RESP; /* set response bit */
if ((llcp->ctrl & 0xef) == CTRL_XID ) {
llcp->xid_info[0] = 0x81; /* IEEE 802.2 format */
llcp->xid_info[1] = 0x01; /* connectionless */
llcp->xid_info[2] = 0x00; /* window size */
m->m_pkthdr.len = m->m_len =
llcoffset + sizeof (struct ie2_xid_ifield);
} else {
if ((llcp->ctrl & 0xe3) != CTRL_TEST ) {
m_freem(m);
return;
}
}
if (nddp->ndd_demuxer->nd_response)
(*(nddp->ndd_demuxer->nd_response)) (nddp, m, llcoffset);
else
m_freem(m);
return;
}
/***************************************************************************
*
* dmx_8022_add_filter() - Add 802.2 filter to the demuxer
*
* RETURNS : 0 - no errors
* EEXIST - sap/type already in table by another user
* EALREADY - sap/type already in table by you!
* ENOMEM - couldn't allocate entry
***************************************************************************/
dmx_8022_add_filter(nddp, filter, ns_user)
struct ndd *nddp;
struct ns_8022 *filter;
struct ns_user *ns_user; /* the details */
{
int error;
struct ns_8022_user *new_user, *fup;
NET_MALLOC(new_user, struct ns_8022_user *, sizeof(struct ns_8022_user),
M_TEMP, M_WAITOK);
if (new_user == (struct ns_8022_user *) NULL)
return(ENOMEM);
bzero(new_user, sizeof(struct ns_8022_user));
new_user->user = *ns_user;
new_user->filter = *filter;
if ((fup=dmx_8022_get_user(filter, nddp))) {
NET_FREE(new_user, M_TEMP);
if (!(bcmp(&fup->user, ns_user, sizeof(ns_user_t))))
return(EALREADY);
else
return(EEXIST);
}
insque(new_user, nddp->ndd_nsdemux->dsap_heads[filter->dsap].prev);
return(0);
}
/***************************************************************************
* dmx_8022_del_filter() - Deletes a 802.2 filter
*
* RETURNS : 0 - no errors
* ENOENT - the type was not found
***************************************************************************/
dmx_8022_del_filter(nddp, filter)
struct ndd *nddp;
struct ns_8022 *filter;
{
struct ns_8022_user *fup;
fup = dmx_8022_get_user(filter, nddp);
if (fup == NULL)
return(ENOENT);
remque(fup);
NET_FREE(fup, M_TEMP);
return(0);
}
/***************************************************************************
*
* dmx_add_status() - Add status filter to the demuxer
*
***************************************************************************/
dmx_add_status(nddp, filter, ns_statuser)
struct ndd *nddp;
struct ns_com_status *filter;
struct ns_statuser *ns_statuser;
{
struct com_status_user *new_status_user;
struct com_status_user *status_head;
if (filter->filtertype != NS_STATUS_MASK)
return(EINVAL);
status_head = &(nddp->ndd_nsdemux->com_status_head);
NET_MALLOC(new_status_user, struct com_status_user *,
sizeof(struct com_status_user), M_TEMP, M_WAITOK);
if (new_status_user == (struct com_status_user *)NULL)
return(ENOMEM);
bzero(new_status_user, sizeof(*new_status_user));
filter->sid = new_status_user;
new_status_user->user = *ns_statuser;
new_status_user->filter = *filter;
insque(new_status_user, status_head->prev);
return(0);
}
/***************************************************************************
*
* dmx_del_status() - Delete a status filter from the demuxer
*
***************************************************************************/
dmx_del_status(nddp, filter)
struct ndd *nddp;
struct ns_com_status *filter;
{
struct com_status_user *sup;
struct com_status_user *status_head;
if (filter->filtertype != NS_STATUS_MASK)
return(EINVAL);
status_head = &(nddp->ndd_nsdemux->com_status_head);
for (sup = status_head->next; sup != status_head; sup = sup->next) {
if (sup->filter.sid == filter->sid)
break;
}
if (sup != status_head) {
remque(sup);
NET_FREE(sup, M_TEMP);
return(0);
}
return(ENOENT);
}
/***************************************************************************
*
* Deliver status to all registered users that match the status.
*
***************************************************************************/
void
dmx_status(nddp, status)
struct ndd *nddp;
struct ndd_statblk *status;
{
struct com_status_user *sup;
struct com_status_user *status_head;
if (nddp->ndd_nsdemux == (struct ns_dmx_ctl *) NULL)
return;
status_head = &(nddp->ndd_nsdemux->com_status_head);
for (sup = status_head->next; sup != status_head; sup = sup->next) {
if ( (sup->filter.mask & status->code) != 0 )
(*(sup->user.isr)) (nddp, status, sup->user.isr_data);
}
return;
}
/***************************************************************************
*
* dmx_8022_get_user() - retrieves a user based upon filter
*
***************************************************************************/
struct ns_8022_user *
dmx_8022_get_user(filter, nddp)
struct ns_8022 *filter;
struct ndd *nddp;
{
struct ns_8022_user *ns_8022_user;
ASSERT(nddp->ndd_nsdemux != (struct ns_dmx_ctl *) NULL);
if (nddp->ndd_nsdemux == (struct ns_dmx_ctl *) NULL)
return(NULL);
DMX_8022_GET_USER(ns_8022_user, filter->dsap, filter->ethertype,
filter->orgcode, nddp->ndd_nsdemux);
return(ns_8022_user);
}
/***************************************************************************
*
* Initialize common demuxer services for a NDD.
*
***************************************************************************/
dmx_init(nddp)
struct ndd *nddp;
{
struct com_status_user *status_head;
struct ns_8022_user_head *dsap_heads;
int i;
if (nddp->ndd_nsdemux != NULL)
return(0);
NET_MALLOC(nddp->ndd_nsdemux, struct ns_dmx_ctl *,
sizeof(struct ns_dmx_ctl), M_TEMP, M_WAITOK);
if (nddp->ndd_nsdemux == NULL)
return(ENOMEM);
bzero(nddp->ndd_nsdemux, sizeof(*nddp->ndd_nsdemux));
status_head = &(nddp->ndd_nsdemux->com_status_head);
status_head->next = status_head->prev = status_head;
dsap_heads = nddp->ndd_nsdemux->dsap_heads;
for (i = 0 ; i < NS_MAX_SAPS ; i++)
dsap_heads[i].next = dsap_heads[i].prev =
(struct ns_8022_user *) &dsap_heads[i];
return(0);
}
/***************************************************************************
*
* Terminate common demuxer services for a NDD.
*
***************************************************************************/
void
dmx_term(nddp)
struct ndd *nddp;
{
if (nddp->ndd_nsdemux == NULL)
return;
NET_FREE(nddp->ndd_nsdemux, M_TEMP);
nddp->ndd_nsdemux = NULL;
return;
}
/***************************************************************************
*
* RETURNS :
* EEXIST - af already in table
* EINVAL - af out of range
* 0 - no errors
*
***************************************************************************/
nd_config_proto(af, config_proto)
u_short af;
struct config_proto *config_proto;
{
if (af >= THEMAX)
return(EINVAL);
if (af_table[af].sap)
return(EEXIST);
af_table[af].config = *config_proto;
af_table[af].sap = 1;
return(0);
}
/***************************************************************************
* Path for DLPI protocols to register.
*
* RETURNS :
* EEXIST - sap/type already in table
* ENOMEM - table overflow.
* 0 - no errors
*
***************************************************************************/
int nd_config_sap(sap, type, config_proto, af)
u_short sap;
u_short type;
struct config_proto *config_proto;
u_short *af;
{
int i, x;
for (i=(THEMAX/2); i < THEMAX; i++) {
if (af_table[i].sap) {
if (af_table[i].sap == sap && af_table[i].type == type)
return (EEXIST);
continue;
} else
break;
}
if (i >= THEMAX)
return (ENOMEM);
if (x = nd_config_proto(i,config_proto))
return(x);
af_table[i].sap = sap;
af_table[i].type = type;
*af = i;
return(0);
}
/***************************************************************************
* Routine for DLPI to find registered address families
*
* RETURNS :
* af
* 0 - not found
*
***************************************************************************/
int nd_find_af(sap, type)
u_short sap;
u_short type;
{
int i;
for (i=(THEMAX/2); i < THEMAX; i++) {
if (af_table[i].sap) {
if (af_table[i].sap == sap && af_table[i].type == type)
return (i);
continue;
} else
return(0);
}
return(0);
}