windows-version-bump-20041109
[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 AFS_DJGPP_ENV
17 #ifndef KERNEL
18 #ifndef AFS_NT40_ENV
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/time.h>
22 #include <net/if.h>
23 #include <netinet/in.h>
24 #include <sys/ioctl.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 #endif
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(afs_int32 buffer[], int maxSize)
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             printf("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         if (ifm->ifm_flags & IFF_LOOPBACK) {
192             continue;           /* skip aliased loopbacks as well. */
193         }
194         while (addrcount > 0) {
195             struct sockaddr_in *a;
196
197             info.rti_addrs = ifam->ifam_addrs;
198
199             /* Expand the compacted addresses */
200             rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
201                       &info);
202             if (info.rti_info[RTAX_IFA]->sa_family != AF_INET)
203                 continue;
204             a = info.rti_info[RTAX_IFA];
205
206             if (count >= maxSize)       /* no more space */
207                 printf("Too many interfaces..ignoring 0x%x\n",
208                        a->sin_addr.s_addr);
209             else
210                 buffer[count++] = a->sin_addr.s_addr;
211             addrcount--;
212             ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
213         }
214     }
215     free(buf);
216     return count;
217 }
218
219 int
220 rxi_getAllAddrMaskMtu(afs_int32 addrBuffer[], afs_int32 maskBuffer[],
221                       afs_int32 mtuBuffer[], int maxSize)
222 {
223     int s;
224
225     size_t needed;
226     int mib[6];
227     struct if_msghdr *ifm, *nextifm;
228     struct ifa_msghdr *ifam;
229     struct sockaddr_dl *sdl;
230     struct rt_addrinfo info;
231     char *buf, *lim, *next;
232     int count = 0, addrcount = 0;
233
234     mib[0] = CTL_NET;
235     mib[1] = PF_ROUTE;
236     mib[2] = 0;
237     mib[3] = AF_INET;           /* address family */
238     mib[4] = NET_RT_IFLIST;
239     mib[5] = 0;
240     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
241         return 0;
242     if ((buf = malloc(needed)) == NULL)
243         return 0;
244     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
245         free(buf);
246         return 0;
247     }
248     s = socket(PF_INET, SOCK_DGRAM, 0);
249     if (s < 0)
250         return 0;
251     lim = buf + needed;
252     next = buf;
253     while (next < lim) {
254         ifm = (struct if_msghdr *)next;
255         if (ifm->ifm_type != RTM_IFINFO) {
256             printf("out of sync parsing NET_RT_IFLIST\n");
257             free(buf);
258             return 0;
259         }
260         sdl = (struct sockaddr_dl *)(ifm + 1);
261         next += ifm->ifm_msglen;
262         ifam = NULL;
263         addrcount = 0;
264         while (next < lim) {
265             nextifm = (struct if_msghdr *)next;
266             if (nextifm->ifm_type != RTM_NEWADDR)
267                 break;
268             if (ifam == NULL)
269                 ifam = (struct ifa_msghdr *)nextifm;
270             addrcount++;
271             next += nextifm->ifm_msglen;
272         }
273         if ((ifm->ifm_flags & IFF_UP) == 0)
274             continue;           /* not up */
275         while (addrcount > 0) {
276             struct sockaddr_in *a;
277
278             info.rti_addrs = ifam->ifam_addrs;
279
280             /* Expand the compacted addresses */
281             rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
282                       &info);
283             if (info.rti_info[RTAX_IFA]->sa_family != AF_INET)
284                 continue;
285             a = info.rti_info[RTAX_IFA];
286
287             if (count >= maxSize) {     /* no more space */
288                 printf("Too many interfaces..ignoring 0x%x\n",
289                        a->sin_addr.s_addr);
290             } else {
291                 struct ifreq ifr;
292
293                 addrBuffer[count] = a->sin_addr.s_addr;
294                 a = info.rti_info[RTAX_NETMASK];
295                 if (a)
296                     maskBuffer[count] = a->sin_addr.s_addr;
297                 else
298                     maskBuffer[count] = htonl(0xffffffff);
299                 memset(&ifr, sizeof(ifr), 0);
300                 ifr.ifr_addr.sa_family = AF_INET;
301                 strncpy(ifr.ifr_name, sdl->sdl_data, sdl->sdl_nlen);
302                 if (ioctl(s, SIOCGIFMTU, (caddr_t) & ifr) < 0)
303                     mtuBuffer[count] = htonl(1500);
304                 else
305                     mtuBuffer[count] = htonl(ifr.ifr_mtu);
306                 count++;
307             }
308             addrcount--;
309             ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
310         }
311     }
312     free(buf);
313     return count;
314 }
315 #else
316 static int
317 rx_getAllAddr_internal(afs_int32 buffer[], int maxSize, int loopbacks)
318 {
319     int s;
320     int i, len, count = 0;
321     struct ifconf ifc;
322     struct ifreq ifs[NIFS], *ifr;
323     struct sockaddr_in *a;
324 #if    defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
325     char *cp, *cplim, *cpnext;  /* used only for AIX 41 */
326 #endif
327
328     s = socket(AF_INET, SOCK_DGRAM, 0);
329     if (s < 0)
330         return 0;
331     ifc.ifc_len = sizeof(ifs);
332     ifc.ifc_buf = (caddr_t) ifs;
333     i = ioctl(s, SIOCGIFCONF, &ifc);
334     if (i < 0)
335         return 0;
336     len = ifc.ifc_len / sizeof(struct ifreq);
337     if (len > NIFS)
338         len = NIFS;
339 #if    defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
340     if (ifc.ifc_len > sizeof(ifs))      /* safety check */
341         ifc.ifc_len = sizeof(ifs);
342     for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
343          cp < cplim;
344 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
345          cp += _SIZEOF_ADDR_IFREQ(*ifr)
346 #else
347 #ifdef AFS_AIX51_ENV
348          cp = cpnext
349 #else
350          cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))
351 #endif
352 #endif
353         ) 
354 #else
355     for (i = 0; i < len; ++i) 
356 #endif
357     {
358 #if    defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
359         ifr = (struct ifreq *)cp;
360 #else
361         ifr = &ifs[i];
362 #endif
363         a = (struct sockaddr_in *)&ifr->ifr_addr;
364 #ifdef AFS_AIX51_ENV
365         cpnext = cp + sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a));
366 #endif
367         if (a->sin_family != AF_INET)
368             continue;
369         if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
370             perror("SIOCGIFFLAGS");
371             continue;           /* ignore this address */
372         }
373         if (a->sin_addr.s_addr != 0) {
374             if (!loopbacks) {
375                 if (a->sin_addr.s_addr == htonl(0x7f000001)) 
376                     continue;   /* skip loopback address as well. */
377             } else {
378                 if (ifr->ifr_flags & IFF_LOOPBACK) 
379                     continue;   /* skip aliased loopbacks as well. */
380             }
381             if (count >= maxSize)       /* no more space */
382                 printf("Too many interfaces..ignoring 0x%x\n",
383                        a->sin_addr.s_addr);
384             else
385                 buffer[count++] = a->sin_addr.s_addr;
386         }
387     }
388     close(s);
389     return count;
390 }
391
392 int
393 rx_getAllAddr(afs_int32 buffer[], int maxSize)
394 {
395     return rx_getAllAddr_internal(buffer, maxSize, 0);
396 }
397
398 /* this function returns the total number of interface addresses
399  * the buffer has to be passed in by the caller. It also returns
400  * the interface mask. If AFS_USERSPACE_IP_ADDR is defined, it
401  * gets the mask which is then passed into the kernel and is used
402  * by afsi_SetServerIPRank().
403  */
404 int
405 rxi_getAllAddrMaskMtu(afs_int32 addrBuffer[], afs_int32 maskBuffer[],
406                       afs_int32 mtuBuffer[], int maxSize)
407 {
408     int s;
409     int i, len, count = 0;
410     struct ifconf ifc;
411     struct ifreq ifs[NIFS], *ifr;
412     struct sockaddr_in *a;
413 #if     defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
414     char *cp, *cplim;           /* used only for AIX 41 */
415 #endif
416
417 #if !defined(AFS_USERSPACE_IP_ADDR)
418     count = rx_getAllAddr_internal(addrBuffer, 1024, 1);
419     for (i = 0; i < count; i++) {
420         maskBuffer[i] = htonl(0xffffffff);
421         mtuBuffer[i] = htonl(1500);
422     }
423     return count;
424 #else /* AFS_USERSPACE_IP_ADDR */
425     s = socket(AF_INET, SOCK_DGRAM, 0);
426     if (s < 0)
427         return 0;
428
429     ifc.ifc_len = sizeof(ifs);
430     ifc.ifc_buf = (caddr_t) ifs;
431     i = ioctl(s, SIOCGIFCONF, &ifc);
432     if (i < 0) {
433         close(s);
434         return 0;
435     }
436     len = ifc.ifc_len / sizeof(struct ifreq);
437     if (len > NIFS)
438         len = NIFS;
439
440 #if     defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
441     if (ifc.ifc_len > sizeof(ifs))      /* safety check */
442         ifc.ifc_len = sizeof(ifs);
443     for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
444          cp < cplim;
445          cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))) {
446         ifr = (struct ifreq *)cp;
447 #else
448     for (i = 0; i < len; ++i) {
449         ifr = &ifs[i];
450 #endif
451         a = (struct sockaddr_in *)&ifr->ifr_addr;
452         if (a->sin_addr.s_addr != 0 && a->sin_family == AF_INET) {
453
454             if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
455                 perror("SIOCGIFFLAGS");
456                 continue;       /* ignore this address */
457             }
458
459             if (count >= maxSize) {     /* no more space */
460                 printf("Too many interfaces..ignoring 0x%x\n",
461                        a->sin_addr.s_addr);
462                 continue;
463             }
464
465             addrBuffer[count] = a->sin_addr.s_addr;
466
467             if (ioctl(s, SIOCGIFNETMASK, (caddr_t) ifr) < 0) {
468                 perror("SIOCGIFNETMASK");
469                 maskBuffer[count] = htonl(0xffffffff);
470             } else {
471                 maskBuffer[count] = (((struct sockaddr_in *)
472                                       (&ifr->ifr_addr))->sin_addr).s_addr;
473             }
474
475             mtuBuffer[count] = htonl(1500);
476 #ifdef SIOCGIFMTU
477             if (ioctl(s, SIOCGIFMTU, (caddr_t) ifr) < 0) {
478                 perror("SIOCGIFMTU");
479             } else {
480                 mtuBuffer[count] = htonl(ifr->ifr_metric);
481             }
482 #endif /* SIOCGIFMTU */
483 #ifdef SIOCRIPMTU
484             if (ioctl(s, SIOCRIPMTU, (caddr_t) ifr) < 0) {
485                 perror("SIOCRIPMTU");
486             } else {
487                 mtuBuffer[count] = htonl(ifr->ifr_metric);
488             }
489 #endif /* SIOCRIPMTU */
490
491             count++;
492         }
493     }
494     close(s);
495     return count;
496 #endif /* AFS_USERSPACE_IP_ADDR */
497 }
498 #endif
499
500 #endif /* ! AFS_NT40_ENV */
501 #endif /* !KERNEL || UKERNEL */
502
503 #endif /* !AFS_DJGPP_ENV */