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