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