in6_len2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
in6_lifaddr_ioctl(so, cmd, data, ifp, p)	struct socket *so;	u_long cmd;	caddr_t	data;	struct ifnet *ifp;	struct proc *p;{	struct if_laddrreq *iflr = (struct if_laddrreq *)data;	struct ifaddr *ifa;	struct sockaddr *sa;	/* sanity checks */	if (!data || !ifp) {		panic("invalid argument to in6_lifaddr_ioctl");		/* NOTREACHED */	}	switch (cmd) {	case SIOCGLIFADDR:		/* address must be specified on GET with IFLR_PREFIX */		if ((iflr->flags & IFLR_PREFIX) == 0)			break;		/* FALLTHROUGH */	case SIOCALIFADDR:	case SIOCDLIFADDR:		/* address must be specified on ADD and DELETE */		sa = (struct sockaddr *)&iflr->addr;		if (sa->sa_family != AF_INET6)			return EINVAL;		if (sa->sa_len != sizeof(struct sockaddr_in6))			return EINVAL;		/* XXX need improvement */		sa = (struct sockaddr *)&iflr->dstaddr;		if (sa->sa_family && sa->sa_family != AF_INET6)			return EINVAL;		if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6))			return EINVAL;		break;	default: /* shouldn't happen */#if 0		panic("invalid cmd to in6_lifaddr_ioctl");		/* NOTREACHED */#else		return EOPNOTSUPP;#endif	}	if (sizeof(struct in6_addr) * 8 < iflr->prefixlen)		return EINVAL;	switch (cmd) {	case SIOCALIFADDR:	    {		struct in6_aliasreq ifra;		struct in6_addr *hostid = NULL;		int prefixlen;		if ((iflr->flags & IFLR_PREFIX) != 0) {			struct sockaddr_in6 *sin6;			/*			 * hostid is to fill in the hostid part of the			 * address.  hostid points to the first link-local			 * address attached to the interface.			 */			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);			if (!ifa)				return EADDRNOTAVAIL;			hostid = IFA_IN6(ifa);		 	/* prefixlen must be <= 64. */			if (64 < iflr->prefixlen)				return EINVAL;			prefixlen = iflr->prefixlen;			/* hostid part must be zero. */			sin6 = (struct sockaddr_in6 *)&iflr->addr;			if (sin6->sin6_addr.s6_addr32[2] != 0			 || sin6->sin6_addr.s6_addr32[3] != 0) {				return EINVAL;			}		} else			prefixlen = iflr->prefixlen;		/* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */		bzero(&ifra, sizeof(ifra));		bcopy(iflr->iflr_name, ifra.ifra_name,			sizeof(ifra.ifra_name));		bcopy(&iflr->addr, &ifra.ifra_addr,			((struct sockaddr *)&iflr->addr)->sa_len);		if (hostid) {			/* fill in hostid part */			ifra.ifra_addr.sin6_addr.s6_addr32[2] =				hostid->s6_addr32[2];			ifra.ifra_addr.sin6_addr.s6_addr32[3] =				hostid->s6_addr32[3];		}		if (((struct sockaddr *)&iflr->dstaddr)->sa_family) {	/*XXX*/			bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,				((struct sockaddr *)&iflr->dstaddr)->sa_len);			if (hostid) {				ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] =					hostid->s6_addr32[2];				ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] =					hostid->s6_addr32[3];			}		}		ifra.ifra_prefixmask.sin6_family = AF_INET6;		ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);		in6_len2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);		ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX;		return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra,				   ifp, p);	    }	case SIOCGLIFADDR:	case SIOCDLIFADDR:	    {		struct in6_ifaddr *ia;		struct in6_addr mask, candidate, match;		struct sockaddr_in6 *sin6;		int cmp;		bzero(&mask, sizeof(mask));		if (iflr->flags & IFLR_PREFIX) {			/* lookup a prefix rather than address. */			in6_len2mask(&mask, iflr->prefixlen);			sin6 = (struct sockaddr_in6 *)&iflr->addr;			bcopy(&sin6->sin6_addr, &match, sizeof(match));			match.s6_addr32[0] &= mask.s6_addr32[0];			match.s6_addr32[1] &= mask.s6_addr32[1];			match.s6_addr32[2] &= mask.s6_addr32[2];			match.s6_addr32[3] &= mask.s6_addr32[3];			/* if you set extra bits, that's wrong */			if (bcmp(&match, &sin6->sin6_addr, sizeof(match)))				return EINVAL;			cmp = 1;		} else {			if (cmd == SIOCGLIFADDR) {				/* on getting an address, take the 1st match */				cmp = 0;	/*XXX*/			} else {				/* on deleting an address, do exact match */				in6_len2mask(&mask, 128);				sin6 = (struct sockaddr_in6 *)&iflr->addr;				bcopy(&sin6->sin6_addr, &match, sizeof(match));				cmp = 1;			}		}		for (ifa = ifp->if_addrlist.tqh_first;		     ifa;		     ifa = ifa->ifa_list.tqe_next)		{			if (ifa->ifa_addr->sa_family != AF_INET6)				continue;			if (!cmp)				break;			bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));			candidate.s6_addr32[0] &= mask.s6_addr32[0];			candidate.s6_addr32[1] &= mask.s6_addr32[1];			candidate.s6_addr32[2] &= mask.s6_addr32[2];			candidate.s6_addr32[3] &= mask.s6_addr32[3];			if (IN6_ARE_ADDR_EQUAL(&candidate, &match))				break;		}		if (!ifa)			return EADDRNOTAVAIL;		ia = ifa2ia6(ifa);		if (cmd == SIOCGLIFADDR) {			/* fill in the if_laddrreq structure */			bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {				bcopy(&ia->ia_dstaddr, &iflr->dstaddr,					ia->ia_dstaddr.sin6_len);			} else				bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));			iflr->prefixlen =				in6_mask2len(&ia->ia_prefixmask.sin6_addr);			iflr->flags = ia->ia6_flags;	/*XXX*/			return 0;		} else {			struct in6_aliasreq ifra;			/* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */			bzero(&ifra, sizeof(ifra));			bcopy(iflr->iflr_name, ifra.ifra_name,				sizeof(ifra.ifra_name));			bcopy(&ia->ia_addr, &ifra.ifra_addr,				ia->ia_addr.sin6_len);			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {				bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,					ia->ia_dstaddr.sin6_len);			} else {				bzero(&ifra.ifra_dstaddr,				    sizeof(ifra.ifra_dstaddr));			}			bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr,				ia->ia_prefixmask.sin6_len);			ifra.ifra_flags = ia->ia6_flags;			return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,				ifp, p);		}	    }	}	return EOPNOTSUPP;	/*just for safety*/}