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 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <string.h> 31 #include <stropts.h> 32 #include <errno.h> 33 #include <sys/sysmacros.h> 34 #include <sys/socket.h> 35 #include <sys/sockio.h> 36 #include <netinet/in.h> 37 38 int 39 getsourcefilter(int s, uint32_t interface, struct sockaddr *group, 40 socklen_t grouplen, uint32_t *fmode, uint_t *numsrc, 41 struct sockaddr_storage *slist) 42 { 43 struct group_filter *gf; 44 int mallocsize, orig_numsrc, cpsize, rtnerr; 45 46 mallocsize = (*numsrc == 0) ? 47 sizeof (struct group_filter) : GROUP_FILTER_SIZE(*numsrc); 48 gf = (struct group_filter *)malloc(mallocsize); 49 if (gf == NULL) { 50 errno = ENOMEM; 51 return (-1); 52 } 53 54 gf->gf_interface = interface; 55 gf->gf_numsrc = orig_numsrc = *numsrc; 56 switch (group->sa_family) { 57 case AF_INET: 58 if (grouplen < sizeof (struct sockaddr_in)) { 59 rtnerr = ENOPROTOOPT; 60 goto done; 61 } 62 (void) memcpy((void *)&gf->gf_group, (void *)group, 63 sizeof (struct sockaddr_in)); 64 break; 65 case AF_INET6: 66 if (grouplen < sizeof (struct sockaddr_in6)) { 67 rtnerr = ENOPROTOOPT; 68 goto done; 69 } 70 (void) memcpy((void *)&gf->gf_group, (void *)group, 71 sizeof (struct sockaddr_in6)); 72 break; 73 default: 74 rtnerr = EAFNOSUPPORT; 75 goto done; 76 } 77 78 rtnerr = ioctl(s, SIOCGMSFILTER, (void *)gf); 79 if (rtnerr == -1) { 80 rtnerr = errno; 81 goto done; 82 } 83 84 *fmode = gf->gf_fmode; 85 *numsrc = gf->gf_numsrc; 86 cpsize = MIN(orig_numsrc, *numsrc) * sizeof (struct sockaddr_storage); 87 (void) memcpy((void *)slist, (void *)gf->gf_slist, cpsize); 88 89 done: 90 free(gf); 91 errno = rtnerr; 92 if (errno != 0) 93 return (-1); 94 95 return (0); 96 } 97 98 int 99 setsourcefilter(int s, uint32_t interface, struct sockaddr *group, 100 socklen_t grouplen, uint32_t fmode, uint_t numsrc, 101 struct sockaddr_storage *slist) 102 { 103 struct group_filter *gf; 104 int mallocsize, rtnerr; 105 106 mallocsize = (numsrc == 0) ? 107 sizeof (struct group_filter) : GROUP_FILTER_SIZE(numsrc); 108 gf = (struct group_filter *)malloc(mallocsize); 109 if (gf == NULL) { 110 errno = ENOMEM; 111 return (-1); 112 } 113 114 switch (group->sa_family) { 115 case AF_INET: 116 if (grouplen < sizeof (struct sockaddr_in)) { 117 rtnerr = ENOPROTOOPT; 118 goto done; 119 } 120 (void) memcpy((void *)&gf->gf_group, (void *)group, 121 sizeof (struct sockaddr_in)); 122 break; 123 case AF_INET6: 124 if (grouplen < sizeof (struct sockaddr_in6)) { 125 rtnerr = ENOPROTOOPT; 126 goto done; 127 } 128 (void) memcpy((void *)&gf->gf_group, (void *)group, 129 sizeof (struct sockaddr_in6)); 130 break; 131 default: 132 rtnerr = EAFNOSUPPORT; 133 goto done; 134 } 135 gf->gf_interface = interface; 136 gf->gf_fmode = fmode; 137 gf->gf_numsrc = numsrc; 138 (void) memcpy((void *)gf->gf_slist, (void *)slist, 139 (numsrc * sizeof (struct sockaddr_storage))); 140 141 rtnerr = ioctl(s, SIOCSMSFILTER, (void *)gf); 142 if (rtnerr == -1) { 143 rtnerr = errno; 144 } 145 146 done: 147 free(gf); 148 errno = rtnerr; 149 if (errno != 0) 150 return (-1); 151 152 return (0); 153 } 154 155 int 156 getipv4sourcefilter(int s, struct in_addr interface, struct in_addr group, 157 uint32_t *fmode, uint32_t *numsrc, struct in_addr *slist) 158 { 159 struct ip_msfilter *imsf; 160 int mallocsize, orig_numsrc, cpsize, rtnerr; 161 162 mallocsize = (*numsrc == 0) ? 163 sizeof (struct ip_msfilter) : IP_MSFILTER_SIZE(*numsrc); 164 imsf = (struct ip_msfilter *)malloc(mallocsize); 165 if (imsf == NULL) { 166 errno = ENOMEM; 167 return (-1); 168 } 169 170 imsf->imsf_interface = interface; 171 imsf->imsf_numsrc = orig_numsrc = *numsrc; 172 imsf->imsf_multiaddr = group; 173 174 rtnerr = ioctl(s, SIOCGIPMSFILTER, (void *)imsf); 175 if (rtnerr == -1) { 176 rtnerr = errno; 177 goto done; 178 } 179 180 *fmode = imsf->imsf_fmode; 181 *numsrc = imsf->imsf_numsrc; 182 cpsize = MIN(orig_numsrc, *numsrc) * sizeof (struct in_addr); 183 (void) memcpy((void *)slist, (void *)imsf->imsf_slist, cpsize); 184 185 done: 186 free(imsf); 187 errno = rtnerr; 188 if (errno != 0) 189 return (-1); 190 191 return (0); 192 } 193 194 int 195 setipv4sourcefilter(int s, struct in_addr interface, struct in_addr group, 196 uint32_t fmode, uint32_t numsrc, struct in_addr *slist) 197 { 198 struct ip_msfilter *imsf; 199 int mallocsize, rtnerr; 200 201 mallocsize = (numsrc == 0) ? 202 sizeof (struct ip_msfilter) : IP_MSFILTER_SIZE(numsrc); 203 imsf = (struct ip_msfilter *)malloc(mallocsize); 204 if (imsf == NULL) { 205 errno = ENOMEM; 206 return (-1); 207 } 208 209 imsf->imsf_multiaddr = group; 210 imsf->imsf_interface = interface; 211 imsf->imsf_fmode = fmode; 212 imsf->imsf_numsrc = numsrc; 213 (void) memcpy((void *)imsf->imsf_slist, (void *)slist, 214 (numsrc * sizeof (struct in_addr))); 215 216 rtnerr = ioctl(s, SIOCSIPMSFILTER, (void *)imsf); 217 if (rtnerr == -1) { 218 rtnerr = errno; 219 } 220 221 free(imsf); 222 errno = rtnerr; 223 if (errno != 0) 224 return (-1); 225 226 return (0); 227 } 228