firewire_inet_pr_module.cpp [plain text]
#ifndef INET
#define INET 1
#endif
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 <sys/sysctl.h>
#include <net/dlil.h>
#include <net/if.h>
#include <net/route.h>
#include <net/if_llc.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/kpi_protocol.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_arp.h>
#include <sys/socketvar.h>
#include "firewire.h"
#include "if_firewire.h"
}
#include "IOFireWireIP.h"
extern void firewire_arpintr __P((mbuf_t m));
extern errno_t firewire_inet_arp __P((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));
extern void firewire_inet_event __P((ifnet_t ifp,
__unused protocol_family_t protocol,
const struct kev_msg *event));
static errno_t
inet_firewire_input(
__unused ifnet_t ifp,
__unused protocol_family_t protocol_family,
mbuf_t m,
char *frame_header)
{
struct firewire_header *eh = (struct firewire_header *)frame_header;
u_short fw_type;
ifnet_touch_lastchange(ifp);
fw_type = ntohs(eh->fw_type);
switch (fw_type)
{
case FWTYPE_IP:
{
mbuf_pullup(&m, sizeof(struct ip));
if (m == NULL)
return EJUSTRETURN;
errno_t ret = proto_input(PF_INET, m);
if( ret )
mbuf_freem(m);
return ret;
}
case FWTYPE_ARP:
firewire_arpintr(m);
break;
default:
return ENOENT;
}
return 0;
}
int
inet_firewire_pre_output(
ifnet_t interface,
__unused protocol_family_t protocol_family,
mbuf_t *m0,
const struct sockaddr *dst_netaddr,
void* route,
char *type,
char *edst)
{
mbuf_t m = *m0;
errno_t result = 0;
if ((ifnet_flags(interface) & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
return ENETDOWN;
mbuf_setflags(m, mbuf_flags(m) | MBUF_LOOP);
switch (dst_netaddr->sa_family)
{
case AF_INET:
{
struct sockaddr_dl ll_dest;
result = inet_arp_lookup(interface, (const struct sockaddr_in*)dst_netaddr,
&ll_dest, sizeof(ll_dest), (route_t)route, *m0);
if (result == 0)
{
bcopy(LLADDR(&ll_dest), edst, FIREWIRE_ADDR_LEN);
*(u_int16_t*)type = htons(FWTYPE_IP);
}
}
break;
case AF_UNSPEC:
{
mbuf_setflags(m, mbuf_flags(m) & ~MBUF_LOOP);
register struct firewire_header *fwh = (struct firewire_header *)dst_netaddr->sa_data;
(void)memcpy(edst, fwh->fw_dhost, FIREWIRE_ADDR_LEN);
*(u_short *)type = fwh->fw_type;
}
break;
default:
return EAFNOSUPPORT;
}
return result;
}
static errno_t
firewire_inet_prmod_ioctl(
__unused ifnet_t ifp,
__unused protocol_family_t protocol_family,
__unused unsigned long command,
__unused void* data)
{
return EOPNOTSUPP;
}
static errno_t
firewire_inet_resolve_multi(
ifnet_t ifp,
const struct sockaddr *proto_addr,
struct sockaddr_dl *out_ll,
size_t ll_len)
{
static const size_t minsize = offsetof(struct sockaddr_dl, sdl_data[0]) + FIREWIRE_ADDR_LEN;
const struct sockaddr_in *sin = (const struct sockaddr_in*)proto_addr;
if (proto_addr->sa_family != AF_INET)
return EAFNOSUPPORT;
if (proto_addr->sa_len < sizeof(struct sockaddr_in))
return EINVAL;
if (ll_len < minsize)
return EMSGSIZE;
bzero(out_ll, minsize);
out_ll->sdl_len = minsize;
out_ll->sdl_family = AF_LINK;
out_ll->sdl_index = ifnet_index(ifp);
out_ll->sdl_type = IFT_IEEE1394;
out_ll->sdl_nlen = 0;
out_ll->sdl_alen = FIREWIRE_ADDR_LEN;
out_ll->sdl_slen = 0;
FIREWIRE_MAP_IP_MULTICAST(&sin->sin_addr, LLADDR(out_ll));
return 0;
}
int
firewire_attach_inet(ifnet_t ifp, protocol_family_t protocol_family)
{
struct ifnet_attach_proto_param proto;
struct ifnet_demux_desc demux[2];
u_short en_native=htons(FWTYPE_IP);
u_short arp_native=htons(FWTYPE_ARP);
errno_t error;
bzero(&demux[0], sizeof(demux));
demux[0].type = DLIL_DESC_ETYPE2;
demux[0].data = &en_native;
demux[0].datalen = sizeof(en_native);
demux[1].type = DLIL_DESC_ETYPE2;
demux[1].data = &arp_native;
demux[1].datalen = sizeof(arp_native);
bzero(&proto, sizeof(proto));
proto.demux_list = demux;
proto.demux_count = sizeof(demux) / sizeof(demux[0]);
proto.input = inet_firewire_input;
proto.pre_output = inet_firewire_pre_output;
proto.ioctl = firewire_inet_prmod_ioctl;
proto.event = firewire_inet_event;
proto.resolve = firewire_inet_resolve_multi;
proto.send_arp = firewire_inet_arp;
error = ifnet_attach_protocol(ifp, protocol_family, &proto);
if (error && error != EEXIST)
{
printf("WARNING: firewire_attach_inet can't attach ip to %s%d\n",
ifnet_name(ifp), ifnet_unit(ifp));
}
return error;
}