Restore the "GPL licensing not permitted" in GLUT license headers.
[haiku.git] / src / libs / compat / freebsd_network / device.c
blobda9964752f12c022b1a44ebe5f53b77af33166bc
1 /*
2 * Copyright 2007-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2007, Hugo Santos. All Rights Reserved.
4 * Copyright 2004, Marcus Overhagen. All Rights Reserved.
5 * Distributed under the terms of the MIT License.
6 */
9 #include "device.h"
11 #include <stdlib.h>
12 #include <sys/sockio.h>
14 #include <Drivers.h>
15 #include <ether_driver.h>
17 #include <compat/sys/haiku-module.h>
19 #include <compat/sys/bus.h>
20 #include <compat/sys/mbuf.h>
21 #include <compat/net/ethernet.h>
22 #include <compat/net/if_media.h>
25 static status_t
26 compat_open(const char *name, uint32 flags, void **cookie)
28 struct ifnet *ifp;
29 struct ifreq ifr;
30 int i;
31 status_t status;
33 for (i = 0; i < MAX_DEVICES; i++) {
34 if (gDevices[i] != NULL && !strcmp(gDevices[i]->device_name, name))
35 break;
38 if (i == MAX_DEVICES)
39 return B_ERROR;
41 if (get_module(NET_STACK_MODULE_NAME, (module_info **)&gStack) != B_OK)
42 return B_ERROR;
44 ifp = gDevices[i];
45 if_printf(ifp, "compat_open(0x%" B_PRIx32 ")\n", flags);
47 if (atomic_or(&ifp->open_count, 1)) {
48 put_module(NET_STACK_MODULE_NAME);
49 return B_BUSY;
52 ifp->if_init(ifp->if_softc);
54 if (!HAIKU_DRIVER_REQUIRES(FBSD_WLAN)) {
55 ifp->if_flags &= ~IFF_UP;
56 ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
58 memset(&ifr, 0, sizeof(ifr));
59 ifr.ifr_media = IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0);
60 status = ifp->if_ioctl(ifp, SIOCSIFMEDIA, (caddr_t)&ifr);
61 if (status != B_OK) {
62 ifr.ifr_media = IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0);
63 status = ifp->if_ioctl(ifp, SIOCSIFMEDIA, (caddr_t)&ifr);
67 ifp->if_flags |= IFF_UP;
68 ifp->flags &= ~DEVICE_CLOSED;
69 ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
71 *cookie = ifp;
72 return B_OK;
76 static status_t
77 compat_close(void *cookie)
79 struct ifnet *ifp = cookie;
81 if_printf(ifp, "compat_close()\n");
83 atomic_or(&ifp->flags, DEVICE_CLOSED);
85 wlan_close(cookie);
87 release_sem_etc(ifp->receive_sem, 1, B_RELEASE_ALL);
89 return B_OK;
93 static status_t
94 compat_free(void *cookie)
96 struct ifnet *ifp = cookie;
98 if_printf(ifp, "compat_free()\n");
100 // TODO: empty out the send queue
102 atomic_and(&ifp->open_count, 0);
103 put_module(NET_STACK_MODULE_NAME);
104 return B_OK;
108 static status_t
109 compat_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
111 struct ifnet *ifp = cookie;
112 uint32 semFlags = B_CAN_INTERRUPT;
113 status_t status;
114 struct mbuf *mb;
115 size_t length;
117 //if_printf(ifp, "compat_read(%lld, %p, [%lu])\n", position,
118 // buffer, *numBytes);
120 if (ifp->flags & DEVICE_CLOSED)
121 return B_INTERRUPTED;
123 if (ifp->flags & DEVICE_NON_BLOCK)
124 semFlags |= B_RELATIVE_TIMEOUT;
126 do {
127 status = acquire_sem_etc(ifp->receive_sem, 1, semFlags, 0);
128 if (ifp->flags & DEVICE_CLOSED)
129 return B_INTERRUPTED;
131 if (status == B_WOULD_BLOCK) {
132 *numBytes = 0;
133 return B_OK;
134 } else if (status < B_OK)
135 return status;
137 IF_DEQUEUE(&ifp->receive_queue, mb);
138 } while (mb == NULL);
140 length = min_c(max_c((size_t)mb->m_pkthdr.len, 0), *numBytes);
142 #if 0
143 mb = m_defrag(mb, 0);
144 if (mb == NULL) {
145 *numBytes = 0;
146 return B_NO_MEMORY;
148 #endif
150 m_copydata(mb, 0, length, buffer);
151 *numBytes = length;
153 m_freem(mb);
154 return B_OK;
158 static status_t
159 compat_write(void *cookie, off_t position, const void *buffer,
160 size_t *numBytes)
162 struct ifnet *ifp = cookie;
163 struct mbuf *mb;
165 //if_printf(ifp, "compat_write(%lld, %p, [%lu])\n", position,
166 // buffer, *numBytes);
168 if (*numBytes > MHLEN)
169 mb = m_getcl(0, MT_DATA, M_PKTHDR);
170 else
171 mb = m_gethdr(0, MT_DATA);
173 if (mb == NULL)
174 return ENOBUFS;
176 // if we waited, check after if the ifp is still valid
178 mb->m_pkthdr.len = mb->m_len = min_c(*numBytes, (size_t)MCLBYTES);
179 memcpy(mtod(mb, void *), buffer, mb->m_len);
181 return ifp->if_output(ifp, mb, NULL, NULL);
185 static status_t
186 compat_control(void *cookie, uint32 op, void *arg, size_t length)
188 struct ifnet *ifp = cookie;
190 //if_printf(ifp, "compat_control(op %lu, %p, [%lu])\n", op,
191 // arg, length);
193 switch (op) {
194 case ETHER_INIT:
195 return B_OK;
197 case ETHER_GETADDR:
198 return user_memcpy(arg, IF_LLADDR(ifp), ETHER_ADDR_LEN);
200 case ETHER_NONBLOCK:
202 int32 value;
203 if (length < 4)
204 return B_BAD_VALUE;
205 if (user_memcpy(&value, arg, sizeof(int32)) < B_OK)
206 return B_BAD_ADDRESS;
207 if (value)
208 ifp->flags |= DEVICE_NON_BLOCK;
209 else
210 ifp->flags &= ~DEVICE_NON_BLOCK;
211 return B_OK;
214 case ETHER_SETPROMISC:
216 int32 value;
217 if (length < 4)
218 return B_BAD_VALUE;
219 if (user_memcpy(&value, arg, sizeof(int32)) < B_OK)
220 return B_BAD_ADDRESS;
221 if (value)
222 ifp->if_flags |= IFF_PROMISC;
223 else
224 ifp->if_flags &= ~IFF_PROMISC;
225 return ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
228 case ETHER_GETFRAMESIZE:
230 uint32 frameSize;
231 if (length < 4)
232 return B_BAD_VALUE;
234 frameSize = ifp->if_mtu + ETHER_HDR_LEN;
235 return user_memcpy(arg, &frameSize, 4);
238 case ETHER_ADDMULTI:
239 case ETHER_REMMULTI:
241 struct sockaddr_dl address;
243 if ((ifp->if_flags & IFF_MULTICAST) == 0)
244 return B_NOT_SUPPORTED;
246 memset(&address, 0, sizeof(address));
247 address.sdl_family = AF_LINK;
248 memcpy(LLADDR(&address), arg, ETHER_ADDR_LEN);
250 if (op == ETHER_ADDMULTI)
251 return if_addmulti(ifp, (struct sockaddr *)&address, NULL);
253 return if_delmulti(ifp, (struct sockaddr *)&address);
256 case ETHER_GET_LINK_STATE:
258 struct ifmediareq mediareq;
259 ether_link_state_t state;
260 status_t status;
262 if (length < sizeof(ether_link_state_t))
263 return EINVAL;
265 memset(&mediareq, 0, sizeof(mediareq));
266 status = ifp->if_ioctl(ifp, SIOCGIFMEDIA, (caddr_t)&mediareq);
267 if (status < B_OK)
268 return status;
270 state.media = mediareq.ifm_active;
271 if ((mediareq.ifm_status & IFM_ACTIVE) != 0)
272 state.media |= IFM_ACTIVE;
273 if ((mediareq.ifm_active & IFM_10_T) != 0)
274 state.speed = 10000000;
275 else if ((mediareq.ifm_active & IFM_100_TX) != 0)
276 state.speed = 100000000;
277 else
278 state.speed = 1000000000;
279 state.quality = 1000;
281 return user_memcpy(arg, &state, sizeof(ether_link_state_t));
284 case ETHER_SET_LINK_STATE_SEM:
285 if (user_memcpy(&ifp->link_state_sem, arg, sizeof(sem_id)) < B_OK) {
286 ifp->link_state_sem = -1;
287 return B_BAD_ADDRESS;
289 return B_OK;
292 return wlan_control(cookie, op, arg, length);
296 device_hooks gDeviceHooks = {
297 compat_open,
298 compat_close,
299 compat_free,
300 compat_control,
301 compat_read,
302 compat_write,