1 /* 2 * Copyright 2006, 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 <ether_driver.h> 11 #include <ethernet.h> 12 #include <net_buffer.h> 13 #include <net_device.h> 14 15 #include <KernelExport.h> 16 17 #include <errno.h> 18 #include <net/if.h> 19 #include <net/if_types.h> 20 #include <net/if_dl.h> 21 #include <new> 22 #include <stdlib.h> 23 #include <string.h> 24 25 26 struct ethernet_device : net_device { 27 int fd; 28 uint32 frame_size; 29 }; 30 31 32 struct net_buffer_module_info *sBufferModule; 33 34 35 status_t 36 ethernet_init(const char *name, net_device **_device) 37 { 38 // make sure this is a device in /dev/net, but not the 39 // networking (userland) stack driver 40 if (strncmp(name, "/dev/net/", 9) || !strcmp(name, "/dev/net/stack") 41 || !strcmp(name, "/dev/net/userland_server")) 42 return B_BAD_VALUE; 43 44 status_t status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&sBufferModule); 45 if (status < B_OK) 46 return status; 47 48 ethernet_device *device = new (std::nothrow) ethernet_device; 49 if (device == NULL) { 50 put_module(NET_BUFFER_MODULE_NAME); 51 return B_NO_MEMORY; 52 } 53 54 memset(device, 0, sizeof(ethernet_device)); 55 56 strcpy(device->name, name); 57 device->flags = IFF_BROADCAST; 58 device->type = IFT_ETHER; 59 device->mtu = 1500; 60 device->header_length = ETHER_HEADER_LENGTH; 61 device->fd = -1; 62 63 *_device = device; 64 return B_OK; 65 } 66 67 68 status_t 69 ethernet_uninit(net_device *device) 70 { 71 put_module(NET_BUFFER_MODULE_NAME); 72 delete device; 73 74 return B_OK; 75 } 76 77 78 status_t 79 ethernet_up(net_device *_device) 80 { 81 ethernet_device *device = (ethernet_device *)_device; 82 83 device->fd = open(device->name, O_RDWR); 84 if (device->fd < 0) 85 return errno; 86 87 ether_init_params params; 88 memset(¶ms, 0, sizeof(ether_init_params)); 89 if (ioctl(device->fd, ETHER_INIT, ¶ms, sizeof(ether_init_params)) < 0) 90 goto err; 91 92 if (ioctl(device->fd, ETHER_GETADDR, device->address.data, ETHER_ADDRESS_LENGTH) < 0) 93 goto err; 94 95 if (ioctl(device->fd, ETHER_GETFRAMESIZE, &device->frame_size, sizeof(uint32)) < 0) { 96 // this call is obviously optional 97 device->frame_size = ETHER_MAX_FRAME_SIZE; 98 } 99 100 device->address.length = ETHER_ADDRESS_LENGTH; 101 device->mtu = device->frame_size - device->header_length; 102 return B_OK; 103 104 err: 105 close(device->fd); 106 device->fd = -1; 107 return errno; 108 } 109 110 111 void 112 ethernet_down(net_device *_device) 113 { 114 ethernet_device *device = (ethernet_device *)_device; 115 close(device->fd); 116 } 117 118 119 status_t 120 ethernet_control(net_device *_device, int32 op, void *argument, 121 size_t length) 122 { 123 ethernet_device *device = (ethernet_device *)_device; 124 return ioctl(device->fd, op, argument, length); 125 } 126 127 128 status_t 129 ethernet_send_data(net_device *_device, net_buffer *buffer) 130 { 131 ethernet_device *device = (ethernet_device *)_device; 132 133 dprintf("try to send ethernet packet of %lu bytes (flags %ld):\n", buffer->size, buffer->flags); 134 if (buffer->size > device->frame_size || buffer->size < ETHER_HEADER_LENGTH) 135 return B_BAD_VALUE; 136 137 if (sBufferModule->count_iovecs(buffer) > 1) { 138 dprintf("scattered I/O is not yet supported by ethernet device.\n"); 139 return B_NOT_SUPPORTED; 140 } 141 142 struct iovec iovec; 143 sBufferModule->get_iovecs(buffer, &iovec, 1); 144 145 dump_block((const char *)iovec.iov_base, buffer->size, " "); 146 ssize_t bytesWritten = write(device->fd, iovec.iov_base, iovec.iov_len); 147 dprintf("sent: %ld\n", bytesWritten); 148 if (bytesWritten < 0) { 149 device->stats.send.errors++; 150 return bytesWritten; 151 } 152 153 device->stats.send.packets++; 154 device->stats.send.bytes += bytesWritten; 155 156 sBufferModule->free(buffer); 157 return B_OK; 158 } 159 160 161 status_t 162 ethernet_receive_data(net_device *_device, net_buffer **_buffer) 163 { 164 ethernet_device *device = (ethernet_device *)_device; 165 166 // TODO: better header space 167 net_buffer *buffer = sBufferModule->create(256); 168 if (buffer == NULL) 169 return ENOBUFS; 170 171 // TODO: this only works for standard ethernet frames - we need iovecs 172 // for jumbo frame support (or a separate read buffer)! 173 // It would be even nicer to get net_buffers from the ethernet driver 174 // directly. 175 176 ssize_t bytesRead; 177 void *data; 178 179 status_t status = sBufferModule->append_size(buffer, device->frame_size, &data); 180 if (status == B_OK && data == NULL) { 181 dprintf("scattered I/O is not yet supported by ethernet device.\n"); 182 status = B_NOT_SUPPORTED; 183 } 184 if (status < B_OK) 185 goto err; 186 187 bytesRead = read(device->fd, data, device->frame_size); 188 if (bytesRead < 0) { 189 device->stats.receive.errors++; 190 status = bytesRead; 191 goto err; 192 } 193 194 status = sBufferModule->trim(buffer, bytesRead); 195 if (status < B_OK) { 196 device->stats.receive.dropped++; 197 goto err; 198 } 199 200 device->stats.receive.bytes += bytesRead; 201 device->stats.receive.packets++; 202 203 *_buffer = buffer; 204 return B_OK; 205 206 err: 207 sBufferModule->free(buffer); 208 return status; 209 } 210 211 212 status_t 213 ethernet_set_mtu(net_device *_device, size_t mtu) 214 { 215 ethernet_device *device = (ethernet_device *)_device; 216 217 if (mtu > device->frame_size - ETHER_HEADER_LENGTH 218 || mtu <= ETHER_HEADER_LENGTH + 10) 219 return B_BAD_VALUE; 220 221 device->mtu = mtu; 222 return B_OK; 223 } 224 225 226 status_t 227 ethernet_set_promiscuous(net_device *device, bool promiscuous) 228 { 229 return EOPNOTSUPP; 230 } 231 232 233 status_t 234 ethernet_set_media(net_device *device, uint32 media) 235 { 236 return EOPNOTSUPP; 237 } 238 239 240 status_t 241 ethernet_get_multicast_addrs(struct net_device *device, 242 net_hardware_address **addressArray, uint32 count) 243 { 244 return EOPNOTSUPP; 245 } 246 247 248 status_t 249 ethernet_set_multicast_addrs(struct net_device *device, 250 const net_hardware_address **addressArray, uint32 count) 251 { 252 return EOPNOTSUPP; 253 } 254 255 256 static status_t 257 ethernet_std_ops(int32 op, ...) 258 { 259 switch (op) { 260 case B_MODULE_INIT: 261 case B_MODULE_UNINIT: 262 return B_OK; 263 264 default: 265 return B_ERROR; 266 } 267 } 268 269 270 net_device_module_info sEthernetModule = { 271 { 272 "network/devices/ethernet/v1", 273 0, 274 ethernet_std_ops 275 }, 276 ethernet_init, 277 ethernet_uninit, 278 ethernet_up, 279 ethernet_down, 280 ethernet_control, 281 ethernet_send_data, 282 ethernet_receive_data, 283 ethernet_set_mtu, 284 ethernet_set_promiscuous, 285 ethernet_set_media, 286 ethernet_get_multicast_addrs, 287 ethernet_set_multicast_addrs 288 }; 289 290 module_info *modules[] = { 291 (module_info *)&sEthernetModule, 292 NULL 293 }; 294