Simplify filling sockaddr_dl structure for if_resolvemulti()
callback providers. link_init_sdl() function can be used to fill most of the parameters. Use caller stack instead of allocation / freing memory for each request. Do not drop support for extra-long (probably non-existing) link-layer protocols by introducing link_alloc_sdl() (used by if_resolvemulti() callback) and link_free_sdl() (used by caller). Since this change breaks KBI, MFC requires slightly different approach (link_init_sdl() auto-allocating buffer if necessary to handle cases with unmodified if_resolvemulti() callers). MFC after: 2 weeks
This commit is contained in:
@@ -522,11 +522,7 @@ lacp_port_create(struct lagg_port *lgp)
|
||||
boolean_t active = TRUE; /* XXX should be configurable */
|
||||
boolean_t fast = FALSE; /* XXX should be configurable */
|
||||
|
||||
bzero((char *)&sdl, sizeof(sdl));
|
||||
sdl.sdl_len = sizeof(sdl);
|
||||
sdl.sdl_family = AF_LINK;
|
||||
sdl.sdl_index = ifp->if_index;
|
||||
sdl.sdl_type = IFT_ETHER;
|
||||
link_init_sdl(ifp, (struct sockaddr *)&sdl, IFT_ETHER);
|
||||
sdl.sdl_alen = ETHER_ADDR_LEN;
|
||||
|
||||
bcopy(ðermulticastaddr_slowprotocols,
|
||||
|
||||
+45
-6
@@ -1888,6 +1888,38 @@ link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_dl *
|
||||
link_alloc_sdl(size_t size, int flags)
|
||||
{
|
||||
|
||||
return (malloc(size, M_TEMP, flags));
|
||||
}
|
||||
|
||||
void
|
||||
link_free_sdl(struct sockaddr *sa)
|
||||
{
|
||||
free(sa, M_TEMP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills in given sdl with interface basic info.
|
||||
* Returns pointer to filled sdl.
|
||||
*/
|
||||
struct sockaddr_dl *
|
||||
link_init_sdl(struct ifnet *ifp, struct sockaddr *paddr, u_char iftype)
|
||||
{
|
||||
struct sockaddr_dl *sdl;
|
||||
|
||||
sdl = (struct sockaddr_dl *)paddr;
|
||||
memset(sdl, 0, sizeof(struct sockaddr_dl));
|
||||
sdl->sdl_len = sizeof(struct sockaddr_dl);
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_index = ifp->if_index;
|
||||
sdl->sdl_type = iftype;
|
||||
|
||||
return (sdl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark an interface down and notify protocols of
|
||||
* the transition.
|
||||
@@ -2938,6 +2970,7 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
|
||||
{
|
||||
struct ifmultiaddr *ifma, *ll_ifma;
|
||||
struct sockaddr *llsa;
|
||||
struct sockaddr_dl sdl;
|
||||
int error;
|
||||
|
||||
/*
|
||||
@@ -2957,12 +2990,18 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
|
||||
/*
|
||||
* The address isn't already present; resolve the protocol address
|
||||
* into a link layer address, and then look that up, bump its
|
||||
* refcount or allocate an ifma for that also. If 'llsa' was
|
||||
* returned, we will need to free it later.
|
||||
* refcount or allocate an ifma for that also.
|
||||
* Most link layer resolving functions returns address data which
|
||||
* fits inside default sockaddr_dl structure. However callback
|
||||
* can allocate another sockaddr structure, in that case we need to
|
||||
* free it later.
|
||||
*/
|
||||
llsa = NULL;
|
||||
ll_ifma = NULL;
|
||||
if (ifp->if_resolvemulti != NULL) {
|
||||
/* Provide called function with buffer size information */
|
||||
sdl.sdl_len = sizeof(sdl);
|
||||
llsa = (struct sockaddr *)&sdl;
|
||||
error = ifp->if_resolvemulti(ifp, &llsa, sa);
|
||||
if (error)
|
||||
goto unlock_out;
|
||||
@@ -3026,14 +3065,14 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
|
||||
(void) (*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0);
|
||||
}
|
||||
|
||||
if (llsa != NULL)
|
||||
free(llsa, M_IFMADDR);
|
||||
if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl))
|
||||
link_free_sdl(llsa);
|
||||
|
||||
return (0);
|
||||
|
||||
free_llsa_out:
|
||||
if (llsa != NULL)
|
||||
free(llsa, M_IFMADDR);
|
||||
if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl))
|
||||
link_free_sdl(llsa);
|
||||
|
||||
unlock_out:
|
||||
IF_ADDR_WUNLOCK(ifp);
|
||||
|
||||
+2
-16
@@ -786,14 +786,7 @@ arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
|
||||
sin = (struct sockaddr_in *)sa;
|
||||
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
|
||||
return EADDRNOTAVAIL;
|
||||
sdl = malloc(sizeof *sdl, M_IFMADDR,
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (sdl == NULL)
|
||||
return ENOMEM;
|
||||
sdl->sdl_len = sizeof *sdl;
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_index = ifp->if_index;
|
||||
sdl->sdl_type = IFT_ARCNET;
|
||||
sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
|
||||
sdl->sdl_alen = ARC_ADDR_LEN;
|
||||
*LLADDR(sdl) = 0;
|
||||
*llsa = (struct sockaddr *)sdl;
|
||||
@@ -814,14 +807,7 @@ arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
|
||||
}
|
||||
if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
|
||||
return EADDRNOTAVAIL;
|
||||
sdl = malloc(sizeof *sdl, M_IFMADDR,
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (sdl == NULL)
|
||||
return ENOMEM;
|
||||
sdl->sdl_len = sizeof *sdl;
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_index = ifp->if_index;
|
||||
sdl->sdl_type = IFT_ARCNET;
|
||||
sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
|
||||
sdl->sdl_alen = ARC_ADDR_LEN;
|
||||
*LLADDR(sdl) = 0;
|
||||
*llsa = (struct sockaddr *)sdl;
|
||||
|
||||
@@ -69,6 +69,12 @@ struct sockaddr_dl {
|
||||
#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))
|
||||
#define LLINDEX(s) ((s)->sdl_index)
|
||||
|
||||
|
||||
struct ifnet;
|
||||
struct sockaddr_dl *link_alloc_sdl(size_t, int);
|
||||
void link_free_sdl(struct sockaddr *sa);
|
||||
struct sockaddr_dl *link_init_sdl(struct ifnet *, struct sockaddr *, u_char);
|
||||
|
||||
#ifndef _KERNEL
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
+2
-16
@@ -1168,14 +1168,7 @@ ether_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
|
||||
sin = (struct sockaddr_in *)sa;
|
||||
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
|
||||
return EADDRNOTAVAIL;
|
||||
sdl = malloc(sizeof *sdl, M_IFMADDR,
|
||||
M_NOWAIT|M_ZERO);
|
||||
if (sdl == NULL)
|
||||
return ENOMEM;
|
||||
sdl->sdl_len = sizeof *sdl;
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_index = ifp->if_index;
|
||||
sdl->sdl_type = IFT_ETHER;
|
||||
sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
|
||||
sdl->sdl_alen = ETHER_ADDR_LEN;
|
||||
e_addr = LLADDR(sdl);
|
||||
ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
|
||||
@@ -1197,14 +1190,7 @@ ether_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
|
||||
}
|
||||
if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
|
||||
return EADDRNOTAVAIL;
|
||||
sdl = malloc(sizeof *sdl, M_IFMADDR,
|
||||
M_NOWAIT|M_ZERO);
|
||||
if (sdl == NULL)
|
||||
return (ENOMEM);
|
||||
sdl->sdl_len = sizeof *sdl;
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_index = ifp->if_index;
|
||||
sdl->sdl_type = IFT_ETHER;
|
||||
sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
|
||||
sdl->sdl_alen = ETHER_ADDR_LEN;
|
||||
e_addr = LLADDR(sdl);
|
||||
ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
|
||||
|
||||
+2
-16
@@ -729,14 +729,7 @@ fddi_resolvemulti(ifp, llsa, sa)
|
||||
sin = (struct sockaddr_in *)sa;
|
||||
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
|
||||
return (EADDRNOTAVAIL);
|
||||
sdl = malloc(sizeof *sdl, M_IFMADDR,
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (sdl == NULL)
|
||||
return (ENOMEM);
|
||||
sdl->sdl_len = sizeof *sdl;
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_index = ifp->if_index;
|
||||
sdl->sdl_type = IFT_FDDI;
|
||||
sdl = link_init_sdl(ifp, *llsa, IFT_FDDI);
|
||||
sdl->sdl_nlen = 0;
|
||||
sdl->sdl_alen = FDDI_ADDR_LEN;
|
||||
sdl->sdl_slen = 0;
|
||||
@@ -760,14 +753,7 @@ fddi_resolvemulti(ifp, llsa, sa)
|
||||
}
|
||||
if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
|
||||
return (EADDRNOTAVAIL);
|
||||
sdl = malloc(sizeof *sdl, M_IFMADDR,
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (sdl == NULL)
|
||||
return (ENOMEM);
|
||||
sdl->sdl_len = sizeof *sdl;
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_index = ifp->if_index;
|
||||
sdl->sdl_type = IFT_FDDI;
|
||||
sdl = link_init_sdl(ifp, *llsa, IFT_FDDI);
|
||||
sdl->sdl_nlen = 0;
|
||||
sdl->sdl_alen = FDDI_ADDR_LEN;
|
||||
sdl->sdl_slen = 0;
|
||||
|
||||
@@ -721,14 +721,7 @@ iso88025_resolvemulti (ifp, llsa, sa)
|
||||
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
|
||||
return (EADDRNOTAVAIL);
|
||||
}
|
||||
sdl = malloc(sizeof *sdl, M_IFMADDR,
|
||||
M_NOWAIT|M_ZERO);
|
||||
if (sdl == NULL)
|
||||
return (ENOMEM);
|
||||
sdl->sdl_len = sizeof *sdl;
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_index = ifp->if_index;
|
||||
sdl->sdl_type = IFT_ISO88025;
|
||||
sdl = link_init_sdl(ifp, *llsa, IFT_ISO88025);
|
||||
sdl->sdl_alen = ISO88025_ADDR_LEN;
|
||||
e_addr = LLADDR(sdl);
|
||||
ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
|
||||
@@ -751,14 +744,7 @@ iso88025_resolvemulti (ifp, llsa, sa)
|
||||
if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
|
||||
return (EADDRNOTAVAIL);
|
||||
}
|
||||
sdl = malloc(sizeof *sdl, M_IFMADDR,
|
||||
M_NOWAIT|M_ZERO);
|
||||
if (sdl == NULL)
|
||||
return (ENOMEM);
|
||||
sdl->sdl_len = sizeof *sdl;
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_index = ifp->if_index;
|
||||
sdl->sdl_type = IFT_ISO88025;
|
||||
sdl = link_init_sdl(ifp, *llsa, IFT_ISO88025);
|
||||
sdl->sdl_alen = ISO88025_ADDR_LEN;
|
||||
e_addr = LLADDR(sdl);
|
||||
ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
|
||||
|
||||
+1
-5
@@ -1214,12 +1214,8 @@ lagg_ether_cmdmulti(struct lagg_port *lp, int set)
|
||||
|
||||
LAGG_WLOCK_ASSERT(sc);
|
||||
|
||||
bzero((char *)&sdl, sizeof(sdl));
|
||||
sdl.sdl_len = sizeof(sdl);
|
||||
sdl.sdl_family = AF_LINK;
|
||||
sdl.sdl_type = IFT_ETHER;
|
||||
link_init_sdl(ifp, (struct sockaddr *)&sdl, IFT_ETHER);
|
||||
sdl.sdl_alen = ETHER_ADDR_LEN;
|
||||
sdl.sdl_index = ifp->if_index;
|
||||
|
||||
if (set) {
|
||||
TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) {
|
||||
|
||||
@@ -1490,14 +1490,7 @@ ipoib_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
|
||||
sin = (struct sockaddr_in *)sa;
|
||||
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
|
||||
return EADDRNOTAVAIL;
|
||||
sdl = malloc(sizeof *sdl, M_IFMADDR,
|
||||
M_NOWAIT|M_ZERO);
|
||||
if (sdl == NULL)
|
||||
return ENOMEM;
|
||||
sdl->sdl_len = sizeof *sdl;
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_index = ifp->if_index;
|
||||
sdl->sdl_type = IFT_INFINIBAND;
|
||||
sdl = link_init_sdl(ifp, *llsa, IFT_INFINIBAND);
|
||||
sdl->sdl_alen = INFINIBAND_ALEN;
|
||||
e_addr = LLADDR(sdl);
|
||||
ip_ib_mc_map(sin->sin_addr.s_addr, ifp->if_broadcastaddr,
|
||||
@@ -1517,14 +1510,7 @@ ipoib_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
|
||||
return EADDRNOTAVAIL;
|
||||
if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
|
||||
return EADDRNOTAVAIL;
|
||||
sdl = malloc(sizeof *sdl, M_IFMADDR,
|
||||
M_NOWAIT|M_ZERO);
|
||||
if (sdl == NULL)
|
||||
return (ENOMEM);
|
||||
sdl->sdl_len = sizeof *sdl;
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_index = ifp->if_index;
|
||||
sdl->sdl_type = IFT_INFINIBAND;
|
||||
sdl = link_init_sdl(ifp, *llsa, IFT_INFINIBAND);
|
||||
sdl->sdl_alen = INFINIBAND_ALEN;
|
||||
e_addr = LLADDR(sdl);
|
||||
ipv6_ib_mc_map(&sin6->sin6_addr, ifp->if_broadcastaddr, e_addr);
|
||||
|
||||
Reference in New Issue
Block a user