#ifndef INET
#define INET 1
#endif
extern "C"{
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/queue.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/syslog.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>
#include <net/dlil.h>
#include <net/if_llc.h>
#if BRIDGE
#include <net/ethernet.h>
#include <net/bridge.h>
#endif
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/in_arp.h>
}
extern "C"
{
#include "firewire.h"
#include "if_firewire.h"
}
#include "IOFireWireIP.h"
void firewire_arpintr __P((mbuf_t m));
u_char *firewire_sprintf __P((register u_char *p, register u_char *ap));
static void inet_firewire_arp_input __P((mbuf_t m));
void
firewire_arpintr(register mbuf_t m)
{
if (m == 0 || (mbuf_flags(m) & M_PKTHDR) == 0)
panic("arpintr");
inet_firewire_arp_input(m);
}
#if INET
errno_t
firewire_inet_arp(
ifnet_t ifp,
u_short arpop,
const struct sockaddr_dl* sender_hw,
const struct sockaddr* sender_proto,
const struct sockaddr_dl* target_hw,
const struct sockaddr* target_proto)
{
mbuf_t m;
errno_t result;
register struct firewire_header *fwh;
register IP1394_ARP *fwa;
const struct sockaddr_in* sender_ip = (const struct sockaddr_in*)sender_proto;
const struct sockaddr_in* target_ip = (const struct sockaddr_in*)target_proto;
char *datap;
IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp);
if(fwIf == NULL)
return EINVAL;
IOFireWireIP *fwIpObj = (IOFireWireIP*)fwIf->getController();
if(fwIpObj == NULL)
return EINVAL;
LCB *lcb = fwIpObj->getLcb();
if (target_ip == NULL)
return EINVAL;
if ((sender_ip && sender_ip->sin_family != AF_INET) ||
(target_ip && target_ip->sin_family != AF_INET))
return EAFNOSUPPORT;
result = mbuf_gethdr(M_DONTWAIT, MBUF_TYPE_DATA, &m);
if (result != 0)
return result;
mbuf_setlen(m, sizeof(*fwa));
mbuf_pkthdr_setlen(m, sizeof(*fwa));
datap = (char*)mbuf_datastart(m);
datap += mbuf_trailingspace(m);
datap -= (((u_long)datap) & 0x3);
mbuf_setdata(m, datap, sizeof(*fwa));
fwa = (IP1394_ARP*)mbuf_data(m);
bzero((caddr_t)fwa, sizeof(*fwa));
result = mbuf_prepend(&m, sizeof(*fwh), M_DONTWAIT);
if(result != 0)
return result;
fwh = (struct firewire_header*)mbuf_data(m);
fwh->fw_type = htons(FWTYPE_ARP);
fwa->hardwareType = htons(ARP_HDW_TYPE);
fwa->protocolType = htons(FWTYPE_IP);
fwa->hwAddrLen = sizeof(IP1394_HDW_ADDR);
fwa->ipAddrLen = IPV4_ADDR_SIZE;
fwa->opcode = htons(arpop);
fwa->senderMaxRec = lcb->ownHardwareAddress.maxRec;
fwa->sspd = lcb->ownHardwareAddress.spd;
fwa->senderUnicastFifoHi = htons(lcb->ownHardwareAddress.unicastFifoHi);
fwa->senderUnicastFifoLo = htonl(lcb->ownHardwareAddress.unicastFifoLo);
if (sender_hw != NULL)
bcopy(CONST_LLADDR(sender_hw), &fwa->senderUniqueID, sizeof(fwa->senderUniqueID));
else
ifnet_lladdr_copy_bytes(ifp, &fwa->senderUniqueID, FIREWIRE_ADDR_LEN);
ifnet_lladdr_copy_bytes(ifp, fwh->fw_shost, sizeof(fwh->fw_shost));
if (sender_ip != NULL)
fwa->senderIpAddress = sender_ip->sin_addr.s_addr;
else
{
ifaddr_t *addresses;
if (ifnet_get_address_list_family(ifp, &addresses, AF_INET) == 0)
{
fwa->senderIpAddress = ((sockaddr_in*)((ifaddr*)addresses[0])->ifa_addr)->sin_addr.s_addr; ifnet_free_address_list(addresses);
}
else
{
mbuf_free(m);
return ENXIO;
}
}
if (target_hw == 0)
bcopy(fwbroadcastaddr, fwh->fw_dhost, sizeof(fwh->fw_dhost));
else
bcopy(CONST_LLADDR(target_hw), fwh->fw_dhost, sizeof(fwh->fw_dhost));
fwa->targetIpAddress = target_ip->sin_addr.s_addr;
ifnet_output_raw(ifp, PF_INET, m);
return 0;
}
static void
inet_firewire_arp_input(
mbuf_t m)
{
IP1394_ARP *fwa;
struct sockaddr_dl sender_hw;
struct sockaddr_in sender_ip;
struct sockaddr_in target_ip;
ifnet_t ifp = mbuf_pkthdr_rcvif((mbuf_t)m);
IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp);
if(fwIf == NULL)
return;
IOFireWireIP *fwIpObj = (IOFireWireIP*)fwIf->getController();
if(fwIpObj == NULL)
return;
if (mbuf_len(m) < (int)sizeof(IP1394_ARP) &&
mbuf_pullup(&m, sizeof(IP1394_ARP)) != 0)
return;
fwa = (IP1394_ARP*)mbuf_data(m);
if (fwa->hardwareType != htons(ARP_HDW_TYPE) || fwa->protocolType != htons(FWTYPE_IP)
|| fwa->hwAddrLen != sizeof(IP1394_HDW_ADDR) || fwa->ipAddrLen != IPV4_ADDR_SIZE)
{
mbuf_free(m);
return;
}
bzero(&sender_ip, sizeof(sender_ip));
sender_ip.sin_len = sizeof(sender_ip);
sender_ip.sin_family = AF_INET;
sender_ip.sin_addr.s_addr = fwa->senderIpAddress;
target_ip = sender_ip;
target_ip.sin_addr.s_addr = fwa->targetIpAddress;
bzero(&sender_hw, sizeof(sender_hw));
sender_hw.sdl_len = sizeof(sender_hw);
sender_hw.sdl_family = AF_LINK;
sender_hw.sdl_type = IFT_IEEE1394;
sender_hw.sdl_alen = FIREWIRE_ADDR_LEN;
bcopy(&fwa->senderUniqueID, LLADDR(&sender_hw), FIREWIRE_ADDR_LEN);
if(fwIpObj->arpCacheHandler(fwa))
inet_arp_handle_input(ifp, ntohs(fwa->opcode), &sender_hw, &sender_ip, &target_ip);
mbuf_free((mbuf_t)m);
}
void
firewire_inet_event(
ifnet_t ifp,
__unused protocol_family_t protocol,
const struct kev_msg *event)
{
ifaddr_t *addresses;
if (event->vendor_code != KEV_VENDOR_APPLE ||
event->kev_class != KEV_NETWORK_CLASS ||
event->kev_subclass != KEV_DL_SUBCLASS ||
event->event_code != KEV_DL_LINK_ADDRESS_CHANGED)
return;
if (ifnet_get_address_list_family(ifp, &addresses, AF_INET) == 0)
{
int i;
for (i = 0; addresses[i] != NULL; i++)
inet_arp_init_ifaddr(ifp, addresses[i]);
ifnet_free_address_list(addresses);
}
}
#endif
static u_char digits[] = "0123456789abcdef";
u_char *
firewire_sprintf(register u_char *p, register u_char *ap)
{
register u_char *cp;
register int i;
for (cp = p, i = 0; i < 8; i++) {
*cp++ = digits[*ap >> 4];
*cp++ = digits[*ap++ & 0xf];
*cp++ = ':';
}
*--cp = 0;
return (p);
}