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