netwerk/sctp/src/netinet/sctp_bsd_addr.c

Wed, 31 Dec 2014 07:53:36 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:53:36 +0100
branch
TOR_BUG_3246
changeset 5
4ab42b5ab56c
permissions
-rwxr-xr-x

Correct small whitespace inconsistency, lost while renaming variables.

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

mercurial