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:
Hugo Santos
2007-05-09 05:37:46 +00:00
parent 0747d47e40
commit 07ef8870a3
3 changed files with 125 additions and 3 deletions
@@ -580,6 +580,9 @@ struct ifmultiaddr {
struct ifnet *ifma_ifp; /* back-pointer to interface */
u_int ifma_refcount; /* reference count */
void *ifma_protospec; /* protocol-specific state, if any */
/* haiku additions, save a allocation -hugo */
struct sockaddr_dl ifma_addr_storage;
};
#ifdef _KERNEL
+15 -3
View File
@@ -309,9 +309,21 @@ compat_control(void *cookie, uint32 op, void *arg, size_t len)
case ETHER_ADDMULTI:
case ETHER_REMMULTI:
/* TODO */
UNIMPLEMENTED();
return B_ERROR;
{
struct sockaddr_dl address;
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:
{
+107
View File
@@ -99,6 +99,8 @@ if_attach(struct ifnet *ifp)
TAILQ_INIT(&ifp->if_prefixhead);
TAILQ_INIT(&ifp->if_multiaddrs);
IF_ADDR_LOCK_INIT(ifp);
ifq_init((struct ifqueue *)&ifp->if_snd, ifp->if_xname);
}
@@ -106,6 +108,7 @@ if_attach(struct ifnet *ifp)
void
if_detach(struct ifnet *ifp)
{
IF_ADDR_LOCK_DESTROY(ifp);
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
ether_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
struct rtentry *rt0)