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