1 /* 2 * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include <ethernet.h> 11 12 #include <ether_driver.h> 13 #include <net_buffer.h> 14 #include <net_device.h> 15 #include <net_stack.h> 16 17 #include <lock.h> 18 #include <util/AutoLock.h> 19 #include <util/DoublyLinkedList.h> 20 21 #include <KernelExport.h> 22 23 #include <errno.h> 24 #include <net/if.h> 25 #include <net/if_dl.h> 26 #include <net/if_media.h> 27 #include <net/if_types.h> 28 #include <new> 29 #include <stdlib.h> 30 #include <string.h> 31 32 33 struct ethernet_device : net_device, DoublyLinkedListLinkImpl<ethernet_device> { 34 int fd; 35 uint32 frame_size; 36 bool supports_net_buffer; 37 }; 38 39 static const bigtime_t kLinkCheckInterval = 1000000; 40 // 1 second 41 42 net_buffer_module_info *gBufferModule; 43 static net_stack_module_info *sStackModule; 44 45 static mutex sListLock; 46 static DoublyLinkedList<ethernet_device> sCheckList; 47 static sem_id sLinkChangeSemaphore; 48 static thread_id sLinkCheckerThread; 49 50 51 static status_t 52 update_link_state(ethernet_device *device, bool notify = true) 53 { 54 ether_link_state state; 55 if (ioctl(device->fd, ETHER_GET_LINK_STATE, &state, 56 sizeof(ether_link_state)) < 0) { 57 // This device does not support retrieving the link 58 return B_NOT_SUPPORTED; 59 } 60 61 if (device->media != state.media 62 || device->link_quality != state.quality 63 || device->link_speed != state.speed) { 64 device->media = state.media; 65 device->link_quality = state.quality; 66 device->link_speed = state.speed; 67 68 if (device->media & IFM_ACTIVE) { 69 if ((device->flags & IFF_LINK) == 0) { 70 dprintf("%s: link up, media 0x%0x quality %u speed %u\n", 71 device->name, (unsigned int)device->media, 72 (unsigned int)device->link_quality, 73 (unsigned int)device->link_speed); 74 } 75 device->flags |= IFF_LINK; 76 } else { 77 if ((device->flags & IFF_LINK) != 0) { 78 dprintf("%s: link down, media 0x%0x quality %u speed %u\n", 79 device->name, (unsigned int)device->media, 80 (unsigned int)device->link_quality, 81 (unsigned int)device->link_speed); 82 } 83 device->flags &= ~IFF_LINK; 84 } 85 86 87 if (notify) 88 sStackModule->device_link_changed(device); 89 } 90 91 return B_OK; 92 } 93 94 95 static status_t 96 ethernet_link_checker(void *) 97 { 98 while (true) { 99 status_t status = acquire_sem_etc(sLinkChangeSemaphore, 1, 100 B_RELATIVE_TIMEOUT, kLinkCheckInterval); 101 if (status == B_BAD_SEM_ID) 102 break; 103 104 MutexLocker _(sListLock); 105 106 if (sCheckList.IsEmpty()) 107 break; 108 109 // check link state of all existing devices 110 111 DoublyLinkedList<ethernet_device>::Iterator iterator 112 = sCheckList.GetIterator(); 113 while (iterator.HasNext()) { 114 update_link_state(iterator.Next()); 115 } 116 } 117 118 return B_OK; 119 } 120 121 122 // #pragma mark - 123 124 125 status_t 126 ethernet_init(const char *name, net_device **_device) 127 { 128 // Make sure this is a device in /dev/net, but not the 129 // networking (userland) stack driver. 130 // Also make sure the user didn't pass a path like 131 // /dev/net/../etc. 132 if (strncmp(name, "/dev/net/", 9) 133 || !strcmp(name, "/dev/net/userland_server") 134 || strstr(name, "..") != NULL) 135 return B_BAD_VALUE; 136 137 if (access(name, F_OK) != 0) 138 return errno; 139 140 status_t status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule); 141 if (status < B_OK) 142 return status; 143 144 ethernet_device *device = new (std::nothrow) ethernet_device; 145 if (device == NULL) { 146 put_module(NET_BUFFER_MODULE_NAME); 147 return B_NO_MEMORY; 148 } 149 150 memset(device, 0, sizeof(ethernet_device)); 151 152 strcpy(device->name, name); 153 device->flags = IFF_BROADCAST | IFF_LINK; 154 device->type = IFT_ETHER; 155 device->mtu = ETHER_MAX_FRAME_SIZE - ETHER_HEADER_LENGTH; 156 device->media = IFM_ACTIVE | IFM_ETHER; 157 device->header_length = ETHER_HEADER_LENGTH; 158 device->fd = -1; 159 160 *_device = device; 161 return B_OK; 162 } 163 164 165 status_t 166 ethernet_uninit(net_device *device) 167 { 168 put_module(NET_BUFFER_MODULE_NAME); 169 delete device; 170 171 return B_OK; 172 } 173 174 175 status_t 176 ethernet_up(net_device *_device) 177 { 178 ethernet_device *device = (ethernet_device *)_device; 179 180 device->fd = open(device->name, O_RDWR); 181 if (device->fd < 0) 182 return errno; 183 184 uint64 dummy; 185 if (ioctl(device->fd, ETHER_INIT, &dummy, sizeof(dummy)) < 0) 186 goto err; 187 188 if (ioctl(device->fd, ETHER_GETADDR, device->address.data, ETHER_ADDRESS_LENGTH) < 0) 189 goto err; 190 191 if (ioctl(device->fd, ETHER_SEND_NET_BUFFER, NULL, 0) != 0) { 192 // Check if the returned error code is B_BAD_DATA (not EINVAL or EOPNOTSUPP). 193 if (errno == B_BAD_DATA) 194 device->supports_net_buffer = true; 195 } 196 197 if (ioctl(device->fd, ETHER_GETFRAMESIZE, &device->frame_size, sizeof(uint32)) < 0) { 198 // this call is obviously optional 199 device->frame_size = ETHER_MAX_FRAME_SIZE; 200 } 201 202 #if 1 203 // The network stack does not handle path MTU discovery correctly at present, 204 // so don't report frame sizes larger than the standard ethernet maximum. 205 // (We will still handle receiving frames larger than this.) 206 if (device->frame_size > ETHER_MAX_FRAME_SIZE) 207 device->frame_size = ETHER_MAX_FRAME_SIZE; 208 #endif 209 210 if (update_link_state(device, false) == B_OK) { 211 // device supports retrieval of the link state 212 213 // Set the change notification semaphore; doesn't matter 214 // if this is supported by the device or not 215 ioctl(device->fd, ETHER_SET_LINK_STATE_SEM, &sLinkChangeSemaphore, 216 sizeof(sem_id)); 217 218 MutexLocker _(&sListLock); 219 220 if (sCheckList.IsEmpty()) { 221 // start thread 222 sLinkCheckerThread = spawn_kernel_thread(ethernet_link_checker, 223 "ethernet link state checker", B_LOW_PRIORITY, NULL); 224 if (sLinkCheckerThread >= B_OK) 225 resume_thread(sLinkCheckerThread); 226 } 227 228 sCheckList.Add(device); 229 } 230 231 device->address.length = ETHER_ADDRESS_LENGTH; 232 device->mtu = device->frame_size - device->header_length; 233 return B_OK; 234 235 err: 236 close(device->fd); 237 device->fd = -1; 238 return errno; 239 } 240 241 242 void 243 ethernet_down(net_device *_device) 244 { 245 ethernet_device *device = (ethernet_device *)_device; 246 247 MutexLocker _(sListLock); 248 249 // if the device is still part of the list, remove it 250 if (device->GetDoublyLinkedListLink()->next != NULL 251 || device->GetDoublyLinkedListLink()->previous != NULL 252 || device == sCheckList.Head()) 253 sCheckList.Remove(device); 254 255 close(device->fd); 256 device->fd = -1; 257 } 258 259 260 status_t 261 ethernet_control(net_device *_device, int32 op, void *argument, 262 size_t length) 263 { 264 ethernet_device *device = (ethernet_device *)_device; 265 if (ioctl(device->fd, op, argument, length) < 0) 266 return errno; 267 return B_OK; 268 } 269 270 271 status_t 272 ethernet_send_data(net_device *_device, net_buffer *buffer) 273 { 274 ethernet_device *device = (ethernet_device *)_device; 275 276 //dprintf("try to send ethernet packet of %lu bytes (flags %ld):\n", buffer->size, buffer->flags); 277 if (buffer->size > device->frame_size || buffer->size < ETHER_HEADER_LENGTH) 278 return B_BAD_VALUE; 279 280 if (device->supports_net_buffer) { 281 if (ioctl(device->fd, ETHER_SEND_NET_BUFFER, buffer, sizeof(net_buffer)) != 0) 282 return errno; 283 return 0; 284 } 285 286 net_buffer *allocated = NULL; 287 net_buffer *original = buffer; 288 289 if (gBufferModule->count_iovecs(buffer) > 1) { 290 // Create a new buffer containing the data. 291 buffer = gBufferModule->duplicate(original); 292 if (buffer == NULL) 293 return ENOBUFS; 294 295 allocated = buffer; 296 297 if (gBufferModule->count_iovecs(buffer) > 1) { 298 dprintf("ethernet: net_buffer I/O is not supported by underlying device\n"); 299 gBufferModule->free(buffer); 300 device->stats.send.errors++; 301 return B_NOT_SUPPORTED; 302 } 303 } 304 305 struct iovec iovec; 306 gBufferModule->get_iovecs(buffer, &iovec, 1); 307 308 //dump_block((const char *)iovec.iov_base, buffer->size, " "); 309 ssize_t bytesWritten = write(device->fd, iovec.iov_base, iovec.iov_len); 310 //dprintf("sent: %ld\n", bytesWritten); 311 312 if (bytesWritten < 0) { 313 if (allocated) 314 gBufferModule->free(allocated); 315 return errno; 316 } 317 318 gBufferModule->free(original); 319 if (allocated) 320 gBufferModule->free(allocated); 321 return B_OK; 322 } 323 324 325 status_t 326 ethernet_receive_data(net_device *_device, net_buffer **_buffer) 327 { 328 ethernet_device *device = (ethernet_device *)_device; 329 330 if (device->fd == -1) 331 return B_FILE_ERROR; 332 333 if (device->supports_net_buffer) { 334 if (ioctl(device->fd, ETHER_RECEIVE_NET_BUFFER, _buffer, sizeof(net_buffer*)) != 0) 335 return errno; 336 return 0; 337 } 338 339 // read/write only works for standard ethernet frames. For larger frames, 340 // the driver should support send/receive of net_buffers directly, above. 341 342 net_buffer *buffer = gBufferModule->create(256); 343 if (buffer == NULL) 344 return ENOBUFS; 345 346 ssize_t bytesRead; 347 void *data; 348 349 status_t status = gBufferModule->append_size(buffer, device->frame_size, &data); 350 if (status == B_OK && data == NULL) { 351 dprintf("ethernet: net_buffer I/O is not supported by underlying device\n"); 352 status = B_NOT_SUPPORTED; 353 } 354 if (status < B_OK) 355 goto err; 356 357 bytesRead = read(device->fd, data, device->frame_size); 358 if (bytesRead < 0) { 359 status = errno; 360 goto err; 361 } 362 //dump_block((const char *)data, bytesRead, "rcv: "); 363 364 status = gBufferModule->trim(buffer, bytesRead); 365 if (status < B_OK) { 366 atomic_add((int32*)&device->stats.receive.dropped, 1); 367 goto err; 368 } 369 370 *_buffer = buffer; 371 return B_OK; 372 373 err: 374 gBufferModule->free(buffer); 375 return status; 376 } 377 378 379 status_t 380 ethernet_set_mtu(net_device *_device, size_t mtu) 381 { 382 ethernet_device *device = (ethernet_device *)_device; 383 384 if (mtu > device->frame_size - ETHER_HEADER_LENGTH 385 || mtu <= ETHER_HEADER_LENGTH + 10) 386 return B_BAD_VALUE; 387 388 device->mtu = mtu; 389 return B_OK; 390 } 391 392 393 status_t 394 ethernet_set_promiscuous(net_device *_device, bool promiscuous) 395 { 396 ethernet_device *device = (ethernet_device *)_device; 397 398 int32 value = (int32)promiscuous; 399 if (ioctl(device->fd, ETHER_SETPROMISC, &value, sizeof(value)) < 0) 400 return B_NOT_SUPPORTED; 401 402 return B_OK; 403 } 404 405 406 status_t 407 ethernet_set_media(net_device *device, uint32 media) 408 { 409 return B_NOT_SUPPORTED; 410 } 411 412 413 status_t 414 ethernet_add_multicast(struct net_device *_device, const sockaddr *_address) 415 { 416 ethernet_device *device = (ethernet_device *)_device; 417 418 if (_address->sa_family != AF_LINK) 419 return B_BAD_VALUE; 420 421 const sockaddr_dl *address = (const sockaddr_dl *)_address; 422 if (address->sdl_type != IFT_ETHER) 423 return B_BAD_VALUE; 424 425 if (ioctl(device->fd, ETHER_ADDMULTI, LLADDR(address), 6) < 0) 426 return errno; 427 return B_OK; 428 } 429 430 431 status_t 432 ethernet_remove_multicast(struct net_device *_device, const sockaddr *_address) 433 { 434 ethernet_device *device = (ethernet_device *)_device; 435 436 if (_address->sa_family != AF_LINK) 437 return B_BAD_VALUE; 438 439 const sockaddr_dl *address = (const sockaddr_dl *)_address; 440 if (address->sdl_type != IFT_ETHER) 441 return B_BAD_VALUE; 442 443 if (ioctl(device->fd, ETHER_REMMULTI, LLADDR(address), 6) < 0) 444 return errno; 445 return B_OK; 446 } 447 448 449 static status_t 450 ethernet_std_ops(int32 op, ...) 451 { 452 switch (op) { 453 case B_MODULE_INIT: 454 { 455 status_t status = get_module(NET_STACK_MODULE_NAME, 456 (module_info **)&sStackModule); 457 if (status < B_OK) 458 return status; 459 460 new (&sCheckList) DoublyLinkedList<ethernet_device>; 461 // static C++ objects are not initialized in the module startup 462 463 sLinkCheckerThread = -1; 464 465 sLinkChangeSemaphore = create_sem(0, "ethernet link change"); 466 if (sLinkChangeSemaphore < B_OK) { 467 put_module(NET_STACK_MODULE_NAME); 468 return sLinkChangeSemaphore; 469 } 470 471 mutex_init(&sListLock, "ethernet devices"); 472 473 return B_OK; 474 } 475 476 case B_MODULE_UNINIT: 477 { 478 delete_sem(sLinkChangeSemaphore); 479 480 status_t status; 481 wait_for_thread(sLinkCheckerThread, &status); 482 483 mutex_destroy(&sListLock); 484 put_module(NET_STACK_MODULE_NAME); 485 return B_OK; 486 } 487 488 default: 489 return B_ERROR; 490 } 491 } 492 493 494 net_device_module_info sEthernetModule = { 495 { 496 "network/devices/ethernet/v1", 497 0, 498 ethernet_std_ops 499 }, 500 ethernet_init, 501 ethernet_uninit, 502 ethernet_up, 503 ethernet_down, 504 ethernet_control, 505 ethernet_send_data, 506 ethernet_receive_data, 507 ethernet_set_mtu, 508 ethernet_set_promiscuous, 509 ethernet_set_media, 510 ethernet_add_multicast, 511 ethernet_remove_multicast, 512 }; 513 514 module_info *modules[] = { 515 (module_info *)&sEthernetModule, 516 NULL 517 }; 518