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