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.
12 #include <sys/sockio.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>
26 compat_open(const char *name
, uint32 flags
, void **cookie
)
33 for (i
= 0; i
< MAX_DEVICES
; i
++) {
34 if (gDevices
[i
] != NULL
&& !strcmp(gDevices
[i
]->device_name
, name
))
41 if (get_module(NET_STACK_MODULE_NAME
, (module_info
**)&gStack
) != B_OK
)
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
);
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
);
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
);
77 compat_close(void *cookie
)
79 struct ifnet
*ifp
= cookie
;
81 if_printf(ifp
, "compat_close()\n");
83 atomic_or(&ifp
->flags
, DEVICE_CLOSED
);
87 release_sem_etc(ifp
->receive_sem
, 1, B_RELEASE_ALL
);
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
);
109 compat_read(void *cookie
, off_t position
, void *buffer
, size_t *numBytes
)
111 struct ifnet
*ifp
= cookie
;
112 uint32 semFlags
= B_CAN_INTERRUPT
;
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
;
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
) {
134 } else if (status
< B_OK
)
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
);
143 mb
= m_defrag(mb
, 0);
150 m_copydata(mb
, 0, length
, buffer
);
159 compat_write(void *cookie
, off_t position
, const void *buffer
,
162 struct ifnet
*ifp
= cookie
;
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
);
171 mb
= m_gethdr(0, MT_DATA
);
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
);
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,
198 return user_memcpy(arg
, IF_LLADDR(ifp
), ETHER_ADDR_LEN
);
205 if (user_memcpy(&value
, arg
, sizeof(int32
)) < B_OK
)
206 return B_BAD_ADDRESS
;
208 ifp
->flags
|= DEVICE_NON_BLOCK
;
210 ifp
->flags
&= ~DEVICE_NON_BLOCK
;
214 case ETHER_SETPROMISC
:
219 if (user_memcpy(&value
, arg
, sizeof(int32
)) < B_OK
)
220 return B_BAD_ADDRESS
;
222 ifp
->if_flags
|= IFF_PROMISC
;
224 ifp
->if_flags
&= ~IFF_PROMISC
;
225 return ifp
->if_ioctl(ifp
, SIOCSIFFLAGS
, NULL
);
228 case ETHER_GETFRAMESIZE
:
234 frameSize
= ifp
->if_mtu
+ ETHER_HDR_LEN
;
235 return user_memcpy(arg
, &frameSize
, 4);
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
;
262 if (length
< sizeof(ether_link_state_t
))
265 memset(&mediareq
, 0, sizeof(mediareq
));
266 status
= ifp
->if_ioctl(ifp
, SIOCGIFMEDIA
, (caddr_t
)&mediareq
);
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;
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
;
292 return wlan_control(cookie
, op
, arg
, length
);
296 device_hooks gDeviceHooks
= {