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