/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include int getsourcefilter(int s, uint32_t interface, struct sockaddr *group, socklen_t grouplen, uint32_t *fmode, uint_t *numsrc, struct sockaddr_storage *slist) { struct group_filter *gf; int mallocsize, orig_numsrc, cpsize, rtnerr; mallocsize = (*numsrc == 0) ? sizeof (struct group_filter) : GROUP_FILTER_SIZE(*numsrc); gf = (struct group_filter *)malloc(mallocsize); if (gf == NULL) { errno = ENOMEM; return (-1); } gf->gf_interface = interface; gf->gf_numsrc = orig_numsrc = *numsrc; switch (group->sa_family) { case AF_INET: if (grouplen < sizeof (struct sockaddr_in)) { rtnerr = ENOPROTOOPT; goto done; } (void) memcpy((void *)&gf->gf_group, (void *)group, sizeof (struct sockaddr_in)); break; case AF_INET6: if (grouplen < sizeof (struct sockaddr_in6)) { rtnerr = ENOPROTOOPT; goto done; } (void) memcpy((void *)&gf->gf_group, (void *)group, sizeof (struct sockaddr_in6)); break; default: rtnerr = EAFNOSUPPORT; goto done; } rtnerr = ioctl(s, SIOCGMSFILTER, (void *)gf); if (rtnerr == -1) { rtnerr = errno; goto done; } *fmode = gf->gf_fmode; *numsrc = gf->gf_numsrc; cpsize = MIN(orig_numsrc, *numsrc) * sizeof (struct sockaddr_storage); (void) memcpy((void *)slist, (void *)gf->gf_slist, cpsize); done: free(gf); errno = rtnerr; if (errno != 0) return (-1); return (0); } int setsourcefilter(int s, uint32_t interface, struct sockaddr *group, socklen_t grouplen, uint32_t fmode, uint_t numsrc, struct sockaddr_storage *slist) { struct group_filter *gf; int mallocsize, rtnerr; mallocsize = (numsrc == 0) ? sizeof (struct group_filter) : GROUP_FILTER_SIZE(numsrc); gf = (struct group_filter *)malloc(mallocsize); if (gf == NULL) { errno = ENOMEM; return (-1); } switch (group->sa_family) { case AF_INET: if (grouplen < sizeof (struct sockaddr_in)) { rtnerr = ENOPROTOOPT; goto done; } (void) memcpy((void *)&gf->gf_group, (void *)group, sizeof (struct sockaddr_in)); break; case AF_INET6: if (grouplen < sizeof (struct sockaddr_in6)) { rtnerr = ENOPROTOOPT; goto done; } (void) memcpy((void *)&gf->gf_group, (void *)group, sizeof (struct sockaddr_in6)); break; default: rtnerr = EAFNOSUPPORT; goto done; } gf->gf_interface = interface; gf->gf_fmode = fmode; gf->gf_numsrc = numsrc; (void) memcpy((void *)gf->gf_slist, (void *)slist, (numsrc * sizeof (struct sockaddr_storage))); rtnerr = ioctl(s, SIOCSMSFILTER, (void *)gf); if (rtnerr == -1) { rtnerr = errno; } done: free(gf); errno = rtnerr; if (errno != 0) return (-1); return (0); } int getipv4sourcefilter(int s, struct in_addr interface, struct in_addr group, uint32_t *fmode, uint32_t *numsrc, struct in_addr *slist) { struct ip_msfilter *imsf; int mallocsize, orig_numsrc, cpsize, rtnerr; mallocsize = (*numsrc == 0) ? sizeof (struct ip_msfilter) : IP_MSFILTER_SIZE(*numsrc); imsf = (struct ip_msfilter *)malloc(mallocsize); if (imsf == NULL) { errno = ENOMEM; return (-1); } imsf->imsf_interface = interface; imsf->imsf_numsrc = orig_numsrc = *numsrc; imsf->imsf_multiaddr = group; rtnerr = ioctl(s, SIOCGIPMSFILTER, (void *)imsf); if (rtnerr == -1) { rtnerr = errno; goto done; } *fmode = imsf->imsf_fmode; *numsrc = imsf->imsf_numsrc; cpsize = MIN(orig_numsrc, *numsrc) * sizeof (struct in_addr); (void) memcpy((void *)slist, (void *)imsf->imsf_slist, cpsize); done: free(imsf); errno = rtnerr; if (errno != 0) return (-1); return (0); } int setipv4sourcefilter(int s, struct in_addr interface, struct in_addr group, uint32_t fmode, uint32_t numsrc, struct in_addr *slist) { struct ip_msfilter *imsf; int mallocsize, rtnerr; mallocsize = (numsrc == 0) ? sizeof (struct ip_msfilter) : IP_MSFILTER_SIZE(numsrc); imsf = (struct ip_msfilter *)malloc(mallocsize); if (imsf == NULL) { errno = ENOMEM; return (-1); } imsf->imsf_multiaddr = group; imsf->imsf_interface = interface; imsf->imsf_fmode = fmode; imsf->imsf_numsrc = numsrc; (void) memcpy((void *)imsf->imsf_slist, (void *)slist, (numsrc * sizeof (struct in_addr))); rtnerr = ioctl(s, SIOCSIPMSFILTER, (void *)imsf); if (rtnerr == -1) { rtnerr = errno; } free(imsf); errno = rtnerr; if (errno != 0) return (-1); return (0); }