diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /sys/netiso/if_eon.c |
initial import of NetBSD tree
Diffstat (limited to 'sys/netiso/if_eon.c')
-rw-r--r-- | sys/netiso/if_eon.c | 588 |
1 files changed, 588 insertions, 0 deletions
diff --git a/sys/netiso/if_eon.c b/sys/netiso/if_eon.c new file mode 100644 index 00000000000..926cfec802f --- /dev/null +++ b/sys/netiso/if_eon.c @@ -0,0 +1,588 @@ +/* $NetBSD: if_eon.c,v 1.11 1995/06/13 07:13:28 mycroft Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_eon.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * EON rfc + * Layer between IP and CLNL + * + * TODO: + * Put together a current rfc986 address format and get the right offset + * for the nsel + */ + +#ifdef 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 <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(); +void eonrtrequest(); +struct ifnet eonif[1]; + +eonprotoinit() { + (void) eonattach(); +} + +struct eon_llinfo eon_llinfo; +#define PROBE_OK 0; + + +/* + * FUNCTION: eonattach + * + * PURPOSE: autoconf attach routine + * + * RETURNS: void + */ + +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; + /* since everything will go out over ether or token ring */ + + 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.tqh_first); + eon_llinfo.el_qhdr.link = + eon_llinfo.el_qhdr.rlink = &(eon_llinfo.el_qhdr); + + IFDEBUG(D_EON) + printf("eonattach()\n"); + ENDDEBUG +} + + +/* + * FUNCTION: eonioctl + * + * PURPOSE: io controls - ifconfig + * need commands to + * link-UP (core addr) (flags: ES, IS) + * link-DOWN (core addr) (flags: ES, IS) + * must be callable from kernel or user + * + * RETURNS: nothing + */ +eonioctl(ifp, cmd, data) + register struct ifnet *ifp; + u_long cmd; + register caddr_t data; +{ + int s = splimp(); + register int error = 0; + + IFDEBUG(D_EON) + printf("eonioctl (cmd 0x%lx) \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 = satosin(&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 there is a cached route, + * check that it is to the same destination + * and is still up. If not, free it and try again. + */ + if (ro->ro_rt) { + struct sockaddr_in *dst = satosin(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)); +} +/* + * FUNCTION: eonrtrequest + * + * PURPOSE: maintains list of direct eon recipients. + * sets up IP route for rest. + * + * RETURNS: nothing + */ +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; + + /* + * Common Housekeeping + */ + 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; /* unless better below */ + 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: + ipaddrloc = (caddr_t) &satosin(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); +} + +/* + * FUNCTION: eonoutput + * + * PURPOSE: prepend an eon header and hand to IP + * ARGUMENTS: (ifp) is points to the ifnet structure for this unit/device + * (m) is an mbuf *, *m is a CLNL packet + * (dst) is a destination address - have to interp. as + * multicast or broadcast or real address. + * + * RETURNS: unix error code + * + * NOTES: + * + */ +eonoutput(ifp, m, dst, rt) + struct ifnet *ifp; + register struct mbuf *m; /* packet */ + struct sockaddr_iso *dst; /* destination addr */ + 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: + /* put an eon_hdr in the buffer, prepended by an ip header */ + 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]; /* kludge - really want to give CLNP + * the ifp for eon, not for the real device + */ + + 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 *); + /* do a few checks for debugging */ + if( iphdr->ip_p != IPPROTO_EON ) { + IncStat(es_badhdr); + goto drop; + } + /* temporarily drop ip header from the mbuf */ + 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 + + /* checks for debugging */ + 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++; + + { + /* put it on the CLNP queue and set soft interrupt */ + struct ifqueue *ifq; + extern struct ifqueue clnlintrq; + + m->m_pkthdr.rcvif = eonifp; /* KLUDGE */ + 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: + /* TODO: set the dec bit */ + 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: + /* TODO: mark the link down */ + 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: + /* printf("eonctlinput: ICMP cmd 0x%x\n", cmd );*/ + break; + } + return 0; +} + +#endif |