static int
ether_inet6_resolve_multi(ifnet_t ifp, const struct sockaddr *proto_addr,
    struct sockaddr_dl *out_ll, size_t ll_len)
{
	static const size_t minsize =
	    offsetof(struct sockaddr_dl, sdl_data[0]) + ETHER_ADDR_LEN;
	const struct sockaddr_in6 *sin6 =
	    (const struct sockaddr_in6 *)(uintptr_t)(size_t)proto_addr;

	if (proto_addr->sa_family != AF_INET6)
		return (EAFNOSUPPORT);

	if (proto_addr->sa_len < sizeof (struct sockaddr_in6))
		return (EINVAL);

	if (ll_len < minsize)
		return (EMSGSIZE);

	bzero(out_ll, minsize);
	out_ll->sdl_len = minsize;
	out_ll->sdl_family = AF_LINK;
	out_ll->sdl_index = ifp->if_index;
	out_ll->sdl_type = IFT_ETHER;
	out_ll->sdl_nlen = 0;
	out_ll->sdl_alen = ETHER_ADDR_LEN;
	out_ll->sdl_slen = 0;
	ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, LLADDR(out_ll));

	return (0);
}
示例#2
0
static int
ether_resolve_addr(struct ifnet *ifp, struct mbuf *m,
	const struct sockaddr *dst, struct route *ro, u_char *phdr,
	uint32_t *pflags, struct llentry **plle)
{
	struct ether_header *eh;
	uint32_t lleflags = 0;
	int error = 0;
#if defined(INET) || defined(INET6)
	uint16_t etype;
#endif

	if (plle)
		*plle = NULL;
	eh = (struct ether_header *)phdr;

	switch (dst->sa_family) {
#ifdef INET
	case AF_INET:
		if ((m->m_flags & (M_BCAST | M_MCAST)) == 0)
			error = arpresolve(ifp, 0, m, dst, phdr, &lleflags,
			    plle);
		else {
			if (m->m_flags & M_BCAST)
				memcpy(eh->ether_dhost, ifp->if_broadcastaddr,
				    ETHER_ADDR_LEN);
			else {
				const struct in_addr *a;
				a = &(((const struct sockaddr_in *)dst)->sin_addr);
				ETHER_MAP_IP_MULTICAST(a, eh->ether_dhost);
			}
			etype = htons(ETHERTYPE_IP);
			memcpy(&eh->ether_type, &etype, sizeof(etype));
			memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
		}
		break;
#endif
#ifdef INET6
	case AF_INET6:
		if ((m->m_flags & M_MCAST) == 0)
			error = nd6_resolve(ifp, 0, m, dst, phdr, &lleflags,
			    plle);
		else {
			const struct in6_addr *a6;
			a6 = &(((const struct sockaddr_in6 *)dst)->sin6_addr);
			ETHER_MAP_IPV6_MULTICAST(a6, eh->ether_dhost);
			etype = htons(ETHERTYPE_IPV6);
			memcpy(&eh->ether_type, &etype, sizeof(etype));
			memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
		}
		break;
#endif
	default:
		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
		if (m != NULL)
			m_freem(m);
		return (EAFNOSUPPORT);
	}

	if (error == EHOSTDOWN) {
		if (ro != NULL && (ro->ro_flags & RT_HAS_GW) != 0)
			error = EHOSTUNREACH;
	}

	if (error != 0)
		return (error);

	*pflags = RT_MAY_LOOP;
	if (lleflags & LLE_IFADDR)
		*pflags |= RT_L2_ME;

	return (0);
}