]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/net/getifmaddrs.c
lib: Remove ancient SCCS tags.
[FreeBSD/FreeBSD.git] / lib / libc / net / getifmaddrs.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2003 Bruce M. Simpson.
5  * All rights reserved
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include "namespace.h"
30 #include <sys/param.h>
31 #include <sys/sysctl.h>
32 #include <sys/ioctl.h>
33 #include <sys/socket.h>
34 #include <net/if.h>
35 #include <net/if_dl.h>
36 #include <net/route.h>
37
38 #include <errno.h>
39 #include <ifaddrs.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include "un-namespace.h"
43
44 #define SALIGN  (sizeof(long) - 1)
45 #define SA_RLEN(sa)     ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
46                             (SALIGN + 1))
47 #define MAX_SYSCTL_TRY  5
48 #define RTA_MASKS       (RTA_GATEWAY | RTA_IFP | RTA_IFA)
49
50 int
51 getifmaddrs(struct ifmaddrs **pif)
52 {
53         int icnt = 1;
54         int dcnt = 0;
55         int ntry = 0;
56         size_t len;
57         size_t needed;
58         int mib[6];
59         int i;
60         char *buf;
61         char *data;
62         char *next;
63         char *p;
64         struct ifma_msghdr *ifmam;
65         struct ifmaddrs *ifa, *ift;
66         struct rt_msghdr *rtm;
67         struct sockaddr *sa;
68
69         mib[0] = CTL_NET;
70         mib[1] = PF_ROUTE;
71         mib[2] = 0;             /* protocol */
72         mib[3] = 0;             /* wildcard address family */
73         mib[4] = NET_RT_IFMALIST;
74         mib[5] = 0;             /* no flags */
75         do {
76                 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
77                         return (-1);
78                 if ((buf = malloc(needed)) == NULL)
79                         return (-1);
80                 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
81                         if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
82                                 free(buf);
83                                 return (-1);
84                         }
85                         free(buf);
86                         buf = NULL;
87                 } 
88         } while (buf == NULL);
89
90         for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
91                 rtm = (struct rt_msghdr *)(void *)next;
92                 if (rtm->rtm_version != RTM_VERSION)
93                         continue;
94                 switch (rtm->rtm_type) {
95                 case RTM_NEWMADDR:
96                         ifmam = (struct ifma_msghdr *)(void *)rtm;
97                         if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
98                                 break;
99                         icnt++;
100                         p = (char *)(ifmam + 1);
101                         for (i = 0; i < RTAX_MAX; i++) {
102                                 if ((RTA_MASKS & ifmam->ifmam_addrs &
103                                     (1 << i)) == 0)
104                                         continue;
105                                 sa = (struct sockaddr *)(void *)p;
106                                 len = SA_RLEN(sa);
107                                 dcnt += len;
108                                 p += len;
109                         }
110                         break;
111                 }
112         }
113
114         data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt);
115         if (data == NULL) {
116                 free(buf);
117                 return (-1);
118         }
119
120         ifa = (struct ifmaddrs *)(void *)data;
121         data += sizeof(struct ifmaddrs) * icnt;
122
123         memset(ifa, 0, sizeof(struct ifmaddrs) * icnt);
124         ift = ifa;
125
126         for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
127                 rtm = (struct rt_msghdr *)(void *)next;
128                 if (rtm->rtm_version != RTM_VERSION)
129                         continue;
130
131                 switch (rtm->rtm_type) {
132                 case RTM_NEWMADDR:
133                         ifmam = (struct ifma_msghdr *)(void *)rtm;
134                         if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
135                                 break;
136
137                         p = (char *)(ifmam + 1);
138                         for (i = 0; i < RTAX_MAX; i++) {
139                                 if ((RTA_MASKS & ifmam->ifmam_addrs &
140                                     (1 << i)) == 0)
141                                         continue;
142                                 sa = (struct sockaddr *)(void *)p;
143                                 len = SA_RLEN(sa);
144                                 switch (i) {
145                                 case RTAX_GATEWAY:
146                                         ift->ifma_lladdr =
147                                             (struct sockaddr *)(void *)data;
148                                         memcpy(data, p, len);
149                                         data += len;
150                                         break;
151
152                                 case RTAX_IFP:
153                                         ift->ifma_name =
154                                             (struct sockaddr *)(void *)data;
155                                         memcpy(data, p, len);
156                                         data += len;
157                                         break;
158
159                                 case RTAX_IFA:
160                                         ift->ifma_addr =
161                                             (struct sockaddr *)(void *)data;
162                                         memcpy(data, p, len);
163                                         data += len;
164                                         break;
165
166                                 default:
167                                         data += len;
168                                         break;
169                                 }
170                                 p += len;
171                         }
172                         ift->ifma_next = ift + 1;
173                         ift = ift->ifma_next;
174                         break;
175                 }
176         }
177
178         free(buf);
179
180         if (ift > ifa) {
181                 ift--;
182                 ift->ifma_next = NULL;
183                 *pif = ifa;
184         } else {
185                 *pif = NULL;
186                 free(ifa);
187         }
188         return (0);
189 }
190
191 void
192 freeifmaddrs(struct ifmaddrs *ifmp)
193 {
194
195         free(ifmp);
196 }