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
getsourcefilter(int s,uint32_t interface,struct sockaddr * group,socklen_t grouplen,uint32_t * fmode,uint_t * numsrc,struct sockaddr_storage * slist)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
setsourcefilter(int s,uint32_t interface,struct sockaddr * group,socklen_t grouplen,uint32_t fmode,uint_t numsrc,struct sockaddr_storage * slist)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
getipv4sourcefilter(int s,struct in_addr interface,struct in_addr group,uint32_t * fmode,uint32_t * numsrc,struct in_addr * slist)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
setipv4sourcefilter(int s,struct in_addr interface,struct in_addr group,uint32_t fmode,uint32_t numsrc,struct in_addr * slist)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