1/*
2 * Copyright 2004, Broadcom Corporation
3 * All Rights Reserved.
4 *
5 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
6 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
7 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
8 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
9 *
10 * $Id: linux_osl.c,v 1.1.1.1 2008/10/15 03:31:35 james26_jang Exp $
11 */
12
13#include <sys/ioctl.h>
14#include <net/if.h>
15#include <linux/socket.h>
16
17#include "upnp_osl.h"
18#include "upnp_dbg.h"
19#include "upnp.h"
20
21
22struct in_addr *osl_ifaddr(const char *ifname, struct in_addr *inaddr)
23{
24    int sockfd;
25    struct ifreq ifreq;
26
27    if ((sockfd = socket( AF_INET, SOCK_DGRAM, 0 )) < 0) {
28	perror("socket");
29	return NULL;
30    }
31
32    strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
33    if (ioctl(sockfd, SIOCGIFADDR, &ifreq) < 0) {
34	inaddr = NULL;
35    } else {
36	memcpy(inaddr, &(((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr), sizeof(struct in_addr));
37    }
38    close(sockfd);
39    return inaddr;
40}
41
42
43
44int osl_join_multicast(struct iface *pif, int fd, ulong ipaddr, ushort port)
45{
46    struct ip_mreqn    mcreqn;
47    struct ifreq       ifreq;
48    struct sockaddr_in mcaddr;
49    int success = FALSE;
50    int flag;
51
52    do {
53
54	// make sure this interface is capable of MULTICAST...
55	memset(&ifreq, 0, sizeof(ifreq));
56	strcpy(ifreq.ifr_name, pif->ifname);
57	if (ioctl(fd, SIOCGIFFLAGS, (int) &ifreq))
58	    break;
59
60	if ((ifreq.ifr_flags & IFF_MULTICAST) == 0)
61	    break;
62
63	// bind the socket to an address and port.
64	flag = 1;
65	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &flag, sizeof(flag));
66
67	memset(&mcaddr, 0, sizeof(mcaddr));
68	// memcpy(&mcaddr.sin_addr, &pif->inaddr, sizeof(mcaddr.sin_addr));
69	mcaddr.sin_addr.s_addr = htonl( INADDR_ANY );
70	mcaddr.sin_family = AF_INET;
71	mcaddr.sin_port = htons(port);
72	if ( bind(fd, (struct sockaddr *) &mcaddr, sizeof(mcaddr)) )
73	    break;
74
75	// join the multicast group.
76	memset(&ifreq, 0, sizeof(ifreq));
77	strcpy(ifreq.ifr_name, pif->ifname);
78	if (ioctl(fd, SIOCGIFINDEX, &ifreq))
79	    break;
80
81	memset(&mcreqn, 0, sizeof(mcreqn));
82	mcreqn.imr_multiaddr.s_addr = ipaddr;
83	//mcreqn.imr_interface.s_addr = mcaddr.sin_addr.s_addr;
84	// if we get to use struct ip_mreqn, delete the previous line and uncomment the next two
85	mcreqn.imr_address.s_addr = mcaddr.sin_addr.s_addr;
86	mcreqn.imr_ifindex = ifreq.ifr_ifindex;
87	if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcreqn, sizeof(mcreqn)))
88	    break;
89
90	// restrict multicast messages sent on this socket
91	// to only go out this interface and no other
92	// (doesn't say anything about multicast receives.)
93	//
94	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char*) &pif->inaddr, sizeof(pif->inaddr)))
95	    break;
96
97	success = TRUE;
98
99    } while (0);
100
101    // TRUE == success, FALSE otherwise.
102    return success;
103}
104
105
106char *
107safe_snprintf(char *str, int *len, const char *fmt, ...)
108{
109	va_list ap;
110	int n;
111
112	va_start(ap, fmt);
113	n = vsnprintf(str, *len, fmt, ap);
114	va_end(ap);
115
116	if (n > 0) {
117		str += n;
118		*len -= n;
119	} else if (n < 0) {
120		*len = 0;
121	}
122
123	return str;
124}
125