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