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