Home | History | Annotate | Line # | Download | only in net
if_arcsubr.c revision 1.1
      1 /*	$NetBSD: if_arcsubr.c,v 1.1 1995/02/23 07:19:51 glass 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 extern	struct ifnet loif;
     65 
     66 #define senderr(e) { error = (e); goto bad;}
     67 
     68 #define SIN(s) ((struct sockaddr_in *)s)
     69 
     70 /*
     71  * ARCnet output routine.
     72  * Encapsulate a packet of type family for the local net.
     73  * Assumes that ifp is actually pointer to arccom structure.
     74  */
     75 int
     76 arc_output(ifp, m0, dst, rt0)
     77 	register struct ifnet *ifp;
     78 	struct mbuf *m0;
     79 	struct sockaddr *dst;
     80 	struct rtentry *rt0;
     81 {
     82 	int s, error = 0;
     83 	u_char atype, adst;
     84 	register struct mbuf *m = m0;
     85 	register struct rtentry *rt;
     86 	struct mbuf *mcopy = (struct mbuf *)0;
     87 	register struct arc_header *ah;
     88 	int off, len = m->m_pkthdr.len;
     89 	struct arccom *ac = (struct arccom *)ifp;
     90 
     91 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
     92 		senderr(ENETDOWN);
     93 	ifp->if_lastchange = time;
     94 	if (rt = rt0) {
     95 		if ((rt->rt_flags & RTF_UP) == 0) {
     96 			if (rt0 = rt = rtalloc1(dst, 1))
     97 				rt->rt_refcnt--;
     98 			else
     99 				senderr(EHOSTUNREACH);
    100 		}
    101 		if (rt->rt_flags & RTF_GATEWAY) {
    102 			if (rt->rt_gwroute == 0)
    103 				goto lookup;
    104 			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
    105 				rtfree(rt); rt = rt0;
    106 			lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
    107 				if ((rt = rt->rt_gwroute) == 0)
    108 					senderr(EHOSTUNREACH);
    109 			}
    110 		}
    111 		if (rt->rt_flags & RTF_REJECT)
    112 			if (rt->rt_rmx.rmx_expire == 0 ||
    113 			    time.tv_sec < rt->rt_rmx.rmx_expire)
    114 				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
    115 	}
    116 	switch (dst->sa_family) {
    117 
    118 #ifdef INET
    119 	case AF_INET:
    120 
    121 		/*
    122 		 * For now, use the simple IP addr -> ARCnet addr mapping
    123 		 */
    124 		if (m->m_flags & M_BCAST)
    125 			adst = arcbroadcastaddr; /* ARCnet broadcast address */
    126 		else
    127 			adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
    128 
    129 		/* If broadcasting on a simplex interface, loopback a copy */
    130 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
    131 			mcopy = m_copy(m, 0, (int)M_COPYALL);
    132 		off = m->m_pkthdr.len - m->m_len;
    133 		atype = ARCTYPE_IP_OLD;
    134 		break;
    135 #endif
    136 	case AF_UNSPEC:
    137 		ah = (struct arc_header *)dst->sa_data;
    138  		adst = ah->arc_dhost;
    139 		atype = ah->arc_type;
    140 		break;
    141 
    142 	default:
    143 		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
    144 			dst->sa_family);
    145 		senderr(EAFNOSUPPORT);
    146 	}
    147 
    148 
    149 	if (mcopy)
    150 		(void) looutput(ifp, mcopy, dst, rt);
    151 	/*
    152 	 * Add local net header.  If no space in first mbuf,
    153 	 * allocate another.
    154 	 *
    155 	 * For ARCnet, this is just symbolic. The header changes
    156 	 * form and position on its way into the hardware and out of
    157 	 * the wire.  At this point, it contains source, destination and
    158 	 * packet type.
    159 	 */
    160 	M_PREPEND(m, ARC_HDRLEN, M_DONTWAIT);
    161 	if (m == 0)
    162 		senderr(ENOBUFS);
    163 	ah = mtod(m, struct arc_header *);
    164 	ah->arc_type = atype;
    165 	ah->arc_dhost= adst;
    166 	ah->arc_shost= ac->ac_anaddr;
    167 	s = splimp();
    168 	/*
    169 	 * Queue message on interface, and start output if interface
    170 	 * not yet active.
    171 	 */
    172 	if (IF_QFULL(&ifp->if_snd)) {
    173 		IF_DROP(&ifp->if_snd);
    174 		splx(s);
    175 		senderr(ENOBUFS);
    176 	}
    177 	IF_ENQUEUE(&ifp->if_snd, m);
    178 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
    179 		(*ifp->if_start)(ifp);
    180 	splx(s);
    181 
    182 	ifp->if_obytes += len + ARC_HDRLEN;
    183 	return (error);
    184 
    185 bad:
    186 	if (m)
    187 		m_freem(m);
    188 	return (error);
    189 }
    190 
    191 /*
    192  * Process a received Arcnet packet;
    193  * the packet is in the mbuf chain m without
    194  * the ARCnet header, which is provided separately.
    195  */
    196 void
    197 arc_input(ifp, ah, m)
    198 	struct ifnet *ifp;
    199 	register struct arc_header *ah;
    200 	struct mbuf *m;
    201 {
    202 	register struct ifqueue *inq;
    203 	u_char atype;
    204 	int s;
    205 
    206 	if ((ifp->if_flags & IFF_UP) == 0) {
    207 		m_freem(m);
    208 		return;
    209 	}
    210 	ifp->if_lastchange = time;
    211 	ifp->if_ibytes += m->m_pkthdr.len + sizeof (*ah);
    212 
    213 	if (arcbroadcastaddr == ah->arc_dhost) {
    214 		m->m_flags |= M_BCAST;
    215 		ifp->if_imcasts++;
    216 	}
    217 
    218 	atype = ah->arc_type;
    219 	switch (atype) {
    220 #ifdef INET
    221 	case ARCTYPE_IP_OLD:
    222 		schednetisr(NETISR_IP);
    223 		inq = &ipintrq;
    224 		break;
    225 #endif
    226 	default:
    227 		m_freem(m);
    228 		return;
    229 	}
    230 
    231 	s = splimp();
    232 	if (IF_QFULL(inq)) {
    233 		IF_DROP(inq);
    234 		m_freem(m);
    235 	} else
    236 		IF_ENQUEUE(inq, m);
    237 	splx(s);
    238 }
    239 
    240 /*
    241  * Convert Arcnet address to printable (loggable) representation.
    242  */
    243 static char digits[] = "0123456789abcdef";
    244 char *
    245 arc_sprintf(ap)
    246 	register u_char *ap;
    247 {
    248 	static char arcbuf[3];
    249 	register char *cp = arcbuf;
    250 
    251 	*cp++ = digits[*ap >> 4];
    252 	*cp++ = digits[*ap++ & 0xf];
    253 	*cp   = 0;
    254 	return (arcbuf);
    255 }
    256 
    257 /*
    258  * Perform common duties while attaching to interface list
    259  */
    260 void
    261 arc_ifattach(ifp)
    262 	register struct ifnet *ifp;
    263 {
    264 	register struct ifaddr *ifa;
    265 	register struct sockaddr_dl *sdl;
    266 
    267 	ifp->if_type = IFT_ARCNET;
    268 	ifp->if_addrlen = 1;
    269 	ifp->if_hdrlen = ARC_HDRLEN;
    270 	ifp->if_mtu = ARCMTU;
    271 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
    272 		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
    273 		    sdl->sdl_family == AF_LINK) {
    274 			sdl->sdl_type = IFT_ARCNET;
    275 			sdl->sdl_alen = ifp->if_addrlen;
    276 			bcopy((caddr_t)&((struct arccom *)ifp)->ac_anaddr,
    277 			      LLADDR(sdl), ifp->if_addrlen);
    278 			break;
    279 		}
    280 }
    281