rx-mutex-interlocked-macros-20080311
[openafs.git] / src / rx / rx_getaddr.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID
14     ("$Header$");
15
16 #ifndef KERNEL
17 #ifndef AFS_NT40_ENV
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/time.h>
21 #include <net/if.h>
22 #include <netinet/in.h>
23 #include <sys/ioctl.h>
24 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
25 #include <sys/sysctl.h>
26 #include <net/route.h>
27 #include <net/if_dl.h>
28 #endif
29
30 /*
31  * By including this, we get any system dependencies. In particular,
32  * the pthreads for solaris requires the socket call to be mapped.
33  */
34 #include "rx.h"
35 #include "rx_globals.h"
36 #endif /* AFS_NT40_ENV */
37 #else /* KERNEL */
38 #ifdef UKERNEL
39 #include "rx/rx_kcommon.h"
40 #else /* UKERNEL */
41 #include "rx/rx.h"
42 #endif /* UKERNEL */
43 #endif /* KERNEL */
44
45 #define NIFS            512
46
47 #ifdef KERNEL
48 /* only used for generating random noise */
49
50 afs_int32 rxi_tempAddr = 0;     /* default attempt */
51
52 /* set the advisory noise */
53 void
54 rxi_setaddr(afs_int32 x)
55 {
56     rxi_tempAddr = x;
57 }
58
59 /* get approx to net addr */
60 afs_int32
61 rxi_getaddr(void)
62 {
63     return rxi_tempAddr;
64 }
65
66 #endif /* KERNEL */
67
68 #ifndef KERNEL
69
70 /* to satisfy those who call setaddr */
71 void
72 rxi_setaddr(afs_int32 x)
73 {
74 }
75
76 #endif /* !KERNEL */
77
78
79 #if !defined(AFS_NT40_ENV)
80 /* For NT, rxi_getaddr has moved to rx_user.c. rxi_GetIfInfo is called by
81  * rx_Init which sets up the list of addresses for us.
82  */
83
84 #ifndef KERNEL
85
86 /* Return our internet address as a long in network byte order.  Returns zero
87  * if it can't find one.
88  */
89 afs_int32
90 rxi_getaddr(void)
91 {
92     afs_int32 buffer[1024];
93     int count;
94
95     count = rx_getAllAddr(buffer, 1024);
96     if (count > 0)
97         return buffer[0];       /* returns the first address */
98     else
99         return count;
100 }
101
102 #endif /* !KERNEL */
103
104 #if !defined(KERNEL) || defined(UKERNEL)
105
106 #ifndef MAX
107 #define MAX(A,B) (((A)<(B)) ? (B) : (A))
108 #endif
109
110 #ifdef UKERNEL
111 #undef ioctl
112 #undef socket
113 #endif /* UKERNEL */
114
115 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
116 #define ROUNDUP(a) \
117         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
118 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
119
120 static void
121 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
122 {
123     struct sockaddr *sa;
124     int i;
125
126     memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
127     for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
128         if ((rtinfo->rti_addrs & (1 << i)) == 0)
129             continue;
130         rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
131         ADVANCE(cp, sa);
132     }
133 }
134 #endif
135
136
137 /* this function returns the total number of interface addresses 
138 ** the buffer has to be passed in by the caller
139 */
140 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
141 int
142 rx_getAllAddr_internal(afs_int32 buffer[], int maxSize, int loopbacks)
143 {
144     size_t needed;
145     int mib[6];
146     struct if_msghdr *ifm, *nextifm;
147     struct ifa_msghdr *ifam;
148     struct sockaddr_dl *sdl;
149     struct rt_addrinfo info;
150     char *buf, *lim, *next;
151     int count = 0, addrcount = 0;
152
153     mib[0] = CTL_NET;
154     mib[1] = PF_ROUTE;
155     mib[2] = 0;
156     mib[3] = AF_INET;           /* address family */
157     mib[4] = NET_RT_IFLIST;
158     mib[5] = 0;
159     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
160         return 0;
161     if ((buf = malloc(needed)) == NULL)
162         return 0;
163     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
164         free(buf);
165         return 0;
166     }
167     lim = buf + needed;
168     next = buf;
169     while (next < lim) {
170         ifm = (struct if_msghdr *)next;
171         if (ifm->ifm_type != RTM_IFINFO) {
172             dpf(("out of sync parsing NET_RT_IFLIST\n"));
173             free(buf);
174             return 0;
175         }
176         sdl = (struct sockaddr_dl *)(ifm + 1);
177         next += ifm->ifm_msglen;
178         ifam = NULL;
179         addrcount = 0;
180         while (next < lim) {
181             nextifm = (struct if_msghdr *)next;
182             if (nextifm->ifm_type != RTM_NEWADDR)
183                 break;
184             if (ifam == NULL)
185                 ifam = (struct ifa_msghdr *)nextifm;
186             addrcount++;
187             next += nextifm->ifm_msglen;
188         }
189         if ((ifm->ifm_flags & IFF_UP) == 0)
190             continue;           /* not up */
191         while (addrcount > 0) {
192             struct sockaddr_in *a;
193
194             info.rti_addrs = ifam->ifam_addrs;
195
196             /* Expand the compacted addresses */
197             rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
198                       &info);
199             if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) {
200                 addrcount--;
201                 continue;
202             }
203             a = (struct sockaddr_in *) info.rti_info[RTAX_IFA];
204
205             if (count >= maxSize)       /* no more space */
206                 dpf(("Too many interfaces..ignoring 0x%x\n",
207                        a->sin_addr.s_addr));
208             else if (!loopbacks && a->sin_addr.s_addr == htonl(0x7f000001)) {
209                 addrcount--;
210                 continue;       /* skip loopback address as well. */
211             } else if (loopbacks && ifm->ifm_flags & IFF_LOOPBACK) {
212                 addrcount--;
213                 continue;       /* skip aliased loopbacks as well. */
214             } else
215                 buffer[count++] = a->sin_addr.s_addr;
216             addrcount--;
217             ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
218         }
219     }
220     free(buf);
221     return count;
222 }
223
224 int
225 rxi_getAllAddrMaskMtu(afs_int32 addrBuffer[], afs_int32 maskBuffer[],
226                       afs_int32 mtuBuffer[], int maxSize)
227 {
228     int s;
229
230     size_t needed;
231     int mib[6];
232     struct if_msghdr *ifm, *nextifm;
233     struct ifa_msghdr *ifam;
234     struct sockaddr_dl *sdl;
235     struct rt_addrinfo info;
236     char *buf, *lim, *next;
237     int count = 0, addrcount = 0, i;
238
239     mib[0] = CTL_NET;
240     mib[1] = PF_ROUTE;
241     mib[2] = 0;
242     mib[3] = AF_INET;           /* address family */
243     mib[4] = NET_RT_IFLIST;
244     mib[5] = 0;
245     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
246         return 0;
247     if ((buf = malloc(needed)) == NULL)
248         return 0;
249     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
250         free(buf);
251         return 0;
252     }
253     s = socket(PF_INET, SOCK_DGRAM, 0);
254     if (s < 0)
255         return 0;
256     lim = buf + needed;
257     next = buf;
258     while (next < lim) {
259         ifm = (struct if_msghdr *)next;
260         if (ifm->ifm_type != RTM_IFINFO) {
261             dpf(("out of sync parsing NET_RT_IFLIST\n"));
262             free(buf);
263             return 0;
264         }
265         sdl = (struct sockaddr_dl *)(ifm + 1);
266         next += ifm->ifm_msglen;
267         ifam = NULL;
268         addrcount = 0;
269         while (next < lim) {
270             nextifm = (struct if_msghdr *)next;
271             if (nextifm->ifm_type != RTM_NEWADDR)
272                 break;
273             if (ifam == NULL)
274                 ifam = (struct ifa_msghdr *)nextifm;
275             addrcount++;
276             next += nextifm->ifm_msglen;
277         }
278         if ((ifm->ifm_flags & IFF_UP) == 0)
279             continue;           /* not up */
280         while (addrcount > 0) {
281             struct sockaddr_in *a;
282
283             info.rti_addrs = ifam->ifam_addrs;
284
285             /* Expand the compacted addresses */
286             rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
287                       &info);
288             if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) {
289                 addrcount--;
290                 continue;
291             }
292             a = (struct sockaddr_in *) info.rti_info[RTAX_IFA];
293
294             if (a->sin_addr.s_addr != htonl(0x7f000001) ) {
295                 if (count >= maxSize) { /* no more space */
296                     dpf(("Too many interfaces..ignoring 0x%x\n",
297                            a->sin_addr.s_addr));
298                 } else {
299                     struct ifreq ifr;
300                     
301                     addrBuffer[count] = a->sin_addr.s_addr;
302                     a = (struct sockaddr_in *) info.rti_info[RTAX_NETMASK];
303                     if (a)
304                         maskBuffer[count] = a->sin_addr.s_addr;
305                     else
306                         maskBuffer[count] = htonl(0xffffffff);
307                     memset(&ifr, 0, sizeof(ifr));
308                     ifr.ifr_addr.sa_family = AF_INET;
309                     strncpy(ifr.ifr_name, sdl->sdl_data, sdl->sdl_nlen);
310                     if (ioctl(s, SIOCGIFMTU, (caddr_t) & ifr) < 0)
311                         mtuBuffer[count] = htonl(1500);
312                     else
313                         mtuBuffer[count] = htonl(ifr.ifr_mtu);
314                     count++;
315                 }
316             }
317             addrcount--;
318             ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
319         }
320     }
321     free(buf);
322     return count;
323 }
324
325
326 int
327 rx_getAllAddr(afs_int32 buffer[], int maxSize)
328 {
329     return rx_getAllAddr_internal(buffer, maxSize, 0);
330 }
331 /* this function returns the total number of interface addresses
332 ** the buffer has to be passed in by the caller
333 */
334 #else
335 static int
336 rx_getAllAddr_internal(afs_int32 buffer[], int maxSize, int loopbacks)
337 {
338     int s;
339     int i, len, count = 0;
340     struct ifconf ifc;
341     struct ifreq ifs[NIFS], *ifr;
342     struct sockaddr_in *a;
343 #if    defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
344     char *cp, *cplim, *cpnext;  /* used only for AIX 41 */
345 #endif
346
347     s = socket(AF_INET, SOCK_DGRAM, 0);
348     if (s < 0)
349         return 0;
350     ifc.ifc_len = sizeof(ifs);
351     ifc.ifc_buf = (caddr_t) ifs;
352     i = ioctl(s, SIOCGIFCONF, &ifc);
353     if (i < 0)
354         return 0;
355     len = ifc.ifc_len / sizeof(struct ifreq);
356     if (len > NIFS)
357         len = NIFS;
358 #if    defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
359     if (ifc.ifc_len > sizeof(ifs))      /* safety check */
360         ifc.ifc_len = sizeof(ifs);
361     for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
362          cp < cplim;
363 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
364          cp += _SIZEOF_ADDR_IFREQ(*ifr)
365 #else
366 #ifdef AFS_AIX51_ENV
367          cp = cpnext
368 #else
369          cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))
370 #endif
371 #endif
372         ) 
373 #else
374     for (i = 0; i < len; ++i) 
375 #endif
376     {
377 #if    defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
378         ifr = (struct ifreq *)cp;
379 #else
380         ifr = &ifs[i];
381 #endif
382         a = (struct sockaddr_in *)&ifr->ifr_addr;
383 #ifdef AFS_AIX51_ENV
384         cpnext = cp + sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a));
385 #endif
386         if (a->sin_family != AF_INET)
387             continue;
388         if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
389             perror("SIOCGIFFLAGS");
390             continue;           /* ignore this address */
391         }
392         if (a->sin_addr.s_addr != 0) {
393             if (!loopbacks) {
394                 if (a->sin_addr.s_addr == htonl(0x7f000001)) 
395                     continue;   /* skip loopback address as well. */
396             } else {
397                 if (ifr->ifr_flags & IFF_LOOPBACK) 
398                     continue;   /* skip aliased loopbacks as well. */
399             }
400             if (count >= maxSize)       /* no more space */
401                 dpf(("Too many interfaces..ignoring 0x%x\n",
402                        a->sin_addr.s_addr));
403             else
404                 buffer[count++] = a->sin_addr.s_addr;
405         }
406     }
407     close(s);
408     return count;
409 }
410
411 int
412 rx_getAllAddr(afs_int32 buffer[], int maxSize)
413 {
414     return rx_getAllAddr_internal(buffer, maxSize, 0);
415 }
416
417 /* this function returns the total number of interface addresses
418  * the buffer has to be passed in by the caller. It also returns
419  * the interface mask. If AFS_USERSPACE_IP_ADDR is defined, it
420  * gets the mask which is then passed into the kernel and is used
421  * by afsi_SetServerIPRank().
422  */
423 int
424 rxi_getAllAddrMaskMtu(afs_int32 addrBuffer[], afs_int32 maskBuffer[],
425                       afs_int32 mtuBuffer[], int maxSize)
426 {
427     int s;
428     int i, len, count = 0;
429     struct ifconf ifc;
430     struct ifreq ifs[NIFS], *ifr;
431     struct sockaddr_in *a;
432 #if     defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
433     char *cp, *cplim;           /* used only for AIX 41 */
434 #endif
435
436 #if !defined(AFS_USERSPACE_IP_ADDR)
437     count = rx_getAllAddr_internal(addrBuffer, 1024, 0);
438     for (i = 0; i < count; i++) {
439         maskBuffer[i] = htonl(0xffffffff);
440         mtuBuffer[i] = htonl(1500);
441     }
442     return count;
443 #else /* AFS_USERSPACE_IP_ADDR */
444     s = socket(AF_INET, SOCK_DGRAM, 0);
445     if (s < 0)
446         return 0;
447
448     ifc.ifc_len = sizeof(ifs);
449     ifc.ifc_buf = (caddr_t) ifs;
450     i = ioctl(s, SIOCGIFCONF, &ifc);
451     if (i < 0) {
452         close(s);
453         return 0;
454     }
455     len = ifc.ifc_len / sizeof(struct ifreq);
456     if (len > NIFS)
457         len = NIFS;
458
459 #if     defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
460     if (ifc.ifc_len > sizeof(ifs))      /* safety check */
461         ifc.ifc_len = sizeof(ifs);
462     for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
463          cp < cplim;
464          cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))) {
465         ifr = (struct ifreq *)cp;
466 #else
467     for (i = 0; i < len; ++i) {
468         ifr = &ifs[i];
469 #endif
470         a = (struct sockaddr_in *)&ifr->ifr_addr;
471         if (a->sin_addr.s_addr != 0 && a->sin_family == AF_INET) {
472
473             if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
474                 perror("SIOCGIFFLAGS");
475                 continue;       /* ignore this address */
476             }
477
478             if (a->sin_addr.s_addr == htonl(0x7f000001) )
479                 continue;   /* skip loopback address as well. */
480
481             if (count >= maxSize) {     /* no more space */
482                 dpf(("Too many interfaces..ignoring 0x%x\n",
483                        a->sin_addr.s_addr));
484                 continue;
485             }
486
487             addrBuffer[count] = a->sin_addr.s_addr;
488
489             if (ioctl(s, SIOCGIFNETMASK, (caddr_t) ifr) < 0) {
490                 perror("SIOCGIFNETMASK");
491                 maskBuffer[count] = htonl(0xffffffff);
492             } else {
493                 maskBuffer[count] = (((struct sockaddr_in *)
494                                       (&ifr->ifr_addr))->sin_addr).s_addr;
495             }
496
497             mtuBuffer[count] = htonl(1500);
498 #ifdef SIOCGIFMTU
499             if (ioctl(s, SIOCGIFMTU, (caddr_t) ifr) < 0) {
500                 perror("SIOCGIFMTU");
501             } else {
502                 mtuBuffer[count] = htonl(ifr->ifr_metric);
503             }
504 #endif /* SIOCGIFMTU */
505 #ifdef SIOCRIPMTU
506             if (ioctl(s, SIOCRIPMTU, (caddr_t) ifr) < 0) {
507                 perror("SIOCRIPMTU");
508             } else {
509                 mtuBuffer[count] = htonl(ifr->ifr_metric);
510             }
511 #endif /* SIOCRIPMTU */
512
513             count++;
514         }
515     }
516     close(s);
517     return count;
518 #endif /* AFS_USERSPACE_IP_ADDR */
519 }
520 #endif
521
522 #endif /* ! AFS_NT40_ENV */
523 #endif /* !KERNEL || UKERNEL */