1/*
2 * "$Id: getifaddrs.c 11093 2013-07-03 20:48:42Z msweet $"
3 *
4 *   Network interface functions for CUPS.
5 *
6 *   Copyright 2007-2010 by Apple Inc.
7 *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
8 *
9 *   These coded instructions, statements, and computer programs are the
10 *   property of Apple Inc. and are protected by Federal copyright
11 *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12 *   "LICENSE" which should have been included with this file.  If this
13 *   file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * Contents:
16 *
17 *   _cups_getifaddrs()  - Get a list of network interfaces on the system.
18 *   _cups_freeifaddrs() - Free an interface list...
19 */
20
21/*
22 * Include necessary headers.
23 */
24
25#include "http-private.h"
26
27
28#ifndef HAVE_GETIFADDRS
29/*
30 * '_cups_getifaddrs()' - Get a list of network interfaces on the system.
31 */
32
33int					/* O - 0 on success, -1 on error */
34_cups_getifaddrs(struct ifaddrs **addrs)/* O - List of interfaces */
35{
36  int			sock;		/* Socket */
37  char			buffer[65536],	/* Buffer for address info */
38			*bufptr,	/* Pointer into buffer */
39			*bufend;	/* End of buffer */
40  struct ifconf		conf;		/* Interface configurations */
41  struct sockaddr	addr;		/* Address data */
42  struct ifreq		*ifp;		/* Interface data */
43  int			ifpsize;	/* Size of interface data */
44  struct ifaddrs	*temp;		/* Pointer to current interface */
45  struct ifreq		request;	/* Interface request */
46
47
48 /*
49  * Start with an empty list...
50  */
51
52  if (addrs == NULL)
53    return (-1);
54
55  *addrs = NULL;
56
57 /*
58  * Create a UDP socket to get the interface data...
59  */
60
61  memset (&addr, 0, sizeof(addr));
62  if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
63    return (-1);
64
65 /*
66  * Try to get the list of interfaces...
67  */
68
69  conf.ifc_len = sizeof(buffer);
70  conf.ifc_buf = buffer;
71
72  if (ioctl(sock, SIOCGIFCONF, &conf) < 0)
73  {
74   /*
75    * Couldn't get the list of interfaces...
76    */
77
78    close(sock);
79    return (-1);
80  }
81
82 /*
83  * OK, got the list of interfaces, now lets step through the
84  * buffer to pull them out...
85  */
86
87#  ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
88#    define sockaddr_len(a)	((a)->sa_len)
89#  else
90#    define sockaddr_len(a)	(sizeof(struct sockaddr))
91#  endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
92
93  for (bufptr = buffer, bufend = buffer + conf.ifc_len;
94       bufptr < bufend;
95       bufptr += ifpsize)
96  {
97   /*
98    * Get the current interface information...
99    */
100
101    ifp     = (struct ifreq *)bufptr;
102    ifpsize = sizeof(ifp->ifr_name) + sockaddr_len(&(ifp->ifr_addr));
103
104    if (ifpsize < sizeof(struct ifreq))
105      ifpsize = sizeof(struct ifreq);
106
107    memset(&request, 0, sizeof(request));
108    memcpy(request.ifr_name, ifp->ifr_name, sizeof(ifp->ifr_name));
109
110   /*
111    * Check the status of the interface...
112    */
113
114    if (ioctl(sock, SIOCGIFFLAGS, &request) < 0)
115      continue;
116
117   /*
118    * Allocate memory for a single interface record...
119    */
120
121    if ((temp = calloc(1, sizeof(struct ifaddrs))) == NULL)
122    {
123     /*
124      * Unable to allocate memory...
125      */
126
127      close(sock);
128      return (-1);
129    }
130
131   /*
132    * Add this record to the front of the list and copy the name, flags,
133    * and network address...
134    */
135
136    temp->ifa_next  = *addrs;
137    *addrs          = temp;
138    temp->ifa_name  = strdup(ifp->ifr_name);
139    temp->ifa_flags = request.ifr_flags;
140    if ((temp->ifa_addr = calloc(1, sockaddr_len(&(ifp->ifr_addr)))) != NULL)
141      memcpy(temp->ifa_addr, &(ifp->ifr_addr), sockaddr_len(&(ifp->ifr_addr)));
142
143   /*
144    * Try to get the netmask for the interface...
145    */
146
147    if (!ioctl(sock, SIOCGIFNETMASK, &request))
148    {
149     /*
150      * Got it, make a copy...
151      */
152
153      if ((temp->ifa_netmask = calloc(1, sizeof(request.ifr_netmask))) != NULL)
154	memcpy(temp->ifa_netmask, &(request.ifr_netmask),
155	       sizeof(request.ifr_netmask));
156    }
157
158   /*
159    * Then get the broadcast or point-to-point (destination) address,
160    * if applicable...
161    */
162
163    if (temp->ifa_flags & IFF_BROADCAST)
164    {
165     /*
166      * Have a broadcast address, so get it!
167      */
168
169      if (!ioctl(sock, SIOCGIFBRDADDR, &request))
170      {
171       /*
172	* Got it, make a copy...
173	*/
174
175	if ((temp->ifa_broadaddr =
176	         calloc(1, sizeof(request.ifr_broadaddr))) != NULL)
177	  memcpy(temp->ifa_broadaddr, &(request.ifr_broadaddr),
178		 sizeof(request.ifr_broadaddr));
179      }
180    }
181    else if (temp->ifa_flags & IFF_POINTOPOINT)
182    {
183     /*
184      * Point-to-point interface; grab the remote address...
185      */
186
187      if (!ioctl(sock, SIOCGIFDSTADDR, &request))
188      {
189	temp->ifa_dstaddr = malloc(sizeof(request.ifr_dstaddr));
190	memcpy(temp->ifa_dstaddr, &(request.ifr_dstaddr),
191	       sizeof(request.ifr_dstaddr));
192      }
193    }
194  }
195
196 /*
197  * OK, we're done with the socket, close it and return 0...
198  */
199
200  close(sock);
201
202  return (0);
203}
204
205
206/*
207 * '_cups_freeifaddrs()' - Free an interface list...
208 */
209
210void
211_cups_freeifaddrs(struct ifaddrs *addrs)/* I - Interface list to free */
212{
213  struct ifaddrs	*next;		/* Next interface in list */
214
215
216  while (addrs != NULL)
217  {
218   /*
219    * Make a copy of the next interface pointer...
220    */
221
222    next = addrs->ifa_next;
223
224   /*
225    * Free data values as needed...
226    */
227
228    if (addrs->ifa_name)
229    {
230      free(addrs->ifa_name);
231      addrs->ifa_name = NULL;
232    }
233
234    if (addrs->ifa_addr)
235    {
236      free(addrs->ifa_addr);
237      addrs->ifa_addr = NULL;
238    }
239
240    if (addrs->ifa_netmask)
241    {
242      free(addrs->ifa_netmask);
243      addrs->ifa_netmask = NULL;
244    }
245
246    if (addrs->ifa_dstaddr)
247    {
248      free(addrs->ifa_dstaddr);
249      addrs->ifa_dstaddr = NULL;
250    }
251
252   /*
253    * Free this node and continue to the next...
254    */
255
256    free(addrs);
257
258    addrs = next;
259  }
260}
261#endif /* !HAVE_GETIFADDRS */
262
263
264/*
265 * End of "$Id: getifaddrs.c 11093 2013-07-03 20:48:42Z msweet $".
266 */
267