#include <sys/kdebug.h>
#if KDEBUG
#define DBG_SPLT_BFCHK DRVDBG_CODE(DBG_DRVSPLT, 0)
#define DBG_SPLT_APPND DRVDBG_CODE(DBG_DRVSPLT, 1)
#define DBG_SPLT_MBUF DRVDBG_CODE(DBG_DRVSPLT, 2)
#define DBG_SPLT_DUP DRVDBG_CODE(DBG_DRVSPLT, 3)
#define DBG_SPLT_PAD DRVDBG_CODE(DBG_DRVSPLT, 4)
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/socketvar.h>
#include <sys/fcntl.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/domain.h>
#include <sys/mbuf.h>
#include <net/route.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_types.h>
#include <net/if_dl.h>
#include <net/ndrv.h>
#include <net/kext_net.h>
#include <net/dlil.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <net/if_arp.h>
#include "SharedIP.h"
#include "sip.h"
#include <netat/sysglue.h>
#include <netat/at_pcb.h>
#include <netat/at_var.h>
#include <machine/spl.h>
#include <sys/syslog.h>
int atalk_detach(caddr_t cookie);
int
enable_atalk(struct BlueFilter *bf, void *data, struct blueCtlBlock *ifb)
{
int retval, s;
struct sockaddr_at atalk_sockaddr, *sap;
struct ifaddr *ifa = NULL;
struct ifnet *ifp = NULL;
retval = copyin(data, &atalk_sockaddr,
sizeof (struct sockaddr_at));
if (retval) {
#if SIP_DEBUG_ERR
log(LOG_WARNING, "enable_atalk: copyin for data=%x to atalk_sockaddr failed ret=%x\n",
data, retval);
#endif
return (-retval);
}
bf->BF_address = atalk_sockaddr.sat_addr.s_net;
bf->BF_node = atalk_sockaddr.sat_addr.s_node;
#if SIP_DEBUG
log(LOG_WARNING, "enable_atalk: SIP_PROTO_ATALK Flags: %x, AT address %x.%x\n",
bf->BF_flags, atalk_sockaddr.sat_addr.s_net,
atalk_sockaddr.sat_addr.s_node);
#endif
ifp = ndrv_get_ifp(ifb->ifb_so->so_pcb);
bzero((caddr_t)&ifb->XAtalkAddr, sizeof (ifb->XAtalkAddr));
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
if ((sap = (struct sockaddr_at *)ifa->ifa_addr) &&
(sap->sat_family == AF_APPLETALK))
*(&ifb->XAtalkAddr) = *sap;
s = splnet();
if ((retval = atalk_attach_protofltr(ifp, ifb)) != 0) {
#if SIP_DEBUG_ERR
log(LOG_WARNING, "enable_atalk: failed, ifp=%d retval=%d\n",
ifp, retval);
#endif
splx(s);
return(retval);
}
splx(s);
return(BFS_ATALK);
}
static
int atalk_infltr(caddr_t cookie,
struct mbuf **m_orig,
char **etherheader,
struct ifnet **ifnet_ptr)
{
register struct blueCtlBlock *ifb = (struct blueCtlBlock *)cookie;
register struct BlueFilter *bf;
register unsigned char *p;
register unsigned short *s;
struct mbuf * m0, *m = *m_orig;
bf = &ifb->filter[BFS_ATALK];
MDATA_ETHER_START(m);
s = (unsigned short *)*etherheader;
p = (unsigned char *)*etherheader;
#if SIP_DEBUG_FLOW
if (!bf->BF_flags)
log(LOG_WARNING, "atalk_infltr: p0=%x %x, %x, ... %x, net/node %x.%x\n",
p[0],s[6], s[7], s[10], s[13], p[30]);
#endif
if (bf->BF_flags & SIP_PROTO_ENABLE)
if (((p[0] & 0x01) == 0) &&
(p[17] == 0x08) &&
(ntohl(*((unsigned long*)&p[18])) == 0x0007809bL)) {
if (bf->BF_flags & SIP_PROTO_RCV_FILT) {
if ((ntohs(s[13]) == bf->BF_address &&
p[30] == bf->BF_node)) {
#if SIP_DEBUG_FLOW
log(LOG_WARNING, "atalk_infltr: Filter match %x.%x ! ifb=%x so=%x m=%x m_flags=%x\n",
s[13], p[30], ifb, ifb->ifb_so, m, m->m_flags);
#endif
blue_inject(ifb, m);
return(EJUSTRETURN);
} else {
MDATA_ETHER_END(m);
#if SIP_DEBUG_FLOW
log(LOG_WARNING, "atalk_infltr: direct packet not matched: ifb=%x m=%x %x.%x\n",
ifb, m, s[13], p[30]);
#endif
return(0);
}
}
#if SIP_DEBUG
log(LOG_WARNING, "atalk_infltr: SIP_PROTO_RCV_FILT == FALSE\n");
#endif
}
m0 = m_dup(m, M_NOWAIT);
if (m0 == NULL) {
#if SIP_DEBUG_FLOW
log(LOG_WARNING, "atalk_infltr: m_dup failed\n");
#endif
ifb->no_bufs1++;
MDATA_ETHER_END(m);
return(0);
}
#if SIP_DEBUG_FLOW
log(LOG_WARNING, "atalk_infltr: inject for bluebox p0=%x m0=%x m0->m_flags=%x so=%x \n",
p[0], m0, m0->m_flags, ifb->ifb_so);
#endif
blue_inject(ifb, m0);
MDATA_ETHER_END(m);
return (0);
}
static
int atalk_outfltr(caddr_t cookie,
struct mbuf **m_orig,
struct ifnet **ifnet_ptr,
struct sockaddr **dest,
char *dest_linkaddr,
char *frame_type)
{
register struct blueCtlBlock *ifb = (struct blueCtlBlock *)cookie;
register struct BlueFilter *bf;
register unsigned char *p;
struct mbuf * m0, *m = *m_orig;
int total;
int reqlen = (((*dest)->sa_data[0] & 0x01) == 0) ? 17 : 0;
if (reqlen > m->m_pkthdr.len)
return(1);
while ((reqlen > m->m_len) && m->m_next) {
total = m->m_len + (m->m_next)->m_len;
if ((*m_orig = m_pullup(*m_orig, min(reqlen, total))) == 0)
return(-1);
m = *m_orig;
}
bf = &ifb->filter[BFS_ATALK];
p = (unsigned char *)m->m_data;
if (bf->BF_flags & SIP_PROTO_ENABLE) {
if (((*dest)->sa_data[0] & 0x01) == 0) {
if (bf->BF_flags & SIP_PROTO_RCV_FILT)
{
u_int32_t snap1 = ntohl(*(u_int32_t*)(p));
u_int32_t snap2 = ntohl(*(u_int32_t*)(p + 4));
if ((snap1 == 0xaaaa0308) && (snap2 == 0x0007809B))
{
if ((ntohs(*(u_int16_t*)(p + 12)) == bf->BF_address &&
p[16] == bf->BF_node))
{
if (!my_frameout(&m, *ifnet_ptr, &(*dest)->sa_data[0], frame_type))
blue_inject(ifb, m);
*m_orig = 0;
return(EJUSTRETURN);
}
}
else if ((snap1 == 0xaaaa0300) && (snap2 == 0x000080F3) &&
(m->m_len >= 36))
{
u_int16_t net = ((u_int16_t)p[33]) << 8 | p[34];
if ((net == bf->BF_address) &&
(p[35] == bf->BF_node))
{
if (!my_frameout(&m, *ifnet_ptr, &(*dest)->sa_data[0], frame_type))
blue_inject(ifb, m);
*m_orig = 0;
return(EJUSTRETURN);
}
}
}
return 0;
}
m0 = m_dup(m, M_NOWAIT);
if (m0 == NULL)
{
#if SIP_DEBUG_FLOW
log(LOG_WARNING, "atalk_outfltr: m_dup failed\n");
#endif
ifb->no_bufs1++;
*m_orig = m;
return(0);
}
if (!my_frameout(&m0, *ifnet_ptr, &(*dest)->sa_data[0], frame_type))
blue_inject(ifb, m0);
}
*m_orig = m;
return (0);
}
int
atalk_attach_protofltr(struct ifnet *ifp, struct blueCtlBlock *ifb)
{
u_long at_dltag, aarp_dltag;
int retval=0;
struct dlil_pr_flt_str atalk_pfilter =
{ (caddr_t)ifb,
atalk_infltr,
atalk_outfltr,
0,
0,
atalk_detach
};
if (ifb->atalk_proto_filter_id)
retval= atalk_stop(ifb);
if (retval)
return (retval);
ether_attach_at(ifp, &at_dltag, &aarp_dltag);
aarp_dltag = at_dltag;
retval= dlil_attach_protocol_filter(at_dltag, &atalk_pfilter,
&ifb->atalk_proto_filter_id, DLIL_LAST_FILTER);
#if SIP_DEBUG
log(LOG_WARNING, "atalk_attach_protofilter: dltag=%d filter_id=%d retval=%d\n",
at_dltag, ifb->atalk_proto_filter_id, retval);
#endif
return (retval);
}
int
si_send_eth_atalk(register struct mbuf **m_orig, struct blueCtlBlock *ifb)
{
struct mbuf *m1, *m;
unsigned char *p, *p1;
register unsigned short *s;
register unsigned long *l;
struct sockaddr_at *sap;
m = *m_orig;
p = mtod(m, unsigned char *);
s = (unsigned short *)p;
sap = &ifb->XAtalkAddr;
if (sap->sat_family) {
if (p[0] & 0x01) {
m1 = m_dup(m, M_NOWAIT);
#if SIP_DEBUG_FLOW
log(LOG_WARNING, "si_send: broadcast! inject m=%x m1=%x..\n", m, m1);
#endif
if (m1) {
p1 = mtod(m1, unsigned char *);
MDATA_ETHER_END(m1);
m1->m_pkthdr.rcvif = ndrv_get_ifp(ifb->ifb_so->so_pcb);
dlil_inject_pr_input(m1, (char *)p1, ifb->atalk_proto_filter_id);
} else
ifb->no_bufs2++;
return(0);
}
l = (unsigned long *)&s[8];
#if SIP_DEBUG_FLOW
log(LOG_WARNING, "si_send packet: p0=%x len=%x, m_len=%x snap? %x %x:%x, Add:%x.%x\n",
p[0], m->m_len, s[6], s[7], *l, s[10], s[13], p[30]);
#endif
if (ntohl(*l) == 0x03080007 && ntohs(s[10]) == 0x809b) {
if (ntohs(s[13]) == sap->sat_addr.s_net &&
p[30] == sap->sat_addr.s_node)
{
#if SIP_DEBUG_FLOW
log(LOG_WARNING, "si_send: packet is for X side %x.%x m=%x\n",
s[13], p[30], m);
#endif
MDATA_ETHER_END(m);
m->m_pkthdr.rcvif = ndrv_get_ifp(ifb->ifb_so->so_pcb);
dlil_inject_pr_input(m, p, ifb->atalk_proto_filter_id);
return(EJUSTRETURN);
} else
return(0);
} else if (ntohl(*l) == 0x03000000 && ntohs(s[10]) == 0x80f3) {
m1 = m_dup(m, M_NOWAIT);
#if SIP_DEBUG_FLOW
log(LOG_WARNING, "si_send: AARP m=%x m1=%x send to X\n", m, m1);
#endif
if (m1)
{
p1 = mtod(m1, unsigned char *);
MDATA_ETHER_END(m1);
m1->m_pkthdr.rcvif = ndrv_get_ifp(ifb->ifb_so->so_pcb);
dlil_inject_pr_input(m1, p1, ifb->atalk_proto_filter_id);
} else
ifb->no_bufs2++;
return(0);
}
#if SIP_DEBUG_FLOW
log(LOG_WARNING, "si_send: not an Atalk nor AARP...\n");
#endif
return(0);
}
return(0);
}
int
atalk_stop(struct blueCtlBlock *ifb)
{
int retval = 0;
if (ifb == NULL)
return(0);
ifb->atalk_stopping = 1;
if (ifb->atalk_proto_filter_id) {
#if SIP_DEBUG
log(LOG_WARNING, "atalk_stop: deregister AppleTalk proto filter tag=%d\n",
ifb->atalk_proto_filter_id);
#endif
retval = dlil_detach_filter(ifb->atalk_proto_filter_id);
ether_detach_at(ndrv_get_ifp(ifb->ifb_so->so_pcb));
}
ifb->atalk_stopping = 0;
return(retval);
}
int atalk_detach(caddr_t cookie)
{
struct blueCtlBlock *ifb = (struct blueCtlBlock*)cookie;
ifb->atalk_proto_filter_id = 0;
if (!ifb->atalk_stopping)
{
atalk_stop(ifb);
}
return 0;
}