Home | History | Annotate | Download | only in inet
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <unistd.h>
     32 #include <string.h>
     33 #include <stropts.h>
     34 #include <errno.h>
     35 #include <sys/sysmacros.h>
     36 #include <sys/socket.h>
     37 #include <sys/sockio.h>
     38 #include <netinet/in.h>
     39 
     40 int
     41 getsourcefilter(int s, uint32_t interface, struct sockaddr *group,
     42     socklen_t grouplen, uint32_t *fmode, uint_t *numsrc,
     43     struct sockaddr_storage *slist)
     44 {
     45 	struct group_filter *gf;
     46 	int mallocsize, orig_numsrc, cpsize, rtnerr;
     47 
     48 	mallocsize = (*numsrc == 0) ?
     49 	    sizeof (struct group_filter) : GROUP_FILTER_SIZE(*numsrc);
     50 	gf = (struct group_filter *)malloc(mallocsize);
     51 	if (gf == NULL) {
     52 		errno = ENOMEM;
     53 		return (-1);
     54 	}
     55 
     56 	gf->gf_interface = interface;
     57 	gf->gf_numsrc = orig_numsrc = *numsrc;
     58 	switch (group->sa_family) {
     59 	case AF_INET:
     60 		if (grouplen < sizeof (struct sockaddr_in)) {
     61 			rtnerr = ENOPROTOOPT;
     62 			goto done;
     63 		}
     64 		(void) memcpy((void *)&gf->gf_group, (void *)group,
     65 		    sizeof (struct sockaddr_in));
     66 		break;
     67 	case AF_INET6:
     68 		if (grouplen < sizeof (struct sockaddr_in6)) {
     69 			rtnerr = ENOPROTOOPT;
     70 			goto done;
     71 		}
     72 		(void) memcpy((void *)&gf->gf_group, (void *)group,
     73 		    sizeof (struct sockaddr_in6));
     74 		break;
     75 	default:
     76 		rtnerr = EAFNOSUPPORT;
     77 		goto done;
     78 	}
     79 
     80 	rtnerr = ioctl(s, SIOCGMSFILTER, (void *)gf);
     81 	if (rtnerr == -1) {
     82 		rtnerr = errno;
     83 		goto done;
     84 	}
     85 
     86 	*fmode = gf->gf_fmode;
     87 	*numsrc = gf->gf_numsrc;
     88 	cpsize = MIN(orig_numsrc, *numsrc) * sizeof (struct sockaddr_storage);
     89 	(void) memcpy((void *)slist, (void *)gf->gf_slist, cpsize);
     90 
     91 done:
     92 	free(gf);
     93 	errno = rtnerr;
     94 	if (errno != 0)
     95 		return (-1);
     96 
     97 	return (0);
     98 }
     99 
    100 int
    101 setsourcefilter(int s, uint32_t interface, struct sockaddr *group,
    102     socklen_t grouplen, uint32_t fmode, uint_t numsrc,
    103     struct sockaddr_storage *slist)
    104 {
    105 	struct group_filter *gf;
    106 	int mallocsize, rtnerr;
    107 
    108 	mallocsize = (numsrc == 0) ?
    109 	    sizeof (struct group_filter) : GROUP_FILTER_SIZE(numsrc);
    110 	gf = (struct group_filter *)malloc(mallocsize);
    111 	if (gf == NULL) {
    112 		errno = ENOMEM;
    113 		return (-1);
    114 	}
    115 
    116 	switch (group->sa_family) {
    117 	case AF_INET:
    118 		if (grouplen < sizeof (struct sockaddr_in)) {
    119 			rtnerr = ENOPROTOOPT;
    120 			goto done;
    121 		}
    122 		(void) memcpy((void *)&gf->gf_group, (void *)group,
    123 		    sizeof (struct sockaddr_in));
    124 		break;
    125 	case AF_INET6:
    126 		if (grouplen < sizeof (struct sockaddr_in6)) {
    127 			rtnerr = ENOPROTOOPT;
    128 			goto done;
    129 		}
    130 		(void) memcpy((void *)&gf->gf_group, (void *)group,
    131 		    sizeof (struct sockaddr_in6));
    132 		break;
    133 	default:
    134 		rtnerr = EAFNOSUPPORT;
    135 		goto done;
    136 	}
    137 	gf->gf_interface = interface;
    138 	gf->gf_fmode = fmode;
    139 	gf->gf_numsrc = numsrc;
    140 	(void) memcpy((void *)gf->gf_slist, (void *)slist,
    141 	    (numsrc * sizeof (struct sockaddr_storage)));
    142 
    143 	rtnerr = ioctl(s, SIOCSMSFILTER, (void *)gf);
    144 	if (rtnerr == -1) {
    145 		rtnerr = errno;
    146 	}
    147 
    148 done:
    149 	free(gf);
    150 	errno = rtnerr;
    151 	if (errno != 0)
    152 		return (-1);
    153 
    154 	return (0);
    155 }
    156 
    157 int
    158 getipv4sourcefilter(int s, struct in_addr interface, struct in_addr group,
    159     uint32_t *fmode, uint32_t *numsrc, struct in_addr *slist)
    160 {
    161 	struct ip_msfilter *imsf;
    162 	int mallocsize, orig_numsrc, cpsize, rtnerr;
    163 
    164 	mallocsize = (*numsrc == 0) ?
    165 	    sizeof (struct ip_msfilter) : IP_MSFILTER_SIZE(*numsrc);
    166 	imsf = (struct ip_msfilter *)malloc(mallocsize);
    167 	if (imsf == NULL) {
    168 		errno = ENOMEM;
    169 		return (-1);
    170 	}
    171 
    172 	imsf->imsf_interface = interface;
    173 	imsf->imsf_numsrc = orig_numsrc = *numsrc;
    174 	imsf->imsf_multiaddr = group;
    175 
    176 	rtnerr = ioctl(s, SIOCGIPMSFILTER, (void *)imsf);
    177 	if (rtnerr == -1) {
    178 		rtnerr = errno;
    179 		goto done;
    180 	}
    181 
    182 	*fmode = imsf->imsf_fmode;
    183 	*numsrc = imsf->imsf_numsrc;
    184 	cpsize = MIN(orig_numsrc, *numsrc) * sizeof (struct in_addr);
    185 	(void) memcpy((void *)slist, (void *)imsf->imsf_slist, cpsize);
    186 
    187 done:
    188 	free(imsf);
    189 	errno = rtnerr;
    190 	if (errno != 0)
    191 		return (-1);
    192 
    193 	return (0);
    194 }
    195 
    196 int
    197 setipv4sourcefilter(int s, struct in_addr interface, struct in_addr group,
    198     uint32_t fmode, uint32_t numsrc, struct in_addr *slist)
    199 {
    200 	struct ip_msfilter *imsf;
    201 	int mallocsize, rtnerr;
    202 
    203 	mallocsize = (numsrc == 0) ?
    204 	    sizeof (struct ip_msfilter) : IP_MSFILTER_SIZE(numsrc);
    205 	imsf = (struct ip_msfilter *)malloc(mallocsize);
    206 	if (imsf == NULL) {
    207 		errno = ENOMEM;
    208 		return (-1);
    209 	}
    210 
    211 	imsf->imsf_multiaddr = group;
    212 	imsf->imsf_interface = interface;
    213 	imsf->imsf_fmode = fmode;
    214 	imsf->imsf_numsrc = numsrc;
    215 	(void) memcpy((void *)imsf->imsf_slist, (void *)slist,
    216 	    (numsrc * sizeof (struct in_addr)));
    217 
    218 	rtnerr = ioctl(s, SIOCSIPMSFILTER, (void *)imsf);
    219 	if (rtnerr == -1) {
    220 		rtnerr = errno;
    221 	}
    222 
    223 	free(imsf);
    224 	errno = rtnerr;
    225 	if (errno != 0)
    226 		return (-1);
    227 
    228 	return (0);
    229 }
    230