reindent-20030715
[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(cp, cplim, rtinfo)
122      caddr_t cp, cplim;
123      struct rt_addrinfo *rtinfo;
124 {
125     struct sockaddr *sa;
126     int i;
127
128     memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
129     for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
130         if ((rtinfo->rti_addrs & (1 << i)) == 0)
131             continue;
132         rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
133         ADVANCE(cp, sa);
134     }
135 }
136 #endif
137
138
139 /* this function returns the total number of interface addresses 
140 ** the buffer has to be passed in by the caller
141 */
142 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
143 int
144 rx_getAllAddr(buffer, maxSize)
145      afs_int32 buffer[];
146      int maxSize;               /* sizeof of buffer in afs_int32 units */
147 {
148     size_t needed;
149     int mib[6];
150     struct if_msghdr *ifm, *nextifm;
151     struct ifa_msghdr *ifam;
152     struct sockaddr_dl *sdl;
153     struct rt_addrinfo info;
154     char *buf, *lim, *next;
155     int count = 0, addrcount = 0;
156
157     mib[0] = CTL_NET;
158     mib[1] = PF_ROUTE;
159     mib[2] = 0;
160     mib[3] = AF_INET;           /* address family */
161     mib[4] = NET_RT_IFLIST;
162     mib[5] = 0;
163     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
164         return 0;
165     if ((buf = malloc(needed)) == NULL)
166         return 0;
167     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
168         free(buf);
169         return 0;
170     }
171     lim = buf + needed;
172     next = buf;
173     while (next < lim) {
174         ifm = (struct if_msghdr *)next;
175         if (ifm->ifm_type != RTM_IFINFO) {
176             printf("out of sync parsing NET_RT_IFLIST\n");
177             free(buf);
178             return 0;
179         }
180         sdl = (struct sockaddr_dl *)(ifm + 1);
181         next += ifm->ifm_msglen;
182         ifam = NULL;
183         addrcount = 0;
184         while (next < lim) {
185             nextifm = (struct if_msghdr *)next;
186             if (nextifm->ifm_type != RTM_NEWADDR)
187                 break;
188             if (ifam == NULL)
189                 ifam = (struct ifa_msghdr *)nextifm;
190             addrcount++;
191             next += nextifm->ifm_msglen;
192         }
193         if ((ifm->ifm_flags & IFF_UP) == 0)
194             continue;           /* not up */
195         if (ifm->ifm_flags & IFF_LOOPBACK) {
196             continue;           /* skip aliased loopbacks as well. */
197         }
198         while (addrcount > 0) {
199             struct sockaddr_in *a;
200
201             info.rti_addrs = ifam->ifam_addrs;
202
203             /* Expand the compacted addresses */
204             rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
205                       &info);
206             if (info.rti_info[RTAX_IFA]->sa_family != AF_INET)
207                 continue;
208             a = info.rti_info[RTAX_IFA];
209
210             if (count >= maxSize)       /* no more space */
211                 printf("Too many interfaces..ignoring 0x%x\n",
212                        a->sin_addr.s_addr);
213             else
214                 buffer[count++] = a->sin_addr.s_addr;
215             addrcount--;
216             ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
217         }
218     }
219     free(buf);
220     return count;
221 }
222
223 int
224 rxi_getAllAddrMaskMtu(addrBuffer, maskBuffer, mtuBuffer, maxSize)
225      afs_int32 addrBuffer[];    /* the network addrs in net byte order */
226      afs_int32 maskBuffer[];    /* the subnet masks */
227      afs_int32 mtuBuffer[];     /* the MTU sizes */
228      int maxSize;               /* sizeof of buffer in afs_int32 units */
229 {
230     int s;
231
232     size_t needed;
233     int mib[6];
234     struct if_msghdr *ifm, *nextifm;
235     struct ifa_msghdr *ifam;
236     struct sockaddr_dl *sdl;
237     struct rt_addrinfo info;
238     char *buf, *lim, *next;
239     int count = 0, addrcount = 0;
240
241     mib[0] = CTL_NET;
242     mib[1] = PF_ROUTE;
243     mib[2] = 0;
244     mib[3] = AF_INET;           /* address family */
245     mib[4] = NET_RT_IFLIST;
246     mib[5] = 0;
247     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
248         return 0;
249     if ((buf = malloc(needed)) == NULL)
250         return 0;
251     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
252         free(buf);
253         return 0;
254     }
255     s = socket(PF_INET, SOCK_DGRAM, 0);
256     if (s < 0)
257         return 0;
258     lim = buf + needed;
259     next = buf;
260     while (next < lim) {
261         ifm = (struct if_msghdr *)next;
262         if (ifm->ifm_type != RTM_IFINFO) {
263             printf("out of sync parsing NET_RT_IFLIST\n");
264             free(buf);
265             return 0;
266         }
267         sdl = (struct sockaddr_dl *)(ifm + 1);
268         next += ifm->ifm_msglen;
269         ifam = NULL;
270         addrcount = 0;
271         while (next < lim) {
272             nextifm = (struct if_msghdr *)next;
273             if (nextifm->ifm_type != RTM_NEWADDR)
274                 break;
275             if (ifam == NULL)
276                 ifam = (struct ifa_msghdr *)nextifm;
277             addrcount++;
278             next += nextifm->ifm_msglen;
279         }
280         if ((ifm->ifm_flags & IFF_UP) == 0)
281             continue;           /* not up */
282         if (ifm->ifm_flags & IFF_LOOPBACK) {
283             continue;           /* skip aliased loopbacks as well. */
284         }
285         while (addrcount > 0) {
286             struct sockaddr_in *a;
287
288             info.rti_addrs = ifam->ifam_addrs;
289
290             /* Expand the compacted addresses */
291             rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
292                       &info);
293             if (info.rti_info[RTAX_IFA]->sa_family != AF_INET)
294                 continue;
295             a = info.rti_info[RTAX_IFA];
296
297             if (count >= maxSize) {     /* no more space */
298                 printf("Too many interfaces..ignoring 0x%x\n",
299                        a->sin_addr.s_addr);
300             } else {
301                 struct ifreq ifr;
302
303                 addrBuffer[count] = a->sin_addr.s_addr;
304                 a = info.rti_info[RTAX_NETMASK];
305                 if (a)
306                     maskBuffer[count] = a->sin_addr.s_addr;
307                 else
308                     maskBuffer[count] = htonl(0xffffffff);
309                 memset(&ifr, sizeof(ifr), 0);
310                 ifr.ifr_addr.sa_family = AF_INET;
311                 strncpy(ifr.ifr_name, sdl->sdl_data, sdl->sdl_nlen);
312                 if (ioctl(s, SIOCGIFMTU, (caddr_t) & ifr) < 0)
313                     mtuBuffer[count] = htonl(1500);
314                 else
315                     mtuBuffer[count] = htonl(ifr.ifr_mtu);
316                 count++;
317             }
318             addrcount--;
319             ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
320         }
321     }
322     free(buf);
323     return count;
324 }
325
326
327 #else
328 int
329 rx_getAllAddr(buffer, maxSize)
330      afs_int32 buffer[];
331      int maxSize;               /* sizeof of buffer in afs_int32 units */
332 {
333     int s;
334     int i, len, count = 0;
335     struct ifconf ifc;
336     struct ifreq ifs[NIFS], *ifr;
337     struct sockaddr_in *a;
338 #if    defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
339     char *cp, *cplim, *cpnext;  /* used only for AIX 41 */
340 #endif
341
342     s = socket(AF_INET, SOCK_DGRAM, 0);
343     if (s < 0)
344         return 0;
345     ifc.ifc_len = sizeof(ifs);
346     ifc.ifc_buf = (caddr_t) ifs;
347     i = ioctl(s, SIOCGIFCONF, &ifc);
348     if (i < 0)
349         return 0;
350     len = ifc.ifc_len / sizeof(struct ifreq);
351     if (len > NIFS)
352         len = NIFS;
353 #if    defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
354     if (ifc.ifc_len > sizeof(ifs))      /* safety check */
355         ifc.ifc_len = sizeof(ifs);
356     for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
357          cp < cplim;
358 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
359          cp += _SIZEOF_ADDR_IFREQ(*ifr))
360 #else
361 #ifdef AFS_AIX51_ENV
362          cp = cpnext)
363 #else
364          cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a)))
365 #endif
366 #endif
367     {
368         ifr = (struct ifreq *)cp;
369 #else
370     for (i = 0; i < len; ++i) {
371         ifr = &ifs[i];
372 #endif
373         a = (struct sockaddr_in *)&ifr->ifr_addr;
374 #ifdef AFS_AIX51_ENV
375         cpnext = cp + sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a));
376 #endif
377         if (a->sin_family != AF_INET)
378             continue;
379         if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
380             perror("SIOCGIFFLAGS");
381             continue;           /* ignore this address */
382         }
383         if (a->sin_addr.s_addr != 0) {
384             if (ifr->ifr_flags & IFF_LOOPBACK) {
385                 continue;       /* skip aliased loopbacks as well. */
386             }
387             if (count >= maxSize)       /* no more space */
388                 printf("Too many interfaces..ignoring 0x%x\n",
389                        a->sin_addr.s_addr);
390             else
391                 buffer[count++] = a->sin_addr.s_addr;
392         }
393     }
394     close(s);
395     return count;
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(addrBuffer, maskBuffer, mtuBuffer, maxSize)
406      afs_int32 addrBuffer[];    /* the network addrs in net byte order */
407      afs_int32 maskBuffer[];    /* the subnet masks */
408      afs_int32 mtuBuffer[];     /* the MTU sizes */
409      int maxSize;               /* sizeof of buffer in afs_int32 units */
410 {
411     int s;
412     int i, len, count = 0;
413     struct ifconf ifc;
414     struct ifreq ifs[NIFS], *ifr;
415     struct sockaddr_in *a;
416 #if     defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
417     char *cp, *cplim;           /* used only for AIX 41 */
418 #endif
419
420 #if !defined(AFS_USERSPACE_IP_ADDR)
421     count = rx_getAllAddr(addrBuffer, 1024);
422     for (i = 0; i < count; i++) {
423         maskBuffer[i] = htonl(0xffffffff);
424         mtuBuffer[i] = htonl(1500);
425     }
426     return count;
427 #else /* AFS_USERSPACE_IP_ADDR */
428     s = socket(AF_INET, SOCK_DGRAM, 0);
429     if (s < 0)
430         return 0;
431
432     ifc.ifc_len = sizeof(ifs);
433     ifc.ifc_buf = (caddr_t) ifs;
434     i = ioctl(s, SIOCGIFCONF, &ifc);
435     if (i < 0) {
436         close(s);
437         return 0;
438     }
439     len = ifc.ifc_len / sizeof(struct ifreq);
440     if (len > NIFS)
441         len = NIFS;
442
443 #if     defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
444     if (ifc.ifc_len > sizeof(ifs))      /* safety check */
445         ifc.ifc_len = sizeof(ifs);
446     for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
447          cp < cplim;
448          cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))) {
449         ifr = (struct ifreq *)cp;
450 #else
451     for (i = 0; i < len; ++i) {
452         ifr = &ifs[i];
453 #endif
454         a = (struct sockaddr_in *)&ifr->ifr_addr;
455         if (a->sin_addr.s_addr != 0 && a->sin_family == AF_INET) {
456
457             if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
458                 perror("SIOCGIFFLAGS");
459                 continue;       /* ignore this address */
460             }
461             if (ifr->ifr_flags & IFF_LOOPBACK) {
462                 continue;       /* skip aliased loopbacks as well. */
463             }
464
465             if (count >= maxSize) {     /* no more space */
466                 printf("Too many interfaces..ignoring 0x%x\n",
467                        a->sin_addr.s_addr);
468                 continue;
469             }
470
471             addrBuffer[count] = a->sin_addr.s_addr;
472
473             if (ioctl(s, SIOCGIFNETMASK, (caddr_t) ifr) < 0) {
474                 perror("SIOCGIFNETMASK");
475                 maskBuffer[count] = htonl(0xffffffff);
476             } else {
477                 maskBuffer[count] = (((struct sockaddr_in *)
478                                       (&ifr->ifr_addr))->sin_addr).s_addr;
479             }
480
481             mtuBuffer[count] = htonl(1500);
482 #ifdef SIOCGIFMTU
483             if (ioctl(s, SIOCGIFMTU, (caddr_t) ifr) < 0) {
484                 perror("SIOCGIFMTU");
485             } else {
486                 mtuBuffer[count] = htonl(ifr->ifr_metric);
487             }
488 #endif /* SIOCGIFMTU */
489 #ifdef SIOCRIPMTU
490             if (ioctl(s, SIOCRIPMTU, (caddr_t) ifr) < 0) {
491                 perror("SIOCRIPMTU");
492             } else {
493                 mtuBuffer[count] = htonl(ifr->ifr_metric);
494             }
495 #endif /* SIOCRIPMTU */
496
497             count++;
498         }
499     }
500     close(s);
501     return count;
502 #endif /* AFS_USERSPACE_IP_ADDR */
503 }
504 #endif
505
506 #endif /* ! AFS_NT40_ENV */
507 #endif /* !KERNEL || UKERNEL */
508
509 #endif /* !AFS_DJGPP_ENV */