home *** CD-ROM | disk | FTP | other *** search
- /*-
- * Copyright (c) 1991 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 7.16 (Berkeley) 6/27/91
- */
-
- /***********************************************************
- 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
- */
- /*
- * $Header: if_eon.c,v 1.4 88/07/19 15:53:59 hagens Exp $
- * $Source: /usr/argo/sys/netiso/RCS/if_eon.c,v $
- *
- * 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 "param.h"
- #include "systm.h"
- #include "types.h"
- #include "mbuf.h"
- #include "buf.h"
- #include "protosw.h"
- #include "socket.h"
- #include "ioctl.h"
- #include "errno.h"
- #include "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 "iso.h"
- #include "iso_var.h"
- #include "iso_snpac.h"
- #include "argo_debug.h"
- #include "iso_errno.h"
- #include "eonvar.h"
- extern struct timeval time;
- extern struct ifnet loif;
-
- #define EOK 0
-
- int eoninput();
- int eonoutput();
- int eonioctl();
- int eonattach();
- int eoninit();
- int eonrtrequest();
- extern int ip_output();
- 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_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
- }
-
-
- /*
- * 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;
- 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;
- ifa->ifa_llinfolen = sizeof(struct eon_llinfo);
- }
- 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 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 =
- (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));
- }
- /*
- * FUNCTION: eonrtrequest
- *
- * PURPOSE: maintains list of direct eon recipients.
- * sets up IP route for rest.
- *
- * RETURNS: nothing
- */
- 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:
- #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);
- }
-
- /*
- * FUNCTION: eoninit
- *
- * PURPOSE: initialization
- *
- * RETURNS: nothing
- */
-
- eoninit(unit)
- int unit;
- {
- printf("eon driver-init eon%d\n", unit);
- }
-
-
- /*
- * 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);
- 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
-