xref: /netbsd-src/sys/net/if_arcsubr.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
1 /*	$NetBSD: if_arcsubr.c,v 1.3 1995/04/14 17:06:39 chopps 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/syslog.h>
48 #include <sys/errno.h>
49 
50 #include <machine/cpu.h>
51 
52 #include <net/if.h>
53 #include <net/netisr.h>
54 #include <net/route.h>
55 #include <net/if_dl.h>
56 #include <net/if_types.h>
57 
58 #ifdef INET
59 #include <netinet/in.h>
60 #include <netinet/in_var.h>
61 #endif
62 #include <netinet/if_arc.h>
63 
64 u_char	arcbroadcastaddr = 0;
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 with
194  * the ARCnet header.
195  */
196 void
197 arc_input(ifp, m)
198 	struct ifnet *ifp;
199 	struct mbuf *m;
200 {
201 	register struct arc_header *ah;
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 	ah = mtod(m,struct arc_header *);
211 
212 	ifp->if_lastchange = time;
213 	ifp->if_ibytes += m->m_pkthdr.len;
214 
215 	if (arcbroadcastaddr == ah->arc_dhost) {
216 		m->m_flags |= M_BCAST;
217 		ifp->if_imcasts++;
218 	}
219 
220 	atype = ah->arc_type;
221 	switch (atype) {
222 #ifdef INET
223 	case ARCTYPE_IP_OLD:
224 		m_adj(m,ARC_HDRLEN);
225 		schednetisr(NETISR_IP);
226 		inq = &ipintrq;
227 		break;
228 #endif
229 	default:
230 		m_freem(m);
231 		return;
232 	}
233 
234 	s = splimp();
235 	if (IF_QFULL(inq)) {
236 		IF_DROP(inq);
237 		m_freem(m);
238 	} else
239 		IF_ENQUEUE(inq, m);
240 	splx(s);
241 }
242 
243 /*
244  * Convert Arcnet address to printable (loggable) representation.
245  */
246 static char digits[] = "0123456789abcdef";
247 char *
248 arc_sprintf(ap)
249 	register u_char *ap;
250 {
251 	static char arcbuf[3];
252 	register char *cp = arcbuf;
253 
254 	*cp++ = digits[*ap >> 4];
255 	*cp++ = digits[*ap++ & 0xf];
256 	*cp   = 0;
257 	return (arcbuf);
258 }
259 
260 /*
261  * Perform common duties while attaching to interface list
262  */
263 void
264 arc_ifattach(ifp)
265 	register struct ifnet *ifp;
266 {
267 	register struct ifaddr *ifa;
268 	register struct sockaddr_dl *sdl;
269 
270 	ifp->if_type = IFT_ARCNET;
271 	ifp->if_addrlen = 1;
272 	ifp->if_hdrlen = ARC_HDRLEN;
273 	ifp->if_mtu = ARCMTU;
274 	if (((struct arccom *)ifp)->ac_anaddr == 0) {
275 		log(LOG_ERR,"%s%d: link address 0 reserved for broadcasts.\n\
276 Please change it and ifconfig %s%d down up\n",
277 		   ifp->if_name,ifp->if_unit,ifp->if_name,ifp->if_unit);
278 	}
279 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
280 		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
281 		    sdl->sdl_family == AF_LINK) {
282 			sdl->sdl_type = IFT_ARCNET;
283 			sdl->sdl_alen = ifp->if_addrlen;
284 			bcopy((caddr_t)&((struct arccom *)ifp)->ac_anaddr,
285 			      LLADDR(sdl), ifp->if_addrlen);
286 			break;
287 		}
288 }
289