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