1/******************************************************************************
2 * Fichier Module :util.c - An IGMPv3-router implementation
3 ******************************************************************************
4 * Fichier    :	util.c
5 * Description: Implementation des divers routines
6 *		Mars 2001
7 * Date       :	May 18, 2000
8 * Auteur    : lahmadi@loria.fr
9 * Last Modif : Aout 2,  2001
10 *
11 *****************************************************************************/
12#include <stdarg.h>
13/*#include <sys/types.h>
14#include <sys/socket.h>
15#include <sys/ioctl.h>
16#include <net/if.h>
17#include <net/route.h>*/
18
19#include "igmprt.h"
20
21int log_level;
22
23/*
24 * Set/reset the IP_MULTICAST_LOOP. Set/reset is specified by "flag".
25 */
26void k_set_loop(int socket, int flag)
27{
28    u_char loop;
29
30    loop = flag;
31    if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP,
32		   (char *)&loop, sizeof(loop)) < 0)
33	printf("setsockopt IP_MULTICAST_LOOP %u\n", loop);
34}
35
36/*
37 * Set the IP_MULTICAST_IF option on local interface ifa.
38 */
39void k_set_if(int socket, u_long ifa)
40{
41    struct in_addr adr;
42
43    adr.s_addr = ifa;
44    if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF,
45		   (char *)&adr, sizeof(adr)) < 0)
46	printf("setsockopt IP_MULTICAST_IF %s\n", strerror(errno));
47}
48
49
50/*
51 * void debug(int level)
52 *
53 * Write to stdout
54 */
55void debug(int level, const char* fmt, ...)
56{
57	va_list args;
58
59	if (level < log_level)
60		return;
61	va_start(args, fmt);
62	vprintf(fmt, args);
63	va_end(args);
64}
65
66/*
67 * u_short in_cksum(u_short *addr, int len)
68 *
69 * Compute the inet checksum
70 */
71unsigned short in_cksum(unsigned short *addr, int len)
72{
73    int nleft = len;
74    int sum = 0;
75    unsigned short *w = addr;
76    unsigned short answer = 0;
77
78    while (nleft > 1) {
79        sum += *w++;
80        nleft -= 2;
81    }
82    if (nleft == 1) {
83        *(unsigned char*)(&answer) = *(unsigned char*)w;
84        sum += answer;
85    }
86    sum = (sum >> 16) + (sum & 0xffff);
87    answer = ~sum;
88    return (answer);
89}
90
91char* get_if_by_idx(int idx, char* name)
92{
93    FILE *fp;
94    int row = 0, strLen = 0, i;
95    char str[10] = {0};
96    char buf[512] = {0};
97
98    if (!(fp = fopen("/proc/net/dev", "r"))) {
99        return NULL;
100    }
101
102    for (row = 0; row < (idx + 2); row++) {
103        if(!fgets(buf, sizeof(buf), fp))
104            return NULL;
105    }
106
107    i = 0;
108    strLen = 0;
109    while ((buf[i] != '\0') && (buf[i] != '\n') && strLen<IFNAMSIZ) {
110        if ((buf[i] != ' ') && (buf[i] != ':') &&
111            (buf[i] != '\0') && (buf[i] != '\n')) {
112            str[strLen] = buf[i];
113            strLen++;
114        }
115        else if (buf[i] == ':') {
116            str[strLen] = '\0';
117            buf[i] = ' ';
118            break;
119        }
120        buf[i] = ' ';
121        i++;
122    }
123    strcpy(name, str);
124
125    fclose(fp);
126    return (name);
127}
128
129/*
130 * interface_list_t* get_interface_list(short af, short flags, short unflags)
131 *
132 * Get the list of interfaces with an address from family af, and whose flags
133 * match 'flags' and don't match 'unflags'.
134 */
135interface_list_t* get_interface_list(short af, short flags, short unflags)
136{
137    char *p, buf[IFNAMSIZ];
138    interface_list_t *ifp, *ifprev, *list;
139    struct sockaddr *psa;
140    struct ifreq ifr;
141    int sockfd;
142    int i, err;
143
144    sockfd = socket(PF_INET, SOCK_DGRAM, 0);
145    if (sockfd <= 0)
146        return NULL;
147
148    list = ifp = ifprev = NULL;
149    for (i=1; ; i++) {
150        //p = if_indextoname(i, buf);
151        p = get_if_by_idx(i, buf);
152        if (p == NULL)
153            break;
154
155        strncpy(ifr.ifr_name, p, IFNAMSIZ);
156        err = ioctl(sockfd, SIOCGIFADDR, (void*)&ifr);
157        psa = &ifr.ifr_ifru.ifru_addr;
158        if (err == -1 || psa->sa_family != af)
159            continue;
160        err = ioctl(sockfd, SIOCGIFFLAGS, (void*)&ifr);
161        if (err == -1)
162            continue;
163        if (((ifr.ifr_flags & flags) != flags) ||
164            ((ifr.ifr_flags & unflags) != 0))
165            continue;
166        ifp = (interface_list_t*) malloc(sizeof(*ifp));
167        if (ifp) {
168            strncpy(ifp->ifl_name, ifr.ifr_name, IFNAMSIZ);
169            memcpy(&ifp->ifl_addr, psa, sizeof(*psa));
170            ifp->ifl_next = NULL;
171            if (list == NULL)
172                list = ifp;
173            if (ifprev != NULL)
174                ifprev->ifl_next = ifp;
175            ifprev = ifp;
176        }
177    }
178    close(sockfd);
179    return list;
180}
181
182/*
183 * void free_interface_list(interface_list_t *ifl)
184 *
185 * Free a list of interfaces
186 */
187void free_interface_list(interface_list_t *ifl)
188{
189    interface_list_t *ifp = ifl;
190
191    while (ifp) {
192        ifl = ifp;
193        ifp = ifp->ifl_next;
194        free(ifl);
195    }
196}
197
198/*
199 * short get_interface_flags(char *ifname)
200 *
201 * Get the value of the flags for a certain interface
202 */
203short get_interface_flags(char *ifname)
204{
205    struct ifreq ifr;
206    int sockfd, err;
207
208    sockfd = socket(PF_INET, SOCK_DGRAM, 0);
209    if (sockfd <= 0)
210        return -1;
211	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
212	err = ioctl(sockfd, SIOCGIFFLAGS, (void*)&ifr);
213	close(sockfd);
214	if (err == -1)
215		return -1;
216	return ifr.ifr_flags;
217}
218
219/*
220 * short set_interface_flags(char *ifname, short flags)
221 *
222 * Set the value of the flags for a certain interface
223 */
224short set_interface_flags(char *ifname, short flags)
225{
226    struct ifreq ifr;
227    int sockfd, err;
228
229    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
230	//sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
231    if (sockfd <= 0)
232        return -1;
233	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
234	ifr.ifr_flags = flags;
235	err = ioctl(sockfd, SIOCSIFFLAGS, (void*)&ifr);
236	close(sockfd);
237	if (err == -1)
238		return -1;
239	return 0;
240}
241
242/*
243 * short get_interface_flags(char *ifname)
244 *
245 * Get the value of the flags for a certain interface
246 */
247int get_interface_mtu(char *ifname)
248{
249    struct ifreq ifr;
250    int sockfd, err;
251
252    sockfd = socket(PF_INET, SOCK_DGRAM, 0);
253    if (sockfd <= 0)
254        return -1;
255	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
256	err = ioctl(sockfd, SIOCGIFMTU, (void*)&ifr);
257	close(sockfd);
258	if (err == -1)
259		return -1;
260	return ifr.ifr_mtu;
261}
262
263/*
264 * int mrouter_onoff(int sockfd, int onoff)
265 *
266 * Tell the kernel if a multicast router is on or off
267 */
268int mrouter_onoff(int sockfd, int onoff)
269{
270    int err, cmd, i;
271
272	cmd = (onoff) ? MRT_INIT : MRT_DONE;
273	i = 1;
274	err = setsockopt(sockfd, IPPROTO_IP, cmd, (void*)&i, sizeof(i));
275	return err;
276}
277
278
279/*
280 * function name: wordToOption
281 * input: char *word, a pointer to the word
282 * output: int; a number corresponding to the code of the word
283 * operation: converts the result of the string comparisons into numerics.
284 * comments: called by config_vifs_from_file()
285 */
286int
287wordToOption(char *word)
288{
289  if (EQUAL(word, ""))
290    return EMPTY;
291  if (EQUAL(word, "igmpversion"))
292    return IGMPVERSION;
293  if (EQUAL(word, "is_querier"))
294    return IS_QUERIER;
295  if (EQUAL(word,"upstream"))
296    return UPSTREAM;
297  return UNKNOWN;
298}
299
300char * next_word(char **s)
301{
302  char *w;
303
304  w = *s;
305  while (*w == ' ' || *w == '\t')
306    w++;
307
308  *s = w;
309  for(;;) {
310    switch (**s) {
311    case ' '  :
312    case '\t' :
313      **s = '\0';
314      (*s)++;
315      return(w);
316    case '\n' :
317    case '#'  :
318      **s = '\0';
319      return(w);
320    case '\0' :
321      return(w);
322    default   :
323      if (isascii(**s) && isupper(**s))
324	**s = tolower(**s);
325      (*s)++;
326    }
327  }
328}
329