if_ethersubr.c revision 1.21.4.3 1 /* $NetBSD: if_ethersubr.c,v 1.21.4.3 1997/02/12 16:52:14 is Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/mbuf.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/ioctl.h>
46 #include <sys/errno.h>
47 #include <sys/syslog.h>
48
49 #include <machine/cpu.h>
50
51 #include <net/if.h>
52 #include <net/netisr.h>
53 #include <net/route.h>
54 #include <net/if_llc.h>
55 #include <net/if_dl.h>
56 #include <net/if_types.h>
57
58 #include <net/if_ether.h>
59
60 #include <netinet/in.h>
61 #ifdef INET
62 #include <netinet/in_var.h>
63 #endif
64 #include <netinet/if_ether.h>
65
66 #ifdef NS
67 #include <netns/ns.h>
68 #include <netns/ns_if.h>
69 #endif
70
71 #ifdef ISO
72 #include <netiso/argo_debug.h>
73 #include <netiso/iso.h>
74 #include <netiso/iso_var.h>
75 #include <netiso/iso_snpac.h>
76 #endif
77
78 #ifdef LLC
79 #include <netccitt/dll.h>
80 #include <netccitt/llc_var.h>
81 #endif
82
83 #if defined(LLC) && defined(CCITT)
84 extern struct ifqueue pkintrq;
85 #endif
86
87 u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
88 #define senderr(e) { error = (e); goto bad;}
89
90 #define SIN(x) ((struct sockaddr_in *)x)
91
92 /*
93 * Ethernet output routine.
94 * Encapsulate a packet of type family for the local net.
95 * Assumes that ifp is actually pointer to ethercom structure.
96 */
97 int
98 ether_output(ifp, m0, dst, rt0)
99 register struct ifnet *ifp;
100 struct mbuf *m0;
101 struct sockaddr *dst;
102 struct rtentry *rt0;
103 {
104 u_int16_t etype;
105 int s, error = 0;
106 u_char edst[6];
107 register struct mbuf *m = m0;
108 register struct rtentry *rt;
109 struct mbuf *mcopy = (struct mbuf *)0;
110 register struct ether_header *eh;
111 struct arphdr *ah;
112
113 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
114 senderr(ENETDOWN);
115 ifp->if_lastchange = time;
116 if ((rt = rt0) != NULL) {
117 if ((rt->rt_flags & RTF_UP) == 0) {
118 if ((rt0 = rt = rtalloc1(dst, 1)) != NULL)
119 rt->rt_refcnt--;
120 else
121 senderr(EHOSTUNREACH);
122 }
123 if (rt->rt_flags & RTF_GATEWAY) {
124 if (rt->rt_gwroute == 0)
125 goto lookup;
126 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
127 rtfree(rt); rt = rt0;
128 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
129 if ((rt = rt->rt_gwroute) == 0)
130 senderr(EHOSTUNREACH);
131 }
132 }
133 if (rt->rt_flags & RTF_REJECT)
134 if (rt->rt_rmx.rmx_expire == 0 ||
135 time.tv_sec < rt->rt_rmx.rmx_expire)
136 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
137 }
138 switch (dst->sa_family) {
139
140 #ifdef INET
141 case AF_INET:
142 if (m->m_flags & M_BCAST)
143 bcopy((caddr_t)etherbroadcastaddr, (caddr_t)edst,
144 sizeof(edst));
145
146 else if (m->m_flags & M_MCAST) {
147 ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr,
148 (caddr_t)edst)
149
150 } else if (!arpresolve(ifp, rt, m, dst, edst))
151 return (0); /* if not yet resolved */
152 /* If broadcasting on a simplex interface, loopback a copy */
153 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
154 mcopy = m_copy(m, 0, (int)M_COPYALL);
155 etype = htons(ETHERTYPE_IP);
156 break;
157
158 case AF_ARP:
159 ah = mtod(m, struct arphdr *);
160 if (m->m_flags & M_BCAST)
161 bcopy((caddr_t)etherbroadcastaddr, (caddr_t)edst,
162 sizeof(edst));
163 else
164 bcopy((caddr_t)ar_tha(ah),
165 (caddr_t)edst, sizeof(edst));
166
167 ah->ar_hrd = htons(ARPHRD_ETHER);
168
169 switch(ntohs(ah->ar_op)) {
170 case ARPOP_REVREQUEST:
171 case ARPOP_REVREPLY:
172 etype = htons(ETHERTYPE_REVARP);
173 break;
174
175 case ARPOP_REQUEST:
176 case ARPOP_REPLY:
177 default:
178 etype = htons(ETHERTYPE_ARP);
179 }
180
181 break;
182 #endif
183 #ifdef NS
184 case AF_NS:
185 etype = htons(ETHERTYPE_NS);
186 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
187 (caddr_t)edst, sizeof (edst));
188 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
189 return (looutput(ifp, m, dst, rt));
190 /* If broadcasting on a simplex interface, loopback a copy */
191 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
192 mcopy = m_copy(m, 0, (int)M_COPYALL);
193 break;
194 #endif
195 #ifdef ISO
196 case AF_ISO: {
197 int snpalen;
198 struct llc *l;
199 register struct sockaddr_dl *sdl;
200
201 if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) &&
202 sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) {
203 bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst));
204 } else {
205 error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
206 (char *)edst, &snpalen);
207 if (error)
208 goto bad; /* Not Resolved */
209 }
210 /* If broadcasting on a simplex interface, loopback a copy */
211 if (*edst & 1)
212 m->m_flags |= (M_BCAST|M_MCAST);
213 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
214 (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
215 M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
216 if (mcopy) {
217 eh = mtod(mcopy, struct ether_header *);
218 bcopy((caddr_t)edst,
219 (caddr_t)eh->ether_dhost, sizeof (edst));
220 bcopy(LLADDR(ifp->if_sadl),
221 (caddr_t)eh->ether_shost, sizeof (edst));
222 }
223 }
224 M_PREPEND(m, 3, M_DONTWAIT);
225 if (m == NULL)
226 return (0);
227 etype = htons(m->m_pkthdr.len);
228 l = mtod(m, struct llc *);
229 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
230 l->llc_control = LLC_UI;
231 #ifdef ARGO_DEBUG
232 if (argo_debug[D_ETHER]) {
233 int i;
234 printf("unoutput: sending pkt to: ");
235 for (i=0; i<6; i++)
236 printf("%x ", edst[i] & 0xff);
237 printf("\n");
238 }
239 #endif
240 } break;
241 #endif /* ISO */
242 #ifdef LLC
243 /* case AF_NSAP: */
244 case AF_CCITT: {
245 register struct sockaddr_dl *sdl =
246 (struct sockaddr_dl *) rt -> rt_gateway;
247
248 if (sdl && sdl->sdl_family == AF_LINK
249 && sdl->sdl_alen > 0) {
250 bcopy(LLADDR(sdl), (char *)edst,
251 sizeof(edst));
252 } else goto bad; /* Not a link interface ? Funny ... */
253 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
254 (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
255 M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
256 if (mcopy) {
257 eh = mtod(mcopy, struct ether_header *);
258 bcopy((caddr_t)edst,
259 (caddr_t)eh->ether_dhost, sizeof (edst));
260 bcopy(LLADDR(ifp->if_sadl),
261 (caddr_t)eh->ether_shost, sizeof (edst));
262 }
263 }
264 etype = htons(m->m_pkthdr.len);
265 #ifdef LLC_DEBUG
266 {
267 int i;
268 register struct llc *l = mtod(m, struct llc *);
269
270 printf("ether_output: sending LLC2 pkt to: ");
271 for (i=0; i<6; i++)
272 printf("%x ", edst[i] & 0xff);
273 printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n",
274 m->m_pkthdr.len, l->llc_dsap & 0xff, l->llc_ssap &0xff,
275 l->llc_control & 0xff);
276
277 }
278 #endif /* LLC_DEBUG */
279 } break;
280 #endif /* LLC */
281
282 case AF_UNSPEC:
283 eh = (struct ether_header *)dst->sa_data;
284 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
285 /* AF_UNSPEC doesn't swap the byte order of the ether_type. */
286 etype = eh->ether_type;
287 break;
288
289 default:
290 printf("%s: can't handle af%d\n", ifp->if_xname,
291 dst->sa_family);
292 senderr(EAFNOSUPPORT);
293 }
294
295 if (mcopy)
296 (void) looutput(ifp, mcopy, dst, rt);
297
298 /*
299 * Add local net header. If no space in first mbuf,
300 * allocate another.
301 */
302 M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
303 if (m == 0)
304 senderr(ENOBUFS);
305 eh = mtod(m, struct ether_header *);
306 bcopy((caddr_t)&etype,(caddr_t)&eh->ether_type,
307 sizeof(eh->ether_type));
308 bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
309 bcopy(LLADDR(ifp->if_sadl), (caddr_t)eh->ether_shost,
310 sizeof(eh->ether_shost));
311 s = splimp();
312 /*
313 * Queue message on interface, and start output if interface
314 * not yet active.
315 */
316 if (IF_QFULL(&ifp->if_snd)) {
317 IF_DROP(&ifp->if_snd);
318 splx(s);
319 senderr(ENOBUFS);
320 }
321 ifp->if_obytes += m->m_pkthdr.len;
322 IF_ENQUEUE(&ifp->if_snd, m);
323 if ((ifp->if_flags & IFF_OACTIVE) == 0)
324 (*ifp->if_start)(ifp);
325 splx(s);
326 if (m->m_flags & M_MCAST)
327 ifp->if_omcasts++;
328 return (error);
329
330 bad:
331 if (m)
332 m_freem(m);
333 return (error);
334 }
335
336 /*
337 * Process a received Ethernet packet;
338 * the packet is in the mbuf chain m without
339 * the ether header, which is provided separately.
340 */
341 void
342 ether_input(ifp, eh, m)
343 struct ifnet *ifp;
344 register struct ether_header *eh;
345 struct mbuf *m;
346 {
347 register struct ifqueue *inq;
348 u_int16_t etype;
349 int s;
350 #if defined (ISO) || defined (LLC)
351 register struct llc *l;
352 struct ethercom *ac = (struct ethercom *)ifp;
353 #endif
354
355 if ((ifp->if_flags & IFF_UP) == 0) {
356 m_freem(m);
357 return;
358 }
359 ifp->if_lastchange = time;
360 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
361 if (eh->ether_dhost[0] & 1) {
362 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
363 sizeof(etherbroadcastaddr)) == 0)
364 m->m_flags |= M_BCAST;
365 else
366 m->m_flags |= M_MCAST;
367 }
368 if (m->m_flags & (M_BCAST|M_MCAST))
369 ifp->if_imcasts++;
370
371 etype = ntohs(eh->ether_type);
372 switch (etype) {
373 #ifdef INET
374 case ETHERTYPE_IP:
375 schednetisr(NETISR_IP);
376 inq = &ipintrq;
377 break;
378
379 case ETHERTYPE_ARP:
380 schednetisr(NETISR_ARP);
381 inq = &arpintrq;
382 break;
383
384 case ETHERTYPE_REVARP:
385 revarpinput(m); /* XXX queue? */
386 return;
387 #endif
388 #ifdef NS
389 case ETHERTYPE_NS:
390 schednetisr(NETISR_NS);
391 inq = &nsintrq;
392 break;
393
394 #endif
395 default:
396 #if defined (ISO) || defined (LLC)
397 if (etype > ETHERMTU)
398 goto dropanyway;
399 l = mtod(m, struct llc *);
400 switch (l->llc_dsap) {
401 #ifdef ISO
402 case LLC_ISO_LSAP:
403 switch (l->llc_control) {
404 case LLC_UI:
405 /* LLC_UI_P forbidden in class 1 service */
406 if ((l->llc_dsap == LLC_ISO_LSAP) &&
407 (l->llc_ssap == LLC_ISO_LSAP)) {
408 /* LSAP for ISO */
409 if (m->m_pkthdr.len > etype)
410 m_adj(m, etype - m->m_pkthdr.len);
411 m->m_data += 3; /* XXX */
412 m->m_len -= 3; /* XXX */
413 m->m_pkthdr.len -= 3; /* XXX */
414 M_PREPEND(m, sizeof *eh, M_DONTWAIT);
415 if (m == 0)
416 return;
417 *mtod(m, struct ether_header *) = *eh;
418 #ifdef ARGO_DEBUG
419 if (argo_debug[D_ETHER])
420 printf("clnp packet");
421 #endif
422 schednetisr(NETISR_ISO);
423 inq = &clnlintrq;
424 break;
425 }
426 goto dropanyway;
427
428 case LLC_XID:
429 case LLC_XID_P:
430 if(m->m_len < 6)
431 goto dropanyway;
432 l->llc_window = 0;
433 l->llc_fid = 9;
434 l->llc_class = 1;
435 l->llc_dsap = l->llc_ssap = 0;
436 /* Fall through to */
437 case LLC_TEST:
438 case LLC_TEST_P:
439 {
440 struct sockaddr sa;
441 register struct ether_header *eh2;
442 int i;
443 u_char c = l->llc_dsap;
444
445 l->llc_dsap = l->llc_ssap;
446 l->llc_ssap = c;
447 if (m->m_flags & (M_BCAST | M_MCAST))
448 bcopy(LLADDR(ifp->if_sadl),
449 (caddr_t)eh->ether_dhost, 6);
450 sa.sa_family = AF_UNSPEC;
451 sa.sa_len = sizeof(sa);
452 eh2 = (struct ether_header *)sa.sa_data;
453 for (i = 0; i < 6; i++) {
454 eh2->ether_shost[i] = c = eh->ether_dhost[i];
455 eh2->ether_dhost[i] =
456 eh->ether_dhost[i] = eh->ether_shost[i];
457 eh->ether_shost[i] = c;
458 }
459 ifp->if_output(ifp, m, &sa, NULL);
460 return;
461 }
462 default:
463 m_freem(m);
464 return;
465 }
466 break;
467 #endif /* ISO */
468 #ifdef LLC
469 case LLC_X25_LSAP:
470 {
471 if (m->m_pkthdr.len > etype)
472 m_adj(m, etype - m->m_pkthdr.len);
473 M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT);
474 if (m == 0)
475 return;
476 if ( !sdl_sethdrif(ifp, eh->ether_shost, LLC_X25_LSAP,
477 eh->ether_dhost, LLC_X25_LSAP, 6,
478 mtod(m, struct sdl_hdr *)))
479 panic("ETHER cons addr failure");
480 mtod(m, struct sdl_hdr *)->sdlhdr_len = etype;
481 #ifdef LLC_DEBUG
482 printf("llc packet\n");
483 #endif /* LLC_DEBUG */
484 schednetisr(NETISR_CCITT);
485 inq = &llcintrq;
486 break;
487 }
488 #endif /* LLC */
489 dropanyway:
490 default:
491 m_freem(m);
492 return;
493 }
494 #else /* ISO || LLC */
495 m_freem(m);
496 return;
497 #endif /* ISO || LLC */
498 }
499
500 s = splimp();
501 if (IF_QFULL(inq)) {
502 IF_DROP(inq);
503 m_freem(m);
504 } else
505 IF_ENQUEUE(inq, m);
506 splx(s);
507 }
508
509 /*
510 * Convert Ethernet address to printable (loggable) representation.
511 */
512 static char digits[] = "0123456789abcdef";
513 char *
514 ether_sprintf(ap)
515 register u_char *ap;
516 {
517 register i;
518 static char etherbuf[18];
519 register char *cp = etherbuf;
520
521 for (i = 0; i < 6; i++) {
522 *cp++ = digits[*ap >> 4];
523 *cp++ = digits[*ap++ & 0xf];
524 *cp++ = ':';
525 }
526 *--cp = 0;
527 return (etherbuf);
528 }
529
530 /*
531 * Perform common duties while attaching to interface list
532 */
533 void
534 ether_ifattach(ifp, lla)
535 register struct ifnet *ifp;
536 u_int8_t * lla;
537 {
538 register struct sockaddr_dl *sdl;
539
540 ifp->if_type = IFT_ETHER;
541 ifp->if_addrlen = 6;
542 ifp->if_hdrlen = 14;
543 ifp->if_mtu = ETHERMTU;
544 ifp->if_output = ether_output;
545 if ((sdl = ifp->if_sadl) &&
546 sdl->sdl_family == AF_LINK) {
547 sdl->sdl_type = IFT_ETHER;
548 sdl->sdl_alen = ifp->if_addrlen;
549 bcopy((caddr_t)lla, LLADDR(sdl), ifp->if_addrlen);
550 }
551 LIST_INIT(&((struct ethercom *)ifp)->ec_multiaddrs);
552 }
553
554 u_char ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
555 u_char ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
556 /*
557 * Add an Ethernet multicast address or range of addresses to the list for a
558 * given interface.
559 */
560 int
561 ether_addmulti(ifr, ec)
562 struct ifreq *ifr;
563 register struct ethercom *ec;
564 {
565 register struct ether_multi *enm;
566 struct sockaddr_in *sin;
567 u_char addrlo[6];
568 u_char addrhi[6];
569 int s = splimp();
570
571 switch (ifr->ifr_addr.sa_family) {
572
573 case AF_UNSPEC:
574 bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
575 bcopy(addrlo, addrhi, 6);
576 break;
577
578 #ifdef INET
579 case AF_INET:
580 sin = (struct sockaddr_in *)&(ifr->ifr_addr);
581 if (sin->sin_addr.s_addr == INADDR_ANY) {
582 /*
583 * An IP address of INADDR_ANY means listen to all
584 * of the Ethernet multicast addresses used for IP.
585 * (This is for the sake of IP multicast routers.)
586 */
587 bcopy(ether_ipmulticast_min, addrlo, 6);
588 bcopy(ether_ipmulticast_max, addrhi, 6);
589 }
590 else {
591 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
592 bcopy(addrlo, addrhi, 6);
593 }
594 break;
595 #endif
596
597 default:
598 splx(s);
599 return (EAFNOSUPPORT);
600 }
601
602 /*
603 * Verify that we have valid Ethernet multicast addresses.
604 */
605 if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) {
606 splx(s);
607 return (EINVAL);
608 }
609 /*
610 * See if the address range is already in the list.
611 */
612 ETHER_LOOKUP_MULTI(addrlo, addrhi, ec, enm);
613 if (enm != NULL) {
614 /*
615 * Found it; just increment the reference count.
616 */
617 ++enm->enm_refcount;
618 splx(s);
619 return (0);
620 }
621 /*
622 * New address or range; malloc a new multicast record
623 * and link it into the interface's multicast list.
624 */
625 enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT);
626 if (enm == NULL) {
627 splx(s);
628 return (ENOBUFS);
629 }
630 bcopy(addrlo, enm->enm_addrlo, 6);
631 bcopy(addrhi, enm->enm_addrhi, 6);
632 enm->enm_ec = ec;
633 enm->enm_refcount = 1;
634 LIST_INSERT_HEAD(&ec->ec_multiaddrs, enm, enm_list);
635 ec->ec_multicnt++;
636 splx(s);
637 /*
638 * Return ENETRESET to inform the driver that the list has changed
639 * and its reception filter should be adjusted accordingly.
640 */
641 return (ENETRESET);
642 }
643
644 /*
645 * Delete a multicast address record.
646 */
647 int
648 ether_delmulti(ifr, ec)
649 struct ifreq *ifr;
650 register struct ethercom *ec;
651 {
652 register struct ether_multi *enm;
653 struct sockaddr_in *sin;
654 u_char addrlo[6];
655 u_char addrhi[6];
656 int s = splimp();
657
658 switch (ifr->ifr_addr.sa_family) {
659
660 case AF_UNSPEC:
661 bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
662 bcopy(addrlo, addrhi, 6);
663 break;
664
665 #ifdef INET
666 case AF_INET:
667 sin = (struct sockaddr_in *)&(ifr->ifr_addr);
668 if (sin->sin_addr.s_addr == INADDR_ANY) {
669 /*
670 * An IP address of INADDR_ANY means stop listening
671 * to the range of Ethernet multicast addresses used
672 * for IP.
673 */
674 bcopy(ether_ipmulticast_min, addrlo, 6);
675 bcopy(ether_ipmulticast_max, addrhi, 6);
676 }
677 else {
678 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
679 bcopy(addrlo, addrhi, 6);
680 }
681 break;
682 #endif
683
684 default:
685 splx(s);
686 return (EAFNOSUPPORT);
687 }
688
689 /*
690 * Look up the address in our list.
691 */
692 ETHER_LOOKUP_MULTI(addrlo, addrhi, ec, enm);
693 if (enm == NULL) {
694 splx(s);
695 return (ENXIO);
696 }
697 if (--enm->enm_refcount != 0) {
698 /*
699 * Still some claims to this record.
700 */
701 splx(s);
702 return (0);
703 }
704 /*
705 * No remaining claims to this record; unlink and free it.
706 */
707 LIST_REMOVE(enm, enm_list);
708 free(enm, M_IFMADDR);
709 ec->ec_multicnt--;
710 splx(s);
711 /*
712 * Return ENETRESET to inform the driver that the list has changed
713 * and its reception filter should be adjusted accordingly.
714 */
715 return (ENETRESET);
716 }
717