freebsd compat. layer: multicast support.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21081 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -580,6 +580,9 @@ struct ifmultiaddr {
|
|||||||
struct ifnet *ifma_ifp; /* back-pointer to interface */
|
struct ifnet *ifma_ifp; /* back-pointer to interface */
|
||||||
u_int ifma_refcount; /* reference count */
|
u_int ifma_refcount; /* reference count */
|
||||||
void *ifma_protospec; /* protocol-specific state, if any */
|
void *ifma_protospec; /* protocol-specific state, if any */
|
||||||
|
|
||||||
|
/* haiku additions, save a allocation -hugo */
|
||||||
|
struct sockaddr_dl ifma_addr_storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
|
|||||||
@@ -309,9 +309,21 @@ compat_control(void *cookie, uint32 op, void *arg, size_t len)
|
|||||||
|
|
||||||
case ETHER_ADDMULTI:
|
case ETHER_ADDMULTI:
|
||||||
case ETHER_REMMULTI:
|
case ETHER_REMMULTI:
|
||||||
/* TODO */
|
{
|
||||||
UNIMPLEMENTED();
|
struct sockaddr_dl address;
|
||||||
return B_ERROR;
|
|
||||||
|
if (!(ifp->if_flags & IFF_MULTICAST) == 0)
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
|
||||||
|
memset(&address, 0, sizeof(address));
|
||||||
|
address.sdl_family = AF_LINK;
|
||||||
|
memcpy(LLADDR(&address), arg, ETHER_ADDR_LEN);
|
||||||
|
|
||||||
|
if (op == ETHER_ADDMULTI)
|
||||||
|
return if_addmulti(ifp, (struct sockaddr *)&address, NULL);
|
||||||
|
else
|
||||||
|
return if_delmulti(ifp, (struct sockaddr *)&address);
|
||||||
|
}
|
||||||
|
|
||||||
case ETHER_GET_LINK_STATE:
|
case ETHER_GET_LINK_STATE:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -99,6 +99,8 @@ if_attach(struct ifnet *ifp)
|
|||||||
TAILQ_INIT(&ifp->if_prefixhead);
|
TAILQ_INIT(&ifp->if_prefixhead);
|
||||||
TAILQ_INIT(&ifp->if_multiaddrs);
|
TAILQ_INIT(&ifp->if_multiaddrs);
|
||||||
|
|
||||||
|
IF_ADDR_LOCK_INIT(ifp);
|
||||||
|
|
||||||
ifq_init((struct ifqueue *)&ifp->if_snd, ifp->if_xname);
|
ifq_init((struct ifqueue *)&ifp->if_snd, ifp->if_xname);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +108,7 @@ if_attach(struct ifnet *ifp)
|
|||||||
void
|
void
|
||||||
if_detach(struct ifnet *ifp)
|
if_detach(struct ifnet *ifp)
|
||||||
{
|
{
|
||||||
|
IF_ADDR_LOCK_DESTROY(ifp);
|
||||||
ifq_uninit((struct ifqueue *)&ifp->if_snd);
|
ifq_uninit((struct ifqueue *)&ifp->if_snd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +150,110 @@ if_link_state_change(struct ifnet *ifp, int link_state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct ifmultiaddr *
|
||||||
|
if_findmulti(struct ifnet *ifp, struct sockaddr *_address)
|
||||||
|
{
|
||||||
|
struct sockaddr_dl *address = (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct ifmultiaddr *
|
||||||
|
_if_addmulti(struct ifnet *ifp, struct sockaddr *address)
|
||||||
|
{
|
||||||
|
struct ifmultiaddr *addr = if_findmulti(ifp, address);
|
||||||
|
|
||||||
|
if (addr != NULL) {
|
||||||
|
addr->ifma_refcount++;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = (struct ifmultiaddr *)malloc(sizeof(struct ifmultiaddr));
|
||||||
|
if (addr == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
addr->ifma_lladdr = NULL;
|
||||||
|
addr->ifma_ifp = ifp;
|
||||||
|
addr->ifma_protospec = NULL;
|
||||||
|
|
||||||
|
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 addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
if_addmulti(struct ifnet *ifp, struct sockaddr *address,
|
||||||
|
struct ifmultiaddr **out)
|
||||||
|
{
|
||||||
|
struct ifmultiaddr *result;
|
||||||
|
int refcount = 0;
|
||||||
|
|
||||||
|
IF_ADDR_LOCK(ifp);
|
||||||
|
result = _if_addmulti(ifp, address);
|
||||||
|
if (result)
|
||||||
|
refcount = result->ifma_refcount;
|
||||||
|
IF_ADDR_UNLOCK(ifp);
|
||||||
|
|
||||||
|
if (result == NULL)
|
||||||
|
return ENOBUFS;
|
||||||
|
|
||||||
|
if (refcount == 1)
|
||||||
|
ifp->if_ioctl(ifp, SIOCADDMULTI, NULL);
|
||||||
|
|
||||||
|
if (out)
|
||||||
|
(*out) = result;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
if_delete_multiaddr(struct ifnet *ifp, struct ifmultiaddr *ifma)
|
||||||
|
{
|
||||||
|
TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
|
||||||
|
free(ifma);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
if_delmulti(struct ifnet *ifp, struct sockaddr *address)
|
||||||
|
{
|
||||||
|
struct ifmultiaddr *addr;
|
||||||
|
int deleted = 0;
|
||||||
|
|
||||||
|
IF_ADDR_LOCK(ifp);
|
||||||
|
addr = if_findmulti(ifp, address);
|
||||||
|
if (addr != NULL) {
|
||||||
|
addr->ifma_refcount--;
|
||||||
|
if (addr->ifma_refcount == 0) {
|
||||||
|
if_delete_multiaddr(ifp, addr);
|
||||||
|
deleted = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IF_ADDR_UNLOCK(ifp);
|
||||||
|
|
||||||
|
if (deleted)
|
||||||
|
ifp->if_ioctl(ifp, SIOCDELMULTI, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
ether_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
|
ether_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
|
||||||
struct rtentry *rt0)
|
struct rtentry *rt0)
|
||||||
|
|||||||
Reference in New Issue
Block a user