if_arcsubr.c revision 1.3 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