xref: /freebsd/sys/netinet/sctp_bsd_addr.c (revision 0696e1203e263e97d808da8f7064c68ceb8147c2)
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