1 | /* $NetBSD: if_ethersubr.c,v 1.229 2016/10/18 07:30:30 ozaki-r Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
5 | * 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. Neither the name of the project nor the names of its contributors |
16 | * may be used to endorse or promote products derived from this software |
17 | * without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Copyright (c) 1982, 1989, 1993 |
34 | * The Regents of the University of California. All rights reserved. |
35 | * |
36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions |
38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. |
44 | * 3. Neither the name of the University nor the names of its contributors |
45 | * may be used to endorse or promote products derived from this software |
46 | * without specific prior written permission. |
47 | * |
48 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
58 | * SUCH DAMAGE. |
59 | * |
60 | * @(#)if_ethersubr.c 8.2 (Berkeley) 4/4/96 |
61 | */ |
62 | |
63 | #include <sys/cdefs.h> |
64 | __KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.229 2016/10/18 07:30:30 ozaki-r Exp $" ); |
65 | |
66 | #ifdef _KERNEL_OPT |
67 | #include "opt_inet.h" |
68 | #include "opt_atalk.h" |
69 | #include "opt_mbuftrace.h" |
70 | #include "opt_mpls.h" |
71 | #include "opt_gateway.h" |
72 | #include "opt_pppoe.h" |
73 | #include "opt_net_mpsafe.h" |
74 | #endif |
75 | |
76 | #include "vlan.h" |
77 | #include "pppoe.h" |
78 | #include "bridge.h" |
79 | #include "arp.h" |
80 | #include "agr.h" |
81 | |
82 | #include <sys/sysctl.h> |
83 | #include <sys/malloc.h> |
84 | #include <sys/mbuf.h> |
85 | #include <sys/mutex.h> |
86 | #include <sys/ioctl.h> |
87 | #include <sys/errno.h> |
88 | #include <sys/device.h> |
89 | #include <sys/rnd.h> |
90 | #include <sys/rndsource.h> |
91 | #include <sys/cpu.h> |
92 | |
93 | #include <net/if.h> |
94 | #include <net/netisr.h> |
95 | #include <net/route.h> |
96 | #include <net/if_llc.h> |
97 | #include <net/if_dl.h> |
98 | #include <net/if_types.h> |
99 | #include <net/pktqueue.h> |
100 | |
101 | #include <net/if_media.h> |
102 | #include <dev/mii/mii.h> |
103 | #include <dev/mii/miivar.h> |
104 | |
105 | #if NARP == 0 |
106 | /* |
107 | * XXX there should really be a way to issue this warning from within config(8) |
108 | */ |
109 | #error You have included NETATALK or a pseudo-device in your configuration that depends on the presence of ethernet interfaces, but have no such interfaces configured. Check if you really need pseudo-device bridge, pppoe, vlan or options NETATALK. |
110 | #endif |
111 | |
112 | #include <net/bpf.h> |
113 | |
114 | #include <net/if_ether.h> |
115 | #include <net/if_vlanvar.h> |
116 | |
117 | #if NPPPOE > 0 |
118 | #include <net/if_pppoe.h> |
119 | #endif |
120 | |
121 | #if NAGR > 0 |
122 | #include <net/agr/ieee8023_slowprotocols.h> /* XXX */ |
123 | #include <net/agr/ieee8023ad.h> |
124 | #include <net/agr/if_agrvar.h> |
125 | #endif |
126 | |
127 | #if NBRIDGE > 0 |
128 | #include <net/if_bridgevar.h> |
129 | #endif |
130 | |
131 | #include <netinet/in.h> |
132 | #ifdef INET |
133 | #include <netinet/in_var.h> |
134 | #endif |
135 | #include <netinet/if_inarp.h> |
136 | |
137 | #ifdef INET6 |
138 | #ifndef INET |
139 | #include <netinet/in.h> |
140 | #endif |
141 | #include <netinet6/in6_var.h> |
142 | #include <netinet6/nd6.h> |
143 | #endif |
144 | |
145 | |
146 | #include "carp.h" |
147 | #if NCARP > 0 |
148 | #include <netinet/ip_carp.h> |
149 | #endif |
150 | |
151 | #ifdef NETATALK |
152 | #include <netatalk/at.h> |
153 | #include <netatalk/at_var.h> |
154 | #include <netatalk/at_extern.h> |
155 | |
156 | #define llc_snap_org_code llc_un.type_snap.org_code |
157 | #define llc_snap_ether_type llc_un.type_snap.ether_type |
158 | |
159 | extern u_char at_org_code[3]; |
160 | extern u_char aarp_org_code[3]; |
161 | #endif /* NETATALK */ |
162 | |
163 | #ifdef MPLS |
164 | #include <netmpls/mpls.h> |
165 | #include <netmpls/mpls_var.h> |
166 | #endif |
167 | |
168 | static struct timeval bigpktppslim_last; |
169 | static int bigpktppslim = 2; /* XXX */ |
170 | static int bigpktpps_count; |
171 | static kmutex_t bigpktpps_lock __cacheline_aligned; |
172 | |
173 | |
174 | const uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = |
175 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
176 | const uint8_t ethermulticastaddr_slowprotocols[ETHER_ADDR_LEN] = |
177 | { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 }; |
178 | #define senderr(e) { error = (e); goto bad;} |
179 | |
180 | static int ether_output(struct ifnet *, struct mbuf *, |
181 | const struct sockaddr *, const struct rtentry *); |
182 | |
183 | /* |
184 | * Ethernet output routine. |
185 | * Encapsulate a packet of type family for the local net. |
186 | * Assumes that ifp is actually pointer to ethercom structure. |
187 | */ |
188 | static int |
189 | ether_output(struct ifnet * const ifp0, struct mbuf * const m0, |
190 | const struct sockaddr * const dst, |
191 | const struct rtentry *rt) |
192 | { |
193 | uint16_t etype = 0; |
194 | int error = 0, hdrcmplt = 0; |
195 | uint8_t esrc[6], edst[6]; |
196 | struct mbuf *m = m0; |
197 | struct mbuf *mcopy = NULL; |
198 | struct ether_header *eh; |
199 | struct ifnet *ifp = ifp0; |
200 | #ifdef INET |
201 | struct arphdr *ah; |
202 | #endif /* INET */ |
203 | #ifdef NETATALK |
204 | struct at_ifaddr *aa; |
205 | #endif /* NETATALK */ |
206 | |
207 | /* |
208 | * some paths such as carp_output() call ethr_output() with "ifp" |
209 | * argument as other than ether ifnet. |
210 | */ |
211 | KASSERT(ifp->if_output != ether_output |
212 | || ifp->if_extflags & IFEF_OUTPUT_MPSAFE); |
213 | |
214 | #ifdef MBUFTRACE |
215 | m_claimm(m, ifp->if_mowner); |
216 | #endif |
217 | |
218 | #if NCARP > 0 |
219 | if (ifp->if_type == IFT_CARP) { |
220 | struct ifaddr *ifa; |
221 | int s = pserialize_read_enter(); |
222 | |
223 | /* loop back if this is going to the carp interface */ |
224 | if (dst != NULL && ifp0->if_link_state == LINK_STATE_UP && |
225 | (ifa = ifa_ifwithaddr(dst)) != NULL) { |
226 | if (ifa->ifa_ifp == ifp0) { |
227 | pserialize_read_exit(s); |
228 | return looutput(ifp0, m, dst, rt); |
229 | } |
230 | } |
231 | pserialize_read_exit(s); |
232 | |
233 | ifp = ifp->if_carpdev; |
234 | /* ac = (struct arpcom *)ifp; */ |
235 | |
236 | if ((ifp0->if_flags & (IFF_UP|IFF_RUNNING)) != |
237 | (IFF_UP|IFF_RUNNING)) |
238 | senderr(ENETDOWN); |
239 | } |
240 | #endif /* NCARP > 0 */ |
241 | |
242 | if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) |
243 | senderr(ENETDOWN); |
244 | |
245 | switch (dst->sa_family) { |
246 | |
247 | #ifdef INET |
248 | case AF_INET: |
249 | #ifndef NET_MPSAFE |
250 | KERNEL_LOCK(1, NULL); |
251 | #endif |
252 | if (m->m_flags & M_BCAST) |
253 | (void)memcpy(edst, etherbroadcastaddr, sizeof(edst)); |
254 | else if (m->m_flags & M_MCAST) |
255 | ETHER_MAP_IP_MULTICAST(&satocsin(dst)->sin_addr, edst); |
256 | else if ((error = arpresolve(ifp, rt, m, dst, edst, |
257 | sizeof(edst))) != 0) { |
258 | #ifndef NET_MPSAFE |
259 | KERNEL_UNLOCK_ONE(NULL); |
260 | #endif |
261 | return error == EWOULDBLOCK ? 0 : error; |
262 | } |
263 | #ifndef NET_MPSAFE |
264 | KERNEL_UNLOCK_ONE(NULL); |
265 | #endif |
266 | /* If broadcasting on a simplex interface, loopback a copy */ |
267 | if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) |
268 | mcopy = m_copy(m, 0, (int)M_COPYALL); |
269 | etype = htons(ETHERTYPE_IP); |
270 | break; |
271 | |
272 | case AF_ARP: |
273 | ah = mtod(m, struct arphdr *); |
274 | if (m->m_flags & M_BCAST) |
275 | (void)memcpy(edst, etherbroadcastaddr, sizeof(edst)); |
276 | else { |
277 | void *tha = ar_tha(ah); |
278 | |
279 | if (tha == NULL) { |
280 | /* fake with ARPHDR_IEEE1394 */ |
281 | return 0; |
282 | } |
283 | memcpy(edst, tha, sizeof(edst)); |
284 | } |
285 | |
286 | ah->ar_hrd = htons(ARPHRD_ETHER); |
287 | |
288 | switch (ntohs(ah->ar_op)) { |
289 | case ARPOP_REVREQUEST: |
290 | case ARPOP_REVREPLY: |
291 | etype = htons(ETHERTYPE_REVARP); |
292 | break; |
293 | |
294 | case ARPOP_REQUEST: |
295 | case ARPOP_REPLY: |
296 | default: |
297 | etype = htons(ETHERTYPE_ARP); |
298 | } |
299 | |
300 | break; |
301 | #endif |
302 | #ifdef INET6 |
303 | case AF_INET6: |
304 | if (!nd6_storelladdr(ifp, rt, m, dst, edst, sizeof(edst))){ |
305 | /* something bad happened */ |
306 | return (0); |
307 | } |
308 | etype = htons(ETHERTYPE_IPV6); |
309 | break; |
310 | #endif |
311 | #ifdef NETATALK |
312 | case AF_APPLETALK: { |
313 | struct ifaddr *ifa; |
314 | int s; |
315 | |
316 | KERNEL_LOCK(1, NULL); |
317 | if (!aarpresolve(ifp, m, (const struct sockaddr_at *)dst, edst)) { |
318 | #ifdef NETATALKDEBUG |
319 | printf("aarpresolv failed\n" ); |
320 | #endif /* NETATALKDEBUG */ |
321 | KERNEL_UNLOCK_ONE(NULL); |
322 | return (0); |
323 | } |
324 | /* |
325 | * ifaddr is the first thing in at_ifaddr |
326 | */ |
327 | s = pserialize_read_enter(); |
328 | ifa = at_ifawithnet((const struct sockaddr_at *)dst, ifp); |
329 | if (ifa == NULL) { |
330 | pserialize_read_exit(s); |
331 | KERNEL_UNLOCK_ONE(NULL); |
332 | goto bad; |
333 | } |
334 | aa = (struct at_ifaddr *)ifa; |
335 | |
336 | /* |
337 | * In the phase 2 case, we need to prepend an mbuf for the |
338 | * llc header. Since we must preserve the value of m, |
339 | * which is passed to us by value, we m_copy() the first |
340 | * mbuf, and use it for our llc header. |
341 | */ |
342 | if (aa->aa_flags & AFA_PHASE2) { |
343 | struct llc llc; |
344 | |
345 | M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); |
346 | llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; |
347 | llc.llc_control = LLC_UI; |
348 | memcpy(llc.llc_snap_org_code, at_org_code, |
349 | sizeof(llc.llc_snap_org_code)); |
350 | llc.llc_snap_ether_type = htons(ETHERTYPE_ATALK); |
351 | memcpy(mtod(m, void *), &llc, sizeof(struct llc)); |
352 | } else { |
353 | etype = htons(ETHERTYPE_ATALK); |
354 | } |
355 | pserialize_read_exit(s); |
356 | KERNEL_UNLOCK_ONE(NULL); |
357 | break; |
358 | } |
359 | #endif /* NETATALK */ |
360 | case pseudo_AF_HDRCMPLT: |
361 | hdrcmplt = 1; |
362 | memcpy(esrc, |
363 | ((const struct ether_header *)dst->sa_data)->ether_shost, |
364 | sizeof(esrc)); |
365 | /* FALLTHROUGH */ |
366 | |
367 | case AF_UNSPEC: |
368 | memcpy(edst, |
369 | ((const struct ether_header *)dst->sa_data)->ether_dhost, |
370 | sizeof(edst)); |
371 | /* AF_UNSPEC doesn't swap the byte order of the ether_type. */ |
372 | etype = ((const struct ether_header *)dst->sa_data)->ether_type; |
373 | break; |
374 | |
375 | default: |
376 | printf("%s: can't handle af%d\n" , ifp->if_xname, |
377 | dst->sa_family); |
378 | senderr(EAFNOSUPPORT); |
379 | } |
380 | |
381 | #ifdef MPLS |
382 | KERNEL_LOCK(1, NULL); |
383 | { |
384 | struct m_tag *mtag; |
385 | mtag = m_tag_find(m, PACKET_TAG_MPLS, NULL); |
386 | if (mtag != NULL) { |
387 | /* Having the tag itself indicates it's MPLS */ |
388 | etype = htons(ETHERTYPE_MPLS); |
389 | m_tag_delete(m, mtag); |
390 | } |
391 | } |
392 | KERNEL_UNLOCK_ONE(NULL); |
393 | #endif |
394 | |
395 | if (mcopy) |
396 | (void)looutput(ifp, mcopy, dst, rt); |
397 | |
398 | /* If no ether type is set, this must be a 802.2 formatted packet. |
399 | */ |
400 | if (etype == 0) |
401 | etype = htons(m->m_pkthdr.len); |
402 | /* |
403 | * Add local net header. If no space in first mbuf, |
404 | * allocate another. |
405 | */ |
406 | M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); |
407 | if (m == 0) |
408 | senderr(ENOBUFS); |
409 | eh = mtod(m, struct ether_header *); |
410 | /* Note: etype is already in network byte order. */ |
411 | (void)memcpy(&eh->ether_type, &etype, sizeof(eh->ether_type)); |
412 | memcpy(eh->ether_dhost, edst, sizeof(edst)); |
413 | if (hdrcmplt) |
414 | memcpy(eh->ether_shost, esrc, sizeof(eh->ether_shost)); |
415 | else |
416 | memcpy(eh->ether_shost, CLLADDR(ifp->if_sadl), |
417 | sizeof(eh->ether_shost)); |
418 | |
419 | #if NCARP > 0 |
420 | if (ifp0 != ifp && ifp0->if_type == IFT_CARP) { |
421 | memcpy(eh->ether_shost, CLLADDR(ifp0->if_sadl), |
422 | sizeof(eh->ether_shost)); |
423 | } |
424 | #endif /* NCARP > 0 */ |
425 | |
426 | if ((error = pfil_run_hooks(ifp->if_pfil, &m, ifp, PFIL_OUT)) != 0) |
427 | return (error); |
428 | if (m == NULL) |
429 | return (0); |
430 | |
431 | #if NBRIDGE > 0 |
432 | /* |
433 | * Bridges require special output handling. |
434 | */ |
435 | if (ifp->if_bridge) |
436 | return (bridge_output(ifp, m, NULL, NULL)); |
437 | #endif |
438 | |
439 | #if NCARP > 0 |
440 | if (ifp != ifp0) |
441 | ifp0->if_obytes += m->m_pkthdr.len + ETHER_HDR_LEN; |
442 | #endif /* NCARP > 0 */ |
443 | |
444 | #ifdef ALTQ |
445 | KERNEL_LOCK(1, NULL); |
446 | /* |
447 | * If ALTQ is enabled on the parent interface, do |
448 | * classification; the queueing discipline might not |
449 | * require classification, but might require the |
450 | * address family/header pointer in the pktattr. |
451 | */ |
452 | if (ALTQ_IS_ENABLED(&ifp->if_snd)) |
453 | altq_etherclassify(&ifp->if_snd, m); |
454 | KERNEL_UNLOCK_ONE(NULL); |
455 | #endif |
456 | return ifq_enqueue(ifp, m); |
457 | |
458 | bad: |
459 | if (m) |
460 | m_freem(m); |
461 | return (error); |
462 | } |
463 | |
464 | #ifdef ALTQ |
465 | /* |
466 | * This routine is a slight hack to allow a packet to be classified |
467 | * if the Ethernet headers are present. It will go away when ALTQ's |
468 | * classification engine understands link headers. |
469 | */ |
470 | void |
471 | altq_etherclassify(struct ifaltq *ifq, struct mbuf *m) |
472 | { |
473 | struct ether_header *eh; |
474 | uint16_t ether_type; |
475 | int hlen, af, hdrsize; |
476 | void *hdr; |
477 | |
478 | hlen = ETHER_HDR_LEN; |
479 | eh = mtod(m, struct ether_header *); |
480 | |
481 | ether_type = htons(eh->ether_type); |
482 | |
483 | if (ether_type < ETHERMTU) { |
484 | /* LLC/SNAP */ |
485 | struct llc *llc = (struct llc *)(eh + 1); |
486 | hlen += 8; |
487 | |
488 | if (m->m_len < hlen || |
489 | llc->llc_dsap != LLC_SNAP_LSAP || |
490 | llc->llc_ssap != LLC_SNAP_LSAP || |
491 | llc->llc_control != LLC_UI) { |
492 | /* Not SNAP. */ |
493 | goto bad; |
494 | } |
495 | |
496 | ether_type = htons(llc->llc_un.type_snap.ether_type); |
497 | } |
498 | |
499 | switch (ether_type) { |
500 | case ETHERTYPE_IP: |
501 | af = AF_INET; |
502 | hdrsize = 20; /* sizeof(struct ip) */ |
503 | break; |
504 | |
505 | case ETHERTYPE_IPV6: |
506 | af = AF_INET6; |
507 | hdrsize = 40; /* sizeof(struct ip6_hdr) */ |
508 | break; |
509 | |
510 | default: |
511 | af = AF_UNSPEC; |
512 | hdrsize = 0; |
513 | break; |
514 | } |
515 | |
516 | while (m->m_len <= hlen) { |
517 | hlen -= m->m_len; |
518 | m = m->m_next; |
519 | } |
520 | if (m->m_len < (hlen + hdrsize)) { |
521 | /* |
522 | * protocol header not in a single mbuf. |
523 | * We can't cope with this situation right |
524 | * now (but it shouldn't ever happen, really, anyhow). |
525 | */ |
526 | #ifdef DEBUG |
527 | printf("altq_etherclassify: headers span multiple mbufs: " |
528 | "%d < %d\n" , m->m_len, (hlen + hdrsize)); |
529 | #endif |
530 | goto bad; |
531 | } |
532 | |
533 | m->m_data += hlen; |
534 | m->m_len -= hlen; |
535 | |
536 | hdr = mtod(m, void *); |
537 | |
538 | if (ALTQ_NEEDS_CLASSIFY(ifq)) |
539 | m->m_pkthdr.pattr_class = |
540 | (*ifq->altq_classify)(ifq->altq_clfier, m, af); |
541 | m->m_pkthdr.pattr_af = af; |
542 | m->m_pkthdr.pattr_hdr = hdr; |
543 | |
544 | m->m_data -= hlen; |
545 | m->m_len += hlen; |
546 | |
547 | return; |
548 | |
549 | bad: |
550 | m->m_pkthdr.pattr_class = NULL; |
551 | m->m_pkthdr.pattr_hdr = NULL; |
552 | m->m_pkthdr.pattr_af = AF_UNSPEC; |
553 | } |
554 | #endif /* ALTQ */ |
555 | |
556 | /* |
557 | * Process a received Ethernet packet; |
558 | * the packet is in the mbuf chain m with |
559 | * the ether header. |
560 | */ |
561 | void |
562 | ether_input(struct ifnet *ifp, struct mbuf *m) |
563 | { |
564 | struct ethercom *ec = (struct ethercom *) ifp; |
565 | pktqueue_t *pktq = NULL; |
566 | struct ifqueue *inq = NULL; |
567 | uint16_t etype; |
568 | struct ether_header *eh; |
569 | size_t ehlen; |
570 | static int earlypkts; |
571 | int isr = 0; |
572 | #if defined (LLC) || defined(NETATALK) |
573 | struct llc *l; |
574 | #endif |
575 | |
576 | KASSERT(!cpu_intr_p()); |
577 | |
578 | if ((ifp->if_flags & IFF_UP) == 0) { |
579 | m_freem(m); |
580 | return; |
581 | } |
582 | |
583 | #ifdef MBUFTRACE |
584 | m_claimm(m, &ec->ec_rx_mowner); |
585 | #endif |
586 | eh = mtod(m, struct ether_header *); |
587 | etype = ntohs(eh->ether_type); |
588 | ehlen = sizeof(*eh); |
589 | |
590 | if(__predict_false(earlypkts < 100 || !rnd_initial_entropy)) { |
591 | rnd_add_data(NULL, eh, ehlen, 0); |
592 | earlypkts++; |
593 | } |
594 | |
595 | /* |
596 | * Determine if the packet is within its size limits. |
597 | */ |
598 | if (etype != ETHERTYPE_MPLS && m->m_pkthdr.len > |
599 | ETHER_MAX_FRAME(ifp, etype, m->m_flags & M_HASFCS)) { |
600 | mutex_enter(&bigpktpps_lock); |
601 | if (ppsratecheck(&bigpktppslim_last, &bigpktpps_count, |
602 | bigpktppslim)) { |
603 | printf("%s: discarding oversize frame (len=%d)\n" , |
604 | ifp->if_xname, m->m_pkthdr.len); |
605 | } |
606 | mutex_exit(&bigpktpps_lock); |
607 | m_freem(m); |
608 | return; |
609 | } |
610 | |
611 | if (ETHER_IS_MULTICAST(eh->ether_dhost)) { |
612 | /* |
613 | * If this is not a simplex interface, drop the packet |
614 | * if it came from us. |
615 | */ |
616 | if ((ifp->if_flags & IFF_SIMPLEX) == 0 && |
617 | memcmp(CLLADDR(ifp->if_sadl), eh->ether_shost, |
618 | ETHER_ADDR_LEN) == 0) { |
619 | m_freem(m); |
620 | return; |
621 | } |
622 | |
623 | if (memcmp(etherbroadcastaddr, |
624 | eh->ether_dhost, ETHER_ADDR_LEN) == 0) |
625 | m->m_flags |= M_BCAST; |
626 | else |
627 | m->m_flags |= M_MCAST; |
628 | ifp->if_imcasts++; |
629 | } |
630 | |
631 | /* If the CRC is still on the packet, trim it off. */ |
632 | if (m->m_flags & M_HASFCS) { |
633 | m_adj(m, -ETHER_CRC_LEN); |
634 | m->m_flags &= ~M_HASFCS; |
635 | } |
636 | |
637 | ifp->if_ibytes += m->m_pkthdr.len; |
638 | |
639 | #if NCARP > 0 |
640 | if (__predict_false(ifp->if_carp && ifp->if_type != IFT_CARP)) { |
641 | /* |
642 | * clear M_PROMISC, in case the packets comes from a |
643 | * vlan |
644 | */ |
645 | m->m_flags &= ~M_PROMISC; |
646 | if (carp_input(m, (uint8_t *)&eh->ether_shost, |
647 | (uint8_t *)&eh->ether_dhost, eh->ether_type) == 0) |
648 | return; |
649 | } |
650 | #endif /* NCARP > 0 */ |
651 | if ((m->m_flags & (M_BCAST|M_MCAST|M_PROMISC)) == 0 && |
652 | (ifp->if_flags & IFF_PROMISC) != 0 && |
653 | memcmp(CLLADDR(ifp->if_sadl), eh->ether_dhost, |
654 | ETHER_ADDR_LEN) != 0) { |
655 | m->m_flags |= M_PROMISC; |
656 | } |
657 | |
658 | if ((m->m_flags & M_PROMISC) == 0) { |
659 | if (pfil_run_hooks(ifp->if_pfil, &m, ifp, PFIL_IN) != 0) |
660 | return; |
661 | if (m == NULL) |
662 | return; |
663 | |
664 | eh = mtod(m, struct ether_header *); |
665 | etype = ntohs(eh->ether_type); |
666 | ehlen = sizeof(*eh); |
667 | } |
668 | |
669 | #if NAGR > 0 |
670 | if (ifp->if_agrprivate && |
671 | __predict_true(etype != ETHERTYPE_SLOWPROTOCOLS)) { |
672 | m->m_flags &= ~M_PROMISC; |
673 | agr_input(ifp, m); |
674 | return; |
675 | } |
676 | #endif /* NAGR > 0 */ |
677 | |
678 | /* |
679 | * If VLANs are configured on the interface, check to |
680 | * see if the device performed the decapsulation and |
681 | * provided us with the tag. |
682 | */ |
683 | if (ec->ec_nvlans && m_tag_find(m, PACKET_TAG_VLAN, NULL) != NULL) { |
684 | #if NVLAN > 0 |
685 | /* |
686 | * vlan_input() will either recursively call ether_input() |
687 | * or drop the packet. |
688 | */ |
689 | vlan_input(ifp, m); |
690 | #else |
691 | m_freem(m); |
692 | #endif |
693 | return; |
694 | } |
695 | |
696 | /* |
697 | * Handle protocols that expect to have the Ethernet header |
698 | * (and possibly FCS) intact. |
699 | */ |
700 | switch (etype) { |
701 | case ETHERTYPE_VLAN: { |
702 | struct ether_vlan_header *evl = (void *)eh; |
703 | /* |
704 | * If there is a tag of 0, then the VLAN header was probably |
705 | * just being used to store the priority. Extract the ether |
706 | * type, and if IP or IPV6, let them deal with it. |
707 | */ |
708 | if (m->m_len <= sizeof(*evl) |
709 | && EVL_VLANOFTAG(evl->evl_tag) == 0) { |
710 | etype = ntohs(evl->evl_proto); |
711 | ehlen = sizeof(*evl); |
712 | if ((m->m_flags & M_PROMISC) == 0 |
713 | && (etype == ETHERTYPE_IP |
714 | || etype == ETHERTYPE_IPV6)) |
715 | break; |
716 | } |
717 | #if NVLAN > 0 |
718 | /* |
719 | * vlan_input() will either recursively call ether_input() |
720 | * or drop the packet. |
721 | */ |
722 | if (((struct ethercom *)ifp)->ec_nvlans != 0) |
723 | vlan_input(ifp, m); |
724 | else |
725 | #endif /* NVLAN > 0 */ |
726 | m_freem(m); |
727 | return; |
728 | } |
729 | #if NPPPOE > 0 |
730 | case ETHERTYPE_PPPOEDISC: |
731 | pppoedisc_input(ifp, m); |
732 | return; |
733 | case ETHERTYPE_PPPOE: |
734 | pppoe_input(ifp, m); |
735 | return; |
736 | #endif /* NPPPOE > 0 */ |
737 | case ETHERTYPE_SLOWPROTOCOLS: { |
738 | uint8_t subtype; |
739 | |
740 | #if defined(DIAGNOSTIC) |
741 | if (m->m_pkthdr.len < sizeof(*eh) + sizeof(subtype)) { |
742 | panic("ether_input: too short slow protocol packet" ); |
743 | } |
744 | #endif |
745 | m_copydata(m, sizeof(*eh), sizeof(subtype), &subtype); |
746 | switch (subtype) { |
747 | #if NAGR > 0 |
748 | case SLOWPROTOCOLS_SUBTYPE_LACP: |
749 | if (ifp->if_agrprivate) { |
750 | ieee8023ad_lacp_input(ifp, m); |
751 | return; |
752 | } |
753 | break; |
754 | |
755 | case SLOWPROTOCOLS_SUBTYPE_MARKER: |
756 | if (ifp->if_agrprivate) { |
757 | ieee8023ad_marker_input(ifp, m); |
758 | return; |
759 | } |
760 | break; |
761 | #endif /* NAGR > 0 */ |
762 | default: |
763 | if (subtype == 0 || subtype > 10) { |
764 | /* illegal value */ |
765 | m_freem(m); |
766 | return; |
767 | } |
768 | /* unknown subtype */ |
769 | break; |
770 | } |
771 | /* FALLTHROUGH */ |
772 | } |
773 | default: |
774 | if (m->m_flags & M_PROMISC) { |
775 | m_freem(m); |
776 | return; |
777 | } |
778 | } |
779 | |
780 | /* If the CRC is still on the packet, trim it off. */ |
781 | if (m->m_flags & M_HASFCS) { |
782 | m_adj(m, -ETHER_CRC_LEN); |
783 | m->m_flags &= ~M_HASFCS; |
784 | } |
785 | |
786 | if (etype > ETHERMTU + sizeof (struct ether_header)) { |
787 | /* Strip off the Ethernet header. */ |
788 | m_adj(m, ehlen); |
789 | |
790 | switch (etype) { |
791 | #ifdef INET |
792 | case ETHERTYPE_IP: |
793 | #ifdef GATEWAY |
794 | if (ipflow_fastforward(m)) |
795 | return; |
796 | #endif |
797 | pktq = ip_pktq; |
798 | break; |
799 | |
800 | case ETHERTYPE_ARP: |
801 | isr = NETISR_ARP; |
802 | inq = &arpintrq; |
803 | break; |
804 | |
805 | case ETHERTYPE_REVARP: |
806 | revarpinput(m); /* XXX queue? */ |
807 | return; |
808 | #endif |
809 | #ifdef INET6 |
810 | case ETHERTYPE_IPV6: |
811 | if (__predict_false(!in6_present)) { |
812 | m_freem(m); |
813 | return; |
814 | } |
815 | #ifdef GATEWAY |
816 | if (ip6flow_fastforward(&m)) |
817 | return; |
818 | #endif |
819 | pktq = ip6_pktq; |
820 | break; |
821 | #endif |
822 | #ifdef NETATALK |
823 | case ETHERTYPE_ATALK: |
824 | isr = NETISR_ATALK; |
825 | inq = &atintrq1; |
826 | break; |
827 | case ETHERTYPE_AARP: |
828 | /* probably this should be done with a NETISR as well */ |
829 | aarpinput(ifp, m); /* XXX */ |
830 | return; |
831 | #endif /* NETATALK */ |
832 | #ifdef MPLS |
833 | case ETHERTYPE_MPLS: |
834 | isr = NETISR_MPLS; |
835 | inq = &mplsintrq; |
836 | break; |
837 | #endif |
838 | default: |
839 | m_freem(m); |
840 | return; |
841 | } |
842 | } else { |
843 | #if defined (LLC) || defined (NETATALK) |
844 | l = (struct llc *)(eh+1); |
845 | switch (l->llc_dsap) { |
846 | #ifdef NETATALK |
847 | case LLC_SNAP_LSAP: |
848 | switch (l->llc_control) { |
849 | case LLC_UI: |
850 | if (l->llc_ssap != LLC_SNAP_LSAP) { |
851 | goto dropanyway; |
852 | } |
853 | |
854 | if (memcmp(&(l->llc_snap_org_code)[0], |
855 | at_org_code, sizeof(at_org_code)) == 0 && |
856 | ntohs(l->llc_snap_ether_type) == |
857 | ETHERTYPE_ATALK) { |
858 | inq = &atintrq2; |
859 | m_adj(m, sizeof(struct ether_header) |
860 | + sizeof(struct llc)); |
861 | isr = NETISR_ATALK; |
862 | break; |
863 | } |
864 | |
865 | if (memcmp(&(l->llc_snap_org_code)[0], |
866 | aarp_org_code, |
867 | sizeof(aarp_org_code)) == 0 && |
868 | ntohs(l->llc_snap_ether_type) == |
869 | ETHERTYPE_AARP) { |
870 | m_adj( m, sizeof(struct ether_header) |
871 | + sizeof(struct llc)); |
872 | aarpinput(ifp, m); /* XXX */ |
873 | return; |
874 | } |
875 | |
876 | default: |
877 | goto dropanyway; |
878 | } |
879 | break; |
880 | dropanyway: |
881 | #endif |
882 | default: |
883 | m_freem(m); |
884 | return; |
885 | } |
886 | #else /* ISO || LLC || NETATALK*/ |
887 | m_freem(m); |
888 | return; |
889 | #endif /* ISO || LLC || NETATALK*/ |
890 | } |
891 | |
892 | if (__predict_true(pktq)) { |
893 | #ifdef NET_MPSAFE |
894 | const u_int h = curcpu()->ci_index; |
895 | #else |
896 | const uint32_t h = pktq_rps_hash(m); |
897 | #endif |
898 | if (__predict_false(!pktq_enqueue(pktq, m, h))) { |
899 | m_freem(m); |
900 | } |
901 | return; |
902 | } |
903 | |
904 | if (__predict_false(!inq)) { |
905 | /* Should not happen. */ |
906 | m_freem(m); |
907 | return; |
908 | } |
909 | |
910 | IFQ_LOCK(inq); |
911 | if (IF_QFULL(inq)) { |
912 | IF_DROP(inq); |
913 | IFQ_UNLOCK(inq); |
914 | m_freem(m); |
915 | } else { |
916 | IF_ENQUEUE(inq, m); |
917 | IFQ_UNLOCK(inq); |
918 | schednetisr(isr); |
919 | } |
920 | } |
921 | |
922 | /* |
923 | * Convert Ethernet address to printable (loggable) representation. |
924 | */ |
925 | char * |
926 | ether_sprintf(const u_char *ap) |
927 | { |
928 | static char etherbuf[3 * ETHER_ADDR_LEN]; |
929 | return ether_snprintf(etherbuf, sizeof(etherbuf), ap); |
930 | } |
931 | |
932 | char * |
933 | ether_snprintf(char *buf, size_t len, const u_char *ap) |
934 | { |
935 | char *cp = buf; |
936 | size_t i; |
937 | |
938 | for (i = 0; i < len / 3; i++) { |
939 | *cp++ = hexdigits[*ap >> 4]; |
940 | *cp++ = hexdigits[*ap++ & 0xf]; |
941 | *cp++ = ':'; |
942 | } |
943 | *--cp = '\0'; |
944 | return buf; |
945 | } |
946 | |
947 | /* |
948 | * Perform common duties while attaching to interface list |
949 | */ |
950 | void |
951 | ether_ifattach(struct ifnet *ifp, const uint8_t *lla) |
952 | { |
953 | struct ethercom *ec = (struct ethercom *)ifp; |
954 | |
955 | ifp->if_extflags |= IFEF_OUTPUT_MPSAFE; |
956 | ifp->if_type = IFT_ETHER; |
957 | ifp->if_hdrlen = ETHER_HDR_LEN; |
958 | ifp->if_dlt = DLT_EN10MB; |
959 | ifp->if_mtu = ETHERMTU; |
960 | ifp->if_output = ether_output; |
961 | ifp->_if_input = ether_input; |
962 | if (ifp->if_baudrate == 0) |
963 | ifp->if_baudrate = IF_Mbps(10); /* just a default */ |
964 | |
965 | if_set_sadl(ifp, lla, ETHER_ADDR_LEN, !ETHER_IS_LOCAL(lla)); |
966 | |
967 | LIST_INIT(&ec->ec_multiaddrs); |
968 | ifp->if_broadcastaddr = etherbroadcastaddr; |
969 | bpf_attach(ifp, DLT_EN10MB, sizeof(struct ether_header)); |
970 | #ifdef MBUFTRACE |
971 | strlcpy(ec->ec_tx_mowner.mo_name, ifp->if_xname, |
972 | sizeof(ec->ec_tx_mowner.mo_name)); |
973 | strlcpy(ec->ec_tx_mowner.mo_descr, "tx" , |
974 | sizeof(ec->ec_tx_mowner.mo_descr)); |
975 | strlcpy(ec->ec_rx_mowner.mo_name, ifp->if_xname, |
976 | sizeof(ec->ec_rx_mowner.mo_name)); |
977 | strlcpy(ec->ec_rx_mowner.mo_descr, "rx" , |
978 | sizeof(ec->ec_rx_mowner.mo_descr)); |
979 | MOWNER_ATTACH(&ec->ec_tx_mowner); |
980 | MOWNER_ATTACH(&ec->ec_rx_mowner); |
981 | ifp->if_mowner = &ec->ec_tx_mowner; |
982 | #endif |
983 | } |
984 | |
985 | void |
986 | ether_ifdetach(struct ifnet *ifp) |
987 | { |
988 | struct ethercom *ec = (void *) ifp; |
989 | struct ether_multi *enm; |
990 | int s; |
991 | |
992 | /* |
993 | * Prevent further calls to ioctl (for example turning off |
994 | * promiscuous mode from the bridge code), which eventually can |
995 | * call if_init() which can cause panics because the interface |
996 | * is in the process of being detached. Return device not configured |
997 | * instead. |
998 | */ |
999 | ifp->if_ioctl = (int (*)(struct ifnet *, u_long, void *))enxio; |
1000 | |
1001 | #if NBRIDGE > 0 |
1002 | if (ifp->if_bridge) |
1003 | bridge_ifdetach(ifp); |
1004 | #endif |
1005 | |
1006 | bpf_detach(ifp); |
1007 | |
1008 | #if NVLAN > 0 |
1009 | if (ec->ec_nvlans) |
1010 | vlan_ifdetach(ifp); |
1011 | #endif |
1012 | |
1013 | s = splnet(); |
1014 | while ((enm = LIST_FIRST(&ec->ec_multiaddrs)) != NULL) { |
1015 | LIST_REMOVE(enm, enm_list); |
1016 | free(enm, M_IFMADDR); |
1017 | ec->ec_multicnt--; |
1018 | } |
1019 | splx(s); |
1020 | |
1021 | ifp->if_mowner = NULL; |
1022 | MOWNER_DETACH(&ec->ec_rx_mowner); |
1023 | MOWNER_DETACH(&ec->ec_tx_mowner); |
1024 | } |
1025 | |
1026 | #if 0 |
1027 | /* |
1028 | * This is for reference. We have a table-driven version |
1029 | * of the little-endian crc32 generator, which is faster |
1030 | * than the double-loop. |
1031 | */ |
1032 | uint32_t |
1033 | ether_crc32_le(const uint8_t *buf, size_t len) |
1034 | { |
1035 | uint32_t c, crc, carry; |
1036 | size_t i, j; |
1037 | |
1038 | crc = 0xffffffffU; /* initial value */ |
1039 | |
1040 | for (i = 0; i < len; i++) { |
1041 | c = buf[i]; |
1042 | for (j = 0; j < 8; j++) { |
1043 | carry = ((crc & 0x01) ? 1 : 0) ^ (c & 0x01); |
1044 | crc >>= 1; |
1045 | c >>= 1; |
1046 | if (carry) |
1047 | crc = (crc ^ ETHER_CRC_POLY_LE); |
1048 | } |
1049 | } |
1050 | |
1051 | return (crc); |
1052 | } |
1053 | #else |
1054 | uint32_t |
1055 | ether_crc32_le(const uint8_t *buf, size_t len) |
1056 | { |
1057 | static const uint32_t crctab[] = { |
1058 | 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, |
1059 | 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, |
1060 | 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, |
1061 | 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c |
1062 | }; |
1063 | uint32_t crc; |
1064 | size_t i; |
1065 | |
1066 | crc = 0xffffffffU; /* initial value */ |
1067 | |
1068 | for (i = 0; i < len; i++) { |
1069 | crc ^= buf[i]; |
1070 | crc = (crc >> 4) ^ crctab[crc & 0xf]; |
1071 | crc = (crc >> 4) ^ crctab[crc & 0xf]; |
1072 | } |
1073 | |
1074 | return (crc); |
1075 | } |
1076 | #endif |
1077 | |
1078 | uint32_t |
1079 | ether_crc32_be(const uint8_t *buf, size_t len) |
1080 | { |
1081 | uint32_t c, crc, carry; |
1082 | size_t i, j; |
1083 | |
1084 | crc = 0xffffffffU; /* initial value */ |
1085 | |
1086 | for (i = 0; i < len; i++) { |
1087 | c = buf[i]; |
1088 | for (j = 0; j < 8; j++) { |
1089 | carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01); |
1090 | crc <<= 1; |
1091 | c >>= 1; |
1092 | if (carry) |
1093 | crc = (crc ^ ETHER_CRC_POLY_BE) | carry; |
1094 | } |
1095 | } |
1096 | |
1097 | return (crc); |
1098 | } |
1099 | |
1100 | #ifdef INET |
1101 | const uint8_t ether_ipmulticast_min[ETHER_ADDR_LEN] = |
1102 | { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; |
1103 | const uint8_t ether_ipmulticast_max[ETHER_ADDR_LEN] = |
1104 | { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff }; |
1105 | #endif |
1106 | #ifdef INET6 |
1107 | const uint8_t ether_ip6multicast_min[ETHER_ADDR_LEN] = |
1108 | { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; |
1109 | const uint8_t ether_ip6multicast_max[ETHER_ADDR_LEN] = |
1110 | { 0x33, 0x33, 0xff, 0xff, 0xff, 0xff }; |
1111 | #endif |
1112 | |
1113 | /* |
1114 | * ether_aton implementation, not using a static buffer. |
1115 | */ |
1116 | int |
1117 | ether_aton_r(u_char *dest, size_t len, const char *str) |
1118 | { |
1119 | const u_char *cp = (const void *)str; |
1120 | u_char *ep; |
1121 | |
1122 | #define atox(c) (((c) <= '9') ? ((c) - '0') : ((toupper(c) - 'A') + 10)) |
1123 | |
1124 | if (len < ETHER_ADDR_LEN) |
1125 | return ENOSPC; |
1126 | |
1127 | ep = dest + ETHER_ADDR_LEN; |
1128 | |
1129 | while (*cp) { |
1130 | if (!isxdigit(*cp)) |
1131 | return EINVAL; |
1132 | *dest = atox(*cp); |
1133 | cp++; |
1134 | if (isxdigit(*cp)) { |
1135 | *dest = (*dest << 4) | atox(*cp); |
1136 | dest++; |
1137 | cp++; |
1138 | } else |
1139 | dest++; |
1140 | if (dest == ep) |
1141 | return *cp == '\0' ? 0 : ENAMETOOLONG; |
1142 | switch (*cp) { |
1143 | case ':': |
1144 | case '-': |
1145 | case '.': |
1146 | cp++; |
1147 | break; |
1148 | } |
1149 | } |
1150 | return ENOBUFS; |
1151 | } |
1152 | |
1153 | /* |
1154 | * Convert a sockaddr into an Ethernet address or range of Ethernet |
1155 | * addresses. |
1156 | */ |
1157 | int |
1158 | ether_multiaddr(const struct sockaddr *sa, uint8_t addrlo[ETHER_ADDR_LEN], |
1159 | uint8_t addrhi[ETHER_ADDR_LEN]) |
1160 | { |
1161 | #ifdef INET |
1162 | const struct sockaddr_in *sin; |
1163 | #endif /* INET */ |
1164 | #ifdef INET6 |
1165 | const struct sockaddr_in6 *sin6; |
1166 | #endif /* INET6 */ |
1167 | |
1168 | switch (sa->sa_family) { |
1169 | |
1170 | case AF_UNSPEC: |
1171 | memcpy(addrlo, sa->sa_data, ETHER_ADDR_LEN); |
1172 | memcpy(addrhi, addrlo, ETHER_ADDR_LEN); |
1173 | break; |
1174 | |
1175 | #ifdef INET |
1176 | case AF_INET: |
1177 | sin = satocsin(sa); |
1178 | if (sin->sin_addr.s_addr == INADDR_ANY) { |
1179 | /* |
1180 | * An IP address of INADDR_ANY means listen to |
1181 | * or stop listening to all of the Ethernet |
1182 | * multicast addresses used for IP. |
1183 | * (This is for the sake of IP multicast routers.) |
1184 | */ |
1185 | memcpy(addrlo, ether_ipmulticast_min, ETHER_ADDR_LEN); |
1186 | memcpy(addrhi, ether_ipmulticast_max, ETHER_ADDR_LEN); |
1187 | } |
1188 | else { |
1189 | ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); |
1190 | memcpy(addrhi, addrlo, ETHER_ADDR_LEN); |
1191 | } |
1192 | break; |
1193 | #endif |
1194 | #ifdef INET6 |
1195 | case AF_INET6: |
1196 | sin6 = satocsin6(sa); |
1197 | if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
1198 | /* |
1199 | * An IP6 address of 0 means listen to or stop |
1200 | * listening to all of the Ethernet multicast |
1201 | * address used for IP6. |
1202 | * (This is used for multicast routers.) |
1203 | */ |
1204 | memcpy(addrlo, ether_ip6multicast_min, ETHER_ADDR_LEN); |
1205 | memcpy(addrhi, ether_ip6multicast_max, ETHER_ADDR_LEN); |
1206 | } else { |
1207 | ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, addrlo); |
1208 | memcpy(addrhi, addrlo, ETHER_ADDR_LEN); |
1209 | } |
1210 | break; |
1211 | #endif |
1212 | |
1213 | default: |
1214 | return EAFNOSUPPORT; |
1215 | } |
1216 | return 0; |
1217 | } |
1218 | |
1219 | /* |
1220 | * Add an Ethernet multicast address or range of addresses to the list for a |
1221 | * given interface. |
1222 | */ |
1223 | int |
1224 | ether_addmulti(const struct sockaddr *sa, struct ethercom *ec) |
1225 | { |
1226 | struct ether_multi *enm; |
1227 | u_char addrlo[ETHER_ADDR_LEN]; |
1228 | u_char addrhi[ETHER_ADDR_LEN]; |
1229 | int s = splnet(), error; |
1230 | |
1231 | error = ether_multiaddr(sa, addrlo, addrhi); |
1232 | if (error != 0) { |
1233 | splx(s); |
1234 | return error; |
1235 | } |
1236 | |
1237 | /* |
1238 | * Verify that we have valid Ethernet multicast addresses. |
1239 | */ |
1240 | if (!ETHER_IS_MULTICAST(addrlo) || !ETHER_IS_MULTICAST(addrhi)) { |
1241 | splx(s); |
1242 | return EINVAL; |
1243 | } |
1244 | /* |
1245 | * See if the address range is already in the list. |
1246 | */ |
1247 | ETHER_LOOKUP_MULTI(addrlo, addrhi, ec, enm); |
1248 | if (enm != NULL) { |
1249 | /* |
1250 | * Found it; just increment the reference count. |
1251 | */ |
1252 | ++enm->enm_refcount; |
1253 | splx(s); |
1254 | return 0; |
1255 | } |
1256 | /* |
1257 | * New address or range; malloc a new multicast record |
1258 | * and link it into the interface's multicast list. |
1259 | */ |
1260 | enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT); |
1261 | if (enm == NULL) { |
1262 | splx(s); |
1263 | return ENOBUFS; |
1264 | } |
1265 | memcpy(enm->enm_addrlo, addrlo, 6); |
1266 | memcpy(enm->enm_addrhi, addrhi, 6); |
1267 | enm->enm_refcount = 1; |
1268 | LIST_INSERT_HEAD(&ec->ec_multiaddrs, enm, enm_list); |
1269 | ec->ec_multicnt++; |
1270 | splx(s); |
1271 | /* |
1272 | * Return ENETRESET to inform the driver that the list has changed |
1273 | * and its reception filter should be adjusted accordingly. |
1274 | */ |
1275 | return ENETRESET; |
1276 | } |
1277 | |
1278 | /* |
1279 | * Delete a multicast address record. |
1280 | */ |
1281 | int |
1282 | ether_delmulti(const struct sockaddr *sa, struct ethercom *ec) |
1283 | { |
1284 | struct ether_multi *enm; |
1285 | u_char addrlo[ETHER_ADDR_LEN]; |
1286 | u_char addrhi[ETHER_ADDR_LEN]; |
1287 | int s = splnet(), error; |
1288 | |
1289 | error = ether_multiaddr(sa, addrlo, addrhi); |
1290 | if (error != 0) { |
1291 | splx(s); |
1292 | return (error); |
1293 | } |
1294 | |
1295 | /* |
1296 | * Look ur the address in our list. |
1297 | */ |
1298 | ETHER_LOOKUP_MULTI(addrlo, addrhi, ec, enm); |
1299 | if (enm == NULL) { |
1300 | splx(s); |
1301 | return (ENXIO); |
1302 | } |
1303 | if (--enm->enm_refcount != 0) { |
1304 | /* |
1305 | * Still some claims to this record. |
1306 | */ |
1307 | splx(s); |
1308 | return (0); |
1309 | } |
1310 | /* |
1311 | * No remaining claims to this record; unlink and free it. |
1312 | */ |
1313 | LIST_REMOVE(enm, enm_list); |
1314 | free(enm, M_IFMADDR); |
1315 | ec->ec_multicnt--; |
1316 | splx(s); |
1317 | /* |
1318 | * Return ENETRESET to inform the driver that the list has changed |
1319 | * and its reception filter should be adjusted accordingly. |
1320 | */ |
1321 | return (ENETRESET); |
1322 | } |
1323 | |
1324 | void |
1325 | ether_set_ifflags_cb(struct ethercom *ec, ether_cb_t cb) |
1326 | { |
1327 | ec->ec_ifflags_cb = cb; |
1328 | } |
1329 | |
1330 | /* |
1331 | * Common ioctls for Ethernet interfaces. Note, we must be |
1332 | * called at splnet(). |
1333 | */ |
1334 | int |
1335 | ether_ioctl(struct ifnet *ifp, u_long cmd, void *data) |
1336 | { |
1337 | struct ethercom *ec = (void *) ifp; |
1338 | struct eccapreq *eccr; |
1339 | struct ifreq *ifr = (struct ifreq *)data; |
1340 | struct if_laddrreq *iflr = data; |
1341 | const struct sockaddr_dl *sdl; |
1342 | static const uint8_t zero[ETHER_ADDR_LEN]; |
1343 | int error; |
1344 | |
1345 | switch (cmd) { |
1346 | case SIOCINITIFADDR: |
1347 | { |
1348 | struct ifaddr *ifa = (struct ifaddr *)data; |
1349 | if (ifa->ifa_addr->sa_family != AF_LINK |
1350 | && (ifp->if_flags & (IFF_UP|IFF_RUNNING)) != |
1351 | (IFF_UP|IFF_RUNNING)) { |
1352 | ifp->if_flags |= IFF_UP; |
1353 | if ((error = (*ifp->if_init)(ifp)) != 0) |
1354 | return error; |
1355 | } |
1356 | #ifdef INET |
1357 | if (ifa->ifa_addr->sa_family == AF_INET) |
1358 | arp_ifinit(ifp, ifa); |
1359 | #endif /* INET */ |
1360 | return 0; |
1361 | } |
1362 | |
1363 | case SIOCSIFMTU: |
1364 | { |
1365 | int maxmtu; |
1366 | |
1367 | if (ec->ec_capabilities & ETHERCAP_JUMBO_MTU) |
1368 | maxmtu = ETHERMTU_JUMBO; |
1369 | else |
1370 | maxmtu = ETHERMTU; |
1371 | |
1372 | if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > maxmtu) |
1373 | return EINVAL; |
1374 | else if ((error = ifioctl_common(ifp, cmd, data)) != ENETRESET) |
1375 | return error; |
1376 | else if (ifp->if_flags & IFF_UP) { |
1377 | /* Make sure the device notices the MTU change. */ |
1378 | return (*ifp->if_init)(ifp); |
1379 | } else |
1380 | return 0; |
1381 | } |
1382 | |
1383 | case SIOCSIFFLAGS: |
1384 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) |
1385 | return error; |
1386 | switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) { |
1387 | case IFF_RUNNING: |
1388 | /* |
1389 | * If interface is marked down and it is running, |
1390 | * then stop and disable it. |
1391 | */ |
1392 | (*ifp->if_stop)(ifp, 1); |
1393 | break; |
1394 | case IFF_UP: |
1395 | /* |
1396 | * If interface is marked up and it is stopped, then |
1397 | * start it. |
1398 | */ |
1399 | return (*ifp->if_init)(ifp); |
1400 | case IFF_UP|IFF_RUNNING: |
1401 | error = 0; |
1402 | if (ec->ec_ifflags_cb == NULL || |
1403 | (error = (*ec->ec_ifflags_cb)(ec)) == ENETRESET) { |
1404 | /* |
1405 | * Reset the interface to pick up |
1406 | * changes in any other flags that |
1407 | * affect the hardware state. |
1408 | */ |
1409 | return (*ifp->if_init)(ifp); |
1410 | } else |
1411 | return error; |
1412 | case 0: |
1413 | break; |
1414 | } |
1415 | return 0; |
1416 | case SIOCGETHERCAP: |
1417 | eccr = (struct eccapreq *)data; |
1418 | eccr->eccr_capabilities = ec->ec_capabilities; |
1419 | eccr->eccr_capenable = ec->ec_capenable; |
1420 | return 0; |
1421 | case SIOCADDMULTI: |
1422 | return ether_addmulti(ifreq_getaddr(cmd, ifr), ec); |
1423 | case SIOCDELMULTI: |
1424 | return ether_delmulti(ifreq_getaddr(cmd, ifr), ec); |
1425 | case SIOCSIFMEDIA: |
1426 | case SIOCGIFMEDIA: |
1427 | if (ec->ec_mii == NULL) |
1428 | return ENOTTY; |
1429 | return ifmedia_ioctl(ifp, ifr, &ec->ec_mii->mii_media, cmd); |
1430 | case SIOCALIFADDR: |
1431 | sdl = satocsdl(sstocsa(&iflr->addr)); |
1432 | if (sdl->sdl_family != AF_LINK) |
1433 | ; |
1434 | else if (ETHER_IS_MULTICAST(CLLADDR(sdl))) |
1435 | return EINVAL; |
1436 | else if (memcmp(zero, CLLADDR(sdl), sizeof(zero)) == 0) |
1437 | return EINVAL; |
1438 | /*FALLTHROUGH*/ |
1439 | default: |
1440 | return ifioctl_common(ifp, cmd, data); |
1441 | } |
1442 | return 0; |
1443 | } |
1444 | |
1445 | /* |
1446 | * Enable/disable passing VLAN packets if the parent interface supports it. |
1447 | * Return: |
1448 | * 0: Ok |
1449 | * -1: Parent interface does not support vlans |
1450 | * >0: Error |
1451 | */ |
1452 | int |
1453 | ether_enable_vlan_mtu(struct ifnet *ifp) |
1454 | { |
1455 | int error; |
1456 | struct ethercom *ec = (void *)ifp; |
1457 | |
1458 | /* Already have VLAN's do nothing. */ |
1459 | if (ec->ec_nvlans != 0) |
1460 | return 0; |
1461 | |
1462 | /* Parent does not support VLAN's */ |
1463 | if ((ec->ec_capabilities & ETHERCAP_VLAN_MTU) == 0) |
1464 | return -1; |
1465 | |
1466 | /* |
1467 | * Parent supports the VLAN_MTU capability, |
1468 | * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames; |
1469 | * enable it. |
1470 | */ |
1471 | ec->ec_capenable |= ETHERCAP_VLAN_MTU; |
1472 | |
1473 | /* Interface is down, defer for later */ |
1474 | if ((ifp->if_flags & IFF_UP) == 0) |
1475 | return 0; |
1476 | |
1477 | if ((error = if_flags_set(ifp, ifp->if_flags)) == 0) |
1478 | return 0; |
1479 | |
1480 | ec->ec_capenable &= ~ETHERCAP_VLAN_MTU; |
1481 | return error; |
1482 | } |
1483 | |
1484 | int |
1485 | ether_disable_vlan_mtu(struct ifnet *ifp) |
1486 | { |
1487 | int error; |
1488 | struct ethercom *ec = (void *)ifp; |
1489 | |
1490 | /* We still have VLAN's, defer for later */ |
1491 | if (ec->ec_nvlans != 0) |
1492 | return 0; |
1493 | |
1494 | /* Parent does not support VLAB's, nothing to do. */ |
1495 | if ((ec->ec_capenable & ETHERCAP_VLAN_MTU) == 0) |
1496 | return -1; |
1497 | |
1498 | /* |
1499 | * Disable Tx/Rx of VLAN-sized frames. |
1500 | */ |
1501 | ec->ec_capenable &= ~ETHERCAP_VLAN_MTU; |
1502 | |
1503 | /* Interface is down, defer for later */ |
1504 | if ((ifp->if_flags & IFF_UP) == 0) |
1505 | return 0; |
1506 | |
1507 | if ((error = if_flags_set(ifp, ifp->if_flags)) == 0) |
1508 | return 0; |
1509 | |
1510 | ec->ec_capenable |= ETHERCAP_VLAN_MTU; |
1511 | return error; |
1512 | } |
1513 | |
1514 | static int |
1515 | ether_multicast_sysctl(SYSCTLFN_ARGS) |
1516 | { |
1517 | struct ether_multi *enm; |
1518 | struct ether_multi_sysctl addr; |
1519 | struct ifnet *ifp; |
1520 | struct ethercom *ec; |
1521 | int error = 0; |
1522 | size_t written; |
1523 | struct psref psref; |
1524 | int bound; |
1525 | |
1526 | if (namelen != 1) |
1527 | return EINVAL; |
1528 | |
1529 | bound = curlwp_bind(); |
1530 | ifp = if_get_byindex(name[0], &psref); |
1531 | if (ifp == NULL) { |
1532 | error = ENODEV; |
1533 | goto out; |
1534 | } |
1535 | if (ifp->if_type != IFT_ETHER) { |
1536 | if_put(ifp, &psref); |
1537 | *oldlenp = 0; |
1538 | goto out; |
1539 | } |
1540 | ec = (struct ethercom *)ifp; |
1541 | |
1542 | if (oldp == NULL) { |
1543 | if_put(ifp, &psref); |
1544 | *oldlenp = ec->ec_multicnt * sizeof(addr); |
1545 | goto out; |
1546 | } |
1547 | |
1548 | memset(&addr, 0, sizeof(addr)); |
1549 | error = 0; |
1550 | written = 0; |
1551 | |
1552 | LIST_FOREACH(enm, &ec->ec_multiaddrs, enm_list) { |
1553 | if (written + sizeof(addr) > *oldlenp) |
1554 | break; |
1555 | addr.enm_refcount = enm->enm_refcount; |
1556 | memcpy(addr.enm_addrlo, enm->enm_addrlo, ETHER_ADDR_LEN); |
1557 | memcpy(addr.enm_addrhi, enm->enm_addrhi, ETHER_ADDR_LEN); |
1558 | error = sysctl_copyout(l, &addr, oldp, sizeof(addr)); |
1559 | if (error) |
1560 | break; |
1561 | written += sizeof(addr); |
1562 | oldp = (char *)oldp + sizeof(addr); |
1563 | } |
1564 | if_put(ifp, &psref); |
1565 | |
1566 | *oldlenp = written; |
1567 | out: |
1568 | curlwp_bindx(bound); |
1569 | return error; |
1570 | } |
1571 | |
1572 | SYSCTL_SETUP(sysctl_net_ether_setup, "sysctl net.ether subtree setup" ) |
1573 | { |
1574 | const struct sysctlnode *rnode = NULL; |
1575 | |
1576 | sysctl_createv(clog, 0, NULL, &rnode, |
1577 | CTLFLAG_PERMANENT, |
1578 | CTLTYPE_NODE, "ether" , |
1579 | SYSCTL_DESCR("Ethernet-specific information" ), |
1580 | NULL, 0, NULL, 0, |
1581 | CTL_NET, CTL_CREATE, CTL_EOL); |
1582 | |
1583 | sysctl_createv(clog, 0, &rnode, NULL, |
1584 | CTLFLAG_PERMANENT, |
1585 | CTLTYPE_NODE, "multicast" , |
1586 | SYSCTL_DESCR("multicast addresses" ), |
1587 | ether_multicast_sysctl, 0, NULL, 0, |
1588 | CTL_CREATE, CTL_EOL); |
1589 | } |
1590 | |
1591 | void |
1592 | etherinit(void) |
1593 | { |
1594 | mutex_init(&bigpktpps_lock, MUTEX_DEFAULT, IPL_NET); |
1595 | } |
1596 | |