Deleted Added
full compact
if_arcsubr.c (109771) if_arcsubr.c (110106)
1/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */
1/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */
2/* $FreeBSD: head/sys/net/if_arcsubr.c 109771 2003-01-24 01:32:20Z fjoe $ */
2/* $FreeBSD: head/sys/net/if_arcsubr.c 110106 2003-01-30 15:55:02Z fjoe $ */
3
4/*
5 * Copyright (c) 1994, 1995 Ignatios Souvatzis
6 * Copyright (c) 1982, 1989, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
38 * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93
39 *
40 */
41#include "opt_inet.h"
42#include "opt_inet6.h"
43#include "opt_ipx.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/malloc.h>
49#include <sys/mbuf.h>
50#include <sys/protosw.h>
51#include <sys/socket.h>
52#include <sys/sockio.h>
53#include <sys/errno.h>
54#include <sys/syslog.h>
55
56#include <machine/cpu.h>
57
58#include <net/if.h>
59#include <net/netisr.h>
60#include <net/route.h>
61#include <net/if_dl.h>
62#include <net/if_types.h>
63#include <net/if_arc.h>
64#include <net/if_arp.h>
65#include <net/bpf.h>
66
67#if defined(INET) || defined(INET6)
68#include <netinet/in.h>
69#include <netinet/in_var.h>
70#include <netinet/if_ether.h>
71#endif
72
73#ifdef INET6
74#include <netinet6/nd6.h>
75#endif
76
77#ifdef IPX
78#include <netipx/ipx.h>
79#include <netipx/ipx_if.h>
80#endif
81
82MODULE_VERSION(arcnet, 1);
83
84#define ARCNET_ALLOW_BROKEN_ARP
85
86static struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
87static int arc_resolvemulti(struct ifnet *, struct sockaddr **,
88 struct sockaddr *);
89
90u_int8_t arcbroadcastaddr = 0;
91
3
4/*
5 * Copyright (c) 1994, 1995 Ignatios Souvatzis
6 * Copyright (c) 1982, 1989, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
38 * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93
39 *
40 */
41#include "opt_inet.h"
42#include "opt_inet6.h"
43#include "opt_ipx.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/malloc.h>
49#include <sys/mbuf.h>
50#include <sys/protosw.h>
51#include <sys/socket.h>
52#include <sys/sockio.h>
53#include <sys/errno.h>
54#include <sys/syslog.h>
55
56#include <machine/cpu.h>
57
58#include <net/if.h>
59#include <net/netisr.h>
60#include <net/route.h>
61#include <net/if_dl.h>
62#include <net/if_types.h>
63#include <net/if_arc.h>
64#include <net/if_arp.h>
65#include <net/bpf.h>
66
67#if defined(INET) || defined(INET6)
68#include <netinet/in.h>
69#include <netinet/in_var.h>
70#include <netinet/if_ether.h>
71#endif
72
73#ifdef INET6
74#include <netinet6/nd6.h>
75#endif
76
77#ifdef IPX
78#include <netipx/ipx.h>
79#include <netipx/ipx_if.h>
80#endif
81
82MODULE_VERSION(arcnet, 1);
83
84#define ARCNET_ALLOW_BROKEN_ARP
85
86static struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
87static int arc_resolvemulti(struct ifnet *, struct sockaddr **,
88 struct sockaddr *);
89
90u_int8_t arcbroadcastaddr = 0;
91
92#define ARC_LLADDR(ifp) (*(u_int8_t *)IF_LLADDR(ifp))
93
92#define senderr(e) { error = (e); goto bad;}
93#define SIN(s) ((struct sockaddr_in *)s)
94#define SIPX(s) ((struct sockaddr_ipx *)s)
95
96/*
97 * ARCnet output routine.
98 * Encapsulate a packet of type family for the local net.
99 * Assumes that ifp is actually pointer to arccom structure.
100 */
101int
102arc_output(ifp, m, dst, rt0)
103 struct ifnet *ifp;
104 struct mbuf *m;
105 struct sockaddr *dst;
106 struct rtentry *rt0;
107{
108 struct rtentry *rt;
109 struct arccom *ac;
110 struct arc_header *ah;
111 int error;
112 u_int8_t atype, adst;
113 int loop_copy = 0;
94#define senderr(e) { error = (e); goto bad;}
95#define SIN(s) ((struct sockaddr_in *)s)
96#define SIPX(s) ((struct sockaddr_ipx *)s)
97
98/*
99 * ARCnet output routine.
100 * Encapsulate a packet of type family for the local net.
101 * Assumes that ifp is actually pointer to arccom structure.
102 */
103int
104arc_output(ifp, m, dst, rt0)
105 struct ifnet *ifp;
106 struct mbuf *m;
107 struct sockaddr *dst;
108 struct rtentry *rt0;
109{
110 struct rtentry *rt;
111 struct arccom *ac;
112 struct arc_header *ah;
113 int error;
114 u_int8_t atype, adst;
115 int loop_copy = 0;
116 int isphds;
114
115 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
116 return(ENETDOWN); /* m, m1 aren't initialized yet */
117
118 error = 0;
119 ac = (struct arccom *)ifp;
120
121 if ((rt = rt0)) {
122 if ((rt->rt_flags & RTF_UP) == 0) {
123 if ((rt0 = rt = rtalloc1(dst, 1, 0UL)))
124 rt->rt_refcnt--;
125 else
126 senderr(EHOSTUNREACH);
127 }
128 if (rt->rt_flags & RTF_GATEWAY) {
129 if (rt->rt_gwroute == 0)
130 goto lookup;
131 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
132 rtfree(rt); rt = rt0;
133 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL);
134 if ((rt = rt->rt_gwroute) == 0)
135 senderr(EHOSTUNREACH);
136 }
137 }
138 if (rt->rt_flags & RTF_REJECT)
139 if (rt->rt_rmx.rmx_expire == 0 ||
140 time_second < rt->rt_rmx.rmx_expire)
141 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
142 }
143
144 switch (dst->sa_family) {
145#ifdef INET
146 case AF_INET:
147
148 /*
149 * For now, use the simple IP addr -> ARCnet addr mapping
150 */
151 if (m->m_flags & (M_BCAST|M_MCAST))
152 adst = arcbroadcastaddr; /* ARCnet broadcast address */
153 else if (ifp->if_flags & IFF_NOARP)
154 adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
155 else if (!arpresolve(ifp, rt, m, dst, &adst, rt0))
156 return 0; /* not resolved yet */
157
158 atype = (ifp->if_flags & IFF_LINK0) ?
159 ARCTYPE_IP_OLD : ARCTYPE_IP;
160 break;
161#endif
162#ifdef INET6
163 case AF_INET6:
164#ifdef OLDIP6OUTPUT
165 if (!nd6_resolve(ifp, rt, m, dst, (u_char *)&adst))
166 return(0); /* if not yet resolves */
167#else
168 if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)&adst))
169 return(0); /* it must be impossible, but... */
170#endif /* OLDIP6OUTPUT */
171 atype = ARCTYPE_INET6;
172 break;
173#endif
174#ifdef IPX
175 case AF_IPX:
176 adst = SIPX(dst)->sipx_addr.x_host.c_host[5];
177 atype = ARCTYPE_IPX;
178 if (adst == 0xff)
179 adst = arcbroadcastaddr;
180 break;
181#endif
182
183 case AF_UNSPEC:
184 loop_copy = -1;
185 ah = (struct arc_header *)dst->sa_data;
186 adst = ah->arc_dhost;
187 atype = ah->arc_type;
188
189 if (atype == ARCTYPE_ARP) {
190 atype = (ifp->if_flags & IFF_LINK0) ?
191 ARCTYPE_ARP_OLD: ARCTYPE_ARP;
192
193#ifdef ARCNET_ALLOW_BROKEN_ARP
194 /*
195 * XXX It's not clear per RFC826 if this is needed, but
196 * "assigned numbers" say this is wrong.
197 * However, e.g., AmiTCP 3.0Beta used it... we make this
198 * switchable for emergency cases. Not perfect, but...
199 */
200 if (ifp->if_flags & IFF_LINK2)
201 mtod(m, struct arphdr *)->ar_pro = atype - 1;
202#endif
203 }
204 break;
205
206 default:
207 if_printf(ifp, "can't handle af%d\n", dst->sa_family);
208 senderr(EAFNOSUPPORT);
209 }
210
117
118 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
119 return(ENETDOWN); /* m, m1 aren't initialized yet */
120
121 error = 0;
122 ac = (struct arccom *)ifp;
123
124 if ((rt = rt0)) {
125 if ((rt->rt_flags & RTF_UP) == 0) {
126 if ((rt0 = rt = rtalloc1(dst, 1, 0UL)))
127 rt->rt_refcnt--;
128 else
129 senderr(EHOSTUNREACH);
130 }
131 if (rt->rt_flags & RTF_GATEWAY) {
132 if (rt->rt_gwroute == 0)
133 goto lookup;
134 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
135 rtfree(rt); rt = rt0;
136 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL);
137 if ((rt = rt->rt_gwroute) == 0)
138 senderr(EHOSTUNREACH);
139 }
140 }
141 if (rt->rt_flags & RTF_REJECT)
142 if (rt->rt_rmx.rmx_expire == 0 ||
143 time_second < rt->rt_rmx.rmx_expire)
144 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
145 }
146
147 switch (dst->sa_family) {
148#ifdef INET
149 case AF_INET:
150
151 /*
152 * For now, use the simple IP addr -> ARCnet addr mapping
153 */
154 if (m->m_flags & (M_BCAST|M_MCAST))
155 adst = arcbroadcastaddr; /* ARCnet broadcast address */
156 else if (ifp->if_flags & IFF_NOARP)
157 adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
158 else if (!arpresolve(ifp, rt, m, dst, &adst, rt0))
159 return 0; /* not resolved yet */
160
161 atype = (ifp->if_flags & IFF_LINK0) ?
162 ARCTYPE_IP_OLD : ARCTYPE_IP;
163 break;
164#endif
165#ifdef INET6
166 case AF_INET6:
167#ifdef OLDIP6OUTPUT
168 if (!nd6_resolve(ifp, rt, m, dst, (u_char *)&adst))
169 return(0); /* if not yet resolves */
170#else
171 if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)&adst))
172 return(0); /* it must be impossible, but... */
173#endif /* OLDIP6OUTPUT */
174 atype = ARCTYPE_INET6;
175 break;
176#endif
177#ifdef IPX
178 case AF_IPX:
179 adst = SIPX(dst)->sipx_addr.x_host.c_host[5];
180 atype = ARCTYPE_IPX;
181 if (adst == 0xff)
182 adst = arcbroadcastaddr;
183 break;
184#endif
185
186 case AF_UNSPEC:
187 loop_copy = -1;
188 ah = (struct arc_header *)dst->sa_data;
189 adst = ah->arc_dhost;
190 atype = ah->arc_type;
191
192 if (atype == ARCTYPE_ARP) {
193 atype = (ifp->if_flags & IFF_LINK0) ?
194 ARCTYPE_ARP_OLD: ARCTYPE_ARP;
195
196#ifdef ARCNET_ALLOW_BROKEN_ARP
197 /*
198 * XXX It's not clear per RFC826 if this is needed, but
199 * "assigned numbers" say this is wrong.
200 * However, e.g., AmiTCP 3.0Beta used it... we make this
201 * switchable for emergency cases. Not perfect, but...
202 */
203 if (ifp->if_flags & IFF_LINK2)
204 mtod(m, struct arphdr *)->ar_pro = atype - 1;
205#endif
206 }
207 break;
208
209 default:
210 if_printf(ifp, "can't handle af%d\n", dst->sa_family);
211 senderr(EAFNOSUPPORT);
212 }
213
211 M_PREPEND(m, ARC_HDRLEN, M_NOWAIT);
214 isphds = arc_isphds(atype);
215 M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, M_NOWAIT);
212 if (m == 0)
213 senderr(ENOBUFS);
214 ah = mtod(m, struct arc_header *);
215 ah->arc_type = atype;
216 ah->arc_dhost = adst;
216 if (m == 0)
217 senderr(ENOBUFS);
218 ah = mtod(m, struct arc_header *);
219 ah->arc_type = atype;
220 ah->arc_dhost = adst;
217 ah->arc_shost = *IF_LLADDR(ifp);
221 ah->arc_shost = ARC_LLADDR(ifp);
222 if (isphds) {
223 ah->arc_flag = 0;
224 ah->arc_seqid = 0;
225 }
218
219 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
220 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
221 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
222
223 (void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN);
224 } else if (ah->arc_dhost == ah->arc_shost) {
225 (void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN);
226 return (0); /* XXX */
227 }
228 }
229
230 BPF_MTAP(ifp, m);
231
232 if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) {
233 m = 0;
234 senderr(ENOBUFS);
235 }
236
237 return (error);
238
239bad:
240 if (m)
241 m_freem(m);
242 return (error);
243}
244
245void
246arc_frag_init(ifp)
247 struct ifnet *ifp;
248{
249 struct arccom *ac;
250
251 ac = (struct arccom *)ifp;
252 ac->curr_frag = 0;
253}
254
255struct mbuf *
256arc_frag_next(ifp)
257 struct ifnet *ifp;
258{
259 struct arccom *ac;
260 struct mbuf *m;
261 struct arc_header *ah;
262
263 ac = (struct arccom *)ifp;
264 if ((m = ac->curr_frag) == 0) {
265 int tfrags;
266
267 /* dequeue new packet */
268 IF_DEQUEUE(&ifp->if_snd, m);
269 if (m == 0)
270 return 0;
271
272 ah = mtod(m, struct arc_header *);
273 if (!arc_isphds(ah->arc_type))
274 return m;
275
276 ++ac->ac_seqid; /* make the seqid unique */
277 tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA;
278 ac->fsflag = 2 * tfrags - 3;
279 ac->sflag = 0;
280 ac->rsflag = ac->fsflag;
281 ac->arc_dhost = ah->arc_dhost;
282 ac->arc_shost = ah->arc_shost;
283 ac->arc_type = ah->arc_type;
284
226
227 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
228 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
229 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
230
231 (void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN);
232 } else if (ah->arc_dhost == ah->arc_shost) {
233 (void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN);
234 return (0); /* XXX */
235 }
236 }
237
238 BPF_MTAP(ifp, m);
239
240 if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) {
241 m = 0;
242 senderr(ENOBUFS);
243 }
244
245 return (error);
246
247bad:
248 if (m)
249 m_freem(m);
250 return (error);
251}
252
253void
254arc_frag_init(ifp)
255 struct ifnet *ifp;
256{
257 struct arccom *ac;
258
259 ac = (struct arccom *)ifp;
260 ac->curr_frag = 0;
261}
262
263struct mbuf *
264arc_frag_next(ifp)
265 struct ifnet *ifp;
266{
267 struct arccom *ac;
268 struct mbuf *m;
269 struct arc_header *ah;
270
271 ac = (struct arccom *)ifp;
272 if ((m = ac->curr_frag) == 0) {
273 int tfrags;
274
275 /* dequeue new packet */
276 IF_DEQUEUE(&ifp->if_snd, m);
277 if (m == 0)
278 return 0;
279
280 ah = mtod(m, struct arc_header *);
281 if (!arc_isphds(ah->arc_type))
282 return m;
283
284 ++ac->ac_seqid; /* make the seqid unique */
285 tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA;
286 ac->fsflag = 2 * tfrags - 3;
287 ac->sflag = 0;
288 ac->rsflag = ac->fsflag;
289 ac->arc_dhost = ah->arc_dhost;
290 ac->arc_shost = ah->arc_shost;
291 ac->arc_type = ah->arc_type;
292
285 m_adj(m, ARC_HDRLEN);
293 m_adj(m, ARC_HDRNEWLEN);
286 ac->curr_frag = m;
287 }
288
289 /* split out next fragment and return it */
290 if (ac->sflag < ac->fsflag) {
291 /* we CAN'T have short packets here */
292 ac->curr_frag = m_split(m, ARC_MAX_DATA, M_NOWAIT);
293 if (ac->curr_frag == 0) {
294 m_freem(m);
295 return 0;
296 }
297
298 M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
299 if (m == 0) {
300 m_freem(ac->curr_frag);
301 ac->curr_frag = 0;
302 return 0;
303 }
304
305 ah = mtod(m, struct arc_header *);
306 ah->arc_flag = ac->rsflag;
307 ah->arc_seqid = ac->ac_seqid;
308
309 ac->sflag += 2;
310 ac->rsflag = ac->sflag;
311 } else if ((m->m_pkthdr.len >=
312 ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
313 (m->m_pkthdr.len <=
314 ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
315 ac->curr_frag = 0;
316
317 M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_NOWAIT);
318 if (m == 0)
319 return 0;
320
321 ah = mtod(m, struct arc_header *);
322 ah->arc_flag = 0xFF;
323 ah->arc_seqid = 0xFFFF;
324 ah->arc_type2 = ac->arc_type;
325 ah->arc_flag2 = ac->sflag;
326 ah->arc_seqid2 = ac->ac_seqid;
327 } else {
328 ac->curr_frag = 0;
329
330 M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
331 if (m == 0)
332 return 0;
333
334 ah = mtod(m, struct arc_header *);
335 ah->arc_flag = ac->sflag;
336 ah->arc_seqid = ac->ac_seqid;
337 }
338
339 ah->arc_dhost = ac->arc_dhost;
340 ah->arc_shost = ac->arc_shost;
341 ah->arc_type = ac->arc_type;
342
343 return m;
344}
345
346/*
347 * Defragmenter. Returns mbuf if last packet found, else
348 * NULL. frees imcoming mbuf as necessary.
349 */
350
351static __inline struct mbuf *
352arc_defrag(ifp, m)
353 struct ifnet *ifp;
354 struct mbuf *m;
355{
356 struct arc_header *ah, *ah1;
357 struct arccom *ac;
358 struct ac_frag *af;
359 struct mbuf *m1;
360 char *s;
361 int newflen;
362 u_char src,dst,typ;
363
364 ac = (struct arccom *)ifp;
365
366 if (m->m_len < ARC_HDRNEWLEN) {
367 m = m_pullup(m, ARC_HDRNEWLEN);
368 if (m == NULL) {
369 ++ifp->if_ierrors;
370 return NULL;
371 }
372 }
373
374 ah = mtod(m, struct arc_header *);
375 typ = ah->arc_type;
376
377 if (!arc_isphds(typ))
378 return m;
379
380 src = ah->arc_shost;
381 dst = ah->arc_dhost;
382
383 if (ah->arc_flag == 0xff) {
384 m_adj(m, 4);
385
386 if (m->m_len < ARC_HDRNEWLEN) {
387 m = m_pullup(m, ARC_HDRNEWLEN);
388 if (m == NULL) {
389 ++ifp->if_ierrors;
390 return NULL;
391 }
392 }
393
394 ah = mtod(m, struct arc_header *);
395 }
396
397 af = &ac->ac_fragtab[src];
398 m1 = af->af_packet;
399 s = "debug code error";
400
401 if (ah->arc_flag & 1) {
402 /*
403 * first fragment. We always initialize, which is
404 * about the right thing to do, as we only want to
405 * accept one fragmented packet per src at a time.
406 */
407 if (m1 != NULL)
408 m_freem(m1);
409
410 af->af_packet = m;
411 m1 = m;
412 af->af_maxflag = ah->arc_flag;
413 af->af_lastseen = 0;
414 af->af_seqid = ah->arc_seqid;
415
416 return NULL;
417 /* notreached */
418 } else {
419 /* check for unfragmented packet */
420 if (ah->arc_flag == 0)
421 return m;
422
423 /* do we have a first packet from that src? */
424 if (m1 == NULL) {
425 s = "no first frag";
426 goto outofseq;
427 }
428
429 ah1 = mtod(m1, struct arc_header *);
430
431 if (ah->arc_seqid != ah1->arc_seqid) {
432 s = "seqid differs";
433 goto outofseq;
434 }
435
436 if (typ != ah1->arc_type) {
437 s = "type differs";
438 goto outofseq;
439 }
440
441 if (dst != ah1->arc_dhost) {
442 s = "dest host differs";
443 goto outofseq;
444 }
445
446 /* typ, seqid and dst are ok here. */
447
448 if (ah->arc_flag == af->af_lastseen) {
449 m_freem(m);
450 return NULL;
451 }
452
453 if (ah->arc_flag == af->af_lastseen + 2) {
454 /* ok, this is next fragment */
455 af->af_lastseen = ah->arc_flag;
456 m_adj(m,ARC_HDRNEWLEN);
457
458 /*
459 * m_cat might free the first mbuf (with pkthdr)
460 * in 2nd chain; therefore:
461 */
462
463 newflen = m->m_pkthdr.len;
464
465 m_cat(m1,m);
466
467 m1->m_pkthdr.len += newflen;
468
469 /* is it the last one? */
470 if (af->af_lastseen > af->af_maxflag) {
471 af->af_packet = NULL;
472 return(m1);
473 } else
474 return NULL;
475 }
476 s = "other reason";
477 /* if all else fails, it is out of sequence, too */
478 }
479outofseq:
480 if (m1) {
481 m_freem(m1);
482 af->af_packet = NULL;
483 }
484
485 if (m)
486 m_freem(m);
487
488 log(LOG_INFO,"%s%d: got out of seq. packet: %s\n",
489 ifp->if_name, ifp->if_unit, s);
490
491 return NULL;
492}
493
494/*
495 * return 1 if Packet Header Definition Standard, else 0.
496 * For now: old IP, old ARP aren't obviously. Lacking correct information,
497 * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
498 * (Apple and Novell corporations were involved, among others, in PHDS work).
499 * Easiest is to assume that everybody else uses that, too.
500 */
501int
502arc_isphds(type)
503 u_int8_t type;
504{
505 return (type != ARCTYPE_IP_OLD &&
506 type != ARCTYPE_ARP_OLD &&
507 type != ARCTYPE_DIAGNOSE);
508}
509
510/*
511 * Process a received Arcnet packet;
512 * the packet is in the mbuf chain m with
513 * the ARCnet header.
514 */
515void
516arc_input(ifp, m)
517 struct ifnet *ifp;
518 struct mbuf *m;
519{
520 struct arc_header *ah;
521 struct ifqueue *inq;
522 u_int8_t atype;
523
524 if ((ifp->if_flags & IFF_UP) == 0) {
525 m_freem(m);
526 return;
527 }
528
529 /* possibly defragment: */
530 m = arc_defrag(ifp, m);
531 if (m == NULL)
532 return;
533
534 BPF_MTAP(ifp, m);
535
536 ah = mtod(m, struct arc_header *);
537 /* does this belong to us? */
294 ac->curr_frag = m;
295 }
296
297 /* split out next fragment and return it */
298 if (ac->sflag < ac->fsflag) {
299 /* we CAN'T have short packets here */
300 ac->curr_frag = m_split(m, ARC_MAX_DATA, M_NOWAIT);
301 if (ac->curr_frag == 0) {
302 m_freem(m);
303 return 0;
304 }
305
306 M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
307 if (m == 0) {
308 m_freem(ac->curr_frag);
309 ac->curr_frag = 0;
310 return 0;
311 }
312
313 ah = mtod(m, struct arc_header *);
314 ah->arc_flag = ac->rsflag;
315 ah->arc_seqid = ac->ac_seqid;
316
317 ac->sflag += 2;
318 ac->rsflag = ac->sflag;
319 } else if ((m->m_pkthdr.len >=
320 ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
321 (m->m_pkthdr.len <=
322 ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
323 ac->curr_frag = 0;
324
325 M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_NOWAIT);
326 if (m == 0)
327 return 0;
328
329 ah = mtod(m, struct arc_header *);
330 ah->arc_flag = 0xFF;
331 ah->arc_seqid = 0xFFFF;
332 ah->arc_type2 = ac->arc_type;
333 ah->arc_flag2 = ac->sflag;
334 ah->arc_seqid2 = ac->ac_seqid;
335 } else {
336 ac->curr_frag = 0;
337
338 M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
339 if (m == 0)
340 return 0;
341
342 ah = mtod(m, struct arc_header *);
343 ah->arc_flag = ac->sflag;
344 ah->arc_seqid = ac->ac_seqid;
345 }
346
347 ah->arc_dhost = ac->arc_dhost;
348 ah->arc_shost = ac->arc_shost;
349 ah->arc_type = ac->arc_type;
350
351 return m;
352}
353
354/*
355 * Defragmenter. Returns mbuf if last packet found, else
356 * NULL. frees imcoming mbuf as necessary.
357 */
358
359static __inline struct mbuf *
360arc_defrag(ifp, m)
361 struct ifnet *ifp;
362 struct mbuf *m;
363{
364 struct arc_header *ah, *ah1;
365 struct arccom *ac;
366 struct ac_frag *af;
367 struct mbuf *m1;
368 char *s;
369 int newflen;
370 u_char src,dst,typ;
371
372 ac = (struct arccom *)ifp;
373
374 if (m->m_len < ARC_HDRNEWLEN) {
375 m = m_pullup(m, ARC_HDRNEWLEN);
376 if (m == NULL) {
377 ++ifp->if_ierrors;
378 return NULL;
379 }
380 }
381
382 ah = mtod(m, struct arc_header *);
383 typ = ah->arc_type;
384
385 if (!arc_isphds(typ))
386 return m;
387
388 src = ah->arc_shost;
389 dst = ah->arc_dhost;
390
391 if (ah->arc_flag == 0xff) {
392 m_adj(m, 4);
393
394 if (m->m_len < ARC_HDRNEWLEN) {
395 m = m_pullup(m, ARC_HDRNEWLEN);
396 if (m == NULL) {
397 ++ifp->if_ierrors;
398 return NULL;
399 }
400 }
401
402 ah = mtod(m, struct arc_header *);
403 }
404
405 af = &ac->ac_fragtab[src];
406 m1 = af->af_packet;
407 s = "debug code error";
408
409 if (ah->arc_flag & 1) {
410 /*
411 * first fragment. We always initialize, which is
412 * about the right thing to do, as we only want to
413 * accept one fragmented packet per src at a time.
414 */
415 if (m1 != NULL)
416 m_freem(m1);
417
418 af->af_packet = m;
419 m1 = m;
420 af->af_maxflag = ah->arc_flag;
421 af->af_lastseen = 0;
422 af->af_seqid = ah->arc_seqid;
423
424 return NULL;
425 /* notreached */
426 } else {
427 /* check for unfragmented packet */
428 if (ah->arc_flag == 0)
429 return m;
430
431 /* do we have a first packet from that src? */
432 if (m1 == NULL) {
433 s = "no first frag";
434 goto outofseq;
435 }
436
437 ah1 = mtod(m1, struct arc_header *);
438
439 if (ah->arc_seqid != ah1->arc_seqid) {
440 s = "seqid differs";
441 goto outofseq;
442 }
443
444 if (typ != ah1->arc_type) {
445 s = "type differs";
446 goto outofseq;
447 }
448
449 if (dst != ah1->arc_dhost) {
450 s = "dest host differs";
451 goto outofseq;
452 }
453
454 /* typ, seqid and dst are ok here. */
455
456 if (ah->arc_flag == af->af_lastseen) {
457 m_freem(m);
458 return NULL;
459 }
460
461 if (ah->arc_flag == af->af_lastseen + 2) {
462 /* ok, this is next fragment */
463 af->af_lastseen = ah->arc_flag;
464 m_adj(m,ARC_HDRNEWLEN);
465
466 /*
467 * m_cat might free the first mbuf (with pkthdr)
468 * in 2nd chain; therefore:
469 */
470
471 newflen = m->m_pkthdr.len;
472
473 m_cat(m1,m);
474
475 m1->m_pkthdr.len += newflen;
476
477 /* is it the last one? */
478 if (af->af_lastseen > af->af_maxflag) {
479 af->af_packet = NULL;
480 return(m1);
481 } else
482 return NULL;
483 }
484 s = "other reason";
485 /* if all else fails, it is out of sequence, too */
486 }
487outofseq:
488 if (m1) {
489 m_freem(m1);
490 af->af_packet = NULL;
491 }
492
493 if (m)
494 m_freem(m);
495
496 log(LOG_INFO,"%s%d: got out of seq. packet: %s\n",
497 ifp->if_name, ifp->if_unit, s);
498
499 return NULL;
500}
501
502/*
503 * return 1 if Packet Header Definition Standard, else 0.
504 * For now: old IP, old ARP aren't obviously. Lacking correct information,
505 * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
506 * (Apple and Novell corporations were involved, among others, in PHDS work).
507 * Easiest is to assume that everybody else uses that, too.
508 */
509int
510arc_isphds(type)
511 u_int8_t type;
512{
513 return (type != ARCTYPE_IP_OLD &&
514 type != ARCTYPE_ARP_OLD &&
515 type != ARCTYPE_DIAGNOSE);
516}
517
518/*
519 * Process a received Arcnet packet;
520 * the packet is in the mbuf chain m with
521 * the ARCnet header.
522 */
523void
524arc_input(ifp, m)
525 struct ifnet *ifp;
526 struct mbuf *m;
527{
528 struct arc_header *ah;
529 struct ifqueue *inq;
530 u_int8_t atype;
531
532 if ((ifp->if_flags & IFF_UP) == 0) {
533 m_freem(m);
534 return;
535 }
536
537 /* possibly defragment: */
538 m = arc_defrag(ifp, m);
539 if (m == NULL)
540 return;
541
542 BPF_MTAP(ifp, m);
543
544 ah = mtod(m, struct arc_header *);
545 /* does this belong to us? */
538 if ((ifp->if_flags & IFF_PROMISC) != 0
546 if ((ifp->if_flags & IFF_PROMISC) == 0
539 && ah->arc_dhost != arcbroadcastaddr
547 && ah->arc_dhost != arcbroadcastaddr
540 && ah->arc_dhost != *IF_LLADDR(ifp)) {
548 && ah->arc_dhost != ARC_LLADDR(ifp)) {
541 m_freem(m);
542 return;
543 }
544
545 ifp->if_ibytes += m->m_pkthdr.len;
546
547 if (ah->arc_dhost == arcbroadcastaddr) {
548 m->m_flags |= M_BCAST|M_MCAST;
549 ifp->if_imcasts++;
550 }
551
552 atype = ah->arc_type;
553 switch (atype) {
554#ifdef INET
555 case ARCTYPE_IP:
556 m_adj(m, ARC_HDRNEWLEN);
557 if (ipflow_fastforward(m))
558 return;
559 schednetisr(NETISR_IP);
560 inq = &ipintrq;
561 break;
562
563 case ARCTYPE_IP_OLD:
564 m_adj(m, ARC_HDRLEN);
565 if (ipflow_fastforward(m))
566 return;
567 schednetisr(NETISR_IP);
568 inq = &ipintrq;
569 break;
570
571 case ARCTYPE_ARP:
572 if (ifp->if_flags & IFF_NOARP) {
573 /* Discard packet if ARP is disabled on interface */
574 m_freem(m);
575 return;
576 }
577 m_adj(m, ARC_HDRNEWLEN);
578 schednetisr(NETISR_ARP);
579 inq = &arpintrq;
580#ifdef ARCNET_ALLOW_BROKEN_ARP
581 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
582#endif
583 break;
584
585 case ARCTYPE_ARP_OLD:
586 if (ifp->if_flags & IFF_NOARP) {
587 /* Discard packet if ARP is disabled on interface */
588 m_freem(m);
589 return;
590 }
591 m_adj(m, ARC_HDRLEN);
592 schednetisr(NETISR_ARP);
593 inq = &arpintrq;
594#ifdef ARCNET_ALLOW_BROKEN_ARP
595 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
596#endif
597 break;
598#endif
599#ifdef INET6
600 case ARCTYPE_INET6:
601 m_adj(m, ARC_HDRNEWLEN);
602 schednetisr(NETISR_IPV6);
603 inq = &ip6intrq;
604 break;
605#endif
606#ifdef IPX
607 case ARCTYPE_IPX:
608 m_adj(m, ARC_HDRNEWLEN);
609 schednetisr(NETISR_IPX);
610 inq = &ipxintrq;
611 break;
612#endif
613 default:
614 m_freem(m);
615 return;
616 }
617
618 IF_HANDOFF(inq, m, NULL);
619}
620
621/*
622 * Register (new) link level address.
623 */
624void
625arc_storelladdr(ifp, lla)
626 struct ifnet *ifp;
627 u_int8_t lla;
628{
549 m_freem(m);
550 return;
551 }
552
553 ifp->if_ibytes += m->m_pkthdr.len;
554
555 if (ah->arc_dhost == arcbroadcastaddr) {
556 m->m_flags |= M_BCAST|M_MCAST;
557 ifp->if_imcasts++;
558 }
559
560 atype = ah->arc_type;
561 switch (atype) {
562#ifdef INET
563 case ARCTYPE_IP:
564 m_adj(m, ARC_HDRNEWLEN);
565 if (ipflow_fastforward(m))
566 return;
567 schednetisr(NETISR_IP);
568 inq = &ipintrq;
569 break;
570
571 case ARCTYPE_IP_OLD:
572 m_adj(m, ARC_HDRLEN);
573 if (ipflow_fastforward(m))
574 return;
575 schednetisr(NETISR_IP);
576 inq = &ipintrq;
577 break;
578
579 case ARCTYPE_ARP:
580 if (ifp->if_flags & IFF_NOARP) {
581 /* Discard packet if ARP is disabled on interface */
582 m_freem(m);
583 return;
584 }
585 m_adj(m, ARC_HDRNEWLEN);
586 schednetisr(NETISR_ARP);
587 inq = &arpintrq;
588#ifdef ARCNET_ALLOW_BROKEN_ARP
589 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
590#endif
591 break;
592
593 case ARCTYPE_ARP_OLD:
594 if (ifp->if_flags & IFF_NOARP) {
595 /* Discard packet if ARP is disabled on interface */
596 m_freem(m);
597 return;
598 }
599 m_adj(m, ARC_HDRLEN);
600 schednetisr(NETISR_ARP);
601 inq = &arpintrq;
602#ifdef ARCNET_ALLOW_BROKEN_ARP
603 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
604#endif
605 break;
606#endif
607#ifdef INET6
608 case ARCTYPE_INET6:
609 m_adj(m, ARC_HDRNEWLEN);
610 schednetisr(NETISR_IPV6);
611 inq = &ip6intrq;
612 break;
613#endif
614#ifdef IPX
615 case ARCTYPE_IPX:
616 m_adj(m, ARC_HDRNEWLEN);
617 schednetisr(NETISR_IPX);
618 inq = &ipxintrq;
619 break;
620#endif
621 default:
622 m_freem(m);
623 return;
624 }
625
626 IF_HANDOFF(inq, m, NULL);
627}
628
629/*
630 * Register (new) link level address.
631 */
632void
633arc_storelladdr(ifp, lla)
634 struct ifnet *ifp;
635 u_int8_t lla;
636{
629 *IF_LLADDR(ifp) = lla;
637 ARC_LLADDR(ifp) = lla;
630}
631
632/*
633 * Perform common duties while attaching to interface list
634 */
635void
636arc_ifattach(ifp, lla)
637 struct ifnet *ifp;
638 u_int8_t lla;
639{
640 struct ifaddr *ifa;
641 struct sockaddr_dl *sdl;
642 struct arccom *ac;
643
644 if_attach(ifp);
645 ifp->if_type = IFT_ARCNET;
646 ifp->if_addrlen = 1;
647 ifp->if_hdrlen = ARC_HDRLEN;
648 ifp->if_mtu = 1500;
649 ifp->if_resolvemulti = arc_resolvemulti;
650 if (ifp->if_baudrate == 0)
651 ifp->if_baudrate = 2500000;
652#if __FreeBSD_version < 500000
653 ifa = ifnet_addrs[ifp->if_index - 1];
654#else
655 ifa = ifaddr_byindex(ifp->if_index);
656#endif
657 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__));
658 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
659 sdl->sdl_type = IFT_ARCNET;
660 sdl->sdl_alen = ifp->if_addrlen;
661
662 if (ifp->if_flags & IFF_BROADCAST)
663 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
664
665 ac = (struct arccom *)ifp;
666 ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
667 if (lla == 0) {
668 /* XXX this message isn't entirely clear, to me -- cgd */
669 log(LOG_ERR,"%s%d: link address 0 reserved for broadcasts. Please change it and ifconfig %s%d down up\n",
670 ifp->if_name, ifp->if_unit, ifp->if_name, ifp->if_unit);
671 }
672 arc_storelladdr(ifp, lla);
673
674 ifp->if_broadcastaddr = &arcbroadcastaddr;
675
676 bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
677}
678
679void
680arc_ifdetach(ifp)
681 struct ifnet *ifp;
682{
683 bpfdetach(ifp);
684 if_detach(ifp);
685}
686
687int
688arc_ioctl(ifp, command, data)
689 struct ifnet *ifp;
690 int command;
691 caddr_t data;
692{
693 struct ifaddr *ifa = (struct ifaddr *) data;
694 struct ifreq *ifr = (struct ifreq *) data;
695 int error = 0;
696
697 switch (command) {
698 case SIOCSIFADDR:
699 ifp->if_flags |= IFF_UP;
700 switch (ifa->ifa_addr->sa_family) {
701#ifdef INET
702 case AF_INET:
703 ifp->if_init(ifp->if_softc); /* before arpwhohas */
704 arp_ifinit(ifp, ifa);
705 break;
706#endif
707#ifdef IPX
708 /*
709 * XXX This code is probably wrong
710 */
711 case AF_IPX:
712 {
713 struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
714
715 if (ipx_nullhost(*ina))
638}
639
640/*
641 * Perform common duties while attaching to interface list
642 */
643void
644arc_ifattach(ifp, lla)
645 struct ifnet *ifp;
646 u_int8_t lla;
647{
648 struct ifaddr *ifa;
649 struct sockaddr_dl *sdl;
650 struct arccom *ac;
651
652 if_attach(ifp);
653 ifp->if_type = IFT_ARCNET;
654 ifp->if_addrlen = 1;
655 ifp->if_hdrlen = ARC_HDRLEN;
656 ifp->if_mtu = 1500;
657 ifp->if_resolvemulti = arc_resolvemulti;
658 if (ifp->if_baudrate == 0)
659 ifp->if_baudrate = 2500000;
660#if __FreeBSD_version < 500000
661 ifa = ifnet_addrs[ifp->if_index - 1];
662#else
663 ifa = ifaddr_byindex(ifp->if_index);
664#endif
665 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__));
666 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
667 sdl->sdl_type = IFT_ARCNET;
668 sdl->sdl_alen = ifp->if_addrlen;
669
670 if (ifp->if_flags & IFF_BROADCAST)
671 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
672
673 ac = (struct arccom *)ifp;
674 ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
675 if (lla == 0) {
676 /* XXX this message isn't entirely clear, to me -- cgd */
677 log(LOG_ERR,"%s%d: link address 0 reserved for broadcasts. Please change it and ifconfig %s%d down up\n",
678 ifp->if_name, ifp->if_unit, ifp->if_name, ifp->if_unit);
679 }
680 arc_storelladdr(ifp, lla);
681
682 ifp->if_broadcastaddr = &arcbroadcastaddr;
683
684 bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
685}
686
687void
688arc_ifdetach(ifp)
689 struct ifnet *ifp;
690{
691 bpfdetach(ifp);
692 if_detach(ifp);
693}
694
695int
696arc_ioctl(ifp, command, data)
697 struct ifnet *ifp;
698 int command;
699 caddr_t data;
700{
701 struct ifaddr *ifa = (struct ifaddr *) data;
702 struct ifreq *ifr = (struct ifreq *) data;
703 int error = 0;
704
705 switch (command) {
706 case SIOCSIFADDR:
707 ifp->if_flags |= IFF_UP;
708 switch (ifa->ifa_addr->sa_family) {
709#ifdef INET
710 case AF_INET:
711 ifp->if_init(ifp->if_softc); /* before arpwhohas */
712 arp_ifinit(ifp, ifa);
713 break;
714#endif
715#ifdef IPX
716 /*
717 * XXX This code is probably wrong
718 */
719 case AF_IPX:
720 {
721 struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
722
723 if (ipx_nullhost(*ina))
716 ina->x_host.c_host[5] = *IF_LLADDR(ifp);
724 ina->x_host.c_host[5] = ARC_LLADDR(ifp);
717 else
718 arc_storelladdr(ifp, ina->x_host.c_host[5]);
719
720 /*
721 * Set new address
722 */
723 ifp->if_init(ifp->if_softc);
724 break;
725 }
726#endif
727 default:
728 ifp->if_init(ifp->if_softc);
729 break;
730 }
731 break;
732
733 case SIOCGIFADDR:
734 {
735 struct sockaddr *sa;
736
737 sa = (struct sockaddr *) &ifr->ifr_data;
725 else
726 arc_storelladdr(ifp, ina->x_host.c_host[5]);
727
728 /*
729 * Set new address
730 */
731 ifp->if_init(ifp->if_softc);
732 break;
733 }
734#endif
735 default:
736 ifp->if_init(ifp->if_softc);
737 break;
738 }
739 break;
740
741 case SIOCGIFADDR:
742 {
743 struct sockaddr *sa;
744
745 sa = (struct sockaddr *) &ifr->ifr_data;
738 bcopy(IF_LLADDR(ifp),
739 (caddr_t) sa->sa_data, ARC_ADDR_LEN);
746 *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp);
740 }
741 break;
742
743 case SIOCADDMULTI:
744 case SIOCDELMULTI:
745 if (ifr == NULL)
746 error = EAFNOSUPPORT;
747 else {
748 switch (ifr->ifr_addr.sa_family) {
749 case AF_INET:
750 case AF_INET6:
751 error = 0;
752 break;
753 default:
754 error = EAFNOSUPPORT;
755 break;
756 }
757 }
758 break;
759
760 case SIOCSIFMTU:
761 /*
762 * Set the interface MTU.
763 * mtu can't be larger than ARCMTU for RFC1051
764 * and can't be larger than ARC_PHDS_MTU
765 */
766 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
767 ifr->ifr_mtu > ARC_PHDS_MAXMTU)
768 error = EINVAL;
769 else
770 ifp->if_mtu = ifr->ifr_mtu;
771 break;
772 }
773
774 return (error);
775}
776
777/* based on ether_resolvemulti() */
778int
779arc_resolvemulti(ifp, llsa, sa)
780 struct ifnet *ifp;
781 struct sockaddr **llsa;
782 struct sockaddr *sa;
783{
784 struct sockaddr_dl *sdl;
785 struct sockaddr_in *sin;
786#ifdef INET6
787 struct sockaddr_in6 *sin6;
788#endif
789
790 switch(sa->sa_family) {
791 case AF_LINK:
792 /*
793 * No mapping needed. Just check that it's a valid MC address.
794 */
795 sdl = (struct sockaddr_dl *)sa;
796 if (*LLADDR(sdl) != arcbroadcastaddr)
797 return EADDRNOTAVAIL;
798 *llsa = 0;
799 return 0;
800#ifdef INET
801 case AF_INET:
802 sin = (struct sockaddr_in *)sa;
803 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
804 return EADDRNOTAVAIL;
805 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
806 M_ZERO);
807 sdl->sdl_len = sizeof *sdl;
808 sdl->sdl_family = AF_LINK;
809 sdl->sdl_index = ifp->if_index;
810 sdl->sdl_type = IFT_ARCNET;
811 sdl->sdl_alen = ARC_ADDR_LEN;
812 *LLADDR(sdl) = 0;
813 *llsa = (struct sockaddr *)sdl;
814 return 0;
815#endif
816#ifdef INET6
817 case AF_INET6:
818 sin6 = (struct sockaddr_in6 *)sa;
819 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
820 /*
821 * An IP6 address of 0 means listen to all
822 * of the Ethernet multicast address used for IP6.
823 * (This is used for multicast routers.)
824 */
825 ifp->if_flags |= IFF_ALLMULTI;
826 *llsa = 0;
827 return 0;
828 }
829 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
830 return EADDRNOTAVAIL;
831 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
832 M_ZERO);
833 sdl->sdl_len = sizeof *sdl;
834 sdl->sdl_family = AF_LINK;
835 sdl->sdl_index = ifp->if_index;
836 sdl->sdl_type = IFT_ARCNET;
837 sdl->sdl_alen = ARC_ADDR_LEN;
838 *LLADDR(sdl) = 0;
839 *llsa = (struct sockaddr *)sdl;
840 return 0;
841#endif
842
843 default:
844 /*
845 * Well, the text isn't quite right, but it's the name
846 * that counts...
847 */
848 return EAFNOSUPPORT;
849 }
850}
747 }
748 break;
749
750 case SIOCADDMULTI:
751 case SIOCDELMULTI:
752 if (ifr == NULL)
753 error = EAFNOSUPPORT;
754 else {
755 switch (ifr->ifr_addr.sa_family) {
756 case AF_INET:
757 case AF_INET6:
758 error = 0;
759 break;
760 default:
761 error = EAFNOSUPPORT;
762 break;
763 }
764 }
765 break;
766
767 case SIOCSIFMTU:
768 /*
769 * Set the interface MTU.
770 * mtu can't be larger than ARCMTU for RFC1051
771 * and can't be larger than ARC_PHDS_MTU
772 */
773 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
774 ifr->ifr_mtu > ARC_PHDS_MAXMTU)
775 error = EINVAL;
776 else
777 ifp->if_mtu = ifr->ifr_mtu;
778 break;
779 }
780
781 return (error);
782}
783
784/* based on ether_resolvemulti() */
785int
786arc_resolvemulti(ifp, llsa, sa)
787 struct ifnet *ifp;
788 struct sockaddr **llsa;
789 struct sockaddr *sa;
790{
791 struct sockaddr_dl *sdl;
792 struct sockaddr_in *sin;
793#ifdef INET6
794 struct sockaddr_in6 *sin6;
795#endif
796
797 switch(sa->sa_family) {
798 case AF_LINK:
799 /*
800 * No mapping needed. Just check that it's a valid MC address.
801 */
802 sdl = (struct sockaddr_dl *)sa;
803 if (*LLADDR(sdl) != arcbroadcastaddr)
804 return EADDRNOTAVAIL;
805 *llsa = 0;
806 return 0;
807#ifdef INET
808 case AF_INET:
809 sin = (struct sockaddr_in *)sa;
810 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
811 return EADDRNOTAVAIL;
812 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
813 M_ZERO);
814 sdl->sdl_len = sizeof *sdl;
815 sdl->sdl_family = AF_LINK;
816 sdl->sdl_index = ifp->if_index;
817 sdl->sdl_type = IFT_ARCNET;
818 sdl->sdl_alen = ARC_ADDR_LEN;
819 *LLADDR(sdl) = 0;
820 *llsa = (struct sockaddr *)sdl;
821 return 0;
822#endif
823#ifdef INET6
824 case AF_INET6:
825 sin6 = (struct sockaddr_in6 *)sa;
826 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
827 /*
828 * An IP6 address of 0 means listen to all
829 * of the Ethernet multicast address used for IP6.
830 * (This is used for multicast routers.)
831 */
832 ifp->if_flags |= IFF_ALLMULTI;
833 *llsa = 0;
834 return 0;
835 }
836 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
837 return EADDRNOTAVAIL;
838 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
839 M_ZERO);
840 sdl->sdl_len = sizeof *sdl;
841 sdl->sdl_family = AF_LINK;
842 sdl->sdl_index = ifp->if_index;
843 sdl->sdl_type = IFT_ARCNET;
844 sdl->sdl_alen = ARC_ADDR_LEN;
845 *LLADDR(sdl) = 0;
846 *llsa = (struct sockaddr *)sdl;
847 return 0;
848#endif
849
850 default:
851 /*
852 * Well, the text isn't quite right, but it's the name
853 * that counts...
854 */
855 return EAFNOSUPPORT;
856 }
857}