IOFWEthernetShim.cpp [plain text]
extern "C"{
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/dlil.h>
#include <sys/syslog.h>
#include <sys/socketvar.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/if_ether.h>
#include <net/ethernet.h>
extern void _logMbuf(struct mbuf * m);
}
#include <IOKit/firewire/IOFireWireDevice.h>
#include "IOFWEthernetShim.h"
extern const OSSymbol *gFireWireVendor_ID;
UInt8 vbits[3] = {0x00, 0x54, 0x04};
extern UInt8 bcastAddr[];
OSDefineMetaClassAndStructors(IOFWEthernetShim, OSObject);
OSMetaClassDefineReservedUnused(IOFWEthernetShim, 0);
OSMetaClassDefineReservedUnused(IOFWEthernetShim, 1);
bool IOFWEthernetShim::initAll(IOFireWireIP *provider, LCB *lcb)
{
fwIpObj = provider;
fLcb = lcb;
broadcastHandle = (TNF_HANDLE*)IOMalloc(sizeof(TNF_HANDLE));
fwIpObj->fwResolve(fLcb, M_BCAST, NULL, broadcastHandle, NULL);
fwMemHandles = (UInt8*)IOMalloc(sizeof(FW_INDEX) * MAX_FW_HANDLE_INDEX);
fMemIndex = 0;
return true;
}
void IOFWEthernetShim::free()
{
if(fwMemHandles){
IOFree(fwMemHandles, (sizeof(FW_INDEX) * MAX_FW_HANDLE_INDEX));
fwMemHandles = NULL;
}
if(broadcastHandle){
IOFree(broadcastHandle, sizeof(TNF_HANDLE));
broadcastHandle = NULL;
}
OSObject::free();
return;
}
UInt32 IOFWEthernetShim::getFwIndex(UInt32 idx)
{
if(idx > MAX_FW_HANDLE_INDEX)
return NULL;
return (ULONG)(fwMemHandles + (sizeof(FW_INDEX)*idx));
}
UInt32 IOFWEthernetShim::getNextFwIndex(UInt32 *idx)
{
if(fMemIndex >= MAX_FW_HANDLE_INDEX)
fMemIndex = 0;
*idx = fMemIndex;
return (ULONG)(fwMemHandles + (sizeof(FW_INDEX)*fMemIndex++));
}
void* IOFWEthernetShim::fwIndexExists(TNF_HANDLE *handle, UInt32 *index)
{
FW_INDEX *fwi;
UInt32 idx = 0;
for(idx = 0;idx <= MAX_FW_HANDLE_INDEX; idx++)
{
fwi = (FW_INDEX *)(fwMemHandles + (sizeof(FW_INDEX)*idx));
if(fwi->handle == handle)
{
*index = idx;
return ((void*)fwi);
}
}
return NULL;
}
IOReturn IOFWEthernetShim::sendPacket(
struct mbuf *m,
void *reserved)
{
register ethshimheader *eh = NULL;
int status = kIOReturnSuccess;
eh = mtod(m, ethshimheader*);
if(eh == NULL)
return kIOReturnError;
switch(htons(eh->frametype))
{
case ETHERTYPE_ARP:
status = sendArpPacket(m);
fwIpObj->freePacket(m);
break;
case ETHERTYPE_IP:
status = sendIPPacket(m);
break;
default :
fwIpObj->freePacket(m);
break;
}
return status;
}
IOReturn IOFWEthernetShim::sendArpPacket(struct mbuf *m)
{
arpshimpkt *arphdr = NULL;
UInt32 status = kIOReturnSuccess;
vm_address_t src;
src = mtod(m, vm_offset_t);
if(src == NULL)
return kIOReturnError;
arphdr = (arpshimpkt*)(src + sizeof(firewire_header));
switch(htons(arphdr->ar_op))
{
case ARP_REQUEST:
status = txArpRequest(m);
break;
case ARP_RESPONSE:
txArpResponse(NULL, 0);
break;
}
return status;
}
IOReturn IOFWEthernetShim::txArpRequest(struct mbuf *m)
{
arpshimpkt* arphdr = NULL;
UInt8 flags = 0;
UInt8 *bytePtr = NULL;
UInt32 cmdLen = 0;
ARP_HOLD arpHold;
SOCKADDR_IN socket;
UInt32 status = kIOReturnError;
ARB *arb;
vm_address_t src;
src = mtod(m, vm_offset_t);
if(src == NULL)
return kIOReturnError;
cmdLen = m->m_pkthdr.len;
arphdr = (arpshimpkt*)(src + sizeof(firewire_header));
bzero(&socket, sizeof(SOCKADDR_IN));
socket.sin_family = 0;
socket.sin_len = sizeof(SOCKADDR_IN);
if (bcmp(arphdr->arp_tpa, arphdr->arp_spa, IP_ADDR_LEN) == 0)
{
bytePtr = (UInt8*)&fLcb->ownIpAddress;
bcopy(arphdr->arp_tpa, bytePtr, 4);
}
if (bcmp(arphdr->arp_tpa, "0x00000000", IP_ADDR_LEN) != 0)
{
bcopy((void*)arphdr->arp_tpa, (void*)&socket.sin_addr, IP_ADDR_LEN);
}
arpHold.callback = NULL; arpHold.socket = (void*)cmdLen;
arpHold.passThru1 = fwIpObj;
arpHold.passThru2 = NULL;
if((arb = fwIpObj->getUnicastArb(fLcb, socket.sin_addr)) == NULL)
{
arpHold.ipDatagram = IOMalloc(cmdLen);
if(arpHold.ipDatagram == NULL)
return status;
bcopy((void*)src, arpHold.ipDatagram, cmdLen);
if((arb = (ARB*)fwIpObj->allocateCBlk(fLcb)) == NULL)
return status;
arb->ipAddress = socket.sin_addr;
arb->datagramPending = TRUE;
memcpy(&arb->arpHold, &arpHold, sizeof(ARP_HOLD));
fwIpObj->linkCBlk(&fLcb->unicastArb, arb);
fwIpObj->txFwARP(fLcb, ARP_REQUEST, arb->ipAddress, 0);
status = kIOReturnSuccess;
}
else
{
if(arb->arpHold.ipDatagram == NULL)
{
arpHold.ipDatagram = IOMalloc(cmdLen);
bcopy((void*)src, arpHold.ipDatagram, cmdLen);
}
else
{
arpHold.ipDatagram = arb->arpHold.ipDatagram;
}
status = fwIpObj->fwResolve(fLcb, flags, &socket, &arb->handle, &arpHold);
if(status == 1)
{
arpCallback(arpHold.ipDatagram, arpHold.socket, arpHold.passThru1,
&arb->handle);
status = kIOReturnSuccess;
}
}
return status;
}
IOReturn IOFWEthernetShim::sendIPPacket(struct mbuf *m)
{
ethshimheader *eh = NULL;
IOReturn status = kIOReturnError;
eh = mtod(m, ethshimheader*);
if(eh == NULL)
return status;
if(bcmp(eh->dstaddr, vbits, 3) == 0)
{
status = sendUnicastPacket(m);
}
else
{
status = sendMulticastPacket(m);
}
return status;
}
IOReturn IOFWEthernetShim::sendMulticastPacket(struct mbuf *m)
{
ipshimhdr *iphdr = NULL;
ARB *mcarb = NULL;
SOCKADDR_IN socket;
ARP_HOLD arpHold;
IOReturn status = kIOReturnError;
vm_address_t src;
struct mbuf *temp;
src = mtod(m, vm_offset_t);
if(src == NULL)
return status;
if(m->m_len == sizeof(firewire_header))
{
temp = m->m_next;
if(temp == NULL)
return status;
src = mtod(temp, vm_offset_t);
if(temp->m_len < (int)sizeof(ipshimhdr))
return status;
iphdr = (ipshimhdr*)(src);
}
else
{
iphdr = (ipshimhdr*)(src + sizeof(firewire_header));
}
bzero(&socket, sizeof(SOCKADDR_IN));
socket.sin_family = 0;
socket.sin_len = sizeof(SOCKADDR_IN);
mcarb = fwIpObj->getMulticastArb(fLcb, iphdr->ip_dst);
if(mcarb == NULL)
{
if ((mcarb = (ARB*)fwIpObj->allocateCBlk(fLcb)) == NULL)
{
IOLog("No CBLK available for new entry in MCAP cache\n");
return status; }
mcarb->ipAddress = iphdr->ip_dst;
socket.sin_addr = iphdr->ip_dst;
fwIpObj->fwResolve(fLcb, M_MCAST, &socket, &mcarb->handle, &arpHold);
fwIpObj->linkCBlk(&fLcb->multicastArb, mcarb);
fwIpObj->txMCAP(fLcb, NULL, mcarb->handle.multicast.groupAddress);
}
status = fwIpObj->txIP(NULL, m, &mcarb->handle);
return status;
}
IOReturn IOFWEthernetShim::sendUnicastPacket(struct mbuf *m)
{
ethshimheader *eh = NULL;
UInt32 handle = 0;
V_MACADDR *vMacAddr = NULL;
FW_INDEX *fwIdx = NULL;
eh = mtod(m, ethshimheader*);
if(eh == NULL)
return kIOReturnError;
if(bcmp(eh->dstaddr, vbits, 3) == 0)
{
vMacAddr = (V_MACADDR*)eh->dstaddr;
fwIdx = (FW_INDEX*)getFwIndex(vMacAddr->idx);
handle = (UInt32)((fwIdx != NULL && fwIdx->handle != NULL) ?
fwIdx->handle: broadcastHandle);
}
else
{
handle = (UInt32)broadcastHandle;
}
return (fwIpObj->txIP(NULL, m, (void*)handle));
}
void IOFWEthernetShim::arpCallback(void* pFrame, void* param2, void* param3, void* param4)
{
UInt32 cmdLen = (UInt32)param2;
UInt8 srcaddr[IP_ADDR_LEN];
TNF_HANDLE *pHandle;
ethshimheader *eh;
arpshimpkt *arphdr;
struct mbuf *rxMBuf;
FW_INDEX *fwIndex = NULL;
UInt32 idx = 0;
V_MACADDR *vMacAddr = NULL;
#ifdef FIREWIRETODO
DRB *drb = NULL;
IOFireWireDevice *fDevice = NULL;
OSObject *prop;
char tempAddr[FIREWIRE_ADDR_LEN];
#endif
if ((rxMBuf = fwIpObj->getMBuf(cmdLen)) != NULL) {
memcpy(rxMBuf->m_data, pFrame, rxMBuf->m_pkthdr.len = rxMBuf->m_len = cmdLen);
eh = (ethshimheader*)rxMBuf->m_data;
eh->frametype = ETHERTYPE_ARP;
bcopy(bcastAddr, eh->dstaddr, ETH_ADDR_LEN);
arphdr = (arpshimpkt*)(rxMBuf->m_data + sizeof(firewire_header));
pHandle = (TNF_HANDLE*)param4;
#ifdef FIREWIRETODO
drb = fwIpObj->getDrbFromDeviceID(fwIpObj->getLcb(), (void*)pHandle->unicast.deviceID);
if(drb == NULL)
{
IOLog("OOps, null drb !, ARP RESPONSE will be dropped\n");
return;
}
IOLog("Remote Device GUID = 0x%lx:0x%lx \n", drb->eui64.hi, drb->eui64.lo);
if(drb->deviceID == kInvalidIPDeviceRefID)
{
IOLog("Null deviceID, lets go home !\n");
return;
}
fDevice = (IOFireWireDevice*)drb->deviceID;
prop = fDevice->getProperty(gFireWireVendor_ID);
if(prop == 0)
{
IOLog("gFireWireVendor_ID property not found\n");
return;
}
OSNumber *num = OSDynamicCast(OSNumber, prop);
if(num != 0)
{
IOLog("Remote Device Vendor ID %d\n", num->unsigned32BitValue());
}
CSRNodeUniqueID fwuid = fDevice->getUniqueID();
fwIpObj->makeEthernetAddress(&fwuid, tempAddr, num->unsigned32BitValue());
IOLog("Remote Device Ethernet address %02x:%02x:%02x:%02x:%02x:%02x\n",
tempAddr[0],
tempAddr[1],
tempAddr[2],
tempAddr[5],
tempAddr[6],
tempAddr[7]);
#endif
fwIndex = (FW_INDEX*)fwIndexExists(pHandle, &idx);
if(fwIndex == NULL)
fwIndex = (FW_INDEX*)getNextFwIndex(&idx);
fwIndex->handle = pHandle;
bcopy(arphdr->arp_spa, srcaddr, IP_ADDR_LEN);
bcopy(arphdr->arp_tpa, arphdr->arp_spa, IP_ADDR_LEN);
bcopy(srcaddr, arphdr->arp_tpa, IP_ADDR_LEN);
vMacAddr = (V_MACADDR*)arphdr->arp_sha;
vMacAddr->vendor[0] = vbits[0];
vMacAddr->vendor[1] = vbits[1];
vMacAddr->vendor[2] = vbits[2];
vMacAddr->inst = (UInt8)fwIpObj->ourUnitNumber();
vMacAddr->idx = idx;
arphdr->ar_op = htons(ARP_RESPONSE);
fwIpObj->receivePackets(rxMBuf, rxMBuf->m_pkthdr.len, NULL);
}
}
void IOFWEthernetShim::txArpResponse(
UInt32 *ethBuffer,
UInt32 ethBufferLength)
{
}
void IOFWEthernetShim::recvArpPacket(
UInt32 *ethBuffer,
UInt32 ethBufferLength)
{
}
void IOFWEthernetShim::recvPacket(
UInt32 *ethBuffer,
UInt32 ethBufferLength)
{
}
void IOFWEthernetShim::recvIPPacket(
UInt32 *ethBuffer,
UInt32 ethBufferLength)
{
}