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