Source to bsd/netat/drv_dep.c
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License."
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Copyright 1994 Apple Computer, Inc.
* All Rights Reserved.
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF APPLE COMPUTER, INC.
* The copyright notice above does not evidence any actual or
* intended publication of such source code.
*
*/
#include <localglue.h>
#include <sysglue.h>
#include <at/appletalk.h>
#include <at/elap.h>
#include <at/at_lap.h>
#include <atlog.h>
#include <lap.h>
#include <at_elap.h>
#include <at_aarp.h>
#include <at_pat.h>
#include <routing_tables.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/etherdefs.h>
#include <net/tokendefs.h>
#define DSAP_SNAP 0xaa
extern at_state_t *at_statep;
extern elap_specifics_t elap_specifics[];
static llc_header_t snap_hdr_at = SNAP_HDR_AT;
static llc_header_t snap_hdr_aarp = SNAP_HDR_AARP;
static unsigned char snap_proto_ddp[5] = SNAP_PROTO_AT;
static unsigned char snap_proto_aarp[5] = SNAP_PROTO_AARP;
/* static struct etalk_addr etalk_mcast_base =
{0x09,0x00,0x07,0x00,0x00,0x00}; *** not used ***
*/
int pktsIn, pktsOut;
int xpatcnt = 0;
extern pat_unit_t pat_units[];
#ifndef _AIX
/* struct ifnet atalkif[1]; *** not used *** */
struct ifqueue atalkintrq; /* appletalk and aarp packet input queue */
/* xxdevcnt, xxtype, xxnddp tables are no longer needed since the ifp's
are being initialized as a result of actions taken by the drivers.
There was a bug in which "xxnddp" was indexed by count in one place,
and unit in another place. However upon closer examination we
determined that "xxnddp" is no longer needed.
Annette DeSchon ([email protected]) 11/20/97
*/
short appletalk_inited = 0;
#define FETCH_AND_ADD(x,y) (*x += y)
extern int (*sys_ATsocket )(), (*sys_ATgetmsg)(), (*sys_ATputmsg)();
extern int (*sys_ATPsndreq)(), (*sys_ATPsndrsp)();
extern int (*sys_ATPgetreq)(), (*sys_ATPgetrsp)();
void atalk_load()
{
extern int _ATsocket(), _ATgetmsg(), _ATputmsg();
extern int _ATPsndreq(), _ATPsndrsp(), _ATPgetreq(), _ATPgetrsp();
extern atlock_t ddpall_lock;
extern atlock_t ddpinp_lock;
extern atlock_t arpinp_lock;
sys_ATsocket = _ATsocket;
sys_ATgetmsg = _ATgetmsg;
sys_ATputmsg = _ATputmsg;
sys_ATPsndreq = _ATPsndreq;
sys_ATPsndrsp = _ATPsndrsp;
sys_ATPgetreq = _ATPgetreq;
sys_ATPgetrsp = _ATPgetrsp;
xpatcnt = 0;
ATLOCKINIT(ddpall_lock);
ATLOCKINIT(ddpinp_lock);
ATLOCKINIT(arpinp_lock);
gref_init();
atp_init();
/* adsp_init();
for 2225395
this happens in adsp_open and is undone on ADSP_UNLINK
*/
} /* atalk_load */
void atalk_unload() /* not currently used */
{
extern gbuf_t *scb_resource_m;
extern gbuf_t *atp_resource_m;
sys_ATsocket = 0;
sys_ATgetmsg = 0;
sys_ATputmsg = 0;
sys_ATPsndreq = 0;
sys_ATPsndrsp = 0;
sys_ATPgetreq = 0;
sys_ATPgetrsp = 0;
if (scb_resource_m) {
gbuf_freem(scb_resource_m);
scb_resource_m = 0;
}
if (atp_resource_m) {
gbuf_freem(atp_resource_m);
atp_resource_m = 0;
}
/* CleanupGlobals()
this happens on ADSP_UNLINK for 2225395 */
appletalk_inited = 0;
} /* atalk_unload */
void appletalk_hack_start(nddp)
struct ifnet *nddp;
{
if (!appletalk_inited) {
appletalk_inited =1 ;
atalk_load();
atalkintrq.ifq_maxlen = IFQ_MAXLEN;
}
/* Call to pat_attach(nddp) and the "xx" tables are no longer
needed since the ifp's are being initialized as a result
of actions taken by the drivers. AD 11/21/97 */
} /* appletalk_hack_start */
/* return the unit number of this interface
return -1 if the interface is not found
*/
/* int pat_ifpresent(name) *** not used ***
char *name;
{
struct ifnet *ifp;
if (ifp = (ifunit(name)))
return(ifp->if_unit);
else
return(-1);
}
*/
int
pat_output(pat_id, mlist, dst_addr, type)
int pat_id;
gbuf_t *mlist;
unsigned char *dst_addr;
int type;
{
pat_unit_t *patp;
gbuf_t *m, *m_prev, *new_mlist;
llc_header_t *llc_header;
struct sockaddr dst;
/* this is for ether_output */
dst.sa_family = AF_APPLETALK;
dst.sa_len = sizeof(struct etalk_addr);
bcopy (dst_addr, &dst.sa_data[0], dst.sa_len);
patp = (pat_unit_t *)&pat_units[pat_id];
if (patp->state != PAT_ONLINE) {
gbuf_freel(mlist);
return ENOTREADY;
}
if (patp->xtype == IFTYPE_NULLTALK) {
gbuf_freel(mlist);
return 0;
}
new_mlist = 0;
for (m = mlist; m; m = mlist) {
mlist = gbuf_next(m);
gbuf_next(m) = 0;
gbuf_prepend(m,sizeof(llc_header_t));
if (m == 0) {
if (mlist)
gbuf_freel(mlist);
if (new_mlist)
gbuf_freel(new_mlist);
return 0;
}
llc_header = (llc_header_t *)gbuf_rptr(m);
*llc_header = (type == AARP_AT_TYPE) ? snap_hdr_aarp : snap_hdr_at;
m->m_pkthdr.len = gbuf_msgsize(m);
m->m_pkthdr.rcvif = 0;
if (new_mlist)
gbuf_next(m_prev) = m;
else
new_mlist = m;
m_prev = m;
pktsOut++;
}
while ((m = new_mlist) != 0) {
new_mlist = gbuf_next(m);
gbuf_next(m) = 0;
((struct ifnet *)patp->nddp)->if_output((void *)patp->nddp, m, &dst, NULL);
}
return 0;
} /* pat_output */
int
pat_online (ifName, ifType)
char *ifName;
char *ifType;
{
/*###int pat_input();*/
int pat_id;
pat_unit_t *patp;
register struct ifaddr *ifa;
register struct sockaddr_dl *sdl;
struct ifnet *nddp;
if ((pat_id = pat_ID(ifName)) == -1)
return (-1);
patp = &pat_units[pat_id];
if (patp->xtype == IFTYPE_ETHERTALK) {
if ((nddp = ifunit(ifName)) == NULL)
return -1;
} else if (patp->xtype == IFTYPE_NULLTALK) {
patp->xaddrlen = 6;
bzero(patp->xaddr, patp->xaddrlen);
if (ifType)
*ifType = patp->xtype;
patp->nddp = (void *)0;
patp->state = PAT_ONLINE;
at_statep->flags |= AT_ST_IF_CHANGED;
return (pat_id);
} else
return -1;
/*###********* No need to declare ourself as an if for now
if_attach(NULL, pat_input, 0, 0, 0,
if_name((void *)nddp), if_unit((void *)nddp), "AppleTalk",
622, IFF_BROADCAST, NETIFCLASS_VIRTUAL, 0);
*/
/* if_control((void *)nddp, IFCONTROL_GETADDR, patp->xaddr); */
for (ifa = nddp->if_addrlist; ifa; ifa = ifa->ifa_next)
if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
(sdl->sdl_family == AF_LINK)) {
bcopy(LLADDR(sdl), patp->xaddr, 6);
#ifdef APPLETALK_DEBUG
kprintf("pat_online: our local enet address is=%s\n",
ether_sprintf(patp->xaddr));
#endif
break;
}
patp->xaddrlen = 6;
if (ifType)
*ifType = patp->xtype;
patp->nddp = (void *)nddp;
patp->state = PAT_ONLINE;
at_statep->flags |= AT_ST_IF_CHANGED;
return (pat_id);
} /* pat_online */
void
pat_offline(pat_id)
int pat_id;
{
pat_unit_t *patp = &pat_units[pat_id];
if (patp->state == PAT_ONLINE) {
/*#####
if (patp->xtype != IFTYPE_NULLTALK) {
if_detach((void *)patp->nddp);
}
*/
at_statep->flags |= AT_ST_IF_CHANGED;
bzero(patp, sizeof(pat_unit_t));
}
} /* pat_offline */
int
pat_mcast(pat_id, control, data)
int pat_id;
int control;
unsigned char *data;
{
struct ifnet *nddp;
struct ifreq request;
/* this is for ether_output */
request.ifr_addr.sa_family = AF_UNSPEC;
request.ifr_addr.sa_len = 6; /* warning ### */
bcopy (data, &request.ifr_addr.sa_data[0], 6);
nddp = (struct ifnet *)pat_units[pat_id].nddp;
/*### LD Direct access to the ifp->if_ioctl function */
if (nddp == 0) {
#ifdef APPLETALK_DEBUG
kprintf("pat_mcast: BAD ndpp\n");
#endif
return(-1);
}
#ifdef APPLETALK_DEBUG
else kprintf("pat_mcast: register multicast for ifname=%s\n", nddp->if_name);
#endif
return (*nddp->if_ioctl)(nddp, (control == PAT_REG_MCAST) ?
SIOCADDMULTI : SIOCDELMULTI, &request);
} /* pat_mcast */
void
atalkintr()
{
struct mbuf *m;
struct ifnet *ifp;
int s, ret;
next:
s = splimp();
IF_DEQUEUE(&atalkintrq, m);
splx(s);
if (m == 0)
return;
if ((m->m_flags & M_PKTHDR) == 0) {
#ifdef APPLETALK_DEBUG
kprintf("atalkintr: no HDR on packet received");
#endif
return;
}
ifp = m->m_pkthdr.rcvif;
/* do stuff */
/*
if (m->m_len < ENET_LLC_SIZE &&
(m = m_pullup(m, ENET_LLC_SIZE)) == 0) {
kprintf("atalkintr: packet too small\n");
goto next;
}
*/
ret = pat_input(NULL, ifp, m);
/*
if (ret)
kprintf("atalkintr: pat_input ret=%d\n", ret);
*/
goto next;
} /* atalkintr */
int
pat_input(xddp, nddp, m)
void *xddp;
void *nddp;
gbuf_t *m;
{
#ifdef CHECK_DDPR_FLAG
extern int ddprunning_flag;
#endif
llc_header_t *llc_header;
int pat_id;
pat_unit_t *patp;
char src[6];
enet_header_t *enet_header = (enet_header_t *)gbuf_rptr(m);
for (pat_id=0, patp = &pat_units[pat_id];
pat_id < xpatcnt; pat_id++, patp++) {
if ((patp->state == PAT_ONLINE) && (patp->nddp == nddp))
break;
}
/* if we didn't find a matching interface */
if (pat_id == xpatcnt) {
gbuf_freem(m);
#ifdef CHECK_DDPR_FLAG
FETCH_AND_ADD((atomic_p)&ddprunning_flag, -1);
#endif
return EAFNOSUPPORT;
}
/* Ignore multicast packets from local station */
if (patp->xtype == IFTYPE_ETHERTALK) {
bcopy((char *)enet_header->src, src, sizeof(src));
/*
kprintf("pat_input: Packet received src addr=%s len=%x\n",
ether_sprintf(enet_header->src), enet_header->len);
*/
/* In order to receive packets from the Blue Box, we cannot reject packets
whose source address matches our local address.
if ((enet_header->dst[0] & 1) &&
(bcmp(src, patp->xaddr, sizeof(src)) == 0)) {
#ifdef APPLETALK_DEBUG
kprintf("pat_input: Packet rejected: think it's a local mcast\n");
#endif
gbuf_freem(m);
#ifdef CHECK_DDPR_FLAG
FETCH_AND_ADD((atomic_p)&ddprunning_flag, -1);
#endif
return EAFNOSUPPORT;
}
*/
llc_header = (llc_header_t *)(enet_header+1);
gbuf_rinc(m,(ENET_LLC_SIZE));
#ifdef CHECK_DDPR_FLAG
FETCH_AND_ADD((atomic_p)&ddprunning_flag, 1);
#endif
pktsIn++;
/*
kprintf("pat_input: enet_header: dest=%s LLC_PROTO= %02x%02x\n",
ether_sprintf(enet_header->dst),
llc_header->protocol[3],
llc_header->protocol[4]);
*/
if (LLC_PROTO_EQUAL(llc_header->protocol,snap_proto_aarp)) {
/*
kprintf("pat_input: Calling aarp_func dest=%s LLC_PROTO=%02x%02x\n",
ether_sprintf(enet_header->dst),
llc_header->protocol[3],
llc_header->protocol[4]);
*/
patp->aarp_func(gbuf_rptr(m), patp->context);
gbuf_freem(m);
}
else if (LLC_PROTO_EQUAL(llc_header->protocol,snap_proto_ddp)) {
/* if we're a router take all pkts */
if (!ROUTING_MODE) {
if (patp->addr_check(gbuf_rptr(m), patp->context)
== AARP_ERR_NOT_OURS) {
/*
kprintf("pat_input: Packet Rejected: not for us? dest=%s LLC_PROTO= %02x%02x\n",
ether_sprintf(enet_header->dst),
llc_header->protocol[3],
llc_header->protocol[4]);
*/
gbuf_freem(m);
#ifdef CHECK_DDPR_FLAG
FETCH_AND_ADD((atomic_p)&ddprunning_flag, -1);
#endif
return EAFNOSUPPORT;
}
}
gbuf_set_type(m, MSG_DATA);
elap_input(m, patp->context, src);
} else {
gbuf_rdec(m,(ENET_LLC_SIZE));
#ifdef APPLETALK_DEBUG
kprintf("pat_input: Packet Rejected: wrong LLC_PROTO dest=%s LLC_PROTO= %02x%02x\n",
ether_sprintf(enet_header->dst),
llc_header->protocol[3],
llc_header->protocol[4]);
#endif
gbuf_freem(m);
#ifdef CHECK_DDPR_FLAG
FETCH_AND_ADD((atomic_p)&ddprunning_flag, -1);
#endif
return EAFNOSUPPORT;
}
}
#ifdef CHECK_DDPR_FLAG
FETCH_AND_ADD((atomic_p)&ddprunning_flag, -1);
#endif
return 0;
} /* pat_input */
#else /* AIX section to end of file (not supported) */
/* from beginning of file ... */
#include <sys/cdli.h>
#include <sys/ndd.h>
static struct ns_8022 elap_link; /* The SNAP header description */
static struct ns_user elap_user; /* The interface to the demuxer */
int
pat_ifpresent(name) /* AIX */
char *name;
{
return (int)ifunit(name);
}
int
pat_output(pat_id, mlist, dst_addr, type) /* AIX */
int pat_id;
gbuf_t *mlist;
unsigned char *dst_addr;
int type;
{
int len;
pat_unit_t *patp;
gbuf_t *m, *m_prev, *new_mlist, *m_temp;
struct ndd *nddp;
short size;
enet_header_t *enet_header;
llc_header_t *llc_header;
patp = (pat_unit_t *)&pat_units[pat_id];
if (patp->state != PAT_ONLINE) {
gbuf_freel(mlist);
return ENOTREADY;
}
if (patp->xtype == IFTYPE_NULLTALK) {
gbuf_freel(mlist);
return 0;
}
nddp = (void *)patp->nddp;
new_mlist = 0;
for (m = mlist; m; m = mlist) {
mlist = gbuf_next(m);
gbuf_next(m) = 0;
gbuf_prepend(m,ENET_LLC_SIZE);
if (m == 0) {
if (mlist)
gbuf_freel(mlist);
if (new_mlist)
gbuf_freel(new_mlist);
return 0;
}
enet_header = (enet_header_t *)gbuf_rptr(m);
bcopy(dst_addr, enet_header->dst, sizeof(enet_header->dst));
bcopy(patp->xaddr, enet_header->src, sizeof(enet_header->src));
size = gbuf_msgsize(m);
enet_header->len = size - sizeof(enet_header_t);
llc_header = (llc_header_t *)(gbuf_rptr(m)+sizeof(enet_header_t));
*llc_header = (type == AARP_AT_TYPE) ? snap_hdr_aarp : snap_hdr_at;
m->m_pkthdr.len = size;
m->m_pkthdr.rcvif = 0;
if (new_mlist)
gbuf_next(m_prev) = m;
else
new_mlist = m;
m_prev = m;
pktsOut++;
}
if (new_mlist)
(*nddp->ndd_output)(nddp, new_mlist);
return 0;
}
int
pat_online (ifName, ifType) /* AIX */
char *ifName;
char *ifType;
{
void pat_input();
int pat_id;
pat_unit_t *patp;
struct ndd *nddp;
char ns_name[8];
if ((pat_id = pat_ID(ifName)) == -1)
return (-1);
patp = &pat_units[pat_id];
if (patp->xtype == IFTYPE_ETHERTALK) {
ns_name[0] = ifName[0];
ns_name[1] = 'n';
strcpy(&ns_name[2], &ifName[1]);
} else if (patp->xtype == IFTYPE_NULLTALK) {
patp->xaddrlen = 6;
bzero(patp->xaddr, patp->xaddrlen);
if (ifType)
*ifType = patp->xtype;
patp->nddp = (void *)0;
patp->state = PAT_ONLINE;
at_statep->flags |= AT_ST_IF_CHANGED;
return (pat_id);
} else
return -1;
if (ns_alloc(ns_name, &nddp))
return -1;
bzero(&elap_user, sizeof(elap_user));
elap_user.isr = pat_input;
elap_user.pkt_format = NS_HANDLE_HEADERS|NS_INCLUDE_MAC;
elap_link.filtertype = NS_8022_LLC_DSAP_SNAP;
elap_link.orgcode[0] = 0;
elap_link.orgcode[2] = 0;
elap_link.dsap = DSAP_SNAP;
elap_link.ethertype = 0x80f3; /* AARP SNAP code */
if (ns_add_filter(nddp, &elap_link, sizeof(elap_link), &elap_user))
return -1;
elap_link.orgcode[0] = 0x08;
elap_link.orgcode[2] = 0x07;
elap_link.ethertype = 0x809b; /* DDP SNAP code */
if (ns_add_filter(nddp, &elap_link, sizeof(elap_link), &elap_user)) {
elap_link.orgcode[0] = 0;
elap_link.orgcode[2] = 0;
elap_link.ethertype = 0x80f3; /* AARP SNAP code */
(void)ns_del_filter(nddp, &elap_link, sizeof(elap_link));
return -1;
}
patp->xaddrlen = nddp->ndd_addrlen;
bcopy(nddp->ndd_physaddr, patp->xaddr, patp->xaddrlen);
if (ifType)
*ifType = patp->xtype;
patp->nddp = (void *)nddp;
patp->state = PAT_ONLINE;
at_statep->flags |= AT_ST_IF_CHANGED;
return (pat_id);
}
void
pat_offline(pat_id) /* AIX */
int pat_id;
{
pat_unit_t *patp = &pat_units[pat_id];
if (patp->state == PAT_ONLINE) {
if (patp->xtype != IFTYPE_NULLTALK) {
elap_link.filtertype = NS_8022_LLC_DSAP_SNAP;
elap_link.orgcode[0] = 0;
elap_link.orgcode[2] = 0;
elap_link.dsap = DSAP_SNAP;
elap_link.ethertype = 0x80f3; /* AARP SNAP code */
(void)ns_del_filter(patp->nddp, &elap_link, sizeof(elap_link));
elap_link.orgcode[0] = 0x08;
elap_link.orgcode[2] = 0x07;
elap_link.ethertype = 0x809b; /* DDP SNAP code */
(void)ns_del_filter(patp->nddp, &elap_link, sizeof(elap_link));
ns_free(patp->nddp);
}
at_statep->flags |= AT_ST_IF_CHANGED;
bzero(patp, sizeof(pat_unit_t));
}
}
int
pat_mcast(pat_id, control, data) /* AIX */
int pat_id;
int control;
unsigned char *data;
{
struct ndd *nddp;
nddp = (struct ndd *)pat_units[pat_id].nddp;
return (*nddp->ndd_ctl)(nddp, (control == PAT_REG_MCAST) ?
NDD_ENABLE_ADDRESS : NDD_DISABLE_ADDRESS,
data, nddp->ndd_addrlen);
}
void
pat_input(nddp, m, unused) /* AIX */
struct ndd *nddp;
gbuf_t *m;
void *unused;
{
extern int ddprunning_flag;
llc_header_t *llc_header;
int pat_id;
pat_unit_t *patp;
char src[6];
enet_header_t *enet_header = (enet_header_t *)gbuf_rptr(m);
for (pat_id=0, patp = &pat_units[pat_id];
pat_id < xpatcnt; pat_id++, patp++) {
if ((patp->state == PAT_ONLINE) && (patp->nddp == nddp))
break;
}
if (pat_id == xpatcnt) {
gbuf_freem(m);
return;
}
/* Ignore multicast packets from local station */
if (patp->xtype == IFTYPE_ETHERTALK) {
bcopy((char *)enet_header->src, src, sizeof(src));
if ((enet_header->dst[0] & 1) &&
(bcmp(src, patp->xaddr, sizeof(src)) == 0)) {
gbuf_freem(m);
return;
}
llc_header = (llc_header_t *)(enet_header+1);
}
gbuf_rinc(m,(ENET_LLC_SIZE));
(void)fetch_and_add((atomic_p)&ddprunning_flag, 1);
pktsIn++;
if (LLC_PROTO_EQUAL(llc_header->protocol,snap_proto_aarp)) {
patp->aarp_func(gbuf_rptr(m), patp->context);
gbuf_freem(m);
} else if (LLC_PROTO_EQUAL(llc_header->protocol,snap_proto_ddp)) {
/* if we're a router take all pkts */
if (!ROUTING_MODE) {
if (patp->addr_check(gbuf_rptr(m), patp->context)
== AARP_ERR_NOT_OURS) {
gbuf_freem(m);
(void)fetch_and_add((atomic_p)&ddprunning_flag, -1);
return;
}
}
gbuf_set_type(m, MSG_DATA);
elap_input(m, patp->context, src);
} else
gbuf_freem(m);
(void)fetch_and_add((atomic_p)&ddprunning_flag, -1);
}
#endif /* AIX */