Home | History | Annotate | Line # | Download | only in net
if_arcsubr.c revision 1.2
      1 /*	$NetBSD: if_arcsubr.c,v 1.2 1995/04/11 04:32:09 mycroft Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1994, 1995 Ignatios Souvatzis
      5  * Copyright (c) 1982, 1989, 1993
      6  *	The Regents of the University of California.  All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by the University of
     19  *	California, Berkeley and its contributors.
     20  * 4. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  *
     36  * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
     37  *       @(#)if_ethersubr.c	8.1 (Berkeley) 6/10/93
     38  *
     39  */
     40 
     41 #include <sys/param.h>
     42 #include <sys/systm.h>
     43 #include <sys/kernel.h>
     44 #include <sys/malloc.h>
     45 #include <sys/mbuf.h>
     46 #include <sys/socket.h>
     47 #include <sys/errno.h>
     48 
     49 #include <machine/cpu.h>
     50 
     51 #include <net/if.h>
     52 #include <net/netisr.h>
     53 #include <net/route.h>
     54 #include <net/if_dl.h>
     55 #include <net/if_types.h>
     56 
     57 #ifdef INET
     58 #include <netinet/in.h>
     59 #include <netinet/in_var.h>
     60 #endif
     61 #include <netinet/if_arc.h>
     62 
     63 u_char	arcbroadcastaddr = 0;
     64 
     65 #define senderr(e) { error = (e); goto bad;}
     66 
     67 #define SIN(s) ((struct sockaddr_in *)s)
     68 
     69 /*
     70  * ARCnet output routine.
     71  * Encapsulate a packet of type family for the local net.
     72  * Assumes that ifp is actually pointer to arccom structure.
     73  */
     74 int
     75 arc_output(ifp, m0, dst, rt0)
     76 	register struct ifnet *ifp;
     77 	struct mbuf *m0;
     78 	struct sockaddr *dst;
     79 	struct rtentry *rt0;
     80 {
     81 	int s, error = 0;
     82 	u_char atype, adst;
     83 	register struct mbuf *m = m0;
     84 	register struct rtentry *rt;
     85 	struct mbuf *mcopy = (struct mbuf *)0;
     86 	register struct arc_header *ah;
     87 	int off, len = m->m_pkthdr.len;
     88 	struct arccom *ac = (struct arccom *)ifp;
     89 
     90 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
     91 		senderr(ENETDOWN);
     92 	ifp->if_lastchange = time;
     93 	if (rt = rt0) {
     94 		if ((rt->rt_flags & RTF_UP) == 0) {
     95 			if (rt0 = rt = rtalloc1(dst, 1))
     96 				rt->rt_refcnt--;
     97 			else
     98 				senderr(EHOSTUNREACH);
     99 		}
    100 		if (rt->rt_flags & RTF_GATEWAY) {
    101 			if (rt->rt_gwroute == 0)
    102 				goto lookup;
    103 			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
    104 				rtfree(rt); rt = rt0;
    105 			lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
    106 				if ((rt = rt->rt_gwroute) == 0)
    107 					senderr(EHOSTUNREACH);
    108 			}
    109 		}
    110 		if (rt->rt_flags & RTF_REJECT)
    111 			if (rt->rt_rmx.rmx_expire == 0 ||
    112 			    time.tv_sec < rt->rt_rmx.rmx_expire)
    113 				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
    114 	}
    115 	switch (dst->sa_family) {
    116 
    117 #ifdef INET
    118 	case AF_INET:
    119 
    120 		/*
    121 		 * For now, use the simple IP addr -> ARCnet addr mapping
    122 		 */
    123 		if (m->m_flags & M_BCAST)
    124 			adst = arcbroadcastaddr; /* ARCnet broadcast address */
    125 		else
    126 			adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
    127 
    128 		/* If broadcasting on a simplex interface, loopback a copy */
    129 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
    130 			mcopy = m_copy(m, 0, (int)M_COPYALL);
    131 		off = m->m_pkthdr.len - m->m_len;
    132 		atype = ARCTYPE_IP_OLD;
    133 		break;
    134 #endif
    135 	case AF_UNSPEC:
    136 		ah = (struct arc_header *)dst->sa_data;
    137  		adst = ah->arc_dhost;
    138 		atype = ah->arc_type;
    139 		break;
    140 
    141 	default:
    142 		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
    143 			dst->sa_family);
    144 		senderr(EAFNOSUPPORT);
    145 	}
    146 
    147 
    148 	if (mcopy)
    149 		(void) looutput(ifp, mcopy, dst, rt);
    150 	/*
    151 	 * Add local net header.  If no space in first mbuf,
    152 	 * allocate another.
    153 	 *
    154 	 * For ARCnet, this is just symbolic. The header changes
    155 	 * form and position on its way into the hardware and out of
    156 	 * the wire.  At this point, it contains source, destination and
    157 	 * packet type.
    158 	 */
    159 	M_PREPEND(m, ARC_HDRLEN, M_DONTWAIT);
    160 	if (m == 0)
    161 		senderr(ENOBUFS);
    162 	ah = mtod(m, struct arc_header *);
    163 	ah->arc_type = atype;
    164 	ah->arc_dhost= adst;
    165 	ah->arc_shost= ac->ac_anaddr;
    166 	s = splimp();
    167 	/*
    168 	 * Queue message on interface, and start output if interface
    169 	 * not yet active.
    170 	 */
    171 	if (IF_QFULL(&ifp->if_snd)) {
    172 		IF_DROP(&ifp->if_snd);
    173 		splx(s);
    174 		senderr(ENOBUFS);
    175 	}
    176 	IF_ENQUEUE(&ifp->if_snd, m);
    177 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
    178 		(*ifp->if_start)(ifp);
    179 	splx(s);
    180 
    181 	ifp->if_obytes += len + ARC_HDRLEN;
    182 	return (error);
    183 
    184 bad:
    185 	if (m)
    186 		m_freem(m);
    187 	return (error);
    188 }
    189 
    190 /*
    191  * Process a received Arcnet packet;
    192  * the packet is in the mbuf chain m without
    193  * the ARCnet header, which is provided separately.
    194  */
    195 void
    196 arc_input(ifp, ah, m)
    197 	struct ifnet *ifp;
    198 	register struct arc_header *ah;
    199 	struct mbuf *m;
    200 {
    201 	register struct ifqueue *inq;
    202 	u_char atype;
    203 	int s;
    204 
    205 	if ((ifp->if_flags & IFF_UP) == 0) {
    206 		m_freem(m);
    207 		return;
    208 	}
    209 	ifp->if_lastchange = time;
    210 	ifp->if_ibytes += m->m_pkthdr.len + sizeof (*ah);
    211 
    212 	if (arcbroadcastaddr == ah->arc_dhost) {
    213 		m->m_flags |= M_BCAST;
    214 		ifp->if_imcasts++;
    215 	}
    216 
    217 	atype = ah->arc_type;
    218 	switch (atype) {
    219 #ifdef INET
    220 	case ARCTYPE_IP_OLD:
    221 		schednetisr(NETISR_IP);
    222 		inq = &ipintrq;
    223 		break;
    224 #endif
    225 	default:
    226 		m_freem(m);
    227 		return;
    228 	}
    229 
    230 	s = splimp();
    231 	if (IF_QFULL(inq)) {
    232 		IF_DROP(inq);
    233 		m_freem(m);
    234 	} else
    235 		IF_ENQUEUE(inq, m);
    236 	splx(s);
    237 }
    238 
    239 /*
    240  * Convert Arcnet address to printable (loggable) representation.
    241  */
    242 static char digits[] = "0123456789abcdef";
    243 char *
    244 arc_sprintf(ap)
    245 	register u_char *ap;
    246 {
    247 	static char arcbuf[3];
    248 	register char *cp = arcbuf;
    249 
    250 	*cp++ = digits[*ap >> 4];
    251 	*cp++ = digits[*ap++ & 0xf];
    252 	*cp   = 0;
    253 	return (arcbuf);
    254 }
    255 
    256 /*
    257  * Perform common duties while attaching to interface list
    258  */
    259 void
    260 arc_ifattach(ifp)
    261 	register struct ifnet *ifp;
    262 {
    263 	register struct ifaddr *ifa;
    264 	register struct sockaddr_dl *sdl;
    265 
    266 	ifp->if_type = IFT_ARCNET;
    267 	ifp->if_addrlen = 1;
    268 	ifp->if_hdrlen = ARC_HDRLEN;
    269 	ifp->if_mtu = ARCMTU;
    270 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
    271 		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
    272 		    sdl->sdl_family == AF_LINK) {
    273 			sdl->sdl_type = IFT_ARCNET;
    274 			sdl->sdl_alen = ifp->if_addrlen;
    275 			bcopy((caddr_t)&((struct arccom *)ifp)->ac_anaddr,
    276 			      LLADDR(sdl), ifp->if_addrlen);
    277 			break;
    278 		}
    279 }
    280