From b27873dc4ad63e9121bf32a2301389cf869e1f9b Mon Sep 17 00:00:00 2001 From: Hugo Santos Date: Mon, 7 May 2007 05:29:06 +0000 Subject: [PATCH] freebsd compat. layer: added ETHER_SETPROMISC, ETHER_GET_LINK_STATE and ETHER_SET_LINK_STATE_SEM support. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21050 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../freebsd_network/compat/net/if_media.h | 4 +- src/libs/compat/freebsd_network/device.c | 67 ++++++++++++++++--- src/libs/compat/freebsd_network/device.h | 2 + src/libs/compat/freebsd_network/if.c | 3 +- 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/libs/compat/freebsd_network/compat/net/if_media.h b/src/libs/compat/freebsd_network/compat/net/if_media.h index 61f1f14cd5..79ddd9a012 100644 --- a/src/libs/compat/freebsd_network/compat/net/if_media.h +++ b/src/libs/compat/freebsd_network/compat/net/if_media.h @@ -267,8 +267,8 @@ uint64_t ifmedia_baudrate(int); /* * Status bits */ -#define IFM_AVALID 0x00000001 /* Active bit valid */ -#define IFM_ACTIVE 0x00000002 /* Interface attached to working net */ +#define IFM_AVALID 0x10000000 /* Active bit valid */ +#define IFM_ACTIVE 0x00800000 /* same as Haiku's */ /* Mask of "status valid" bits, for ifconfig(8). */ #define IFM_STATUS_VALID IFM_AVALID diff --git a/src/libs/compat/freebsd_network/device.c b/src/libs/compat/freebsd_network/device.c index 1f2e0e4383..60a1eeefcd 100644 --- a/src/libs/compat/freebsd_network/device.c +++ b/src/libs/compat/freebsd_network/device.c @@ -61,6 +61,8 @@ allocate_device(driver_t *driver) return NULL; } + dev->link_state_sem = -1; + ifq_init(&dev->receive_queue, semName); return dev; @@ -241,29 +243,47 @@ static status_t compat_control(void *cookie, uint32 op, void *arg, size_t len) { device_t dev = cookie; + struct ifnet *ifp = dev->ifp; switch (op) { case ETHER_INIT: return B_OK; case ETHER_GETADDR: - memcpy(arg, IF_LLADDR(dev->ifp), ETHER_ADDR_LEN); - return B_OK; + return user_memcpy(arg, IF_LLADDR(dev->ifp), ETHER_ADDR_LEN); case ETHER_NONBLOCK: - if (*(int32 *)arg) + { + int32 value; + if (len < 4) + return B_BAD_VALUE; + if (user_memcpy(&value, arg, sizeof(int32)) < B_OK) + return B_BAD_ADDRESS; + if (value) dev->flags |= DEVICE_NON_BLOCK; else dev->flags &= ~DEVICE_NON_BLOCK; return B_OK; + } case ETHER_SETPROMISC: - /* TODO */ - return B_ERROR; + { + int32 value; + if (len < 4) + return B_BAD_VALUE; + if (user_memcpy(&value, arg, sizeof(int32)) < B_OK) + return B_BAD_ADDRESS; + if (value) + ifp->if_flags |= IFF_PROMISC; + else + ifp->if_flags &= ~IFF_PROMISC; + return ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL); + } case ETHER_GETFRAMESIZE: - *(uint32 *)arg = dev->ifp->if_mtu; - return B_OK; + if (len < 4) + return B_BAD_VALUE; + return user_memcpy(arg, &dev->ifp->if_mtu, 4); case ETHER_ADDMULTI: case ETHER_REMMULTI: @@ -271,11 +291,38 @@ compat_control(void *cookie, uint32 op, void *arg, size_t len) return B_ERROR; case ETHER_GET_LINK_STATE: - /* TODO */ - return B_ERROR; + { + struct ifmediareq mediareq; + ether_link_state_t state; + status_t status; + + if (len < sizeof(ether_link_state_t)) + return EINVAL; + + memset(&mediareq, 0, sizeof(mediareq)); + status = ifp->if_ioctl(ifp, SIOCGIFMEDIA, &mediareq); + if (status < B_OK) + return status; + + state.media = mediareq.ifm_active; + if (mediareq.ifm_status & IFM_ACTIVE) + state.media |= IFM_ACTIVE; + if (mediareq.ifm_active & IFM_10_T) + state.speed = 10000; + else if (mediareq.ifm_active & IFM_100_TX) + state.speed = 100000; + else + state.speed = 1000000; + state.quality = 1000; + + return user_memcpy(arg, &state, sizeof(ether_link_state_t)); + } case ETHER_SET_LINK_STATE_SEM: - /* TODO */ + if (user_memcpy(&dev->link_state_sem, arg, sizeof(sem_id)) < B_OK) { + dev->link_state_sem = -1; + return B_BAD_ADDRESS; + } return B_OK; } diff --git a/src/libs/compat/freebsd_network/device.h b/src/libs/compat/freebsd_network/device.h index ea56015089..928de881c7 100644 --- a/src/libs/compat/freebsd_network/device.h +++ b/src/libs/compat/freebsd_network/device.h @@ -32,6 +32,8 @@ struct device { struct ifqueue receive_queue; sem_id receive_sem; + sem_id link_state_sem; + struct ifnet * ifp; int unit; diff --git a/src/libs/compat/freebsd_network/if.c b/src/libs/compat/freebsd_network/if.c index f44daa0678..bcd3fe9812 100644 --- a/src/libs/compat/freebsd_network/if.c +++ b/src/libs/compat/freebsd_network/if.c @@ -143,8 +143,7 @@ if_link_state_change(struct ifnet *ifp, int link_state) ifp->if_link_state = link_state; - /* XXX */ - /* wake network stack's link state sem */ + release_sem_etc(ifp->if_dev->link_state_sem, 1, B_DO_NOT_RESCHEDULE); }