#if EON
#define NEON 1
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/buf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/if_dl.h>
#include <net/netisr.h>
#include <net/route.h>
#include <machine/mtpr.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/if_ether.h>
#include <netiso/iso.h>
#include <netiso/iso_var.h>
#include <netiso/iso_snpac.h>
#include <netiso/argo_debug.h>
#include <netiso/iso_errno.h>
#include <netiso/eonvar.h>
extern struct timeval time;
extern struct ifnet loif;
#define EOK 0
int eoninput();
int eonoutput();
int eonioctl();
int eonattach();
int eoninit();
void eonrtrequest();
struct ifnet eonif[1];
eonprotoinit() {
(void) eonattach();
}
struct eon_llinfo eon_llinfo;
#define PROBE_OK 0;
eonattach()
{
register struct ifnet *ifp = eonif;
IFDEBUG(D_EON)
printf("eonattach()\n");
ENDDEBUG
ifp->if_unit = 0;
ifp->if_name = "eon";
ifp->if_mtu = ETHERMTU;
ifp->if_init = eoninit;
ifp->if_ioctl = eonioctl;
ifp->if_output = eonoutput;
ifp->if_type = IFT_EON;
ifp->if_addrlen = 5;
ifp->if_hdrlen = EONIPLEN;
ifp->if_flags = IFF_BROADCAST;
if_attach(ifp);
eonioctl(ifp, SIOCSIFADDR, (caddr_t)ifp->if_addrlist);
eon_llinfo.el_qhdr.link =
eon_llinfo.el_qhdr.rlink = &(eon_llinfo.el_qhdr);
IFDEBUG(D_EON)
printf("eonattach()\n");
ENDDEBUG
}
eonioctl(ifp, cmd, data)
register struct ifnet *ifp;
int cmd;
register caddr_t data;
{
int s = splimp();
register int error = 0;
IFDEBUG(D_EON)
printf("eonioctl (cmd 0x%x) \n", cmd);
ENDDEBUG
switch (cmd) {
register struct ifaddr *ifa;
case SIOCSIFADDR:
if (ifa = (struct ifaddr *)data) {
ifp->if_flags |= IFF_UP;
if (ifa->ifa_addr->sa_family != AF_LINK)
ifa->ifa_rtrequest = eonrtrequest;
}
break;
}
splx(s);
return(error);
}
eoniphdr(hdr, loc, ro, class, zero)
struct route *ro;
register struct eon_iphdr *hdr;
caddr_t loc;
{
struct mbuf mhead;
register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst;
if (zero) {
bzero((caddr_t)hdr, sizeof (*hdr));
bzero((caddr_t)ro, sizeof (*ro));
}
sin->sin_family = AF_INET;
sin->sin_len = sizeof (*sin);
bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr));
if (ro->ro_rt) {
struct sockaddr_in *dst =
(struct sockaddr_in *)rt_key(ro->ro_rt);
if ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
sin->sin_addr.s_addr != dst->sin_addr.s_addr) {
RTFREE(ro->ro_rt);
ro->ro_rt = (struct rtentry *)0;
}
}
rtalloc(ro);
if (ro->ro_rt)
ro->ro_rt->rt_use++;
hdr->ei_ip.ip_dst = sin->sin_addr;
hdr->ei_ip.ip_p = IPPROTO_EON;
hdr->ei_ip.ip_ttl = MAXTTL;
hdr->ei_eh.eonh_class = class;
hdr->ei_eh.eonh_vers = EON_VERSION;
hdr->ei_eh.eonh_csum = 0;
mhead.m_data = (caddr_t) &hdr->ei_eh;
mhead.m_len = sizeof(struct eon_hdr);
mhead.m_next = 0;
IFDEBUG(D_EON)
printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n",
&mhead,
_offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
ENDDEBUG
iso_gen_csum(&mhead,
_offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
}
void
eonrtrequest(cmd, rt, gate)
register struct rtentry *rt;
register struct sockaddr *gate;
{
unsigned long zerodst = 0;
caddr_t ipaddrloc = (caddr_t) &zerodst;
register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo;
switch (cmd) {
case RTM_DELETE:
if (el) {
remque(&(el->el_qhdr));
if (el->el_iproute.ro_rt)
RTFREE(el->el_iproute.ro_rt);
Free(el);
rt->rt_llinfo = 0;
}
return;
case RTM_ADD:
case RTM_RESOLVE:
rt->rt_rmx.rmx_mtu = loif.if_mtu;
R_Malloc(el, struct eon_llinfo *, sizeof(*el));
rt->rt_llinfo = (caddr_t)el;
if (el == 0)
return;
Bzero(el, sizeof(*el));
insque(&(el->el_qhdr), &eon_llinfo.el_qhdr);
el->el_rt = rt;
break;
}
if (gate || (gate = rt->rt_gateway)) switch (gate->sa_family) {
case AF_LINK:
#define SDL(x) ((struct sockaddr_dl *)x)
if (SDL(gate)->sdl_alen == 1)
el->el_snpaoffset = *(u_char *)LLADDR(SDL(gate));
else
ipaddrloc = LLADDR(SDL(gate));
break;
case AF_INET:
#define SIN(x) ((struct sockaddr_in *)x)
ipaddrloc = (caddr_t) &SIN(gate)->sin_addr;
break;
default:
return;
}
el->el_flags |= RTF_UP;
eoniphdr(&el->el_ei, ipaddrloc, &el->el_iproute, EON_NORMAL_ADDR, 0);
if (el->el_iproute.ro_rt)
rt->rt_rmx.rmx_mtu = el->el_iproute.ro_rt->rt_rmx.rmx_mtu
- sizeof(el->el_ei);
}
eoninit(unit)
int unit;
{
printf("eon driver-init eon%d\n", unit);
}
eonoutput(ifp, m, dst, rt)
struct ifnet *ifp;
register struct mbuf *m;
struct sockaddr_iso *dst;
struct rtentry *rt;
{
register struct eon_llinfo *el;
register struct eon_iphdr *ei;
struct route *ro;
int datalen;
struct mbuf *mh;
int error = 0, class = 0, alen = 0;
caddr_t ipaddrloc;
static struct eon_iphdr eon_iphdr;
static struct route route;
IFDEBUG(D_EON)
printf("eonoutput \n" );
ENDDEBUG
ifp->if_lastchange = time;
ifp->if_opackets++;
if (rt == 0 || (el = (struct eon_llinfo *)rt->rt_llinfo) == 0) {
if (dst->siso_family == AF_LINK) {
register struct sockaddr_dl *sdl = (struct sockaddr_dl *)dst;
ipaddrloc = LLADDR(sdl);
alen = sdl->sdl_alen;
} else if (dst->siso_family == AF_ISO && dst->siso_data[0] == AFI_SNA) {
alen = dst->siso_nlen - 1;
ipaddrloc = (caddr_t) dst->siso_data + 1;
}
switch (alen) {
case 5:
class = 4[(u_char *)ipaddrloc];
case 4:
ro = &route;
ei = &eon_iphdr;
eoniphdr(ei, ipaddrloc, ro, class, 1);
goto send;
}
einval:
error = EINVAL;
goto flush;
}
if ((el->el_flags & RTF_UP) == 0) {
eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0);
if ((el->el_flags & RTF_UP) == 0) {
error = EHOSTUNREACH;
goto flush;
}
}
if ((m->m_flags & M_PKTHDR) == 0) {
printf("eon: got non headered packet\n");
goto einval;
}
ei = &el->el_ei;
ro = &el->el_iproute;
if (el->el_snpaoffset) {
if (dst->siso_family == AF_ISO) {
bcopy((caddr_t) &dst->siso_data[el->el_snpaoffset],
(caddr_t) &ei->ei_ip.ip_dst, sizeof(ei->ei_ip.ip_dst));
} else
goto einval;
}
send:
datalen = m->m_pkthdr.len + EONIPLEN;
MGETHDR(mh, M_DONTWAIT, MT_HEADER);
if(mh == (struct mbuf *)0)
goto flush;
mh->m_next = m;
m = mh;
MH_ALIGN(m, sizeof(struct eon_iphdr));
m->m_len = sizeof(struct eon_iphdr);
ifp->if_obytes +=
(ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen));
*mtod(m, struct eon_iphdr *) = *ei;
IFDEBUG(D_EON)
printf("eonoutput dst ip addr : %x\n", ei->ei_ip.ip_dst.s_addr);
printf("eonoutput ip_output : eonip header:\n");
dump_buf(ei, sizeof(struct eon_iphdr));
ENDDEBUG
error = ip_output(m, (struct mbuf *)0, ro, 0, NULL);
m = 0;
if (error) {
ifp->if_oerrors++;
ifp->if_opackets--;
ifp->if_obytes -= datalen;
}
flush:
if (m)
m_freem(m);
return error;
}
eoninput(m, iphlen)
register struct mbuf *m;
int iphlen;
{
register struct eon_hdr *eonhdr;
register struct ip *iphdr;
struct ifnet *eonifp;
int s;
eonifp = &eonif[0];
IFDEBUG(D_EON)
printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n",
m, m?m->m_data:0, m?m->m_len:0);
ENDDEBUG
if (m == 0)
return;
if (iphlen > sizeof (struct ip))
ip_stripoptions(m, (struct mbuf *)0);
if (m->m_len < EONIPLEN) {
if ((m = m_pullup(m, EONIPLEN)) == 0) {
IncStat(es_badhdr);
drop:
IFDEBUG(D_EON)
printf("eoninput: DROP \n" );
ENDDEBUG
eonifp->if_ierrors ++;
m_freem(m);
return;
}
}
eonif->if_ibytes += m->m_pkthdr.len;
eonif->if_lastchange = time;
iphdr = mtod(m, struct ip *);
if( iphdr->ip_p != IPPROTO_EON ) {
IncStat(es_badhdr);
goto drop;
}
m->m_data += sizeof(struct ip);
eonhdr = mtod(m, struct eon_hdr *);
if( iso_check_csum( m, sizeof(struct eon_hdr) ) != EOK ) {
IncStat(es_badcsum);
goto drop;
}
m->m_data -= sizeof(struct ip);
IFDEBUG(D_EON)
printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class );
printf("eoninput: eon header:\n");
dump_buf(eonhdr, sizeof(struct eon_hdr));
ENDDEBUG
if( eonhdr->eonh_vers != EON_VERSION) {
IncStat(es_badhdr);
goto drop;
}
m->m_flags &= ~(M_BCAST|M_MCAST);
switch( eonhdr->eonh_class) {
case EON_BROADCAST:
IncStat(es_in_broad);
m->m_flags |= M_BCAST;
break;
case EON_NORMAL_ADDR:
IncStat(es_in_normal);
break;
case EON_MULTICAST_ES:
IncStat(es_in_multi_es);
m->m_flags |= M_MCAST;
break;
case EON_MULTICAST_IS:
IncStat(es_in_multi_is);
m->m_flags |= M_MCAST;
break;
}
eonifp->if_ipackets++;
{
struct ifqueue *ifq;
extern struct ifqueue clnlintrq;
m->m_pkthdr.rcvif = eonifp;
IFDEBUG(D_EON)
printf("eoninput to clnl IFQ\n");
ENDDEBUG
ifq = &clnlintrq;
s = splimp();
if (IF_QFULL(ifq)) {
IF_DROP(ifq);
m_freem(m);
eonifp->if_iqdrops++;
eonifp->if_ipackets--;
splx(s);
return;
}
IF_ENQUEUE(ifq, m);
IFDEBUG(D_EON)
printf(
"0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n",
m, m->m_len, m->m_type, m->m_data);
dump_buf(mtod(m, caddr_t), m->m_len);
ENDDEBUG
schednetisr(NETISR_ISO);
splx(s);
}
}
int
eonctlinput(cmd, sin)
int cmd;
struct sockaddr_in *sin;
{
extern u_char inetctlerrmap[];
IFDEBUG(D_EON)
printf("eonctlinput: cmd 0x%x addr: ", cmd);
dump_isoaddr(sin);
printf("\n");
ENDDEBUG
if (cmd < 0 || cmd > PRC_NCMDS)
return 0;
IncStat(es_icmp[cmd]);
switch (cmd) {
case PRC_QUENCH:
case PRC_QUENCH2:
break;
case PRC_TIMXCEED_REASS:
case PRC_ROUTEDEAD:
case PRC_HOSTUNREACH:
case PRC_UNREACH_NET:
case PRC_IFDOWN:
case PRC_UNREACH_HOST:
case PRC_HOSTDEAD:
case PRC_TIMXCEED_INTRANS:
break;
case PRC_UNREACH_PROTOCOL:
case PRC_UNREACH_PORT:
case PRC_UNREACH_SRCFAIL:
case PRC_REDIRECT_NET:
case PRC_REDIRECT_HOST:
case PRC_REDIRECT_TOSNET:
case PRC_REDIRECT_TOSHOST:
case PRC_MSGSIZE:
case PRC_PARAMPROB:
break;
}
return 0;
}
#endif