Deleted Added
full compact
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
92#define ARC_LLADDR(ifp) (*(u_int8_t *)IF_LLADDR(ifp))
93
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;
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);
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 }
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);
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
547 && ah->arc_dhost != arcbroadcastaddr
540 && ah->arc_dhost != *IF_LLADDR(ifp)) {
548 && ah->arc_dhost != ARC_LLADDR(ifp)) {
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;
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);
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);
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}