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