1f8829a4aSRandall Stewart /*- 2b1006367SRandall Stewart * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3f8829a4aSRandall Stewart * 4f8829a4aSRandall Stewart * Redistribution and use in source and binary forms, with or without 5f8829a4aSRandall Stewart * modification, are permitted provided that the following conditions are met: 6f8829a4aSRandall Stewart * 7f8829a4aSRandall Stewart * a) Redistributions of source code must retain the above copyright notice, 8f8829a4aSRandall Stewart * this list of conditions and the following disclaimer. 9f8829a4aSRandall Stewart * 10f8829a4aSRandall Stewart * b) Redistributions in binary form must reproduce the above copyright 11f8829a4aSRandall Stewart * notice, this list of conditions and the following disclaimer in 12f8829a4aSRandall Stewart * the documentation and/or other materials provided with the distribution. 13f8829a4aSRandall Stewart * 14f8829a4aSRandall Stewart * c) Neither the name of Cisco Systems, Inc. nor the names of its 15f8829a4aSRandall Stewart * contributors may be used to endorse or promote products derived 16f8829a4aSRandall Stewart * from this software without specific prior written permission. 17f8829a4aSRandall Stewart * 18f8829a4aSRandall Stewart * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19f8829a4aSRandall Stewart * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20f8829a4aSRandall Stewart * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21f8829a4aSRandall Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22f8829a4aSRandall Stewart * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23f8829a4aSRandall Stewart * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24f8829a4aSRandall Stewart * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25f8829a4aSRandall Stewart * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26f8829a4aSRandall Stewart * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27f8829a4aSRandall Stewart * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28f8829a4aSRandall Stewart * THE POSSIBILITY OF SUCH DAMAGE. 29f8829a4aSRandall Stewart */ 30f8829a4aSRandall Stewart 31f8829a4aSRandall Stewart /* $KAME: sctp_output.c,v 1.46 2005/03/06 16:04:17 itojun Exp $ */ 32f8829a4aSRandall Stewart 33f8829a4aSRandall Stewart #include <sys/cdefs.h> 34f8829a4aSRandall Stewart __FBSDID("$FreeBSD$"); 35f8829a4aSRandall Stewart 36f8829a4aSRandall Stewart #include <netinet/sctp_os.h> 37f8829a4aSRandall Stewart #include <netinet/sctp_var.h> 38f8829a4aSRandall Stewart #include <netinet/sctp_pcb.h> 39f8829a4aSRandall Stewart #include <netinet/sctp_header.h> 40f8829a4aSRandall Stewart #include <netinet/sctputil.h> 41f8829a4aSRandall Stewart #include <netinet/sctp_output.h> 42f8829a4aSRandall Stewart #include <netinet/sctp_bsd_addr.h> 43f8829a4aSRandall Stewart #include <netinet/sctp_uio.h> 44f8829a4aSRandall Stewart #include <netinet/sctputil.h> 45f8829a4aSRandall Stewart #include <netinet/sctp_timer.h> 46f8829a4aSRandall Stewart #include <netinet/sctp_asconf.h> 47d06c82f1SRandall Stewart #include <netinet/sctp_sysctl.h> 48f8829a4aSRandall Stewart #include <netinet/sctp_indata.h> 4942551e99SRandall Stewart #include <sys/unistd.h> 50f8829a4aSRandall Stewart 5142551e99SRandall Stewart 52207304d4SRandall Stewart /* Declare all of our malloc named types */ 53207304d4SRandall Stewart 546b4ae356SRandall Stewart /* Note to Michael/Peter for mac-os, 556b4ae356SRandall Stewart * I think mac has this too since I 56207304d4SRandall Stewart * do see the M_PCB type, so I 57207304d4SRandall Stewart * will also put in the mac file the 586b4ae356SRandall Stewart * MALLOC_DECLARE. If this does not 59207304d4SRandall Stewart * work for mac uncomment the defines for 60207304d4SRandall Stewart * the strings that we use in Panda, I put 61207304d4SRandall Stewart * them in comments in the mac-os file. 62207304d4SRandall Stewart */ 63207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_MAP, "sctp_map", "sctp asoc map descriptor"); 64207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_STRMI, "sctp_stri", "sctp stream in array"); 65207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_STRMO, "sctp_stro", "sctp stream out array"); 66207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_ASC_ADDR, "sctp_aadr", "sctp asconf address"); 67207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_ASC_IT, "sctp_a_it", "sctp asconf iterator"); 68207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_AUTH_CL, "sctp_atcl", "sctp auth chunklist"); 69207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_AUTH_KY, "sctp_atky", "sctp auth key"); 70207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_AUTH_HL, "sctp_athm", "sctp auth hmac list"); 71207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_AUTH_IF, "sctp_athi", "sctp auth info"); 72207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_STRESET, "sctp_stre", "sctp stream reset"); 73207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_CMSG, "sctp_cmsg", "sctp CMSG buffer"); 74207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_COPYAL, "sctp_cpal", "sctp copy all"); 75207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_VRF, "sctp_vrf", "sctp vrf struct"); 76207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_IFA, "sctp_ifa", "sctp ifa struct"); 77207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_IFN, "sctp_ifn", "sctp ifn struct"); 78207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_TIMW, "sctp_timw", "sctp time block"); 79207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_MVRF, "sctp_mvrf", "sctp mvrf pcb list"); 80207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_ITER, "sctp_iter", "sctp iterator control"); 81207304d4SRandall Stewart MALLOC_DEFINE(SCTP_M_SOCKOPT, "sctp_socko", "sctp socket option"); 82207304d4SRandall Stewart 83207304d4SRandall Stewart 8442551e99SRandall Stewart #if defined(SCTP_USE_THREAD_BASED_ITERATOR) 8542551e99SRandall Stewart void 8642551e99SRandall Stewart sctp_wakeup_iterator(void) 87f8829a4aSRandall Stewart { 8842551e99SRandall Stewart wakeup(&sctppcbinfo.iterator_running); 89f8829a4aSRandall Stewart } 90f8829a4aSRandall Stewart 9142551e99SRandall Stewart static void 9242551e99SRandall Stewart sctp_iterator_thread(void *v) 93f8829a4aSRandall Stewart { 9442551e99SRandall Stewart SCTP_IPI_ITERATOR_WQ_LOCK(); 9542551e99SRandall Stewart sctppcbinfo.iterator_running = 0; 9642551e99SRandall Stewart while (1) { 9742551e99SRandall Stewart msleep(&sctppcbinfo.iterator_running, 9842551e99SRandall Stewart &sctppcbinfo.ipi_iterator_wq_mtx, 9942551e99SRandall Stewart 0, "waiting_for_work", 0); 10042551e99SRandall Stewart sctp_iterator_worker(); 101f8829a4aSRandall Stewart } 102f8829a4aSRandall Stewart } 103f8829a4aSRandall Stewart 10442551e99SRandall Stewart void 10542551e99SRandall Stewart sctp_startup_iterator(void) 106f8829a4aSRandall Stewart { 10742551e99SRandall Stewart int ret; 108f8829a4aSRandall Stewart 10942551e99SRandall Stewart ret = kthread_create(sctp_iterator_thread, 11042551e99SRandall Stewart (void *)NULL, 11142551e99SRandall Stewart &sctppcbinfo.thread_proc, 11242551e99SRandall Stewart RFPROC, 11342551e99SRandall Stewart SCTP_KTHREAD_PAGES, 11442551e99SRandall Stewart SCTP_KTRHEAD_NAME); 11542551e99SRandall Stewart } 116f8829a4aSRandall Stewart 117f8829a4aSRandall Stewart #endif 118f8829a4aSRandall Stewart 119f8829a4aSRandall Stewart 12042551e99SRandall Stewart void 12142551e99SRandall Stewart sctp_gather_internal_ifa_flags(struct sctp_ifa *ifa) 122f8829a4aSRandall Stewart { 123f8829a4aSRandall Stewart struct in6_ifaddr *ifa6; 124f8829a4aSRandall Stewart 12542551e99SRandall Stewart ifa6 = (struct in6_ifaddr *)ifa->ifa; 12642551e99SRandall Stewart ifa->flags = ifa6->ia6_flags; 127f8829a4aSRandall Stewart if (!ip6_use_deprecated) { 12842551e99SRandall Stewart if (ifa->flags & 129f8829a4aSRandall Stewart IN6_IFF_DEPRECATED) { 13042551e99SRandall Stewart ifa->localifa_flags |= SCTP_ADDR_IFA_UNUSEABLE; 13142551e99SRandall Stewart } else { 13242551e99SRandall Stewart ifa->localifa_flags &= ~SCTP_ADDR_IFA_UNUSEABLE; 133f8829a4aSRandall Stewart } 13442551e99SRandall Stewart } else { 13542551e99SRandall Stewart ifa->localifa_flags &= ~SCTP_ADDR_IFA_UNUSEABLE; 136f8829a4aSRandall Stewart } 13742551e99SRandall Stewart if (ifa->flags & 138f8829a4aSRandall Stewart (IN6_IFF_DETACHED | 139f8829a4aSRandall Stewart IN6_IFF_ANYCAST | 140f8829a4aSRandall Stewart IN6_IFF_NOTREADY)) { 14142551e99SRandall Stewart ifa->localifa_flags |= SCTP_ADDR_IFA_UNUSEABLE; 142f8829a4aSRandall Stewart } else { 14342551e99SRandall Stewart ifa->localifa_flags &= ~SCTP_ADDR_IFA_UNUSEABLE; 144f8829a4aSRandall Stewart } 145f8829a4aSRandall Stewart } 146f8829a4aSRandall Stewart 14742551e99SRandall Stewart 14842551e99SRandall Stewart 14942551e99SRandall Stewart static uint32_t 15042551e99SRandall Stewart sctp_is_desired_interface_type(struct ifaddr *ifa) 151f8829a4aSRandall Stewart { 15242551e99SRandall Stewart int result; 153f8829a4aSRandall Stewart 15442551e99SRandall Stewart /* check the interface type to see if it's one we care about */ 15542551e99SRandall Stewart switch (ifa->ifa_ifp->if_type) { 15642551e99SRandall Stewart case IFT_ETHER: 15742551e99SRandall Stewart case IFT_ISO88023: 15842551e99SRandall Stewart case IFT_ISO88024: 15942551e99SRandall Stewart case IFT_ISO88025: 16042551e99SRandall Stewart case IFT_ISO88026: 16142551e99SRandall Stewart case IFT_STARLAN: 16242551e99SRandall Stewart case IFT_P10: 16342551e99SRandall Stewart case IFT_P80: 16442551e99SRandall Stewart case IFT_HY: 16542551e99SRandall Stewart case IFT_FDDI: 16642551e99SRandall Stewart case IFT_XETHER: 16742551e99SRandall Stewart case IFT_ISDNBASIC: 16842551e99SRandall Stewart case IFT_ISDNPRIMARY: 16942551e99SRandall Stewart case IFT_PTPSERIAL: 17042551e99SRandall Stewart case IFT_PPP: 17142551e99SRandall Stewart case IFT_LOOP: 17242551e99SRandall Stewart case IFT_SLIP: 17342551e99SRandall Stewart case IFT_IP: 17442551e99SRandall Stewart case IFT_IPOVERCDLC: 17542551e99SRandall Stewart case IFT_IPOVERCLAW: 17642551e99SRandall Stewart case IFT_VIRTUALIPADDRESS: 17742551e99SRandall Stewart result = 1; 17842551e99SRandall Stewart break; 17942551e99SRandall Stewart default: 18042551e99SRandall Stewart result = 0; 181f8829a4aSRandall Stewart } 182f8829a4aSRandall Stewart 18342551e99SRandall Stewart return (result); 18442551e99SRandall Stewart } 185f8829a4aSRandall Stewart 18642551e99SRandall Stewart static void 18742551e99SRandall Stewart sctp_init_ifns_for_vrf(int vrfid) 188f8829a4aSRandall Stewart { 18942551e99SRandall Stewart /* 19042551e99SRandall Stewart * Here we must apply ANY locks needed by the IFN we access and also 19142551e99SRandall Stewart * make sure we lock any IFA that exists as we float through the 19242551e99SRandall Stewart * list of IFA's 19342551e99SRandall Stewart */ 194f8829a4aSRandall Stewart struct ifnet *ifn; 195f8829a4aSRandall Stewart struct ifaddr *ifa; 19642551e99SRandall Stewart struct in6_ifaddr *ifa6; 19742551e99SRandall Stewart struct sctp_ifa *sctp_ifa; 19842551e99SRandall Stewart uint32_t ifa_flags; 199f8829a4aSRandall Stewart 200f8829a4aSRandall Stewart TAILQ_FOREACH(ifn, &ifnet, if_list) { 201f8829a4aSRandall Stewart TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) { 20242551e99SRandall Stewart if (ifa->ifa_addr == NULL) { 203f8829a4aSRandall Stewart continue; 204f8829a4aSRandall Stewart } 20542551e99SRandall Stewart if ((ifa->ifa_addr->sa_family != AF_INET) && 20642551e99SRandall Stewart (ifa->ifa_addr->sa_family != AF_INET6) 20742551e99SRandall Stewart ) { 20842551e99SRandall Stewart /* non inet/inet6 skip */ 209f8829a4aSRandall Stewart continue; 210f8829a4aSRandall Stewart } 21142551e99SRandall Stewart if (ifa->ifa_addr->sa_family == AF_INET6) { 21242551e99SRandall Stewart ifa6 = (struct in6_ifaddr *)ifa; 21342551e99SRandall Stewart ifa_flags = ifa6->ia6_flags; 21442551e99SRandall Stewart if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { 21542551e99SRandall Stewart /* skip unspecifed addresses */ 216f8829a4aSRandall Stewart continue; 217f8829a4aSRandall Stewart } 21842551e99SRandall Stewart } else if (ifa->ifa_addr->sa_family == AF_INET) { 21942551e99SRandall Stewart if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) { 22042551e99SRandall Stewart continue; 221f8829a4aSRandall Stewart } 222f8829a4aSRandall Stewart } 22342551e99SRandall Stewart if (sctp_is_desired_interface_type(ifa) == 0) { 22442551e99SRandall Stewart /* non desired type */ 22542551e99SRandall Stewart continue; 226f8829a4aSRandall Stewart } 22742551e99SRandall Stewart if ((ifa->ifa_addr->sa_family == AF_INET6) || 22842551e99SRandall Stewart (ifa->ifa_addr->sa_family == AF_INET)) { 22942551e99SRandall Stewart if (ifa->ifa_addr->sa_family == AF_INET6) { 23042551e99SRandall Stewart ifa6 = (struct in6_ifaddr *)ifa; 23142551e99SRandall Stewart ifa_flags = ifa6->ia6_flags; 232f8829a4aSRandall Stewart } else { 23342551e99SRandall Stewart ifa_flags = 0; 23442551e99SRandall Stewart } 23542551e99SRandall Stewart sctp_ifa = sctp_add_addr_to_vrf(vrfid, 23642551e99SRandall Stewart (void *)ifn, 23742551e99SRandall Stewart ifn->if_index, 23842551e99SRandall Stewart ifn->if_type, 23942551e99SRandall Stewart ifn->if_xname, 24042551e99SRandall Stewart (void *)ifa, 24142551e99SRandall Stewart ifa->ifa_addr, 242d06c82f1SRandall Stewart ifa_flags, 0 24342551e99SRandall Stewart ); 24442551e99SRandall Stewart if (sctp_ifa) { 24542551e99SRandall Stewart sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; 24642551e99SRandall Stewart } 24742551e99SRandall Stewart } 24842551e99SRandall Stewart } 24942551e99SRandall Stewart } 25042551e99SRandall Stewart } 251f8829a4aSRandall Stewart 25242551e99SRandall Stewart 25342551e99SRandall Stewart void 25442551e99SRandall Stewart sctp_init_vrf_list(int vrfid) 25542551e99SRandall Stewart { 25642551e99SRandall Stewart if (vrfid > SCTP_MAX_VRF_ID) 25742551e99SRandall Stewart /* can't do that */ 25842551e99SRandall Stewart return; 25942551e99SRandall Stewart 26042551e99SRandall Stewart /* Don't care about return here */ 26142551e99SRandall Stewart (void)sctp_allocate_vrf(vrfid); 26242551e99SRandall Stewart 263f8829a4aSRandall Stewart /* 26442551e99SRandall Stewart * Now we need to build all the ifn's for this vrf and there 26542551e99SRandall Stewart * addresses 266f8829a4aSRandall Stewart */ 26742551e99SRandall Stewart sctp_init_ifns_for_vrf(vrfid); 268f8829a4aSRandall Stewart } 26942551e99SRandall Stewart 27042551e99SRandall Stewart static uint8_t first_time = 0; 27142551e99SRandall Stewart 27242551e99SRandall Stewart 27342551e99SRandall Stewart void 27442551e99SRandall Stewart sctp_addr_change(struct ifaddr *ifa, int cmd) 27542551e99SRandall Stewart { 27642551e99SRandall Stewart struct sctp_ifa *ifap = NULL; 27742551e99SRandall Stewart uint32_t ifa_flags = 0; 27842551e99SRandall Stewart struct in6_ifaddr *ifa6; 27942551e99SRandall Stewart 28042551e99SRandall Stewart /* 28142551e99SRandall Stewart * BSD only has one VRF, if this changes we will need to hook in the 28242551e99SRandall Stewart * right things here to get the id to pass to the address managment 28342551e99SRandall Stewart * routine. 28442551e99SRandall Stewart */ 28542551e99SRandall Stewart if (first_time == 0) { 28642551e99SRandall Stewart /* Special test to see if my ::1 will showup with this */ 28742551e99SRandall Stewart first_time = 1; 28842551e99SRandall Stewart sctp_init_ifns_for_vrf(SCTP_DEFAULT_VRFID); 289f8829a4aSRandall Stewart } 29042551e99SRandall Stewart if ((cmd != RTM_ADD) && (cmd != RTM_DELETE)) { 29142551e99SRandall Stewart /* don't know what to do with this */ 29242551e99SRandall Stewart return; 293f8829a4aSRandall Stewart } 29442551e99SRandall Stewart if (ifa->ifa_addr == NULL) { 29542551e99SRandall Stewart return; 29642551e99SRandall Stewart } 29742551e99SRandall Stewart if ((ifa->ifa_addr->sa_family != AF_INET) && 29842551e99SRandall Stewart (ifa->ifa_addr->sa_family != AF_INET6) 29942551e99SRandall Stewart ) { 30042551e99SRandall Stewart /* non inet/inet6 skip */ 30142551e99SRandall Stewart return; 30242551e99SRandall Stewart } 30342551e99SRandall Stewart if (ifa->ifa_addr->sa_family == AF_INET6) { 30442551e99SRandall Stewart ifa6 = (struct in6_ifaddr *)ifa; 30542551e99SRandall Stewart ifa_flags = ifa6->ia6_flags; 30642551e99SRandall Stewart if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { 30742551e99SRandall Stewart /* skip unspecifed addresses */ 30842551e99SRandall Stewart return; 30942551e99SRandall Stewart } 31042551e99SRandall Stewart } else if (ifa->ifa_addr->sa_family == AF_INET) { 31142551e99SRandall Stewart if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) { 31242551e99SRandall Stewart return; 313f8829a4aSRandall Stewart } 314f8829a4aSRandall Stewart } 31542551e99SRandall Stewart if (sctp_is_desired_interface_type(ifa) == 0) { 31642551e99SRandall Stewart /* non desired type */ 31742551e99SRandall Stewart return; 318f8829a4aSRandall Stewart } 31942551e99SRandall Stewart if (cmd == RTM_ADD) { 32042551e99SRandall Stewart ifap = sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, (void *)ifa->ifa_ifp, 32142551e99SRandall Stewart ifa->ifa_ifp->if_index, ifa->ifa_ifp->if_type, 32242551e99SRandall Stewart ifa->ifa_ifp->if_xname, 323d06c82f1SRandall Stewart (void *)ifa, ifa->ifa_addr, ifa_flags, 1); 32442551e99SRandall Stewart 32542551e99SRandall Stewart } else if (cmd == RTM_DELETE) { 32642551e99SRandall Stewart 327d06c82f1SRandall Stewart sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, ifa->ifa_ifp->if_index); 32842551e99SRandall Stewart /* 32942551e99SRandall Stewart * We don't bump refcount here so when it completes the 33042551e99SRandall Stewart * final delete will happen. 33142551e99SRandall Stewart */ 33242551e99SRandall Stewart } 333d06c82f1SRandall Stewart } 33442551e99SRandall Stewart 335d06c82f1SRandall Stewart struct mbuf * 336d06c82f1SRandall Stewart sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, 337d06c82f1SRandall Stewart int how, int allonebuf, int type) 338d06c82f1SRandall Stewart { 339d06c82f1SRandall Stewart struct mbuf *m = NULL; 34042551e99SRandall Stewart 341d06c82f1SRandall Stewart m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0); 342d06c82f1SRandall Stewart if (m == NULL) { 343d06c82f1SRandall Stewart /* bad, no memory */ 344d06c82f1SRandall Stewart return (m); 34542551e99SRandall Stewart } 346d06c82f1SRandall Stewart if (allonebuf) { 347d06c82f1SRandall Stewart int siz; 348d06c82f1SRandall Stewart 349d06c82f1SRandall Stewart if (SCTP_BUF_IS_EXTENDED(m)) { 350d06c82f1SRandall Stewart siz = SCTP_BUF_EXTEND_SIZE(m); 351d06c82f1SRandall Stewart } else { 352d06c82f1SRandall Stewart if (want_header) 353d06c82f1SRandall Stewart siz = MHLEN; 354d06c82f1SRandall Stewart else 355d06c82f1SRandall Stewart siz = MLEN; 35642551e99SRandall Stewart } 357d06c82f1SRandall Stewart if (siz < space_needed) { 358d06c82f1SRandall Stewart m_freem(m); 359d06c82f1SRandall Stewart return (NULL); 360d06c82f1SRandall Stewart } 361d06c82f1SRandall Stewart } 362d06c82f1SRandall Stewart if (SCTP_BUF_NEXT(m)) { 363d06c82f1SRandall Stewart sctp_m_freem(SCTP_BUF_NEXT(m)); 364d06c82f1SRandall Stewart SCTP_BUF_NEXT(m) = NULL; 365d06c82f1SRandall Stewart } 366d06c82f1SRandall Stewart #ifdef SCTP_MBUF_LOGGING 367d06c82f1SRandall Stewart if (SCTP_BUF_IS_EXTENDED(m)) { 368d06c82f1SRandall Stewart sctp_log_mb(m, SCTP_MBUF_IALLOC); 369d06c82f1SRandall Stewart } 370d06c82f1SRandall Stewart #endif 371d06c82f1SRandall Stewart return (m); 372f8829a4aSRandall Stewart } 373207304d4SRandall Stewart 374207304d4SRandall Stewart 375207304d4SRandall Stewart #ifdef SCTP_PACKET_LOGGING 376207304d4SRandall Stewart 3770696e120SRandall Stewart int packet_log_writers = 0; 378207304d4SRandall Stewart int packet_log_end = 0; 379207304d4SRandall Stewart uint8_t packet_log_buffer[SCTP_PACKET_LOG_SIZE]; 380207304d4SRandall Stewart 381207304d4SRandall Stewart 382207304d4SRandall Stewart void 383207304d4SRandall Stewart sctp_packet_log(struct mbuf *m, int length) 384207304d4SRandall Stewart { 3850696e120SRandall Stewart int *lenat, thisone; 386207304d4SRandall Stewart void *copyto; 387207304d4SRandall Stewart uint32_t *tick_tock; 3880696e120SRandall Stewart int total_len; 3890696e120SRandall Stewart int grabbed_lock = 0; 3900696e120SRandall Stewart int value, newval, thisend, thisbegin; 391207304d4SRandall Stewart 3920696e120SRandall Stewart /* 3930696e120SRandall Stewart * Buffer layout. -sizeof this entry (total_len) -previous end 3940696e120SRandall Stewart * (value) -ticks of log (ticks) o -ip packet o -as logged - 3950696e120SRandall Stewart * where this started (thisbegin) x <--end points here 3960696e120SRandall Stewart */ 3970696e120SRandall Stewart total_len = SCTP_SIZE32((length + (4 * sizeof(int)))); 398207304d4SRandall Stewart /* Log a packet to the buffer. */ 399207304d4SRandall Stewart if (total_len > SCTP_PACKET_LOG_SIZE) { 400207304d4SRandall Stewart /* Can't log this packet I have not a buffer big enough */ 401207304d4SRandall Stewart return; 402207304d4SRandall Stewart } 403207304d4SRandall Stewart if (length < (SCTP_MIN_V4_OVERHEAD + sizeof(struct sctp_cookie_ack_chunk))) { 404207304d4SRandall Stewart return; 405207304d4SRandall Stewart } 4060696e120SRandall Stewart atomic_add_int(&packet_log_writers, 1); 4070696e120SRandall Stewart try_again: 4080696e120SRandall Stewart if (packet_log_writers > SCTP_PKTLOG_WRITERS_NEED_LOCK) { 409207304d4SRandall Stewart SCTP_IP_PKTLOG_LOCK(); 4100696e120SRandall Stewart grabbed_lock = 1; 4110696e120SRandall Stewart again_locked: 4120696e120SRandall Stewart value = packet_log_end; 4130696e120SRandall Stewart newval = packet_log_end + total_len; 4140696e120SRandall Stewart if (newval >= SCTP_PACKET_LOG_SIZE) { 4150696e120SRandall Stewart /* we wrapped */ 4160696e120SRandall Stewart thisbegin = 0; 4170696e120SRandall Stewart thisend = total_len; 4180696e120SRandall Stewart } else { 4190696e120SRandall Stewart thisbegin = packet_log_end; 4200696e120SRandall Stewart thisend = newval; 4210696e120SRandall Stewart } 4220696e120SRandall Stewart if (!(atomic_cmpset_int(&packet_log_end, value, thisend))) { 4230696e120SRandall Stewart goto again_locked; 4240696e120SRandall Stewart } 4250696e120SRandall Stewart } else { 4260696e120SRandall Stewart value = packet_log_end; 4270696e120SRandall Stewart newval = packet_log_end + total_len; 4280696e120SRandall Stewart if (newval >= SCTP_PACKET_LOG_SIZE) { 4290696e120SRandall Stewart /* we wrapped */ 4300696e120SRandall Stewart thisbegin = 0; 4310696e120SRandall Stewart thisend = total_len; 4320696e120SRandall Stewart } else { 4330696e120SRandall Stewart thisbegin = packet_log_end; 4340696e120SRandall Stewart thisend = newval; 4350696e120SRandall Stewart } 4360696e120SRandall Stewart if (!(atomic_cmpset_int(&packet_log_end, value, thisend))) { 4370696e120SRandall Stewart goto try_again; 4380696e120SRandall Stewart } 4390696e120SRandall Stewart } 4400696e120SRandall Stewart /* Sanity check */ 4410696e120SRandall Stewart if (thisend >= SCTP_PACKET_LOG_SIZE) { 4420696e120SRandall Stewart printf("Insanity stops a log thisbegin:%d thisend:%d writers:%d lock:%d end:%d\n", 4430696e120SRandall Stewart thisbegin, 4440696e120SRandall Stewart thisend, 4450696e120SRandall Stewart packet_log_writers, 4460696e120SRandall Stewart grabbed_lock, 4470696e120SRandall Stewart packet_log_end); 448207304d4SRandall Stewart packet_log_end = 0; 4490696e120SRandall Stewart goto no_log; 450207304d4SRandall Stewart 451207304d4SRandall Stewart } 4520696e120SRandall Stewart lenat = (int *)&packet_log_buffer[thisbegin]; 453207304d4SRandall Stewart *lenat = total_len; 454207304d4SRandall Stewart lenat++; 4550696e120SRandall Stewart *lenat = value; 4560696e120SRandall Stewart lenat++; 457207304d4SRandall Stewart tick_tock = (uint32_t *) lenat; 458207304d4SRandall Stewart lenat++; 459207304d4SRandall Stewart *tick_tock = sctp_get_tick_count(); 460207304d4SRandall Stewart copyto = (void *)lenat; 4610696e120SRandall Stewart thisone = thisend - sizeof(int); 4620696e120SRandall Stewart lenat = (int *)&packet_log_buffer[thisone]; 4630696e120SRandall Stewart *lenat = thisbegin; 4640696e120SRandall Stewart if (grabbed_lock) { 465207304d4SRandall Stewart SCTP_IP_PKTLOG_UNLOCK(); 4660696e120SRandall Stewart grabbed_lock = 0; 4670696e120SRandall Stewart } 468207304d4SRandall Stewart m_copydata(m, 0, length, (caddr_t)copyto); 4690696e120SRandall Stewart no_log: 4700696e120SRandall Stewart if (grabbed_lock) { 4710696e120SRandall Stewart SCTP_IP_PKTLOG_UNLOCK(); 4720696e120SRandall Stewart } 4730696e120SRandall Stewart atomic_subtract_int(&packet_log_writers, 1); 474207304d4SRandall Stewart } 475207304d4SRandall Stewart 476207304d4SRandall Stewart 477207304d4SRandall Stewart int 478207304d4SRandall Stewart sctp_copy_out_packet_log(uint8_t * target, int length) 479207304d4SRandall Stewart { 480207304d4SRandall Stewart /* 481207304d4SRandall Stewart * We wind through the packet log starting at start copying up to 482207304d4SRandall Stewart * length bytes out. We return the number of bytes copied. 483207304d4SRandall Stewart */ 4840696e120SRandall Stewart int tocopy, this_copy; 4850696e120SRandall Stewart int *lenat; 4860696e120SRandall Stewart int did_delay = 0; 487207304d4SRandall Stewart 488207304d4SRandall Stewart tocopy = length; 4890696e120SRandall Stewart if (length < (2 * sizeof(int))) { 4900696e120SRandall Stewart /* not enough room */ 491207304d4SRandall Stewart return (0); 492207304d4SRandall Stewart } 4930696e120SRandall Stewart if (SCTP_PKTLOG_WRITERS_NEED_LOCK) { 4940696e120SRandall Stewart atomic_add_int(&packet_log_writers, SCTP_PKTLOG_WRITERS_NEED_LOCK); 4950696e120SRandall Stewart again: 4960696e120SRandall Stewart if ((did_delay == 0) && (packet_log_writers != SCTP_PKTLOG_WRITERS_NEED_LOCK)) { 497207304d4SRandall Stewart /* 4980696e120SRandall Stewart * we delay here for just a moment hoping the 4990696e120SRandall Stewart * writer(s) that were present when we entered will 5000696e120SRandall Stewart * have left and we only have locking ones that will 5010696e120SRandall Stewart * contend with us for the lock. This does not 5020696e120SRandall Stewart * assure 100% access, but its good enough for a 5030696e120SRandall Stewart * logging facility like this. 504207304d4SRandall Stewart */ 5050696e120SRandall Stewart did_delay = 1; 5060696e120SRandall Stewart DELAY(10); 5070696e120SRandall Stewart goto again; 508207304d4SRandall Stewart } 509207304d4SRandall Stewart } 5100696e120SRandall Stewart SCTP_IP_PKTLOG_LOCK(); 5110696e120SRandall Stewart lenat = (int *)target; 5120696e120SRandall Stewart *lenat = packet_log_end; 5130696e120SRandall Stewart lenat++; 5140696e120SRandall Stewart this_copy = min((length - sizeof(int)), packet_log_end); 5150696e120SRandall Stewart memcpy((void *)lenat, (void *)packet_log_buffer, this_copy); 5160696e120SRandall Stewart if (SCTP_PKTLOG_WRITERS_NEED_LOCK) { 5170696e120SRandall Stewart atomic_subtract_int(&packet_log_writers, SCTP_PKTLOG_WRITERS_NEED_LOCK); 5180696e120SRandall Stewart } 5190696e120SRandall Stewart SCTP_IP_PKTLOG_UNLOCK(); 5200696e120SRandall Stewart return (this_copy + sizeof(int)); 521207304d4SRandall Stewart } 522207304d4SRandall Stewart 523207304d4SRandall Stewart #endif 524