1 /* Set source filter.  Linux version.
2    Copyright (C) 2004-2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <alloca.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdint.h>
24 #include <netinet/in.h>
25 #include <sys/socket.h>
26 #include "getsourcefilter.h"
27 
28 
29 int
setsourcefilter(int s,uint32_t interface,const struct sockaddr * group,socklen_t grouplen,uint32_t fmode,uint32_t numsrc,const struct sockaddr_storage * slist)30 setsourcefilter (int s, uint32_t interface, const struct sockaddr *group,
31 		 socklen_t grouplen, uint32_t fmode, uint32_t numsrc,
32 		 const struct sockaddr_storage *slist)
33 {
34   /* We have to create an struct ip_msfilter object which we can pass
35      to the kernel.  */
36   size_t needed = GROUP_FILTER_SIZE (numsrc);
37   int use_alloca = __libc_use_alloca (needed);
38 
39   struct group_filter *gf;
40   if (use_alloca)
41     gf = (struct group_filter *) alloca (needed);
42   else
43     {
44       gf = (struct group_filter *) malloc (needed);
45       if (gf == NULL)
46 	return -1;
47     }
48 
49   gf->gf_interface = interface;
50   memcpy (&gf->gf_group, group, grouplen);
51   gf->gf_fmode = fmode;
52   gf->gf_numsrc = numsrc;
53   memcpy (gf->gf_slist, slist, numsrc * sizeof (struct sockaddr_storage));
54 
55   /* We need to provide the appropriate socket level value.  */
56   int result;
57   int sol = __get_sol (group->sa_family, grouplen);
58   if (sol == -1)
59     {
60       __set_errno (EINVAL);
61       result = -1;
62     }
63   else
64     result = __setsockopt (s, sol, MCAST_MSFILTER, gf, needed);
65 
66   if (! use_alloca)
67     {
68       int save_errno = errno;
69       free (gf);
70       __set_errno (save_errno);
71     }
72 
73   return result;
74 }
75