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 <sys/syslog.h>
#include <net/if.h>
#include <net/netisr.h>
#include <net/route.h>
#include <net/if_llc.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/if_ether.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socketvar.h>
#include <net/dlil.h>
#include "firewire.h"
#include "if_firewire.h"
extern void ipintr(void);
}
#include "IOFireWireIP.h"
#if BRIDGE
#include <net/bridge.h>
#endif
#if NVLAN > 0
#include <net/if_vlan_var.h>
#endif
#define IFP2AC(IFP) ((struct arpcom *)IFP)
extern void firewire_arpintr __P((struct mbuf *));
extern int firewire_arpresolve __P((struct arpcom *, struct rtentry *, struct mbuf *,
struct sockaddr *, u_char *, struct rtentry *));
int
inet_firewire_input(struct mbuf *m, char *frame_header, struct ifnet *ifp, u_long dl_tag, int sync_ok)
{
register struct firewire_header *eh = (struct firewire_header *) frame_header;
register struct ifqueue *inq=0;
u_short ether_type;
int s;
u_int16_t ptype = 0;
if ((ifp->if_flags & IFF_UP) == 0) {
m_freem(m);
return EJUSTRETURN;
}
getmicrotime(&ifp->if_lastchange);
if (m->m_flags & (M_BCAST|M_MCAST))
ifp->if_imcasts++;
ether_type = ntohs(eh->ether_type);
switch (ether_type) {
case ETHERTYPE_IP:
if (ipflow_fastforward(m))
return EJUSTRETURN;
ptype = mtod(m, struct ip *)->ip_p;
if ((sync_ok == 0) || (ptype != IPPROTO_TCP && ptype != IPPROTO_UDP))
{
schednetisr(NETISR_IP);
}
inq = &ipintrq;
break;
case ETHERTYPE_ARP:
firewire_arpintr(m);
inq = 0;
return 0;
default: {
return ENOENT;
}
}
if (inq == 0)
return ENOENT;
s = splimp();
if (IF_QFULL(inq))
{
IF_DROP(inq);
m_freem(m);
splx(s);
return EJUSTRETURN;
} else
IF_ENQUEUE(inq, m);
splx(s);
if ((sync_ok) && (ptype == IPPROTO_TCP || ptype == IPPROTO_UDP))
{
s = splnet();
ipintr();
splx(s);
}
return 0;
}
int
inet_firewire_pre_output(struct ifnet *ifp, struct mbuf **m0, struct sockaddr *dst_netaddr,
caddr_t route, char *type, char *edst, u_long dl_tag)
{
struct rtentry *rt0 = (struct rtentry *) route;
register struct mbuf *m = *m0;
register struct rtentry *rt;
register struct firewire_header *eh;
int off ; struct arpcom *ac = IFP2AC(ifp);
if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
{
return ENETDOWN;
}
rt = rt0;
if (rt) {
if ((rt->rt_flags & RTF_UP) == 0) {
rt0 = rt = rtalloc1(dst_netaddr, 1, 0UL);
if (rt0)
rtunref(rt);
else{
return EHOSTUNREACH;
}
}
if (rt->rt_flags & RTF_GATEWAY) {
if (rt->rt_gwroute == 0)
goto lookup;
if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
rtfree(rt); rt = rt0;
lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL);
if ((rt = rt->rt_gwroute) == 0) {
return (EHOSTUNREACH);
}
}
}
if (rt->rt_flags & RTF_REJECT)
if (rt->rt_rmx.rmx_expire == 0 || (u_long)time_second < rt->rt_rmx.rmx_expire) {
return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
}
}
m->m_flags |= M_LOOP;
switch (dst_netaddr->sa_family) {
case AF_INET:
if (!firewire_arpresolve(ac, rt, m, dst_netaddr, (u_char*)edst, rt0))
return (EJUSTRETURN); off = m->m_pkthdr.len - m->m_len;
*(u_short *)type = htons(ETHERTYPE_IP);
break;
case AF_UNSPEC:
m->m_flags &= ~M_LOOP;
eh = (struct firewire_header *)dst_netaddr->sa_data;
(void)memcpy(edst, eh->ether_dhost, FIREWIRE_ADDR_LEN);
*(u_short *)type = eh->ether_type;
break;
default:
log(LOG_DEBUG,"%s%d: can't handle af%d\n", ifp->if_name,
ifp->if_unit, dst_netaddr->sa_family);
return EAFNOSUPPORT;
}
return (0);
}
int
firewire_inet_prmod_ioctl(u_long dl_tag, struct ifnet *ifp, long unsigned int command, caddr_t data)
{
int error = EOPNOTSUPP;
return (error);
}
int
firewire_attach_inet(struct ifnet *ifp, u_long *dl_tag)
{
struct dlil_proto_reg_str reg;
struct dlil_demux_desc desc;
struct dlil_demux_desc desc2;
u_long ip_dl_tag = 0;
u_short en_native = ETHERTYPE_IP;
u_short arp_native = ETHERTYPE_ARP;
int stat;
stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, PF_INET, &ip_dl_tag);
if (stat == 0)
{
*dl_tag = ip_dl_tag;
return stat;
}
bzero(®, sizeof(struct dlil_proto_reg_str));
TAILQ_INIT(®.demux_desc_head);
desc.type = DLIL_DESC_RAW;
desc.variants.bitmask.proto_id_length = 0;
desc.variants.bitmask.proto_id = 0;
desc.variants.bitmask.proto_id_mask = 0;
desc.native_type = (u_char*)&en_native;
TAILQ_INSERT_TAIL(®.demux_desc_head, &desc, next);
reg.interface_family = ifp->if_family;
reg.unit_number = ifp->if_unit;
reg.input = inet_firewire_input;
reg.pre_output = inet_firewire_pre_output;
reg.event = 0;
reg.offer = 0;
reg.ioctl = firewire_inet_prmod_ioctl;
reg.default_proto = 1;
reg.protocol_family = PF_INET;
desc2 = desc;
desc2.native_type = (u_char *) &arp_native;
TAILQ_INSERT_TAIL(®.demux_desc_head, &desc2, next);
stat = dlil_attach_protocol(®, &ip_dl_tag);
if(stat)
{
log(LOG_DEBUG,"WARNING: firewire_attach_inet can't attach ip to interface %d PF %x IF %x\n",
stat, reg.protocol_family, reg.interface_family);
return stat;
}
*dl_tag = ip_dl_tag;
return stat;
}
int firewire_detach_inet(struct ifnet *ifp, u_long dl_tag)
{
int stat;
#ifdef FIREWIRETODO
stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, PF_INET, &ip_dl_tag);
if (stat == 0)
{
#endif
stat = dlil_detach_protocol(dl_tag);
if (stat)
{
kprintf("WARNING: firewire_detach_inet can't detach ip from interface\n");
}
#ifdef FIREWIRETODO
}
#endif
return stat;
}