vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / drivers / network / ipro1000 / device.c
blobe15c4e4c15af5052f36640931c334e978718f3c5
1 /* Intel PRO/1000 Family Driver
2 * Copyright (C) 2004 Marcus Overhagen <marcus@overhagen.de>. All rights reserved.
4 * Permission to use, copy, modify and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted, provided
6 * that the above copyright notice appear in all copies, and that both the
7 * copyright notice and this permission notice appear in supporting documentation.
9 * Marcus Overhagen makes no representations about the suitability of this software
10 * for any purpose. It is provided "as is" without express or implied warranty.
12 * MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
13 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
14 * OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
15 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include "debug.h"
22 #include "device.h"
23 #include "driver.h"
24 #include "util.h"
25 #include "if_em.h"
26 #include "if_compat.h"
28 #include <KernelExport.h>
29 #include <driver_settings.h>
31 #include <fcntl.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
36 # include <net/if_media.h>
37 #endif
39 #undef malloc
40 #undef free
42 static int32 gOpenMask = 0;
44 int em_attach(device_t);
45 int em_detach(device_t);
46 void em_media_status(struct ifnet *, struct ifmediareq *);
49 static void
50 ipro1000_read_settings(ipro1000_device *device)
52 void *handle;
53 const char *param;
54 int mtu;
56 handle = load_driver_settings("ipro1000");
57 if (!handle)
58 return;
60 param = get_driver_parameter(handle, "mtu", "-1", "-1");
61 mtu = atoi(param);
62 if (mtu >= 50 && mtu <= 1500)
63 device->maxframesize = mtu + ENET_HEADER_SIZE;
64 else if (mtu != -1)
65 dprintf("ipro1000: unsupported mtu setting '%s' ignored\n", param);
67 unload_driver_settings(handle);
71 status_t
72 ipro1000_open(const char *name, uint32 flags, void** cookie)
74 ipro1000_device *device;
75 char *deviceName;
76 int dev_id;
77 int mask;
79 DEVICE_DEBUGOUT("ipro1000_open()");
81 for (dev_id = 0; (deviceName = gDevNameList[dev_id]) != NULL; dev_id++) {
82 if (!strcmp(name, deviceName))
83 break;
85 if (deviceName == NULL) {
86 ERROROUT("invalid device name");
87 return B_ERROR;
90 // allow only one concurrent access
91 mask = 1 << dev_id;
92 if (atomic_or(&gOpenMask, mask) & mask)
93 return B_BUSY;
95 *cookie = device = (ipro1000_device *)malloc(sizeof(ipro1000_device));
96 if (!device) {
97 atomic_and(&gOpenMask, ~(1 << dev_id));
98 return B_NO_MEMORY;
101 memset(device, 0, sizeof(*device));
103 device->devId = dev_id;
104 device->pciInfo = gDevList[dev_id];
105 device->nonblocking = (flags & O_NONBLOCK) ? true : false;
106 device->closed = false;
108 device->pciBus = device->pciInfo->bus;
109 device->pciDev = device->pciInfo->device;
110 device->pciFunc = device->pciInfo->function;
111 device->adapter = 0;
112 device->maxframesize = 1514; // XXX is MAXIMUM_ETHERNET_FRAME_SIZE = 1518 too much?
114 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
115 device->linkChangeSem = -1;
116 #endif
118 ipro1000_read_settings(device);
120 if (em_attach(device) != 0) {
121 DEVICE_DEBUGOUT("em_attach failed");
122 goto err;
125 return B_OK;
127 err:
128 free(device);
129 atomic_and(&gOpenMask, ~(1 << dev_id));
130 return B_ERROR;
134 status_t
135 ipro1000_close(void* cookie)
137 ipro1000_device *device = (ipro1000_device *)cookie;
138 struct ifnet *ifp = &device->adapter->interface_data.ac_if;
139 DEVICE_DEBUGOUT("ipro1000_close()");
141 device->closed = true;
142 release_sem(ifp->if_rcv_sem);
144 return B_OK;
148 status_t
149 ipro1000_free(void* cookie)
151 ipro1000_device *device = (ipro1000_device *)cookie;
152 DEVICE_DEBUGOUT("ipro1000_free()");
154 if (em_detach(device) != 0) {
155 DEVICE_DEBUGOUT("em_detach failed");
158 free(device);
159 atomic_and(&gOpenMask, ~(1 << device->devId));
160 return B_OK;
164 status_t
165 ipro1000_read(void* cookie, off_t position, void *buf, size_t* num_bytes)
167 ipro1000_device *device = (ipro1000_device *)cookie;
168 struct ifnet *ifp = &device->adapter->interface_data.ac_if;
169 struct mbuf *mb;
170 status_t stat;
171 int len;
173 // DEVICE_DEBUGOUT("ipro1000_read() enter");
175 if (device->closed) {
176 DEVICE_DEBUGOUT("ipro1000_read() interrupted 1");
177 return B_INTERRUPTED;
179 retry:
180 stat = acquire_sem_etc(ifp->if_rcv_sem, 1, B_CAN_INTERRUPT | (device->nonblocking ? B_TIMEOUT : 0), 0);
181 if (device->closed) {
182 // DEVICE_DEBUGOUT("ipro1000_read() interrupted 2"); // net_server will crash if we print this (race condition in net_server?)
183 return B_INTERRUPTED;
185 if (stat == B_WOULD_BLOCK) {
186 DEVICE_DEBUGOUT("ipro1000_read() would block (OK 0 bytes)");
187 *num_bytes = 0;
188 return B_OK;
190 if (stat != B_OK) {
191 DEVICE_DEBUGOUT("ipro1000_read() error");
192 return B_ERROR;
195 IF_DEQUEUE(&ifp->if_rcv, mb);
196 if (!mb) {
197 ERROROUT("ipro1000_read() mbuf not ready");
198 goto retry;
201 len = mb->m_len;
202 if (len < 0)
203 len = 0;
204 if (len > (int)*num_bytes)
205 len = *num_bytes;
207 memcpy(buf, mtod(mb, uint8 *), len); // XXX this is broken for jumbo frames
208 *num_bytes = len;
210 m_freem(mb);
212 // DEVICE_DEBUGOUT1("ipro1000_read() leave, %d bytes", len);
213 return B_OK;
217 status_t
218 ipro1000_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
220 // bigtime_t t = system_time();
221 ipro1000_device *device = (ipro1000_device *)cookie;
222 struct ifnet *ifp = &device->adapter->interface_data.ac_if;
223 struct mbuf *mb;
225 // DEVICE_DEBUGOUT("ipro1000_write() enter");
227 // allocate mbuf
228 for (;;) {
229 MGETHDR(mb, M_DONTWAIT, MT_DATA);
230 if (mb)
231 break;
232 snooze(700);
233 if (device->closed)
234 return B_INTERRUPTED;
237 // DEVICE_DEBUGOUT("ipro1000_write() 1");
239 // allocate memory
240 for (;;) {
241 MCLGET(mb, M_DONTWAIT);
242 if (mb->m_flags & M_EXT)
243 break;
244 snooze(700);
245 if (device->closed) {
246 m_freem(mb);
247 return B_INTERRUPTED;
251 // DEVICE_DEBUGOUT("ipro1000_write() 2");
253 // copy data
254 mb->m_len = *num_bytes;
255 if (mb->m_len > MCLBYTES)
256 mb->m_len = MCLBYTES;
257 memcpy(mtod(mb, uint8 *), buffer, mb->m_len);
259 // DEVICE_DEBUGOUT("ipro1000_write() 3");
261 // add mbuf to send queue
262 IF_APPEND(&ifp->if_snd, mb);
264 // DEVICE_DEBUGOUT("ipro1000_write() 4");
266 // wait for output available
267 while (ifp->if_flags & IFF_OACTIVE) {
268 snooze(700);
269 if (device->closed)
270 return B_INTERRUPTED;
273 // DEVICE_DEBUGOUT("ipro1000_write() 5");
275 // send everything (if still required)
276 if (ifp->if_snd.ifq_head != NULL)
277 ifp->if_start(ifp);
279 // while (ifp->if_snd.ifq_head != NULL) {
280 // ifp->if_start(ifp);
281 // if (ifp->if_snd.ifq_head != NULL) {
282 // snooze(1000);
283 // if (device->closed)
284 // return B_INTERRUPTED;
285 // }
286 // }
288 // t = system_time() - t;
290 // if (t > 20)
291 // DEVICE_DEBUGOUT("write %Ld", t);
293 // DEVICE_DEBUGOUT("ipro1000_write() finished");
295 return B_OK;
299 static struct ifnet *
300 device_ifp(ipro1000_device *device)
302 return &device->adapter->interface_data.ac_if;
306 status_t
307 ipro1000_control(void *cookie, uint32 op, void *arg, size_t len)
309 ipro1000_device *device = (ipro1000_device *)cookie;
311 switch (op) {
312 case ETHER_INIT:
313 DEVICE_DEBUGOUT("ipro1000_control() ETHER_INIT");
314 return B_OK;
316 case ETHER_GETADDR:
317 DEVICE_DEBUGOUT("ipro1000_control() ETHER_GETADDR");
318 memcpy(arg, &device->macaddr, sizeof(device->macaddr));
319 return B_OK;
321 case ETHER_NONBLOCK:
322 if (*(int32 *)arg) {
323 DEVICE_DEBUGOUT("non blocking mode on");
324 device->nonblocking = true;
325 } else {
326 DEVICE_DEBUGOUT("non blocking mode off");
327 device->nonblocking = false;
329 return B_OK;
331 case ETHER_ADDMULTI:
332 case ETHER_REMMULTI:
334 struct ifnet *ifp = device_ifp(device);
335 struct sockaddr_dl address;
337 if (len != ETHER_ADDR_LEN)
338 return EINVAL;
340 memset(&address, 0, sizeof(address));
341 address.sdl_family = AF_LINK;
342 memcpy(LLADDR(&address), arg, ETHER_ADDR_LEN);
344 if (op == ETHER_ADDMULTI)
345 return ether_add_multi(ifp, (struct sockaddr *)&address);
346 else
347 return ether_rem_multi(ifp, (struct sockaddr *)&address);
350 case ETHER_SETPROMISC:
351 if (*(int32 *)arg) {
352 DEVICE_DEBUGOUT("promiscuous mode on not supported");
353 } else {
354 DEVICE_DEBUGOUT("promiscuous mode off");
356 return B_OK;
358 case ETHER_GETFRAMESIZE:
359 DEVICE_DEBUGOUT2("ipro1000_control() ETHER_GETFRAMESIZE, framesize = %d (MTU = %d)", device->maxframesize, device->maxframesize - ENET_HEADER_SIZE);
360 *(uint32*)arg = device->maxframesize;
361 return B_OK;
363 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
364 case ETHER_GET_LINK_STATE:
366 struct ifmediareq mediareq;
367 ether_link_state_t state;
369 if (len < sizeof(ether_link_state_t))
370 return ENOBUFS;
372 em_media_status(device_ifp(device), &mediareq);
374 state.media = mediareq.ifm_active;
375 if (mediareq.ifm_status & IFM_ACTIVE)
376 state.media |= IFM_ACTIVE;
377 if (mediareq.ifm_active & IFM_10_T)
378 state.speed = 10000000;
379 else if (mediareq.ifm_active & IFM_100_TX)
380 state.speed = 100000000;
381 else
382 state.speed = 1000000000;
383 state.quality = 1000;
385 return user_memcpy(arg, &state, sizeof(ether_link_state_t));
388 case ETHER_SET_LINK_STATE_SEM:
390 if (user_memcpy(&device->linkChangeSem, arg, sizeof(sem_id)) < B_OK) {
391 device->linkChangeSem = -1;
392 return B_BAD_ADDRESS;
394 return B_OK;
396 #endif
398 default:
399 DEVICE_DEBUGOUT("ipro1000_control() Invalid command");
400 break;
403 return B_BAD_VALUE;