/src/usrsctp/usrsctplib/netinet/sctp_bsd_addr.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*- |
2 | | * SPDX-License-Identifier: BSD-3-Clause |
3 | | * |
4 | | * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. |
5 | | * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. |
6 | | * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. |
7 | | * |
8 | | * Redistribution and use in source and binary forms, with or without |
9 | | * modification, are permitted provided that the following conditions are met: |
10 | | * |
11 | | * a) Redistributions of source code must retain the above copyright notice, |
12 | | * this list of conditions and the following disclaimer. |
13 | | * |
14 | | * b) Redistributions in binary form must reproduce the above copyright |
15 | | * notice, this list of conditions and the following disclaimer in |
16 | | * the documentation and/or other materials provided with the distribution. |
17 | | * |
18 | | * c) Neither the name of Cisco Systems, Inc. nor the names of its |
19 | | * contributors may be used to endorse or promote products derived |
20 | | * from this software without specific prior written permission. |
21 | | * |
22 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
23 | | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
24 | | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
26 | | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
27 | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
28 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
29 | | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
30 | | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
31 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
32 | | * THE POSSIBILITY OF SUCH DAMAGE. |
33 | | */ |
34 | | |
35 | | #include <netinet/sctp_os.h> |
36 | | #include <netinet/sctp_var.h> |
37 | | #include <netinet/sctp_pcb.h> |
38 | | #include <netinet/sctp_header.h> |
39 | | #include <netinet/sctputil.h> |
40 | | #include <netinet/sctp_output.h> |
41 | | #include <netinet/sctp_bsd_addr.h> |
42 | | #include <netinet/sctp_uio.h> |
43 | | #include <netinet/sctputil.h> |
44 | | #include <netinet/sctp_timer.h> |
45 | | #include <netinet/sctp_asconf.h> |
46 | | #include <netinet/sctp_sysctl.h> |
47 | | #include <netinet/sctp_indata.h> |
48 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
49 | | #include <sys/unistd.h> |
50 | | #endif |
51 | | |
52 | | /* Declare all of our malloc named types */ |
53 | | MALLOC_DEFINE(SCTP_M_MAP, "sctp_map", "sctp asoc map descriptor"); |
54 | | MALLOC_DEFINE(SCTP_M_STRMI, "sctp_stri", "sctp stream in array"); |
55 | | MALLOC_DEFINE(SCTP_M_STRMO, "sctp_stro", "sctp stream out array"); |
56 | | MALLOC_DEFINE(SCTP_M_ASC_ADDR, "sctp_aadr", "sctp asconf address"); |
57 | | MALLOC_DEFINE(SCTP_M_ASC_IT, "sctp_a_it", "sctp asconf iterator"); |
58 | | MALLOC_DEFINE(SCTP_M_AUTH_CL, "sctp_atcl", "sctp auth chunklist"); |
59 | | MALLOC_DEFINE(SCTP_M_AUTH_KY, "sctp_atky", "sctp auth key"); |
60 | | MALLOC_DEFINE(SCTP_M_AUTH_HL, "sctp_athm", "sctp auth hmac list"); |
61 | | MALLOC_DEFINE(SCTP_M_AUTH_IF, "sctp_athi", "sctp auth info"); |
62 | | MALLOC_DEFINE(SCTP_M_STRESET, "sctp_stre", "sctp stream reset"); |
63 | | MALLOC_DEFINE(SCTP_M_CMSG, "sctp_cmsg", "sctp CMSG buffer"); |
64 | | MALLOC_DEFINE(SCTP_M_COPYAL, "sctp_cpal", "sctp copy all"); |
65 | | MALLOC_DEFINE(SCTP_M_VRF, "sctp_vrf", "sctp vrf struct"); |
66 | | MALLOC_DEFINE(SCTP_M_IFA, "sctp_ifa", "sctp ifa struct"); |
67 | | MALLOC_DEFINE(SCTP_M_IFN, "sctp_ifn", "sctp ifn struct"); |
68 | | MALLOC_DEFINE(SCTP_M_TIMW, "sctp_timw", "sctp time block"); |
69 | | MALLOC_DEFINE(SCTP_M_MVRF, "sctp_mvrf", "sctp mvrf pcb list"); |
70 | | MALLOC_DEFINE(SCTP_M_ITER, "sctp_iter", "sctp iterator control"); |
71 | | MALLOC_DEFINE(SCTP_M_SOCKOPT, "sctp_socko", "sctp socket option"); |
72 | | MALLOC_DEFINE(SCTP_M_MCORE, "sctp_mcore", "sctp mcore queue"); |
73 | | |
74 | | /* Global NON-VNET structure that controls the iterator */ |
75 | | struct iterator_control sctp_it_ctl; |
76 | | #if !(defined(__FreeBSD__) && !defined(__Userspace__)) |
77 | | |
78 | | static void |
79 | | sctp_cleanup_itqueue(void) |
80 | 0 | { |
81 | 0 | struct sctp_iterator *it, *nit; |
82 | |
|
83 | 0 | TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) { |
84 | 0 | if (it->function_atend != NULL) { |
85 | 0 | (*it->function_atend) (it->pointer, it->val); |
86 | 0 | } |
87 | 0 | TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); |
88 | 0 | SCTP_FREE(it, SCTP_M_ITER); |
89 | 0 | } |
90 | 0 | } |
91 | | #endif |
92 | | #if defined(__Userspace__) |
93 | | /*__Userspace__ TODO if we use thread based iterator |
94 | | * then the implementation of wakeup will need to change. |
95 | | * Currently we are using timeo_cond for ident so_timeo |
96 | | * but that is not sufficient if we need to use another ident |
97 | | * like wakeup(&sctppcbinfo.iterator_running); |
98 | | */ |
99 | | #endif |
100 | | |
101 | | void |
102 | | sctp_wakeup_iterator(void) |
103 | 0 | { |
104 | 0 | #if defined(SCTP_PROCESS_LEVEL_LOCKS) |
105 | | #if defined(_WIN32) |
106 | | WakeAllConditionVariable(&sctp_it_ctl.iterator_wakeup); |
107 | | #else |
108 | 0 | pthread_cond_broadcast(&sctp_it_ctl.iterator_wakeup); |
109 | 0 | #endif |
110 | | #else |
111 | | wakeup(&sctp_it_ctl.iterator_running); |
112 | | #endif |
113 | 0 | } |
114 | | |
115 | | #if defined(__Userspace__) |
116 | | static void * |
117 | | #else |
118 | | static void |
119 | | #endif |
120 | | sctp_iterator_thread(void *v SCTP_UNUSED) |
121 | 3 | { |
122 | 3 | #if defined(__Userspace__) |
123 | 3 | sctp_userspace_set_threadname("SCTP iterator"); |
124 | 3 | #endif |
125 | 3 | SCTP_IPI_ITERATOR_WQ_LOCK(); |
126 | | /* In FreeBSD this thread never terminates. */ |
127 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
128 | | for (;;) { |
129 | | #else |
130 | 6 | while ((sctp_it_ctl.iterator_flags & SCTP_ITERATOR_MUST_EXIT) == 0) { |
131 | 3 | #endif |
132 | | #if !defined(__Userspace__) |
133 | | msleep(&sctp_it_ctl.iterator_running, |
134 | | #if defined(__FreeBSD__) |
135 | | &sctp_it_ctl.ipi_iterator_wq_mtx, |
136 | | #elif defined(__APPLE__) |
137 | | sctp_it_ctl.ipi_iterator_wq_mtx, |
138 | | #endif |
139 | | 0, "waiting_for_work", 0); |
140 | | #else |
141 | | #if defined(_WIN32) |
142 | | SleepConditionVariableCS(&sctp_it_ctl.iterator_wakeup, &sctp_it_ctl.ipi_iterator_wq_mtx, INFINITE); |
143 | | #else |
144 | 3 | pthread_cond_wait(&sctp_it_ctl.iterator_wakeup, &sctp_it_ctl.ipi_iterator_wq_mtx); |
145 | 3 | #endif |
146 | 3 | #endif |
147 | 3 | #if !(defined(__FreeBSD__) && !defined(__Userspace__)) |
148 | 3 | if (sctp_it_ctl.iterator_flags & SCTP_ITERATOR_MUST_EXIT) { |
149 | 0 | break; |
150 | 0 | } |
151 | 3 | #endif |
152 | 3 | sctp_iterator_worker(); |
153 | 3 | } |
154 | 3 | #if !(defined(__FreeBSD__) && !defined(__Userspace__)) |
155 | | /* Now this thread needs to be terminated */ |
156 | 3 | sctp_cleanup_itqueue(); |
157 | 3 | sctp_it_ctl.iterator_flags |= SCTP_ITERATOR_EXITED; |
158 | 3 | SCTP_IPI_ITERATOR_WQ_UNLOCK(); |
159 | 3 | #if defined(__Userspace__) |
160 | 3 | sctp_wakeup_iterator(); |
161 | 3 | return (NULL); |
162 | | #else |
163 | | wakeup(&sctp_it_ctl.iterator_flags); |
164 | | thread_terminate(current_thread()); |
165 | | #ifdef INVARIANTS |
166 | | panic("Hmm. thread_terminate() continues..."); |
167 | | #endif |
168 | | #endif |
169 | 3 | #endif |
170 | 3 | } |
171 | | |
172 | | void |
173 | | sctp_startup_iterator(void) |
174 | 3 | { |
175 | 3 | if (sctp_it_ctl.thread_proc) { |
176 | | /* You only get one */ |
177 | 0 | return; |
178 | 0 | } |
179 | | /* Initialize global locks here, thus only once. */ |
180 | 3 | SCTP_ITERATOR_LOCK_INIT(); |
181 | 3 | SCTP_IPI_ITERATOR_WQ_INIT(); |
182 | 3 | TAILQ_INIT(&sctp_it_ctl.iteratorhead); |
183 | 3 | #if defined(__Userspace__) |
184 | 3 | if (sctp_userspace_thread_create(&sctp_it_ctl.thread_proc, &sctp_iterator_thread)) { |
185 | 0 | SCTP_PRINTF("ERROR: Creating sctp_iterator_thread failed.\n"); |
186 | 3 | } else { |
187 | 3 | SCTP_BASE_VAR(iterator_thread_started) = 1; |
188 | 3 | } |
189 | | #elif defined(__FreeBSD__) |
190 | | kproc_create(sctp_iterator_thread, |
191 | | (void *)NULL, |
192 | | &sctp_it_ctl.thread_proc, |
193 | | 0, |
194 | | SCTP_KTHREAD_PAGES, |
195 | | SCTP_KTRHEAD_NAME); |
196 | | #elif defined(__APPLE__) |
197 | | kernel_thread_start((thread_continue_t)sctp_iterator_thread, NULL, &sctp_it_ctl.thread_proc); |
198 | | #endif |
199 | 3 | } |
200 | | |
201 | | #ifdef INET6 |
202 | | |
203 | | #if defined(__Userspace__) |
204 | | /* __Userspace__ TODO. struct in6_ifaddr is defined in sys/netinet6/in6_var.h |
205 | | ip6_use_deprecated is defined as int ip6_use_deprecated = 1; in /src/sys/netinet6/in6_proto.c |
206 | | */ |
207 | | void |
208 | | sctp_gather_internal_ifa_flags(struct sctp_ifa *ifa) |
209 | 0 | { |
210 | 0 | return; /* stub */ |
211 | 0 | } |
212 | | #else |
213 | | void |
214 | | sctp_gather_internal_ifa_flags(struct sctp_ifa *ifa) |
215 | | { |
216 | | struct in6_ifaddr *ifa6; |
217 | | |
218 | | ifa6 = (struct in6_ifaddr *)ifa->ifa; |
219 | | ifa->flags = ifa6->ia6_flags; |
220 | | if (!MODULE_GLOBAL(ip6_use_deprecated)) { |
221 | | if (ifa->flags & |
222 | | IN6_IFF_DEPRECATED) { |
223 | | ifa->localifa_flags |= SCTP_ADDR_IFA_UNUSEABLE; |
224 | | } else { |
225 | | ifa->localifa_flags &= ~SCTP_ADDR_IFA_UNUSEABLE; |
226 | | } |
227 | | } else { |
228 | | ifa->localifa_flags &= ~SCTP_ADDR_IFA_UNUSEABLE; |
229 | | } |
230 | | if (ifa->flags & |
231 | | (IN6_IFF_DETACHED | |
232 | | IN6_IFF_ANYCAST | |
233 | | IN6_IFF_NOTREADY)) { |
234 | | ifa->localifa_flags |= SCTP_ADDR_IFA_UNUSEABLE; |
235 | | } else { |
236 | | ifa->localifa_flags &= ~SCTP_ADDR_IFA_UNUSEABLE; |
237 | | } |
238 | | } |
239 | | #endif /* __Userspace__ */ |
240 | | #endif /* INET6 */ |
241 | | |
242 | | #if !defined(__Userspace__) |
243 | | static uint32_t |
244 | | sctp_is_desired_interface_type(struct ifnet *ifn) |
245 | | { |
246 | | int result; |
247 | | |
248 | | /* check the interface type to see if it's one we care about */ |
249 | | #if defined(__APPLE__) && !defined(__Userspace__) |
250 | | switch(ifnet_type(ifn)) { |
251 | | #else |
252 | | switch (ifn->if_type) { |
253 | | #endif |
254 | | case IFT_ETHER: |
255 | | case IFT_ISO88023: |
256 | | case IFT_ISO88024: |
257 | | case IFT_ISO88025: |
258 | | case IFT_ISO88026: |
259 | | case IFT_STARLAN: |
260 | | case IFT_P10: |
261 | | case IFT_P80: |
262 | | case IFT_HY: |
263 | | case IFT_FDDI: |
264 | | case IFT_XETHER: |
265 | | case IFT_ISDNBASIC: |
266 | | case IFT_ISDNPRIMARY: |
267 | | case IFT_PTPSERIAL: |
268 | | case IFT_OTHER: |
269 | | case IFT_PPP: |
270 | | case IFT_LOOP: |
271 | | case IFT_SLIP: |
272 | | case IFT_GIF: |
273 | | case IFT_L2VLAN: |
274 | | case IFT_STF: |
275 | | #if !(defined(__APPLE__) && !defined(__Userspace__)) |
276 | | case IFT_IP: |
277 | | case IFT_IPOVERCDLC: |
278 | | case IFT_IPOVERCLAW: |
279 | | case IFT_PROPVIRTUAL: /* NetGraph Virtual too */ |
280 | | case IFT_VIRTUALIPADDRESS: |
281 | | #endif |
282 | | result = 1; |
283 | | break; |
284 | | default: |
285 | | result = 0; |
286 | | } |
287 | | |
288 | | return (result); |
289 | | } |
290 | | #endif |
291 | | #if defined(__APPLE__) && !defined(__Userspace__) |
292 | | |
293 | | int |
294 | | sctp_is_vmware_interface(struct ifnet *ifn) |
295 | | { |
296 | | return (strncmp(ifnet_name(ifn), "vmnet", 5) == 0); |
297 | | } |
298 | | |
299 | | #endif |
300 | | |
301 | | #if defined(_WIN32) && defined(__Userspace__) |
302 | | #ifdef MALLOC |
303 | | #undef MALLOC |
304 | | #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) |
305 | | #endif |
306 | | #ifdef FREE |
307 | | #undef FREE |
308 | | #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) |
309 | | #endif |
310 | | static void |
311 | | sctp_init_ifns_for_vrf(int vrfid) |
312 | | { |
313 | | #if defined(INET) || defined(INET6) |
314 | | struct sctp_ifa *sctp_ifa; |
315 | | DWORD Err, AdapterAddrsSize; |
316 | | PIP_ADAPTER_ADDRESSES pAdapterAddrs, pAdapt; |
317 | | PIP_ADAPTER_UNICAST_ADDRESS pUnicast; |
318 | | #endif |
319 | | |
320 | | #ifdef INET |
321 | | AdapterAddrsSize = 0; |
322 | | |
323 | | if ((Err = GetAdaptersAddresses(AF_INET, 0, NULL, NULL, &AdapterAddrsSize)) != 0) { |
324 | | if ((Err != ERROR_BUFFER_OVERFLOW) && (Err != ERROR_INSUFFICIENT_BUFFER)) { |
325 | | SCTP_PRINTF("GetAdaptersV4Addresses() sizing failed with error code %d\n", Err); |
326 | | SCTP_PRINTF("err = %d; AdapterAddrsSize = %d\n", Err, AdapterAddrsSize); |
327 | | return; |
328 | | } |
329 | | } |
330 | | |
331 | | /* Allocate memory from sizing information */ |
332 | | if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) { |
333 | | SCTP_PRINTF("Memory allocation error!\n"); |
334 | | return; |
335 | | } |
336 | | /* Get actual adapter information */ |
337 | | if ((Err = GetAdaptersAddresses(AF_INET, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) { |
338 | | SCTP_PRINTF("GetAdaptersV4Addresses() failed with error code %d\n", Err); |
339 | | FREE(pAdapterAddrs); |
340 | | return; |
341 | | } |
342 | | /* Enumerate through each returned adapter and save its information */ |
343 | | for (pAdapt = pAdapterAddrs; pAdapt; pAdapt = pAdapt->Next) { |
344 | | if (pAdapt->IfType == IF_TYPE_IEEE80211 || pAdapt->IfType == IF_TYPE_ETHERNET_CSMACD) { |
345 | | for (pUnicast = pAdapt->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) { |
346 | | if (IN4_ISLINKLOCAL_ADDRESS(&(((struct sockaddr_in *)(pUnicast->Address.lpSockaddr))->sin_addr))) { |
347 | | continue; |
348 | | } |
349 | | sctp_ifa = sctp_add_addr_to_vrf(0, |
350 | | NULL, |
351 | | pAdapt->IfIndex, |
352 | | (pAdapt->IfType == IF_TYPE_IEEE80211)?MIB_IF_TYPE_ETHERNET:pAdapt->IfType, |
353 | | pAdapt->AdapterName, |
354 | | NULL, |
355 | | pUnicast->Address.lpSockaddr, |
356 | | pAdapt->Flags, |
357 | | 0); |
358 | | if (sctp_ifa) { |
359 | | sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; |
360 | | } |
361 | | } |
362 | | } |
363 | | } |
364 | | FREE(pAdapterAddrs); |
365 | | #endif |
366 | | #ifdef INET6 |
367 | | AdapterAddrsSize = 0; |
368 | | |
369 | | if ((Err = GetAdaptersAddresses(AF_INET6, 0, NULL, NULL, &AdapterAddrsSize)) != 0) { |
370 | | if ((Err != ERROR_BUFFER_OVERFLOW) && (Err != ERROR_INSUFFICIENT_BUFFER)) { |
371 | | SCTP_PRINTF("GetAdaptersV6Addresses() sizing failed with error code %d\n", Err); |
372 | | SCTP_PRINTF("err = %d; AdapterAddrsSize = %d\n", Err, AdapterAddrsSize); |
373 | | return; |
374 | | } |
375 | | } |
376 | | /* Allocate memory from sizing information */ |
377 | | if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) { |
378 | | SCTP_PRINTF("Memory allocation error!\n"); |
379 | | return; |
380 | | } |
381 | | /* Get actual adapter information */ |
382 | | if ((Err = GetAdaptersAddresses(AF_INET6, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) { |
383 | | SCTP_PRINTF("GetAdaptersV6Addresses() failed with error code %d\n", Err); |
384 | | FREE(pAdapterAddrs); |
385 | | return; |
386 | | } |
387 | | /* Enumerate through each returned adapter and save its information */ |
388 | | for (pAdapt = pAdapterAddrs; pAdapt; pAdapt = pAdapt->Next) { |
389 | | if (pAdapt->IfType == IF_TYPE_IEEE80211 || pAdapt->IfType == IF_TYPE_ETHERNET_CSMACD) { |
390 | | for (pUnicast = pAdapt->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) { |
391 | | sctp_ifa = sctp_add_addr_to_vrf(0, |
392 | | NULL, |
393 | | pAdapt->Ipv6IfIndex, |
394 | | (pAdapt->IfType == IF_TYPE_IEEE80211)?MIB_IF_TYPE_ETHERNET:pAdapt->IfType, |
395 | | pAdapt->AdapterName, |
396 | | NULL, |
397 | | pUnicast->Address.lpSockaddr, |
398 | | pAdapt->Flags, |
399 | | 0); |
400 | | if (sctp_ifa) { |
401 | | sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; |
402 | | } |
403 | | } |
404 | | } |
405 | | } |
406 | | FREE(pAdapterAddrs); |
407 | | #endif |
408 | | } |
409 | | #elif defined(__Userspace__) |
410 | | static void |
411 | | sctp_init_ifns_for_vrf(int vrfid) |
412 | 3 | { |
413 | 3 | #if defined(INET) || defined(INET6) |
414 | 3 | int rc; |
415 | 3 | struct ifaddrs *ifa, *ifas; |
416 | 3 | struct sctp_ifa *sctp_ifa; |
417 | 3 | uint32_t ifa_flags; |
418 | | |
419 | 3 | rc = getifaddrs(&ifas); |
420 | 3 | if (rc != 0) { |
421 | 0 | return; |
422 | 0 | } |
423 | 15 | for (ifa = ifas; ifa; ifa = ifa->ifa_next) { |
424 | 12 | if (ifa->ifa_addr == NULL) { |
425 | 0 | continue; |
426 | 0 | } |
427 | | #if !defined(INET) |
428 | | if (ifa->ifa_addr->sa_family != AF_INET6) { |
429 | | /* non inet6 skip */ |
430 | | continue; |
431 | | } |
432 | | #elif !defined(INET6) |
433 | | if (ifa->ifa_addr->sa_family != AF_INET) { |
434 | | /* non inet skip */ |
435 | | continue; |
436 | | } |
437 | | #else |
438 | 12 | if ((ifa->ifa_addr->sa_family != AF_INET) && (ifa->ifa_addr->sa_family != AF_INET6)) { |
439 | | /* non inet/inet6 skip */ |
440 | 6 | continue; |
441 | 6 | } |
442 | 6 | #endif |
443 | 6 | #if defined(INET6) |
444 | 6 | if ((ifa->ifa_addr->sa_family == AF_INET6) && |
445 | 6 | IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { |
446 | | /* skip unspecified addresses */ |
447 | 0 | continue; |
448 | 0 | } |
449 | 6 | #endif |
450 | 6 | #if defined(INET) |
451 | 6 | if (ifa->ifa_addr->sa_family == AF_INET && |
452 | 6 | ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) { |
453 | 0 | continue; |
454 | 0 | } |
455 | 6 | #endif |
456 | 6 | ifa_flags = 0; |
457 | 6 | sctp_ifa = sctp_add_addr_to_vrf(vrfid, |
458 | 6 | NULL, |
459 | 6 | if_nametoindex(ifa->ifa_name), |
460 | 6 | 0, |
461 | 6 | ifa->ifa_name, |
462 | 6 | NULL, |
463 | 6 | ifa->ifa_addr, |
464 | 6 | ifa_flags, |
465 | 6 | 0); |
466 | 6 | if (sctp_ifa) { |
467 | 6 | sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; |
468 | 6 | } |
469 | 6 | } |
470 | 3 | freeifaddrs(ifas); |
471 | 3 | #endif |
472 | 3 | } |
473 | | #endif |
474 | | #if defined(__APPLE__) && !defined(__Userspace__) |
475 | | static void |
476 | | sctp_init_ifns_for_vrf(int vrfid) |
477 | | { |
478 | | /* Here we must apply ANY locks needed by the |
479 | | * IFN we access and also make sure we lock |
480 | | * any IFA that exists as we float through the |
481 | | * list of IFA's |
482 | | */ |
483 | | struct ifnet **ifnetlist; |
484 | | uint32_t i, j, count; |
485 | | char name[SCTP_IFNAMSIZ]; |
486 | | struct ifnet *ifn; |
487 | | struct ifaddr **ifaddrlist; |
488 | | struct ifaddr *ifa; |
489 | | struct in6_ifaddr *ifa6; |
490 | | struct sctp_ifa *sctp_ifa; |
491 | | uint32_t ifa_flags; |
492 | | |
493 | | if (ifnet_list_get(IFNET_FAMILY_ANY, &ifnetlist, &count) != 0) { |
494 | | return; |
495 | | } |
496 | | for (i = 0; i < count; i++) { |
497 | | ifn = ifnetlist[i]; |
498 | | if (SCTP_BASE_SYSCTL(sctp_ignore_vmware_interfaces) && sctp_is_vmware_interface(ifn)) { |
499 | | continue; |
500 | | } |
501 | | if (sctp_is_desired_interface_type(ifn) == 0) { |
502 | | /* non desired type */ |
503 | | continue; |
504 | | } |
505 | | if (ifnet_get_address_list(ifn, &ifaddrlist) != 0) { |
506 | | continue; |
507 | | } |
508 | | for (j = 0; ifaddrlist[j] != NULL; j++) { |
509 | | ifa = ifaddrlist[j]; |
510 | | if (ifa->ifa_addr == NULL) { |
511 | | continue; |
512 | | } |
513 | | if ((ifa->ifa_addr->sa_family != AF_INET) && (ifa->ifa_addr->sa_family != AF_INET6)) { |
514 | | /* non inet/inet6 skip */ |
515 | | continue; |
516 | | } |
517 | | if (ifa->ifa_addr->sa_family == AF_INET6) { |
518 | | if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { |
519 | | /* skip unspecified addresses */ |
520 | | continue; |
521 | | } |
522 | | } else { |
523 | | if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == INADDR_ANY) { |
524 | | continue; |
525 | | } |
526 | | } |
527 | | if (ifa->ifa_addr->sa_family == AF_INET6) { |
528 | | ifa6 = (struct in6_ifaddr *)ifa; |
529 | | ifa_flags = ifa6->ia6_flags; |
530 | | } else { |
531 | | ifa_flags = 0; |
532 | | } |
533 | | SCTP_SNPRINTF(name, SCTP_IFNAMSIZ, "%s%d", ifnet_name(ifn), ifnet_unit(ifn)); |
534 | | sctp_ifa = sctp_add_addr_to_vrf(vrfid, |
535 | | (void *)ifn, /* XXX */ |
536 | | ifnet_index(ifn), |
537 | | ifnet_type(ifn), |
538 | | name, |
539 | | (void *)ifa, /* XXX */ |
540 | | ifa->ifa_addr, |
541 | | ifa_flags, |
542 | | 0); |
543 | | if (sctp_ifa) { |
544 | | sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; |
545 | | } |
546 | | } |
547 | | ifnet_free_address_list(ifaddrlist); |
548 | | } |
549 | | ifnet_list_free(ifnetlist); |
550 | | } |
551 | | #endif |
552 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
553 | | static void |
554 | | sctp_init_ifns_for_vrf(int vrfid) |
555 | | { |
556 | | /* Here we must apply ANY locks needed by the |
557 | | * IFN we access and also make sure we lock |
558 | | * any IFA that exists as we float through the |
559 | | * list of IFA's |
560 | | */ |
561 | | struct epoch_tracker et; |
562 | | struct ifnet *ifn; |
563 | | struct ifaddr *ifa; |
564 | | struct sctp_ifa *sctp_ifa; |
565 | | uint32_t ifa_flags; |
566 | | #ifdef INET6 |
567 | | struct in6_ifaddr *ifa6; |
568 | | #endif |
569 | | |
570 | | IFNET_RLOCK(); |
571 | | NET_EPOCH_ENTER(et); |
572 | | CK_STAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_link) { |
573 | | if (sctp_is_desired_interface_type(ifn) == 0) { |
574 | | /* non desired type */ |
575 | | continue; |
576 | | } |
577 | | CK_STAILQ_FOREACH(ifa, &ifn->if_addrhead, ifa_link) { |
578 | | if (ifa->ifa_addr == NULL) { |
579 | | continue; |
580 | | } |
581 | | switch (ifa->ifa_addr->sa_family) { |
582 | | #ifdef INET |
583 | | case AF_INET: |
584 | | if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) { |
585 | | continue; |
586 | | } |
587 | | break; |
588 | | #endif |
589 | | #ifdef INET6 |
590 | | case AF_INET6: |
591 | | if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { |
592 | | /* skip unspecified addresses */ |
593 | | continue; |
594 | | } |
595 | | break; |
596 | | #endif |
597 | | default: |
598 | | continue; |
599 | | } |
600 | | switch (ifa->ifa_addr->sa_family) { |
601 | | #ifdef INET |
602 | | case AF_INET: |
603 | | ifa_flags = 0; |
604 | | break; |
605 | | #endif |
606 | | #ifdef INET6 |
607 | | case AF_INET6: |
608 | | ifa6 = (struct in6_ifaddr *)ifa; |
609 | | ifa_flags = ifa6->ia6_flags; |
610 | | break; |
611 | | #endif |
612 | | default: |
613 | | ifa_flags = 0; |
614 | | break; |
615 | | } |
616 | | sctp_ifa = sctp_add_addr_to_vrf(vrfid, |
617 | | (void *)ifn, |
618 | | ifn->if_index, |
619 | | ifn->if_type, |
620 | | ifn->if_xname, |
621 | | (void *)ifa, |
622 | | ifa->ifa_addr, |
623 | | ifa_flags, |
624 | | 0); |
625 | | if (sctp_ifa) { |
626 | | sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; |
627 | | } |
628 | | } |
629 | | } |
630 | | NET_EPOCH_EXIT(et); |
631 | | IFNET_RUNLOCK(); |
632 | | } |
633 | | #endif |
634 | | |
635 | | void |
636 | | sctp_init_vrf_list(int vrfid) |
637 | 3 | { |
638 | 3 | if (vrfid > SCTP_MAX_VRF_ID) |
639 | | /* can't do that */ |
640 | 0 | return; |
641 | | |
642 | | /* Don't care about return here */ |
643 | 3 | (void)sctp_allocate_vrf(vrfid); |
644 | | |
645 | | /* Now we need to build all the ifn's |
646 | | * for this vrf and there addresses |
647 | | */ |
648 | 3 | sctp_init_ifns_for_vrf(vrfid); |
649 | 3 | } |
650 | | |
651 | | void |
652 | | sctp_addr_change(struct ifaddr *ifa, int cmd) |
653 | 0 | { |
654 | 0 | #if defined(__Userspace__) |
655 | 0 | return; |
656 | | #else |
657 | | uint32_t ifa_flags = 0; |
658 | | |
659 | | if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { |
660 | | return; |
661 | | } |
662 | | /* BSD only has one VRF, if this changes |
663 | | * we will need to hook in the right |
664 | | * things here to get the id to pass to |
665 | | * the address management routine. |
666 | | */ |
667 | | if (SCTP_BASE_VAR(first_time) == 0) { |
668 | | /* Special test to see if my ::1 will showup with this */ |
669 | | SCTP_BASE_VAR(first_time) = 1; |
670 | | sctp_init_ifns_for_vrf(SCTP_DEFAULT_VRFID); |
671 | | } |
672 | | |
673 | | if ((cmd != RTM_ADD) && (cmd != RTM_DELETE)) { |
674 | | /* don't know what to do with this */ |
675 | | return; |
676 | | } |
677 | | |
678 | | if (ifa->ifa_addr == NULL) { |
679 | | return; |
680 | | } |
681 | | if (sctp_is_desired_interface_type(ifa->ifa_ifp) == 0) { |
682 | | /* non desired type */ |
683 | | return; |
684 | | } |
685 | | switch (ifa->ifa_addr->sa_family) { |
686 | | #ifdef INET |
687 | | case AF_INET: |
688 | | if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) { |
689 | | return; |
690 | | } |
691 | | break; |
692 | | #endif |
693 | | #ifdef INET6 |
694 | | case AF_INET6: |
695 | | ifa_flags = ((struct in6_ifaddr *)ifa)->ia6_flags; |
696 | | if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { |
697 | | /* skip unspecified addresses */ |
698 | | return; |
699 | | } |
700 | | break; |
701 | | #endif |
702 | | default: |
703 | | /* non inet/inet6 skip */ |
704 | | return; |
705 | | } |
706 | | if (cmd == RTM_ADD) { |
707 | | (void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, (void *)ifa->ifa_ifp, |
708 | | #if defined(__APPLE__) && !defined(__Userspace__) |
709 | | ifnet_index(ifa->ifa_ifp), ifnet_type(ifa->ifa_ifp), ifnet_name(ifa->ifa_ifp), |
710 | | #else |
711 | | ifa->ifa_ifp->if_index, ifa->ifa_ifp->if_type, ifa->ifa_ifp->if_xname, |
712 | | #endif |
713 | | (void *)ifa, ifa->ifa_addr, ifa_flags, 1); |
714 | | } else { |
715 | | sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, |
716 | | (void *)ifa->ifa_ifp, |
717 | | #if defined(__APPLE__) && !defined(__Userspace__) |
718 | | ifnet_index(ifa->ifa_ifp)); |
719 | | #else |
720 | | ifa->ifa_ifp->if_index); |
721 | | #endif |
722 | | |
723 | | /* We don't bump refcount here so when it completes |
724 | | * the final delete will happen. |
725 | | */ |
726 | | } |
727 | | #endif |
728 | 0 | } |
729 | | |
730 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
731 | | void |
732 | | sctp_addr_change_event_handler(void *arg __unused, struct ifaddr *ifa, int cmd) { |
733 | | sctp_addr_change(ifa, cmd); |
734 | | } |
735 | | #endif |
736 | | #if defined(__APPLE__) && !defined(__Userspace__) |
737 | | void |
738 | | sctp_add_or_del_interfaces(int (*pred)(struct ifnet *), int add) |
739 | | { |
740 | | struct ifnet **ifnetlist; |
741 | | struct ifaddr **ifaddrlist; |
742 | | uint32_t i, j, count; |
743 | | |
744 | | if (ifnet_list_get(IFNET_FAMILY_ANY, &ifnetlist, &count) != 0) { |
745 | | return; |
746 | | } |
747 | | for (i = 0; i < count; i++) { |
748 | | if (!(*pred)(ifnetlist[i])) { |
749 | | continue; |
750 | | } |
751 | | if (ifnet_get_address_list(ifnetlist[i], &ifaddrlist) != 0) { |
752 | | continue; |
753 | | } |
754 | | for (j = 0; ifaddrlist[j] != NULL; j++) { |
755 | | sctp_addr_change(ifaddrlist[j], add ? RTM_ADD : RTM_DELETE); |
756 | | } |
757 | | ifnet_free_address_list(ifaddrlist); |
758 | | } |
759 | | ifnet_list_free(ifnetlist); |
760 | | return; |
761 | | } |
762 | | #endif |
763 | | |
764 | | struct mbuf * |
765 | | sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, |
766 | | int how, int allonebuf, int type) |
767 | 10.1M | { |
768 | 10.1M | struct mbuf *m = NULL; |
769 | 10.1M | #if defined(__FreeBSD__) || defined(__Userspace__) |
770 | 10.1M | #if defined(__Userspace__) |
771 | 10.1M | m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0, allonebuf); |
772 | | #else |
773 | | m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0); |
774 | | #endif |
775 | 10.1M | if (m == NULL) { |
776 | | /* bad, no memory */ |
777 | 0 | return (m); |
778 | 0 | } |
779 | | #if !defined(__Userspace__) |
780 | | if (allonebuf) { |
781 | | if (SCTP_BUF_SIZE(m) < space_needed) { |
782 | | m_freem(m); |
783 | | return (NULL); |
784 | | } |
785 | | KASSERT(SCTP_BUF_NEXT(m) == NULL, ("%s: no chain allowed", __func__)); |
786 | | } |
787 | | #endif |
788 | | #ifdef SCTP_MBUF_LOGGING |
789 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
790 | | sctp_log_mb(m, SCTP_MBUF_IALLOC); |
791 | | } |
792 | | #endif |
793 | | #else |
794 | | int mbuf_threshold; |
795 | | unsigned int size; |
796 | | |
797 | | if (want_header) { |
798 | | MGETHDR(m, how, type); |
799 | | size = MHLEN; |
800 | | } else { |
801 | | MGET(m, how, type); |
802 | | size = MLEN; |
803 | | } |
804 | | if (m == NULL) { |
805 | | return (NULL); |
806 | | } |
807 | | if (allonebuf == 0) { |
808 | | mbuf_threshold = SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count); |
809 | | } else { |
810 | | mbuf_threshold = 1; |
811 | | } |
812 | | |
813 | | if (space_needed > (unsigned int)(((mbuf_threshold - 1) * MLEN) + MHLEN)) { |
814 | | MCLGET(m, how); |
815 | | if (m == NULL) { |
816 | | return (NULL); |
817 | | } |
818 | | if (SCTP_BUF_IS_EXTENDED(m) == 0) { |
819 | | sctp_m_freem(m); |
820 | | return (NULL); |
821 | | } |
822 | | size = SCTP_BUF_EXTEND_SIZE(m); |
823 | | } |
824 | | if (allonebuf != 0 && size < space_needed) { |
825 | | m_freem(m); |
826 | | return (NULL); |
827 | | } |
828 | | SCTP_BUF_LEN(m) = 0; |
829 | | SCTP_BUF_NEXT(m) = SCTP_BUF_NEXT_PKT(m) = NULL; |
830 | | #ifdef SCTP_MBUF_LOGGING |
831 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
832 | | sctp_log_mb(m, SCTP_MBUF_IALLOC); |
833 | | } |
834 | | #endif |
835 | | #endif |
836 | 10.1M | return (m); |
837 | 10.1M | } |
838 | | |
839 | | #ifdef SCTP_PACKET_LOGGING |
840 | | void |
841 | | sctp_packet_log(struct mbuf *m) |
842 | | { |
843 | | int *lenat, thisone; |
844 | | void *copyto; |
845 | | uint32_t *tick_tock; |
846 | | int length; |
847 | | int total_len; |
848 | | int grabbed_lock = 0; |
849 | | int value, newval, thisend, thisbegin; |
850 | | /* |
851 | | * Buffer layout. |
852 | | * -sizeof this entry (total_len) |
853 | | * -previous end (value) |
854 | | * -ticks of log (ticks) |
855 | | * o -ip packet |
856 | | * o -as logged |
857 | | * - where this started (thisbegin) |
858 | | * x <--end points here |
859 | | */ |
860 | | length = SCTP_HEADER_LEN(m); |
861 | | total_len = SCTP_SIZE32((length + (4 * sizeof(int)))); |
862 | | /* Log a packet to the buffer. */ |
863 | | if (total_len> SCTP_PACKET_LOG_SIZE) { |
864 | | /* Can't log this packet I have not a buffer big enough */ |
865 | | return; |
866 | | } |
867 | | if (length < (int)(SCTP_MIN_V4_OVERHEAD + sizeof(struct sctp_cookie_ack_chunk))) { |
868 | | return; |
869 | | } |
870 | | atomic_add_int(&SCTP_BASE_VAR(packet_log_writers), 1); |
871 | | try_again: |
872 | | if (SCTP_BASE_VAR(packet_log_writers) > SCTP_PKTLOG_WRITERS_NEED_LOCK) { |
873 | | SCTP_IP_PKTLOG_LOCK(); |
874 | | grabbed_lock = 1; |
875 | | again_locked: |
876 | | value = SCTP_BASE_VAR(packet_log_end); |
877 | | newval = SCTP_BASE_VAR(packet_log_end) + total_len; |
878 | | if (newval >= SCTP_PACKET_LOG_SIZE) { |
879 | | /* we wrapped */ |
880 | | thisbegin = 0; |
881 | | thisend = total_len; |
882 | | } else { |
883 | | thisbegin = SCTP_BASE_VAR(packet_log_end); |
884 | | thisend = newval; |
885 | | } |
886 | | if (!(atomic_cmpset_int(&SCTP_BASE_VAR(packet_log_end), value, thisend))) { |
887 | | goto again_locked; |
888 | | } |
889 | | } else { |
890 | | value = SCTP_BASE_VAR(packet_log_end); |
891 | | newval = SCTP_BASE_VAR(packet_log_end) + total_len; |
892 | | if (newval >= SCTP_PACKET_LOG_SIZE) { |
893 | | /* we wrapped */ |
894 | | thisbegin = 0; |
895 | | thisend = total_len; |
896 | | } else { |
897 | | thisbegin = SCTP_BASE_VAR(packet_log_end); |
898 | | thisend = newval; |
899 | | } |
900 | | if (!(atomic_cmpset_int(&SCTP_BASE_VAR(packet_log_end), value, thisend))) { |
901 | | goto try_again; |
902 | | } |
903 | | } |
904 | | /* Sanity check */ |
905 | | if (thisend >= SCTP_PACKET_LOG_SIZE) { |
906 | | SCTP_PRINTF("Insanity stops a log thisbegin:%d thisend:%d writers:%d lock:%d end:%d\n", |
907 | | thisbegin, |
908 | | thisend, |
909 | | SCTP_BASE_VAR(packet_log_writers), |
910 | | grabbed_lock, |
911 | | SCTP_BASE_VAR(packet_log_end)); |
912 | | SCTP_BASE_VAR(packet_log_end) = 0; |
913 | | goto no_log; |
914 | | } |
915 | | lenat = (int *)&SCTP_BASE_VAR(packet_log_buffer)[thisbegin]; |
916 | | *lenat = total_len; |
917 | | lenat++; |
918 | | *lenat = value; |
919 | | lenat++; |
920 | | tick_tock = (uint32_t *)lenat; |
921 | | lenat++; |
922 | | *tick_tock = sctp_get_tick_count(); |
923 | | copyto = (void *)lenat; |
924 | | thisone = thisend - sizeof(int); |
925 | | lenat = (int *)&SCTP_BASE_VAR(packet_log_buffer)[thisone]; |
926 | | *lenat = thisbegin; |
927 | | if (grabbed_lock) { |
928 | | SCTP_IP_PKTLOG_UNLOCK(); |
929 | | grabbed_lock = 0; |
930 | | } |
931 | | m_copydata(m, 0, length, (caddr_t)copyto); |
932 | | no_log: |
933 | | if (grabbed_lock) { |
934 | | SCTP_IP_PKTLOG_UNLOCK(); |
935 | | } |
936 | | atomic_subtract_int(&SCTP_BASE_VAR(packet_log_writers), 1); |
937 | | } |
938 | | |
939 | | int |
940 | | sctp_copy_out_packet_log(uint8_t *target, int length) |
941 | | { |
942 | | /* We wind through the packet log starting at |
943 | | * start copying up to length bytes out. |
944 | | * We return the number of bytes copied. |
945 | | */ |
946 | | int this_copy; |
947 | | int *lenat; |
948 | | int did_delay = 0; |
949 | | |
950 | | if (length < (int)(2 * sizeof(int))) { |
951 | | /* not enough room */ |
952 | | return (0); |
953 | | } |
954 | | if (SCTP_PKTLOG_WRITERS_NEED_LOCK) { |
955 | | atomic_add_int(&SCTP_BASE_VAR(packet_log_writers), SCTP_PKTLOG_WRITERS_NEED_LOCK); |
956 | | again: |
957 | | if ((did_delay == 0) && (SCTP_BASE_VAR(packet_log_writers) != SCTP_PKTLOG_WRITERS_NEED_LOCK)) { |
958 | | /* we delay here for just a moment hoping the writer(s) that were |
959 | | * present when we entered will have left and we only have |
960 | | * locking ones that will contend with us for the lock. This |
961 | | * does not assure 100% access, but its good enough for |
962 | | * a logging facility like this. |
963 | | */ |
964 | | did_delay = 1; |
965 | | DELAY(10); |
966 | | goto again; |
967 | | } |
968 | | } |
969 | | SCTP_IP_PKTLOG_LOCK(); |
970 | | lenat = (int *)target; |
971 | | *lenat = SCTP_BASE_VAR(packet_log_end); |
972 | | lenat++; |
973 | | this_copy = min((length - sizeof(int)), SCTP_PACKET_LOG_SIZE); |
974 | | memcpy((void *)lenat, (void *)SCTP_BASE_VAR(packet_log_buffer), this_copy); |
975 | | if (SCTP_PKTLOG_WRITERS_NEED_LOCK) { |
976 | | atomic_subtract_int(&SCTP_BASE_VAR(packet_log_writers), |
977 | | SCTP_PKTLOG_WRITERS_NEED_LOCK); |
978 | | } |
979 | | SCTP_IP_PKTLOG_UNLOCK(); |
980 | | return (this_copy + sizeof(int)); |
981 | | } |
982 | | |
983 | | #endif |