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 #define IFNET_HOLD (void *)(uintptr_t)(-1) 31 32 33 static void 34 insert_into_device_name_list(struct ifnet * ifp) 35 { 36 int i; 37 for (i = 0; i < MAX_DEVICES; i++) { 38 if (gDeviceNameList[i] == NULL) { 39 gDeviceNameList[i] = ifp->device_name; 40 return; 41 } 42 } 43 44 panic("too many devices"); 45 } 46 47 48 static void 49 remove_from_device_name_list(struct ifnet * ifp) 50 { 51 int i; 52 for (i = 0; i < MAX_DEVICES; i++) { 53 if (ifp->device_name == gDeviceNameList[i]) { 54 int last; 55 for (last = i + 1; last < MAX_DEVICES; last++) { 56 if (gDeviceNameList[last] == NULL) 57 break; 58 } 59 last--; 60 61 if (i == last) 62 gDeviceNameList[i] = NULL; 63 else { 64 // switch positions with the last entry 65 gDeviceNameList[i] = gDeviceNameList[last]; 66 gDeviceNameList[last] = NULL; 67 } 68 break; 69 } 70 } 71 } 72 73 74 struct ifnet * 75 ifnet_byindex(u_short idx) 76 { 77 struct ifnet *ifp; 78 79 IFNET_RLOCK_NOSLEEP(); 80 ifp = ifnet_byindex_locked(idx); 81 IFNET_RUNLOCK_NOSLEEP(); 82 83 return (ifp); 84 } 85 86 87 struct ifnet * 88 ifnet_byindex_locked(u_short idx) 89 { 90 struct ifnet *ifp; 91 92 ifp = gDevices[idx]; 93 94 return (ifp); 95 } 96 97 98 static void 99 ifnet_setbyindex_locked(u_short idx, struct ifnet *ifp) 100 { 101 gDevices[idx] = ifp; 102 } 103 104 105 static void 106 ifnet_setbyindex(u_short idx, struct ifnet *ifp) 107 { 108 IFNET_WLOCK(); 109 ifnet_setbyindex_locked(idx, ifp); 110 IFNET_WUNLOCK(); 111 } 112 113 114 static int 115 ifindex_alloc_locked(u_short *idxp) 116 { 117 u_short index; 118 119 for (index = 0; index < MAX_DEVICES; index++) { 120 if (gDevices[index] == NULL) { 121 break; 122 } 123 } 124 125 if (index == MAX_DEVICES) 126 return ENOSPC; 127 128 gDeviceCount++; 129 *idxp = index; 130 131 return ENOERR; 132 } 133 134 135 static void 136 ifindex_free_locked(u_short idx) 137 { 138 gDevices[idx] = NULL; 139 gDeviceCount--; 140 } 141 142 143 struct ifnet * 144 if_alloc(u_char type) 145 { 146 char semName[64]; 147 u_short index; 148 149 struct ifnet *ifp = _kernel_malloc(sizeof(struct ifnet), M_ZERO); 150 if (ifp == NULL) 151 return NULL; 152 153 snprintf(semName, sizeof(semName), "%s receive", gDriverName); 154 155 ifp->receive_sem = create_sem(0, semName); 156 if (ifp->receive_sem < B_OK) 157 goto err1; 158 159 switch (type) { 160 case IFT_ETHER: 161 { 162 ifp->if_l2com = _kernel_malloc(sizeof(struct arpcom), M_ZERO); 163 if (ifp->if_l2com == NULL) 164 goto err2; 165 IFP2AC(ifp)->ac_ifp = ifp; 166 break; 167 } 168 case IFT_IEEE80211: 169 { 170 if (wlan_if_l2com_alloc(ifp) != B_OK) 171 goto err2; 172 break; 173 } 174 } 175 176 ifp->link_state_sem = -1; 177 ifp->open_count = 0; 178 ifp->flags = 0; 179 ifp->if_type = type; 180 ifq_init(&ifp->receive_queue, semName); 181 182 ifp->scan_done_sem = -1; 183 // WLAN specific, doesn't hurt when initilized for other devices 184 185 // Search for the first free device slot, and use that one 186 IFNET_WLOCK(); 187 if (ifindex_alloc_locked(&index) != ENOERR) { 188 IFNET_WUNLOCK(); 189 panic("too many devices"); 190 goto err3; 191 } 192 ifnet_setbyindex_locked(index, IFNET_HOLD); 193 IFNET_WUNLOCK(); 194 195 ifp->if_index = index; 196 ifnet_setbyindex(ifp->if_index, ifp); 197 198 IF_ADDR_LOCK_INIT(ifp); 199 return ifp; 200 201 err3: 202 switch (type) { 203 case IFT_ETHER: 204 case IFT_IEEE80211: 205 _kernel_free(ifp->if_l2com); 206 break; 207 } 208 209 err2: 210 delete_sem(ifp->receive_sem); 211 212 err1: 213 _kernel_free(ifp); 214 return NULL; 215 } 216 217 218 void 219 if_free(struct ifnet *ifp) 220 { 221 // IEEE80211 devices won't be in this list, 222 // so don't try to remove them. 223 if (ifp->if_type == IFT_ETHER) 224 remove_from_device_name_list(ifp); 225 226 IFNET_WLOCK(); 227 ifindex_free_locked(ifp->if_index); 228 IFNET_WUNLOCK(); 229 230 IF_ADDR_LOCK_DESTROY(ifp); 231 switch (ifp->if_type) { 232 case IFT_ETHER: 233 case IFT_IEEE80211: 234 _kernel_free(ifp->if_l2com); 235 break; 236 } 237 238 delete_sem(ifp->receive_sem); 239 ifq_uninit(&ifp->receive_queue); 240 241 _kernel_free(ifp); 242 } 243 244 245 void 246 if_initname(struct ifnet *ifp, const char *name, int unit) 247 { 248 dprintf("if_initname(%p, %s, %d)\n", ifp, name, unit); 249 250 if (name == NULL || name[0] == '\0') 251 panic("interface goes unnamed"); 252 253 ifp->if_dname = name; 254 ifp->if_dunit = unit; 255 256 strlcpy(ifp->if_xname, name, sizeof(ifp->if_xname)); 257 258 snprintf(ifp->device_name, sizeof(ifp->device_name), "net/%s/%i", 259 gDriverName, ifp->if_index); 260 261 driver_printf("%s: /dev/%s\n", gDriverName, ifp->device_name); 262 263 // For wlan devices we only want to see the cloned wlan device 264 // in the list. 265 // Remember: For each wlan device, there is a base device of type 266 // IFT_IEEE80211. On top of that a clone device is created of 267 // type IFT_ETHER. 268 // Haiku shall only see the cloned device as it is the one 269 // FreeBSD 8 uses for wireless i/o, too. 270 if (ifp->if_type == IFT_ETHER) 271 insert_into_device_name_list(ifp); 272 273 ifp->root_device = find_root_device(unit); 274 } 275 276 277 void 278 ifq_init(struct ifqueue *ifq, const char *name) 279 { 280 ifq->ifq_head = NULL; 281 ifq->ifq_tail = NULL; 282 ifq->ifq_len = 0; 283 ifq->ifq_maxlen = IFQ_MAXLEN; 284 ifq->ifq_drops = 0; 285 286 mtx_init(&ifq->ifq_mtx, name, NULL, MTX_DEF); 287 } 288 289 290 void 291 ifq_uninit(struct ifqueue *ifq) 292 { 293 mtx_destroy(&ifq->ifq_mtx); 294 } 295 296 297 static int 298 if_transmit(struct ifnet *ifp, struct mbuf *m) 299 { 300 int error; 301 302 IFQ_HANDOFF(ifp, m, error); 303 return (error); 304 } 305 306 307 void 308 if_attach(struct ifnet *ifp) 309 { 310 TAILQ_INIT(&ifp->if_addrhead); 311 TAILQ_INIT(&ifp->if_prefixhead); 312 TAILQ_INIT(&ifp->if_multiaddrs); 313 314 IF_ADDR_LOCK_INIT(ifp); 315 316 ifp->if_lladdr.sdl_family = AF_LINK; 317 318 ifq_init((struct ifqueue *) &ifp->if_snd, ifp->if_xname); 319 320 if (ifp->if_transmit == NULL) { 321 ifp->if_transmit = if_transmit; 322 } 323 } 324 325 326 void 327 if_detach(struct ifnet *ifp) 328 { 329 if (HAIKU_DRIVER_REQUIRES(FBSD_SWI_TASKQUEUE)) 330 taskqueue_drain(taskqueue_swi, &ifp->if_linktask); 331 332 IF_ADDR_LOCK_DESTROY(ifp); 333 ifq_uninit((struct ifqueue *) &ifp->if_snd); 334 } 335 336 337 void 338 if_start(struct ifnet *ifp) 339 { 340 #ifdef IFF_NEEDSGIANT 341 if (ifp->if_flags & IFF_NEEDSGIANT) 342 panic("freebsd compat.: unsupported giant requirement"); 343 #endif 344 ifp->if_start(ifp); 345 } 346 347 348 int 349 if_printf(struct ifnet *ifp, const char *format, ...) 350 { 351 char buf[256]; 352 va_list vl; 353 va_start(vl, format); 354 vsnprintf(buf, sizeof(buf), format, vl); 355 va_end(vl); 356 357 dprintf("[%s] %s", ifp->device_name, buf); 358 return 0; 359 } 360 361 362 void 363 if_link_state_change(struct ifnet *ifp, int linkState) 364 { 365 if (ifp->if_link_state == linkState) 366 return; 367 368 ifp->if_link_state = linkState; 369 release_sem_etc(ifp->link_state_sem, 1, B_DO_NOT_RESCHEDULE); 370 } 371 372 373 static struct ifmultiaddr * 374 if_findmulti(struct ifnet *ifp, struct sockaddr *_address) 375 { 376 struct sockaddr_dl *address = (struct sockaddr_dl *) _address; 377 struct ifmultiaddr *ifma; 378 379 TAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) { 380 if (memcmp(LLADDR(address), 381 LLADDR((struct sockaddr_dl *)ifma->ifma_addr), ETHER_ADDR_LEN) == 0) 382 return ifma; 383 } 384 385 return NULL; 386 } 387 388 389 static struct ifmultiaddr * 390 _if_addmulti(struct ifnet *ifp, struct sockaddr *address) 391 { 392 struct ifmultiaddr *addr = if_findmulti(ifp, address); 393 394 if (addr != NULL) { 395 addr->ifma_refcount++; 396 return addr; 397 } 398 399 addr = (struct ifmultiaddr *) malloc(sizeof(struct ifmultiaddr)); 400 if (addr == NULL) 401 return NULL; 402 403 addr->ifma_lladdr = NULL; 404 addr->ifma_ifp = ifp; 405 addr->ifma_protospec = NULL; 406 407 memcpy(&addr->ifma_addr_storage, address, sizeof(struct sockaddr_dl)); 408 addr->ifma_addr = (struct sockaddr *) &addr->ifma_addr_storage; 409 410 addr->ifma_refcount = 1; 411 412 TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, addr, ifma_link); 413 414 return addr; 415 } 416 417 418 int 419 if_addmulti(struct ifnet *ifp, struct sockaddr *address, 420 struct ifmultiaddr **out) 421 { 422 struct ifmultiaddr *result; 423 int refcount = 0; 424 425 IF_ADDR_LOCK(ifp); 426 result = _if_addmulti(ifp, address); 427 if (result) 428 refcount = result->ifma_refcount; 429 IF_ADDR_UNLOCK(ifp); 430 431 if (result == NULL) 432 return ENOBUFS; 433 434 if (refcount == 1 && ifp->if_ioctl != NULL) 435 ifp->if_ioctl(ifp, SIOCADDMULTI, NULL); 436 437 if (out) 438 (*out) = result; 439 440 return 0; 441 } 442 443 444 static void 445 if_delete_multiaddr(struct ifnet *ifp, struct ifmultiaddr *ifma) 446 { 447 TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 448 free(ifma); 449 } 450 451 452 int 453 if_delmulti(struct ifnet *ifp, struct sockaddr *address) 454 { 455 struct ifmultiaddr *addr; 456 int deleted = 0; 457 458 IF_ADDR_LOCK(ifp); 459 addr = if_findmulti(ifp, address); 460 if (addr != NULL) { 461 addr->ifma_refcount--; 462 if (addr->ifma_refcount == 0) { 463 if_delete_multiaddr(ifp, addr); 464 deleted = 1; 465 } 466 } 467 IF_ADDR_UNLOCK(ifp); 468 469 if (deleted && ifp->if_ioctl != NULL) 470 ifp->if_ioctl(ifp, SIOCDELMULTI, NULL); 471 472 return 0; 473 } 474 475 476 static void 477 if_freemulti(struct ifmultiaddr *ifma) 478 { 479 if (ifma->ifma_lladdr != NULL) 480 free(ifma->ifma_lladdr); 481 free(ifma->ifma_addr); 482 free(ifma); 483 } 484 485 486 static int 487 if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, 488 int detaching) 489 { 490 ifp = ifma->ifma_ifp; 491 492 if (detaching) { 493 if (ifp != NULL) { 494 ifma->ifma_ifp = NULL; 495 } 496 } 497 498 if (--ifma->ifma_refcount > 0) 499 return 0; 500 501 if (ifp != NULL) 502 TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 503 504 if_freemulti(ifma); 505 506 return 1; 507 } 508 509 510 void 511 if_purgemaddrs(struct ifnet *ifp) 512 { 513 struct ifmultiaddr *ifma; 514 struct ifmultiaddr *next; 515 516 IF_ADDR_LOCK(ifp); 517 TAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) 518 if_delmulti_locked(ifp, ifma, 1); 519 IF_ADDR_UNLOCK(ifp); 520 } 521 522 523 void 524 if_addr_rlock(struct ifnet *ifp) 525 { 526 IF_ADDR_LOCK(ifp); 527 } 528 529 530 void 531 if_addr_runlock(struct ifnet *ifp) 532 { 533 IF_ADDR_UNLOCK(ifp); 534 } 535 536 537 void 538 if_maddr_rlock(struct ifnet *ifp) 539 { 540 IF_ADDR_LOCK(ifp); 541 } 542 543 544 void 545 if_maddr_runlock(struct ifnet *ifp) 546 { 547 IF_ADDR_UNLOCK(ifp); 548 } 549 550 551 int 552 ether_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 553 struct route *ro) 554 { 555 int error = 0; 556 IFQ_HANDOFF(ifp, m, error); 557 return error; 558 } 559 560 561 static void ether_input(struct ifnet *ifp, struct mbuf *m) 562 { 563 IF_ENQUEUE(&ifp->receive_queue, m); 564 release_sem_etc(ifp->receive_sem, 1, B_DO_NOT_RESCHEDULE); 565 } 566 567 568 void 569 ether_ifattach(struct ifnet *ifp, const uint8_t *macAddress) 570 { 571 ifp->if_addrlen = ETHER_ADDR_LEN; 572 ifp->if_hdrlen = ETHER_HDR_LEN; 573 if_attach(ifp); 574 ifp->if_mtu = ETHERMTU; 575 ifp->if_output = ether_output; 576 ifp->if_input = ether_input; 577 ifp->if_resolvemulti = NULL; // done in the stack 578 ifp->if_broadcastaddr = etherbroadcastaddr; 579 580 memcpy(IF_LLADDR(ifp), macAddress, ETHER_ADDR_LEN); 581 582 // TODO: according to FreeBSD's if_ethersubr.c, this should be removed 583 // once all drivers are cleaned up. 584 if (macAddress != IFP2ENADDR(ifp)) 585 memcpy(IFP2ENADDR(ifp), macAddress, ETHER_ADDR_LEN); 586 } 587 588 589 void 590 ether_ifdetach(struct ifnet *ifp) 591 { 592 if_detach(ifp); 593 } 594 595 596 int 597 ether_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 598 { 599 struct ifreq *ifr = (struct ifreq *) data; 600 601 switch (command) { 602 case SIOCSIFMTU: 603 if (ifr->ifr_mtu > ETHERMTU) 604 return EINVAL; 605 else 606 ; 607 // need to fix our ifreq to work with C... 608 // ifp->ifr_mtu = ifr->ifr_mtu; 609 break; 610 611 default: 612 return EINVAL; 613 } 614 615 return 0; 616 } 617