From 09b89797afe0af65822df50011079e16ca8b99b4 Mon Sep 17 00:00:00 2001 From: Hugo Santos Date: Wed, 2 May 2007 00:10:00 +0000 Subject: [PATCH] added ADDMULTI/REMMULTI support to ipro1000. Also cleaned up the compat. layer a bit to reuse some of the system's definitions. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20960 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/posix/net/if.h | 1 + .../kernel/drivers/network/ipro1000/device.c | 33 ++++++-- .../drivers/network/ipro1000/if_compat.c | 78 +++++++++++++++++++ .../drivers/network/ipro1000/if_compat.h | 54 ++++--------- .../kernel/drivers/network/ipro1000/if_em.c | 2 +- .../drivers/network/ipro1000/if_em_osdep.h | 62 +++++++++------ 6 files changed, 162 insertions(+), 68 deletions(-) diff --git a/headers/posix/net/if.h b/headers/posix/net/if.h index 797b8426ce..73215b958a 100644 --- a/headers/posix/net/if.h +++ b/headers/posix/net/if.h @@ -52,6 +52,7 @@ struct ifreq { int ifr_mtu; int ifr_media; int ifr_type; + int ifr_reqcap; }; }; diff --git a/src/add-ons/kernel/drivers/network/ipro1000/device.c b/src/add-ons/kernel/drivers/network/ipro1000/device.c index 1f8ad3d7f6..be04431787 100644 --- a/src/add-ons/kernel/drivers/network/ipro1000/device.c +++ b/src/add-ons/kernel/drivers/network/ipro1000/device.c @@ -296,6 +296,13 @@ ipro1000_write(void* cookie, off_t position, const void* buffer, size_t* num_byt } +static struct ifnet * +device_ifp(ipro1000_device *device) +{ + return &device->adapter->interface_data.ac_if; +} + + status_t ipro1000_control(void *cookie, uint32 op, void *arg, size_t len) { @@ -322,13 +329,24 @@ ipro1000_control(void *cookie, uint32 op, void *arg, size_t len) return B_OK; case ETHER_ADDMULTI: - DEVICE_DEBUGOUT("ipro1000_control() ETHER_ADDMULTI not supported"); - break; - case ETHER_REMMULTI: - DEVICE_DEBUGOUT("ipro1000_control() ETHER_REMMULTI not supported"); - return B_OK; - + { + struct ifnet *ifp = device_ifp(device); + struct sockaddr_dl address; + + if (len != ETHER_ADDR_LEN) + return EINVAL; + + memset(&address, 0, sizeof(address)); + address.sdl_family = AF_LINK; + memcpy(LLADDR(&address), arg, ETHER_ADDR_LEN); + + if (op == ETHER_ADDMULTI) + return ether_add_multi(ifp, (struct sockaddr *)&address); + else + return ether_rem_multi(ifp, (struct sockaddr *)&address); + } + case ETHER_SETPROMISC: if (*(int32 *)arg) { DEVICE_DEBUGOUT("promiscuous mode on not supported"); @@ -345,14 +363,13 @@ ipro1000_control(void *cookie, uint32 op, void *arg, size_t len) #ifdef HAIKU_TARGET_PLATFORM_HAIKU case ETHER_GET_LINK_STATE: { - struct ifnet ifp = { .if_softc = device->adapter }; struct ifmediareq mediareq; ether_link_state_t state; if (len < sizeof(ether_link_state_t)) return ENOBUFS; - em_media_status(&ifp, &mediareq); + em_media_status(device_ifp(device), &mediareq); state.media = mediareq.ifm_active; if (mediareq.ifm_status & IFM_ACTIVE) diff --git a/src/add-ons/kernel/drivers/network/ipro1000/if_compat.c b/src/add-ons/kernel/drivers/network/ipro1000/if_compat.c index 4db9272393..eade03d592 100644 --- a/src/add-ons/kernel/drivers/network/ipro1000/if_compat.c +++ b/src/add-ons/kernel/drivers/network/ipro1000/if_compat.c @@ -22,6 +22,9 @@ #include "debug.h" #include "mempool.h" +#undef malloc +#undef free + spinlock mbuf_lock = 0; struct mbuf * @@ -96,6 +99,8 @@ ether_ifattach(struct ifnet *ifp, const uint8 *etheraddr) INIT_DEBUGOUT("ether_ifattach"); + TAILQ_INIT(&ifp->if_multiaddrs); + memcpy(dev->macaddr, etheraddr, 6); ifp->if_input = ether_input; @@ -108,12 +113,85 @@ ether_ifattach(struct ifnet *ifp, const uint8 *etheraddr) INIT_DEBUGOUT("done calling if_init!"); } + +static struct ifmultiaddr * +ether_find_multi(struct ifnet *ifp, const struct sockaddr *_address) +{ + const struct sockaddr_dl *address = (const struct sockaddr_dl *)_address; + struct ifmultiaddr *ifma; + + TAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) { + if (memcmp(LLADDR(address), + LLADDR((struct sockaddr_dl *)ifma->ifma_addr), + ETHER_ADDR_LEN) == 0) + return ifma; + } + + return NULL; +} + + +int +ether_add_multi(struct ifnet *ifp, const struct sockaddr *address) +{ + struct ifmultiaddr *addr = ether_find_multi(ifp, address); + + if (addr != NULL) { + addr->ifma_refcount++; + return 0; + } + + addr = (struct ifmultiaddr *)malloc(sizeof(struct ifmultiaddr)); + if (addr == NULL) + return ENOBUFS; + + memcpy(&addr->ifma_addr_storage, address, sizeof(struct sockaddr_dl)); + addr->ifma_addr = (struct sockaddr *)&addr->ifma_addr_storage; + + addr->ifma_refcount = 1; + + TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, addr, ifma_link); + + return ifp->if_ioctl(ifp, SIOCADDMULTI, NULL); +} + + +static void +ether_delete_multi(struct ifnet *ifp, struct ifmultiaddr *ifma) +{ + TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); + free(ifma); +} + + +int +ether_rem_multi(struct ifnet *ifp, const struct sockaddr *address) +{ + struct ifmultiaddr *addr = ether_find_multi(ifp, address); + if (addr == NULL) + return EADDRNOTAVAIL; + + addr->ifma_refcount--; + if (addr->ifma_refcount == 0) { + ether_delete_multi(ifp, addr); + return ifp->if_ioctl(ifp, SIOCDELMULTI, NULL); + } + + return 0; +} + + void ether_ifdetach(struct ifnet *ifp) { + struct ifmultiaddr *ifma, *next; + INIT_DEBUGOUT("ether_ifdetach"); delete_sem(ifp->if_rcv_sem); + + TAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) + ether_delete_multi(ifp, ifma); } struct mbuf * diff --git a/src/add-ons/kernel/drivers/network/ipro1000/if_compat.h b/src/add-ons/kernel/drivers/network/ipro1000/if_compat.h index 25a142cbbb..f4cd7a0f9f 100644 --- a/src/add-ons/kernel/drivers/network/ipro1000/if_compat.h +++ b/src/add-ons/kernel/drivers/network/ipro1000/if_compat.h @@ -20,18 +20,16 @@ #define __IF_COMPAT_H #include +#include +#include #include +#include "if_em_osdep.h" // for TAILQ_... + #define __FreeBSD_version 500001 -#define IFF_BROADCAST 0x0001 -#define IFF_SIMPLEX 0x0002 -#define IFF_MULTICAST 0x0004 -#define IFF_RUNNING 0x0008 -#define IFF_OACTIVE 0x0010 -#define IFF_UP 0x0020 -#define IFF_PROMISC 0x0040 -#define IFF_ALLMULTI 0x0080 +#define IFF_RUNNING 0x10000 +#define IFF_OACTIVE 0x20000 #define IFCAP_HWCSUM 0x0001 #define IFCAP_VLAN_HWTAGGING 0x0002 @@ -203,15 +201,19 @@ void m_freem(struct mbuf *mp); void ether_ifattach(struct ifnet *ifp, const uint8 *etheraddr); void ether_ifdetach(struct ifnet *ifp); -#define AF_LINK 0 -struct ifma_addr -{ - int sa_family; // must be AF_LINK -}; +int ether_add_multi(struct ifnet *ifp, const struct sockaddr *address); +int ether_rem_multi(struct ifnet *ifp, const struct sockaddr *address); + +TAILQ_HEAD(ifmultihead, ifmultiaddr); struct ifmultiaddr { - struct ifma_addr *ifma_addr; + TAILQ_ENTRY(ifmultiaddr) ifma_link; + struct sockaddr *ifma_addr; + int ifma_refcount; + + /* private */ + struct sockaddr_dl ifma_addr_storage; }; struct if_data @@ -257,8 +259,8 @@ struct ifnet sem_id if_rcv_sem; -// struct if_multiaddrs if_multiaddrs; // multicast addr list struct if_data if_data; + struct ifmultihead if_multiaddrs; if_start if_start; if_ioctl if_ioctl; @@ -295,34 +297,12 @@ enum { // ioctl commands SIOCSIFCAP, }; -struct ifreq // ioctl command data -{ - uint32 ifr_reqcap; - int ifr_mtu; -}; - // used for media properties #define ifmedia_init(a, b, c, d) #define ifmedia_add(a, b, c, d) #define ifmedia_set(a, b) #define ifmedia_ioctl(ifp, ifr, media, command) 0 -// used inside multicast stuff -struct sockaddr_dl -{ - u_char sdl_len; - u_char sdl_family; - u_short sdl_index; - u_char sdl_type; - u_char sdl_nlen; - u_char sdl_alen; - u_char sdl_slen; - char sdl_data[46]; -}; - -// used inside multicast stuff -#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen)) - // called for SIOCxIFADDR (Get/Set Interface Addr) #define ether_ioctl(ifp, command, data) diff --git a/src/add-ons/kernel/drivers/network/ipro1000/if_em.c b/src/add-ons/kernel/drivers/network/ipro1000/if_em.c index 66a34ce4a0..bd6f1aae62 100644 --- a/src/add-ons/kernel/drivers/network/ipro1000/if_em.c +++ b/src/add-ons/kernel/drivers/network/ipro1000/if_em.c @@ -1293,7 +1293,7 @@ em_set_multi(struct adapter * adapter) u_int8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS]; struct ifmultiaddr *ifma; int mcnt = 0; -// struct ifnet *ifp = &adapter->interface_data.ac_if; + struct ifnet *ifp = &adapter->interface_data.ac_if; IOCTL_DEBUGOUT("em_set_multi: begin"); diff --git a/src/add-ons/kernel/drivers/network/ipro1000/if_em_osdep.h b/src/add-ons/kernel/drivers/network/ipro1000/if_em_osdep.h index 5a0e87ac00..36d3db3bc5 100644 --- a/src/add-ons/kernel/drivers/network/ipro1000/if_em_osdep.h +++ b/src/add-ons/kernel/drivers/network/ipro1000/if_em_osdep.h @@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #define usec_delay(x) snooze(x) @@ -71,18 +72,6 @@ POSSIBILITY OF SUCH DAMAGE. #define hz 1000000LL -typedef uint64 u_int64_t; -typedef uint32 u_int32_t; -typedef uint16 u_int16_t; -typedef uint8 u_int8_t; -typedef uint64 uint64_t; -typedef uint32 uint32_t; -typedef uint16 uint16_t; -typedef uint8 uint8_t; -typedef int64 int64_t; -typedef int32 int32_t; -typedef int16 int16_t; -typedef int8 int8_t; typedef bool boolean_t; typedef unsigned long vm_offset_t; @@ -210,16 +199,45 @@ void driver_free(void *p, int p2); #define E1000_WRITE_REG_ARRAY(hw, reg, index, value) \ E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2), value) +#define TAILQ_HEAD(name, type) \ + struct name { struct type *tqh_first, **tqh_last; } -/* -#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = TAILQ_FIRST((head)); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) -*/ -// used only for multicast setup, fix later... -#define TAILQ_FOREACH(a, b, c) for (a = 0; a != 0; a = 0) +#define TAILQ_ENTRY(type) \ + struct { struct type *tqe_next, **tqe_prev; } + +#define TAILQ_FIRST(head) \ + ((head)->tqh_first) + +#define TAILQ_NEXT(elm, field) \ + ((elm)->field.tqe_next) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); (var); (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ +} while (0) #endif