xref: /haiku/src/libs/compat/freebsd_network/if.c (revision 4bd0c1066b227cec4b79883bdef697c7a27f2e90)
1 /*
2  * Copyright 2009, Colin Günther, coling@gmx.de.
3  * Copyright 2007-2009, Axel Dörfler, axeld@pinc-software.de.
4  * Copyright 2007, Hugo Santos. All Rights Reserved.
5  * Copyright 2004, Marcus Overhagen. All Rights Reserved.
6  *
7  * Distributed under the terms of the MIT License.
8  */
9 
10 
11 #include "device.h"
12 
13 #include <stdio.h>
14 #include <net/if_types.h>
15 #include <sys/sockio.h>
16 
17 #include <compat/sys/bus.h>
18 #include <compat/sys/kernel.h>
19 #include <compat/sys/taskqueue.h>
20 
21 #include <compat/net/if.h>
22 #include <compat/net/if_arp.h>
23 #include <compat/net/if_media.h>
24 #include <compat/net/if_var.h>
25 #include <compat/sys/malloc.h>
26 
27 #include <compat/net/ethernet.h>
28 
29 
30 int ifqmaxlen = IFQ_MAXLEN;
31 
32 
33 #define IFNET_HOLD (void *)(uintptr_t)(-1)
34 
35 
36 static void
37 insert_into_device_name_list(struct ifnet * ifp)
38 {
39 	int i;
40 	for (i = 0; i < MAX_DEVICES; i++) {
41 		if (gDeviceNameList[i] == NULL) {
42 			gDeviceNameList[i] = ifp->device_name;
43 			return;
44 		}
45 	}
46 
47 	panic("too many devices");
48 }
49 
50 
51 static void
52 remove_from_device_name_list(struct ifnet * ifp)
53 {
54 	int i;
55 	for (i = 0; i < MAX_DEVICES; i++) {
56 		if (ifp->device_name == gDeviceNameList[i]) {
57 			int last;
58 			for (last = i + 1; last < MAX_DEVICES; last++) {
59 				if (gDeviceNameList[last] == NULL)
60 					break;
61 			}
62 			last--;
63 
64 			if (i == last)
65 				gDeviceNameList[i] = NULL;
66 			else {
67 				// switch positions with the last entry
68 				gDeviceNameList[i] = gDeviceNameList[last];
69 				gDeviceNameList[last] = NULL;
70 			}
71 			break;
72 		}
73 	}
74 }
75 
76 
77 struct ifnet *
78 ifnet_byindex(u_short idx)
79 {
80 	struct ifnet *ifp;
81 
82 	IFNET_RLOCK_NOSLEEP();
83 	ifp = ifnet_byindex_locked(idx);
84 	IFNET_RUNLOCK_NOSLEEP();
85 
86 	return (ifp);
87 }
88 
89 
90 struct ifnet *
91 ifnet_byindex_locked(u_short idx)
92 {
93 	struct ifnet *ifp;
94 
95 	ifp = gDevices[idx];
96 
97 	return (ifp);
98 }
99 
100 
101 static void
102 ifnet_setbyindex_locked(u_short idx, struct ifnet *ifp)
103 {
104 	gDevices[idx] = ifp;
105 }
106 
107 
108 static void
109 ifnet_setbyindex(u_short idx, struct ifnet *ifp)
110 {
111 	IFNET_WLOCK();
112 	ifnet_setbyindex_locked(idx, ifp);
113 	IFNET_WUNLOCK();
114 }
115 
116 
117 static int
118 ifindex_alloc_locked(u_short *idxp)
119 {
120 	u_short index;
121 
122 	for (index = 0; index < MAX_DEVICES; index++) {
123 		if (gDevices[index] == NULL) {
124 			break;
125 		}
126 	}
127 
128 	if (index == MAX_DEVICES)
129 		return ENOSPC;
130 
131 	gDeviceCount++;
132 	*idxp = index;
133 
134 	return ENOERR;
135 }
136 
137 
138 static void
139 ifindex_free_locked(u_short idx)
140 {
141 	gDevices[idx] = NULL;
142 	gDeviceCount--;
143 }
144 
145 
146 struct ifnet *
147 if_alloc(u_char type)
148 {
149 	char semName[64];
150 	u_short index;
151 
152 	struct ifnet *ifp = _kernel_malloc(sizeof(struct ifnet), M_ZERO);
153 	if (ifp == NULL)
154 		return NULL;
155 
156 	snprintf(semName, sizeof(semName), "%s receive", gDriverName);
157 
158 	ifp->receive_sem = create_sem(0, semName);
159 	if (ifp->receive_sem < B_OK)
160 		goto err1;
161 
162 	switch (type) {
163 		case IFT_ETHER:
164 		{
165 			ifp->if_l2com = _kernel_malloc(sizeof(struct arpcom), M_ZERO);
166 			if (ifp->if_l2com == NULL)
167 				goto err2;
168 			IFP2AC(ifp)->ac_ifp = ifp;
169 			break;
170 		}
171 		case IFT_IEEE80211:
172 		{
173 			if (wlan_if_l2com_alloc(ifp) != B_OK)
174 				goto err2;
175 			break;
176 		}
177 	}
178 
179 	ifp->link_state_sem = -1;
180 	ifp->open_count = 0;
181 	ifp->flags = 0;
182 	ifp->if_type = type;
183 	ifq_init(&ifp->receive_queue, semName);
184 
185 	ifp->scan_done_sem = -1;
186 		// WLAN specific, doesn't hurt when initilized for other devices
187 
188 	// Search for the first free device slot, and use that one
189 	IFNET_WLOCK();
190 	if (ifindex_alloc_locked(&index) != ENOERR) {
191 		IFNET_WUNLOCK();
192 		panic("too many devices");
193 		goto err3;
194 	}
195 	ifnet_setbyindex_locked(index, IFNET_HOLD);
196 	IFNET_WUNLOCK();
197 
198 	ifp->if_index = index;
199 	ifnet_setbyindex(ifp->if_index, ifp);
200 
201 	IF_ADDR_LOCK_INIT(ifp);
202 	return ifp;
203 
204 err3:
205 	switch (type) {
206 		case IFT_ETHER:
207 		case IFT_IEEE80211:
208 			_kernel_free(ifp->if_l2com);
209 			break;
210 	}
211 
212 err2:
213 	delete_sem(ifp->receive_sem);
214 
215 err1:
216 	_kernel_free(ifp);
217 	return NULL;
218 }
219 
220 
221 void
222 if_free(struct ifnet *ifp)
223 {
224 	// IEEE80211 devices won't be in this list,
225 	// so don't try to remove them.
226 	if (ifp->if_type == IFT_ETHER)
227 		remove_from_device_name_list(ifp);
228 
229 	IFNET_WLOCK();
230 	ifindex_free_locked(ifp->if_index);
231 	IFNET_WUNLOCK();
232 
233 	IF_ADDR_LOCK_DESTROY(ifp);
234 	switch (ifp->if_type) {
235 		case IFT_ETHER:
236 		case IFT_IEEE80211:
237 			_kernel_free(ifp->if_l2com);
238 			break;
239 	}
240 
241 	delete_sem(ifp->receive_sem);
242 	ifq_uninit(&ifp->receive_queue);
243 
244 	_kernel_free(ifp);
245 }
246 
247 
248 void
249 if_initname(struct ifnet *ifp, const char *name, int unit)
250 {
251 	dprintf("if_initname(%p, %s, %d)\n", ifp, name, unit);
252 
253 	if (name == NULL || name[0] == '\0')
254 		panic("interface goes unnamed");
255 
256 	ifp->if_dname = name;
257 	ifp->if_dunit = unit;
258 
259 	strlcpy(ifp->if_xname, name, sizeof(ifp->if_xname));
260 
261 	snprintf(ifp->device_name, sizeof(ifp->device_name), "net/%s/%i",
262 		gDriverName, ifp->if_index);
263 
264 	driver_printf("%s: /dev/%s\n", gDriverName, ifp->device_name);
265 
266 	// For wlan devices we only want to see the cloned wlan device
267 	// in the list.
268 	// Remember: For each wlan device, there is a base device of type
269 	//           IFT_IEEE80211. On top of that a clone device is created of
270 	//           type IFT_ETHER.
271 	//           Haiku shall only see the cloned device as it is the one
272 	//           FreeBSD 8 uses for wireless i/o, too.
273 	if (ifp->if_type == IFT_ETHER)
274 		insert_into_device_name_list(ifp);
275 
276 	ifp->root_device = find_root_device(unit);
277 }
278 
279 
280 void
281 ifq_init(struct ifqueue *ifq, const char *name)
282 {
283 	ifq->ifq_head = NULL;
284 	ifq->ifq_tail = NULL;
285 	ifq->ifq_len = 0;
286 	ifq->ifq_maxlen = IFQ_MAXLEN;
287 	ifq->ifq_drops = 0;
288 
289 	mtx_init(&ifq->ifq_mtx, name, NULL, MTX_DEF);
290 }
291 
292 
293 void
294 ifq_uninit(struct ifqueue *ifq)
295 {
296 	mtx_destroy(&ifq->ifq_mtx);
297 }
298 
299 
300 static int
301 if_transmit(struct ifnet *ifp, struct mbuf *m)
302 {
303 	int error;
304 
305 	IFQ_HANDOFF(ifp, m, error);
306 	return (error);
307 }
308 
309 
310 void
311 if_attach(struct ifnet *ifp)
312 {
313 	TAILQ_INIT(&ifp->if_addrhead);
314 	TAILQ_INIT(&ifp->if_prefixhead);
315 	TAILQ_INIT(&ifp->if_multiaddrs);
316 
317 	IF_ADDR_LOCK_INIT(ifp);
318 
319 	ifp->if_lladdr.sdl_family = AF_LINK;
320 
321 	ifq_init((struct ifqueue *) &ifp->if_snd, ifp->if_xname);
322 
323 	if (ifp->if_transmit == NULL) {
324 		ifp->if_transmit = if_transmit;
325 	}
326 }
327 
328 
329 void
330 if_detach(struct ifnet *ifp)
331 {
332 	if (HAIKU_DRIVER_REQUIRES(FBSD_SWI_TASKQUEUE))
333 		taskqueue_drain(taskqueue_swi, &ifp->if_linktask);
334 
335 	IF_ADDR_LOCK_DESTROY(ifp);
336 	ifq_uninit((struct ifqueue *) &ifp->if_snd);
337 }
338 
339 
340 void
341 if_start(struct ifnet *ifp)
342 {
343 #ifdef IFF_NEEDSGIANT
344 	if (ifp->if_flags & IFF_NEEDSGIANT)
345 	panic("freebsd compat.: unsupported giant requirement");
346 #endif
347 	ifp->if_start(ifp);
348 }
349 
350 
351 int
352 if_printf(struct ifnet *ifp, const char *format, ...)
353 {
354 	char buf[256];
355 	va_list vl;
356 	va_start(vl, format);
357 	vsnprintf(buf, sizeof(buf), format, vl);
358 	va_end(vl);
359 
360 	dprintf("[%s] %s", ifp->device_name, buf);
361 	return 0;
362 }
363 
364 
365 void
366 if_link_state_change(struct ifnet *ifp, int linkState)
367 {
368 	if (ifp->if_link_state == linkState)
369 		return;
370 
371 	ifp->if_link_state = linkState;
372 	release_sem_etc(ifp->link_state_sem, 1, B_DO_NOT_RESCHEDULE);
373 }
374 
375 
376 static struct ifmultiaddr *
377 if_findmulti(struct ifnet *ifp, struct sockaddr *_address)
378 {
379 	struct sockaddr_dl *address = (struct sockaddr_dl *) _address;
380 	struct ifmultiaddr *ifma;
381 
382 	TAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) {
383 		if (memcmp(LLADDR(address),
384 			LLADDR((struct sockaddr_dl *)ifma->ifma_addr), ETHER_ADDR_LEN) == 0)
385 			return ifma;
386 	}
387 
388 	return NULL;
389 }
390 
391 
392 /*
393  * if_freemulti: free ifmultiaddr structure and possibly attached related
394  * addresses.  The caller is responsible for implementing reference
395  * counting, notifying the driver, handling routing messages, and releasing
396  * any dependent link layer state.
397  */
398 static void
399 if_freemulti(struct ifmultiaddr *ifma)
400 {
401 
402 	KASSERT(ifma->ifma_refcount == 0, ("if_freemulti: refcount %d",
403 	    ifma->ifma_refcount));
404 	KASSERT(ifma->ifma_protospec == NULL,
405 	    ("if_freemulti: protospec not NULL"));
406 
407 	if (ifma->ifma_lladdr != NULL)
408 		free(ifma->ifma_lladdr);
409 
410 	// Haiku note: We use a field in the ifmultiaddr struct (ifma_addr_storage)
411 	// to store the address and let ifma_addr point to that. We therefore do not
412 	// free it here, as it will be freed as part of freeing the if_multiaddr.
413 	//free(ifma->ifma_addr);
414 
415 	free(ifma);
416 }
417 
418 
419 static struct ifmultiaddr *
420 _if_addmulti(struct ifnet *ifp, struct sockaddr *address)
421 {
422 	struct ifmultiaddr *addr = if_findmulti(ifp, address);
423 
424 	if (addr != NULL) {
425 		addr->ifma_refcount++;
426 		return addr;
427 	}
428 
429 	addr = (struct ifmultiaddr *) malloc(sizeof(struct ifmultiaddr));
430 	if (addr == NULL)
431 		return NULL;
432 
433 	addr->ifma_lladdr = NULL;
434 	addr->ifma_ifp = ifp;
435 	addr->ifma_protospec = NULL;
436 
437 	memcpy(&addr->ifma_addr_storage, address, sizeof(struct sockaddr_dl));
438 	addr->ifma_addr = (struct sockaddr *) &addr->ifma_addr_storage;
439 
440 	addr->ifma_refcount = 1;
441 
442 	TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, addr, ifma_link);
443 
444 	return addr;
445 }
446 
447 
448 int
449 if_addmulti(struct ifnet *ifp, struct sockaddr *address,
450 	struct ifmultiaddr **out)
451 {
452 	struct ifmultiaddr *result;
453 	int refcount = 0;
454 
455 	IF_ADDR_LOCK(ifp);
456 	result = _if_addmulti(ifp, address);
457 	if (result)
458 		refcount = result->ifma_refcount;
459 	IF_ADDR_UNLOCK(ifp);
460 
461 	if (result == NULL)
462 		return ENOBUFS;
463 
464 	if (refcount == 1 && ifp->if_ioctl != NULL)
465 		ifp->if_ioctl(ifp, SIOCADDMULTI, NULL);
466 
467 	if (out)
468 		(*out) = result;
469 
470 	return 0;
471 }
472 
473 
474 static int
475 if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching)
476 {
477 	struct ifmultiaddr *ll_ifma;
478 
479 	if (ifp != NULL && ifma->ifma_ifp != NULL) {
480 		KASSERT(ifma->ifma_ifp == ifp,
481 		    ("%s: inconsistent ifp %p", __func__, ifp));
482 		IF_ADDR_LOCK_ASSERT(ifp);
483 	}
484 
485 	ifp = ifma->ifma_ifp;
486 
487 	/*
488 	 * If the ifnet is detaching, null out references to ifnet,
489 	 * so that upper protocol layers will notice, and not attempt
490 	 * to obtain locks for an ifnet which no longer exists. The
491 	 * routing socket announcement must happen before the ifnet
492 	 * instance is detached from the system.
493 	 */
494 	if (detaching) {
495 #ifdef DIAGNOSTIC
496 		printf("%s: detaching ifnet instance %p\n", __func__, ifp);
497 #endif
498 		/*
499 		 * ifp may already be nulled out if we are being reentered
500 		 * to delete the ll_ifma.
501 		 */
502 		if (ifp != NULL) {
503 #ifndef __HAIKU__
504 			rt_newmaddrmsg(RTM_DELMADDR, ifma);
505 #endif
506 			ifma->ifma_ifp = NULL;
507 		}
508 	}
509 
510 	if (--ifma->ifma_refcount > 0)
511 		return 0;
512 
513 #ifndef __HAIKU__
514 	/*
515 	 * If this ifma is a network-layer ifma, a link-layer ifma may
516 	 * have been associated with it. Release it first if so.
517 	 */
518 	ll_ifma = ifma->ifma_llifma;
519 	if (ll_ifma != NULL) {
520 		KASSERT(ifma->ifma_lladdr != NULL,
521 		    ("%s: llifma w/o lladdr", __func__));
522 		if (detaching)
523 			ll_ifma->ifma_ifp = NULL;	/* XXX */
524 		if (--ll_ifma->ifma_refcount == 0) {
525 			if (ifp != NULL) {
526 				TAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma,
527 				    ifma_link);
528 			}
529 			if_freemulti(ll_ifma);
530 		}
531 	}
532 #endif
533 
534 	if (ifp != NULL)
535 		TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
536 
537 	if_freemulti(ifma);
538 
539 	/*
540 	 * The last reference to this instance of struct ifmultiaddr
541 	 * was released; the hardware should be notified of this change.
542 	 */
543 	return 1;
544 }
545 
546 
547 /*
548  * Delete all multicast group membership for an interface.
549  * Should be used to quickly flush all multicast filters.
550  */
551 void
552 if_delallmulti(struct ifnet *ifp)
553 {
554 	struct ifmultiaddr *ifma;
555 	struct ifmultiaddr *next;
556 
557 	IF_ADDR_LOCK(ifp);
558 	TAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next)
559 		if_delmulti_locked(ifp, ifma, 0);
560 	IF_ADDR_UNLOCK(ifp);
561 }
562 
563 
564 static void
565 if_delete_multiaddr(struct ifnet *ifp, struct ifmultiaddr *ifma)
566 {
567 	TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
568 	free(ifma);
569 }
570 
571 
572 int
573 if_delmulti(struct ifnet *ifp, struct sockaddr *sa)
574 {
575 	struct ifmultiaddr *ifma;
576 	int lastref;
577 #ifdef INVARIANTS
578 	struct ifnet *oifp;
579 
580 	IFNET_RLOCK_NOSLEEP();
581 	TAILQ_FOREACH(oifp, &V_ifnet, if_link)
582 		if (ifp == oifp)
583 			break;
584 	if (ifp != oifp)
585 		ifp = NULL;
586 	IFNET_RUNLOCK_NOSLEEP();
587 
588 	KASSERT(ifp != NULL, ("%s: ifnet went away", __func__));
589 #endif
590 	if (ifp == NULL)
591 		return (ENOENT);
592 
593 	IF_ADDR_LOCK(ifp);
594 	lastref = 0;
595 	ifma = if_findmulti(ifp, sa);
596 	if (ifma != NULL)
597 		lastref = if_delmulti_locked(ifp, ifma, 0);
598 	IF_ADDR_UNLOCK(ifp);
599 
600 	if (ifma == NULL)
601 		return (ENOENT);
602 
603 	if (lastref && ifp->if_ioctl != NULL) {
604 		(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0);
605 	}
606 
607 	return (0);
608 }
609 
610 
611 void
612 if_purgemaddrs(struct ifnet *ifp)
613 {
614 	struct ifmultiaddr *ifma;
615 	struct ifmultiaddr *next;
616 
617 	IF_ADDR_LOCK(ifp);
618 	TAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next)
619 		if_delmulti_locked(ifp, ifma, 1);
620 	IF_ADDR_UNLOCK(ifp);
621 }
622 
623 
624 void
625 if_addr_rlock(struct ifnet *ifp)
626 {
627 	IF_ADDR_LOCK(ifp);
628 }
629 
630 
631 void
632 if_addr_runlock(struct ifnet *ifp)
633 {
634 	IF_ADDR_UNLOCK(ifp);
635 }
636 
637 
638 void
639 if_maddr_rlock(struct ifnet *ifp)
640 {
641 	IF_ADDR_LOCK(ifp);
642 }
643 
644 
645 void
646 if_maddr_runlock(struct ifnet *ifp)
647 {
648 	IF_ADDR_UNLOCK(ifp);
649 }
650 
651 
652 int
653 ether_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
654 	struct route *ro)
655 {
656 	int error = 0;
657 	IFQ_HANDOFF(ifp, m, error);
658 	return error;
659 }
660 
661 
662 static void ether_input(struct ifnet *ifp, struct mbuf *m)
663 {
664 	IF_ENQUEUE(&ifp->receive_queue, m);
665 	release_sem_etc(ifp->receive_sem, 1, B_DO_NOT_RESCHEDULE);
666 }
667 
668 
669 void
670 ether_ifattach(struct ifnet *ifp, const uint8_t *macAddress)
671 {
672 	ifp->if_addrlen = ETHER_ADDR_LEN;
673 	ifp->if_hdrlen = ETHER_HDR_LEN;
674 	if_attach(ifp);
675 	ifp->if_mtu = ETHERMTU;
676 	ifp->if_output = ether_output;
677 	ifp->if_input = ether_input;
678 	ifp->if_resolvemulti = NULL; // done in the stack
679 	ifp->if_broadcastaddr = etherbroadcastaddr;
680 
681 	memcpy(IF_LLADDR(ifp), macAddress, ETHER_ADDR_LEN);
682 
683 	// TODO: according to FreeBSD's if_ethersubr.c, this should be removed
684 	//       once all drivers are cleaned up.
685 	if (macAddress != IFP2ENADDR(ifp))
686 		memcpy(IFP2ENADDR(ifp), macAddress, ETHER_ADDR_LEN);
687 }
688 
689 
690 void
691 ether_ifdetach(struct ifnet *ifp)
692 {
693 	if_detach(ifp);
694 }
695 
696 
697 int
698 ether_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
699 {
700 	struct ifreq *ifr = (struct ifreq *) data;
701 
702 	switch (command) {
703 		case SIOCSIFMTU:
704 			if (ifr->ifr_mtu > ETHERMTU)
705 				return EINVAL;
706 			else
707 				;
708 			// need to fix our ifreq to work with C...
709 			// ifp->ifr_mtu = ifr->ifr_mtu;
710 			break;
711 
712 		default:
713 			return EINVAL;
714 	}
715 
716 	return 0;
717 }
718 
719 
720 void
721 if_inc_counter(struct ifnet *ifp, ift_counter cnt, int64_t inc)
722 {
723 	switch (cnt) {
724 		case IFCOUNTER_IPACKETS:
725 			atomic_add(&ifp->if_ipackets, inc);
726 			break;
727 		case IFCOUNTER_IERRORS:
728 			atomic_add(&ifp->if_ierrors, inc);
729 			break;
730 		case IFCOUNTER_OPACKETS:
731 			atomic_add(&ifp->if_opackets, inc);
732 			break;
733 		case IFCOUNTER_OERRORS:
734 			atomic_add(&ifp->if_oerrors, inc);
735 			break;
736 		case IFCOUNTER_COLLISIONS:
737 			atomic_add(&ifp->if_collisions, inc);
738 			break;
739 		case IFCOUNTER_IBYTES:
740 			atomic_add(&ifp->if_ibytes, inc);
741 			break;
742 		case IFCOUNTER_OBYTES:
743 			atomic_add(&ifp->if_obytes, inc);
744 			break;
745 		case IFCOUNTER_IMCASTS:
746 			atomic_add(&ifp->if_imcasts, inc);
747 			break;
748 		case IFCOUNTER_OMCASTS:
749 			atomic_add(&ifp->if_omcasts, inc);
750 			break;
751 		case IFCOUNTER_IQDROPS:
752 			atomic_add(&ifp->if_iqdrops, inc);
753 			break;
754 		case IFCOUNTER_OQDROPS:
755 			atomic_add(&ifp->if_oqdrops, inc);
756 			break;
757 		case IFCOUNTER_NOPROTO:
758 			atomic_add(&ifp->if_noproto, inc);
759 			break;
760 		case IFCOUNTERS:
761 			KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt));
762 	}
763 }
764