1163953Srrs/*-
2169382Srrs * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3235828Stuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4235828Stuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5163953Srrs *
6163953Srrs * Redistribution and use in source and binary forms, with or without
7163953Srrs * modification, are permitted provided that the following conditions are met:
8163953Srrs *
9163953Srrs * a) Redistributions of source code must retain the above copyright notice,
10228653Stuexen *    this list of conditions and the following disclaimer.
11163953Srrs *
12163953Srrs * b) Redistributions in binary form must reproduce the above copyright
13163953Srrs *    notice, this list of conditions and the following disclaimer in
14228653Stuexen *    the documentation and/or other materials provided with the distribution.
15163953Srrs *
16163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its
17163953Srrs *    contributors may be used to endorse or promote products derived
18163953Srrs *    from this software without specific prior written permission.
19163953Srrs *
20163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30163953Srrs * THE POSSIBILITY OF SUCH DAMAGE.
31163953Srrs */
32163953Srrs
33163953Srrs#include <sys/cdefs.h>
34163953Srrs__FBSDID("$FreeBSD$");
35163953Srrs
36163953Srrs#include <netinet/sctp_os.h>
37163953Srrs#include <netinet/sctp_var.h>
38163953Srrs#include <netinet/sctp_pcb.h>
39163953Srrs#include <netinet/sctp_header.h>
40163953Srrs#include <netinet/sctputil.h>
41163953Srrs#include <netinet/sctp_output.h>
42163953Srrs#include <netinet/sctp_bsd_addr.h>
43163953Srrs#include <netinet/sctp_uio.h>
44163953Srrs#include <netinet/sctputil.h>
45163953Srrs#include <netinet/sctp_timer.h>
46163953Srrs#include <netinet/sctp_asconf.h>
47169208Srrs#include <netinet/sctp_sysctl.h>
48163953Srrs#include <netinet/sctp_indata.h>
49167598Srrs#include <sys/unistd.h>
50163953Srrs
51170091Srrs/* Declare all of our malloc named types */
52170091SrrsMALLOC_DEFINE(SCTP_M_MAP, "sctp_map", "sctp asoc map descriptor");
53170091SrrsMALLOC_DEFINE(SCTP_M_STRMI, "sctp_stri", "sctp stream in array");
54170091SrrsMALLOC_DEFINE(SCTP_M_STRMO, "sctp_stro", "sctp stream out array");
55170091SrrsMALLOC_DEFINE(SCTP_M_ASC_ADDR, "sctp_aadr", "sctp asconf address");
56170091SrrsMALLOC_DEFINE(SCTP_M_ASC_IT, "sctp_a_it", "sctp asconf iterator");
57170091SrrsMALLOC_DEFINE(SCTP_M_AUTH_CL, "sctp_atcl", "sctp auth chunklist");
58170091SrrsMALLOC_DEFINE(SCTP_M_AUTH_KY, "sctp_atky", "sctp auth key");
59170091SrrsMALLOC_DEFINE(SCTP_M_AUTH_HL, "sctp_athm", "sctp auth hmac list");
60170091SrrsMALLOC_DEFINE(SCTP_M_AUTH_IF, "sctp_athi", "sctp auth info");
61170091SrrsMALLOC_DEFINE(SCTP_M_STRESET, "sctp_stre", "sctp stream reset");
62170091SrrsMALLOC_DEFINE(SCTP_M_CMSG, "sctp_cmsg", "sctp CMSG buffer");
63170091SrrsMALLOC_DEFINE(SCTP_M_COPYAL, "sctp_cpal", "sctp copy all");
64170091SrrsMALLOC_DEFINE(SCTP_M_VRF, "sctp_vrf", "sctp vrf struct");
65170091SrrsMALLOC_DEFINE(SCTP_M_IFA, "sctp_ifa", "sctp ifa struct");
66170091SrrsMALLOC_DEFINE(SCTP_M_IFN, "sctp_ifn", "sctp ifn struct");
67170091SrrsMALLOC_DEFINE(SCTP_M_TIMW, "sctp_timw", "sctp time block");
68170091SrrsMALLOC_DEFINE(SCTP_M_MVRF, "sctp_mvrf", "sctp mvrf pcb list");
69170091SrrsMALLOC_DEFINE(SCTP_M_ITER, "sctp_iter", "sctp iterator control");
70170091SrrsMALLOC_DEFINE(SCTP_M_SOCKOPT, "sctp_socko", "sctp socket option");
71218211SrrsMALLOC_DEFINE(SCTP_M_MCORE, "sctp_mcore", "sctp mcore queue");
72170091Srrs
73208160Srrs/* Global NON-VNET structure that controls the iterator */
74208160Srrsstruct iterator_control sctp_it_ctl;
75208160Srrs
76208160Srrs
77167598Srrsvoid
78167598Srrssctp_wakeup_iterator(void)
79163953Srrs{
80208160Srrs	wakeup(&sctp_it_ctl.iterator_running);
81163953Srrs}
82163953Srrs
83167598Srrsstatic void
84228653Stuexensctp_iterator_thread(void *v SCTP_UNUSED)
85163953Srrs{
86167598Srrs	SCTP_IPI_ITERATOR_WQ_LOCK();
87225676Stuexen	/* In FreeBSD this thread never terminates. */
88228653Stuexen	for (;;) {
89208160Srrs		msleep(&sctp_it_ctl.iterator_running,
90208160Srrs		    &sctp_it_ctl.ipi_iterator_wq_mtx,
91175751Srrs		    0, "waiting_for_work", 0);
92167598Srrs		sctp_iterator_worker();
93163953Srrs	}
94163953Srrs}
95163953Srrs
96167598Srrsvoid
97167598Srrssctp_startup_iterator(void)
98163953Srrs{
99258454Stuexen	if (sctp_it_ctl.thread_proc) {
100208160Srrs		/* You only get one */
101208160Srrs		return;
102208160Srrs	}
103258890Stuexen	/* Initialize global locks here, thus only once. */
104258890Stuexen	SCTP_ITERATOR_LOCK_INIT();
105258890Stuexen	SCTP_IPI_ITERATOR_WQ_INIT();
106208160Srrs	TAILQ_INIT(&sctp_it_ctl.iteratorhead);
107258454Stuexen	kproc_create(sctp_iterator_thread,
108208160Srrs	    (void *)NULL,
109208160Srrs	    &sctp_it_ctl.thread_proc,
110167598Srrs	    RFPROC,
111167598Srrs	    SCTP_KTHREAD_PAGES,
112167598Srrs	    SCTP_KTRHEAD_NAME);
113163953Srrs}
114163953Srrs
115178251Srrs#ifdef INET6
116180387Srrs
117167598Srrsvoid
118167598Srrssctp_gather_internal_ifa_flags(struct sctp_ifa *ifa)
119163953Srrs{
120167598Srrs	struct in6_ifaddr *ifa6;
121163953Srrs
122167598Srrs	ifa6 = (struct in6_ifaddr *)ifa->ifa;
123167598Srrs	ifa->flags = ifa6->ia6_flags;
124197288Srrs	if (!MODULE_GLOBAL(ip6_use_deprecated)) {
125167598Srrs		if (ifa->flags &
126167598Srrs		    IN6_IFF_DEPRECATED) {
127167598Srrs			ifa->localifa_flags |= SCTP_ADDR_IFA_UNUSEABLE;
128167598Srrs		} else {
129167598Srrs			ifa->localifa_flags &= ~SCTP_ADDR_IFA_UNUSEABLE;
130163953Srrs		}
131163953Srrs	} else {
132167598Srrs		ifa->localifa_flags &= ~SCTP_ADDR_IFA_UNUSEABLE;
133163953Srrs	}
134167598Srrs	if (ifa->flags &
135167598Srrs	    (IN6_IFF_DETACHED |
136167598Srrs	    IN6_IFF_ANYCAST |
137167598Srrs	    IN6_IFF_NOTREADY)) {
138167598Srrs		ifa->localifa_flags |= SCTP_ADDR_IFA_UNUSEABLE;
139163953Srrs	} else {
140167598Srrs		ifa->localifa_flags &= ~SCTP_ADDR_IFA_UNUSEABLE;
141163953Srrs	}
142163953Srrs}
143163953Srrs
144180387Srrs#endif				/* INET6 */
145163953Srrs
146163953Srrs
147167598Srrsstatic uint32_t
148239035Stuexensctp_is_desired_interface_type(struct ifnet *ifn)
149163953Srrs{
150167598Srrs	int result;
151163953Srrs
152167598Srrs	/* check the interface type to see if it's one we care about */
153239035Stuexen	switch (ifn->if_type) {
154167598Srrs	case IFT_ETHER:
155167598Srrs	case IFT_ISO88023:
156167598Srrs	case IFT_ISO88024:
157167598Srrs	case IFT_ISO88025:
158167598Srrs	case IFT_ISO88026:
159167598Srrs	case IFT_STARLAN:
160167598Srrs	case IFT_P10:
161167598Srrs	case IFT_P80:
162167598Srrs	case IFT_HY:
163167598Srrs	case IFT_FDDI:
164167598Srrs	case IFT_XETHER:
165167598Srrs	case IFT_ISDNBASIC:
166167598Srrs	case IFT_ISDNPRIMARY:
167167598Srrs	case IFT_PTPSERIAL:
168172091Srrs	case IFT_OTHER:
169167598Srrs	case IFT_PPP:
170167598Srrs	case IFT_LOOP:
171167598Srrs	case IFT_SLIP:
172179783Srrs	case IFT_GIF:
173196610Stuexen	case IFT_L2VLAN:
174232724Stuexen	case IFT_STF:
175167598Srrs	case IFT_IP:
176167598Srrs	case IFT_IPOVERCDLC:
177167598Srrs	case IFT_IPOVERCLAW:
178232866Srrs	case IFT_PROPVIRTUAL:	/* NetGraph Virtual too */
179167598Srrs	case IFT_VIRTUALIPADDRESS:
180167598Srrs		result = 1;
181167598Srrs		break;
182167598Srrs	default:
183167598Srrs		result = 0;
184163953Srrs	}
185163953Srrs
186167598Srrs	return (result);
187163953Srrs}
188163953Srrs
189179783Srrs
190191073Srrs
191191073Srrs
192167598Srrsstatic void
193167598Srrssctp_init_ifns_for_vrf(int vrfid)
194163953Srrs{
195163953Srrs	/*
196167598Srrs	 * Here we must apply ANY locks needed by the IFN we access and also
197167598Srrs	 * make sure we lock any IFA that exists as we float through the
198167598Srrs	 * list of IFA's
199163953Srrs	 */
200163953Srrs	struct ifnet *ifn;
201163953Srrs	struct ifaddr *ifa;
202167598Srrs	struct sctp_ifa *sctp_ifa;
203167598Srrs	uint32_t ifa_flags;
204163953Srrs
205221249Stuexen#ifdef INET6
206221249Stuexen	struct in6_ifaddr *ifa6;
207221249Stuexen
208221249Stuexen#endif
209221249Stuexen
210197326Stuexen	IFNET_RLOCK();
211197288Srrs	TAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_list) {
212239035Stuexen		if (sctp_is_desired_interface_type(ifn) == 0) {
213239035Stuexen			/* non desired type */
214239035Stuexen			continue;
215239035Stuexen		}
216229621Sjhb		IF_ADDR_RLOCK(ifn);
217167598Srrs		TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
218167598Srrs			if (ifa->ifa_addr == NULL) {
219163953Srrs				continue;
220163953Srrs			}
221221249Stuexen			switch (ifa->ifa_addr->sa_family) {
222221249Stuexen#ifdef INET
223221249Stuexen			case AF_INET:
224221249Stuexen				if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) {
225221249Stuexen					continue;
226221249Stuexen				}
227221249Stuexen				break;
228221249Stuexen#endif
229221249Stuexen#ifdef INET6
230221249Stuexen			case AF_INET6:
231167598Srrs				if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) {
232167598Srrs					/* skip unspecifed addresses */
233167598Srrs					continue;
234167598Srrs				}
235221249Stuexen				break;
236221249Stuexen#endif
237221249Stuexen			default:
238221249Stuexen				continue;
239163953Srrs			}
240221249Stuexen			switch (ifa->ifa_addr->sa_family) {
241221249Stuexen#ifdef INET
242221249Stuexen			case AF_INET:
243221249Stuexen				ifa_flags = 0;
244221249Stuexen				break;
245221249Stuexen#endif
246221249Stuexen#ifdef INET6
247221249Stuexen			case AF_INET6:
248179783Srrs				ifa6 = (struct in6_ifaddr *)ifa;
249179783Srrs				ifa_flags = ifa6->ia6_flags;
250221249Stuexen				break;
251221249Stuexen#endif
252221249Stuexen			default:
253179783Srrs				ifa_flags = 0;
254221249Stuexen				break;
255163953Srrs			}
256179783Srrs			sctp_ifa = sctp_add_addr_to_vrf(vrfid,
257179783Srrs			    (void *)ifn,
258179783Srrs			    ifn->if_index,
259179783Srrs			    ifn->if_type,
260179783Srrs			    ifn->if_xname,
261179783Srrs			    (void *)ifa,
262179783Srrs			    ifa->ifa_addr,
263179783Srrs			    ifa_flags,
264179783Srrs			    0);
265179783Srrs			if (sctp_ifa) {
266179783Srrs				sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
267179783Srrs			}
268163953Srrs		}
269229621Sjhb		IF_ADDR_RUNLOCK(ifn);
270163953Srrs	}
271197326Stuexen	IFNET_RUNLOCK();
272163953Srrs}
273163953Srrs
274167598Srrsvoid
275167598Srrssctp_init_vrf_list(int vrfid)
276163953Srrs{
277167598Srrs	if (vrfid > SCTP_MAX_VRF_ID)
278167598Srrs		/* can't do that */
279167598Srrs		return;
280163953Srrs
281167598Srrs	/* Don't care about return here */
282167598Srrs	(void)sctp_allocate_vrf(vrfid);
283163953Srrs
284163953Srrs	/*
285167598Srrs	 * Now we need to build all the ifn's for this vrf and there
286167598Srrs	 * addresses
287163953Srrs	 */
288167598Srrs	sctp_init_ifns_for_vrf(vrfid);
289163953Srrs}
290163953Srrs
291167598Srrsvoid
292167598Srrssctp_addr_change(struct ifaddr *ifa, int cmd)
293163953Srrs{
294167598Srrs	uint32_t ifa_flags = 0;
295163953Srrs
296163953Srrs	/*
297167598Srrs	 * BSD only has one VRF, if this changes we will need to hook in the
298167598Srrs	 * right things here to get the id to pass to the address managment
299167598Srrs	 * routine.
300163953Srrs	 */
301179783Srrs	if (SCTP_BASE_VAR(first_time) == 0) {
302167598Srrs		/* Special test to see if my ::1 will showup with this */
303179783Srrs		SCTP_BASE_VAR(first_time) = 1;
304167598Srrs		sctp_init_ifns_for_vrf(SCTP_DEFAULT_VRFID);
305163953Srrs	}
306167598Srrs	if ((cmd != RTM_ADD) && (cmd != RTM_DELETE)) {
307167598Srrs		/* don't know what to do with this */
308167598Srrs		return;
309163953Srrs	}
310167598Srrs	if (ifa->ifa_addr == NULL) {
311167598Srrs		return;
312163953Srrs	}
313239035Stuexen	if (sctp_is_desired_interface_type(ifa->ifa_ifp) == 0) {
314239035Stuexen		/* non desired type */
315239035Stuexen		return;
316239035Stuexen	}
317221249Stuexen	switch (ifa->ifa_addr->sa_family) {
318221249Stuexen#ifdef INET
319221249Stuexen	case AF_INET:
320221249Stuexen		if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) {
321221249Stuexen			return;
322221249Stuexen		}
323221249Stuexen		break;
324221249Stuexen#endif
325221249Stuexen#ifdef INET6
326221249Stuexen	case AF_INET6:
327179783Srrs		ifa_flags = ((struct in6_ifaddr *)ifa)->ia6_flags;
328167598Srrs		if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) {
329167598Srrs			/* skip unspecifed addresses */
330167598Srrs			return;
331163953Srrs		}
332221249Stuexen		break;
333221249Stuexen#endif
334221249Stuexen	default:
335221249Stuexen		/* non inet/inet6 skip */
336221249Stuexen		return;
337163953Srrs	}
338167598Srrs	if (cmd == RTM_ADD) {
339212707Stuexen		(void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, (void *)ifa->ifa_ifp,
340239035Stuexen		    ifa->ifa_ifp->if_index, ifa->ifa_ifp->if_type, ifa->ifa_ifp->if_xname,
341169208Srrs		    (void *)ifa, ifa->ifa_addr, ifa_flags, 1);
342179783Srrs	} else {
343167598Srrs
344172091Srrs		sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr,
345172091Srrs		    ifa->ifa_ifp->if_index,
346239035Stuexen		    ifa->ifa_ifp->if_xname);
347239035Stuexen
348163953Srrs		/*
349167598Srrs		 * We don't bump refcount here so when it completes the
350167598Srrs		 * final delete will happen.
351163953Srrs		 */
352163953Srrs	}
353169208Srrs}
354167598Srrs
355179783Srrsvoid
356179783Srrs     sctp_add_or_del_interfaces(int (*pred) (struct ifnet *), int add){
357179783Srrs	struct ifnet *ifn;
358179783Srrs	struct ifaddr *ifa;
359179783Srrs
360197326Stuexen	IFNET_RLOCK();
361197288Srrs	TAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_list) {
362179783Srrs		if (!(*pred) (ifn)) {
363179783Srrs			continue;
364179783Srrs		}
365179783Srrs		TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
366179783Srrs			sctp_addr_change(ifa, add ? RTM_ADD : RTM_DELETE);
367179783Srrs		}
368179783Srrs	}
369197326Stuexen	IFNET_RUNLOCK();
370179783Srrs}
371179783Srrs
372169208Srrsstruct mbuf *
373169208Srrssctp_get_mbuf_for_msg(unsigned int space_needed, int want_header,
374169208Srrs    int how, int allonebuf, int type)
375169208Srrs{
376169208Srrs	struct mbuf *m = NULL;
377163953Srrs
378169208Srrs	m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0);
379169208Srrs	if (m == NULL) {
380169208Srrs		/* bad, no memory */
381169208Srrs		return (m);
382163953Srrs	}
383169208Srrs	if (allonebuf) {
384169208Srrs		int siz;
385169208Srrs
386169208Srrs		if (SCTP_BUF_IS_EXTENDED(m)) {
387169208Srrs			siz = SCTP_BUF_EXTEND_SIZE(m);
388169208Srrs		} else {
389169208Srrs			if (want_header)
390169208Srrs				siz = MHLEN;
391169208Srrs			else
392169208Srrs				siz = MLEN;
393169208Srrs		}
394169208Srrs		if (siz < space_needed) {
395169208Srrs			m_freem(m);
396169208Srrs			return (NULL);
397169208Srrs		}
398163953Srrs	}
399169208Srrs	if (SCTP_BUF_NEXT(m)) {
400169208Srrs		sctp_m_freem(SCTP_BUF_NEXT(m));
401169208Srrs		SCTP_BUF_NEXT(m) = NULL;
402169208Srrs	}
403169208Srrs#ifdef SCTP_MBUF_LOGGING
404179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
405170744Srrs		if (SCTP_BUF_IS_EXTENDED(m)) {
406170744Srrs			sctp_log_mb(m, SCTP_MBUF_IALLOC);
407170744Srrs		}
408169208Srrs	}
409169208Srrs#endif
410169208Srrs	return (m);
411163953Srrs}
412170091Srrs
413170091Srrs
414170091Srrs#ifdef SCTP_PACKET_LOGGING
415170091Srrsvoid
416237540Stuexensctp_packet_log(struct mbuf *m)
417170091Srrs{
418170138Srrs	int *lenat, thisone;
419170091Srrs	void *copyto;
420170091Srrs	uint32_t *tick_tock;
421237540Stuexen	int length;
422170138Srrs	int total_len;
423170138Srrs	int grabbed_lock = 0;
424170138Srrs	int value, newval, thisend, thisbegin;
425170091Srrs
426170138Srrs	/*
427170138Srrs	 * Buffer layout. -sizeof this entry (total_len) -previous end
428170138Srrs	 * (value) -ticks of log      (ticks) o -ip packet o -as logged -
429170138Srrs	 * where this started (thisbegin) x <--end points here
430170138Srrs	 */
431237540Stuexen	length = SCTP_HEADER_LEN(m);
432170138Srrs	total_len = SCTP_SIZE32((length + (4 * sizeof(int))));
433170091Srrs	/* Log a packet to the buffer. */
434170091Srrs	if (total_len > SCTP_PACKET_LOG_SIZE) {
435170091Srrs		/* Can't log this packet I have not a buffer big enough */
436170091Srrs		return;
437170091Srrs	}
438179783Srrs	if (length < (int)(SCTP_MIN_V4_OVERHEAD + sizeof(struct sctp_cookie_ack_chunk))) {
439170091Srrs		return;
440170091Srrs	}
441179783Srrs	atomic_add_int(&SCTP_BASE_VAR(packet_log_writers), 1);
442170138Srrstry_again:
443179783Srrs	if (SCTP_BASE_VAR(packet_log_writers) > SCTP_PKTLOG_WRITERS_NEED_LOCK) {
444170138Srrs		SCTP_IP_PKTLOG_LOCK();
445170138Srrs		grabbed_lock = 1;
446170138Srrsagain_locked:
447179783Srrs		value = SCTP_BASE_VAR(packet_log_end);
448179783Srrs		newval = SCTP_BASE_VAR(packet_log_end) + total_len;
449170138Srrs		if (newval >= SCTP_PACKET_LOG_SIZE) {
450170138Srrs			/* we wrapped */
451170138Srrs			thisbegin = 0;
452170138Srrs			thisend = total_len;
453170091Srrs		} else {
454179783Srrs			thisbegin = SCTP_BASE_VAR(packet_log_end);
455170138Srrs			thisend = newval;
456170091Srrs		}
457179783Srrs		if (!(atomic_cmpset_int(&SCTP_BASE_VAR(packet_log_end), value, thisend))) {
458170138Srrs			goto again_locked;
459170091Srrs		}
460170091Srrs	} else {
461179783Srrs		value = SCTP_BASE_VAR(packet_log_end);
462179783Srrs		newval = SCTP_BASE_VAR(packet_log_end) + total_len;
463170138Srrs		if (newval >= SCTP_PACKET_LOG_SIZE) {
464170138Srrs			/* we wrapped */
465170138Srrs			thisbegin = 0;
466170138Srrs			thisend = total_len;
467170138Srrs		} else {
468179783Srrs			thisbegin = SCTP_BASE_VAR(packet_log_end);
469170138Srrs			thisend = newval;
470170091Srrs		}
471179783Srrs		if (!(atomic_cmpset_int(&SCTP_BASE_VAR(packet_log_end), value, thisend))) {
472170138Srrs			goto try_again;
473170138Srrs		}
474170091Srrs	}
475170138Srrs	/* Sanity check */
476170138Srrs	if (thisend >= SCTP_PACKET_LOG_SIZE) {
477234995Stuexen		SCTP_PRINTF("Insanity stops a log thisbegin:%d thisend:%d writers:%d lock:%d end:%d\n",
478170138Srrs		    thisbegin,
479170138Srrs		    thisend,
480179783Srrs		    SCTP_BASE_VAR(packet_log_writers),
481170138Srrs		    grabbed_lock,
482179783Srrs		    SCTP_BASE_VAR(packet_log_end));
483179783Srrs		SCTP_BASE_VAR(packet_log_end) = 0;
484170138Srrs		goto no_log;
485170138Srrs
486170091Srrs	}
487179783Srrs	lenat = (int *)&SCTP_BASE_VAR(packet_log_buffer)[thisbegin];
488170091Srrs	*lenat = total_len;
489170091Srrs	lenat++;
490170138Srrs	*lenat = value;
491170138Srrs	lenat++;
492170091Srrs	tick_tock = (uint32_t *) lenat;
493170091Srrs	lenat++;
494170091Srrs	*tick_tock = sctp_get_tick_count();
495170091Srrs	copyto = (void *)lenat;
496170138Srrs	thisone = thisend - sizeof(int);
497179783Srrs	lenat = (int *)&SCTP_BASE_VAR(packet_log_buffer)[thisone];
498170138Srrs	*lenat = thisbegin;
499170138Srrs	if (grabbed_lock) {
500170138Srrs		SCTP_IP_PKTLOG_UNLOCK();
501170138Srrs		grabbed_lock = 0;
502170138Srrs	}
503170091Srrs	m_copydata(m, 0, length, (caddr_t)copyto);
504170138Srrsno_log:
505170138Srrs	if (grabbed_lock) {
506170138Srrs		SCTP_IP_PKTLOG_UNLOCK();
507170138Srrs	}
508179783Srrs	atomic_subtract_int(&SCTP_BASE_VAR(packet_log_writers), 1);
509170091Srrs}
510170091Srrs
511170091Srrs
512170091Srrsint
513170091Srrssctp_copy_out_packet_log(uint8_t * target, int length)
514170091Srrs{
515170091Srrs	/*
516170091Srrs	 * We wind through the packet log starting at start copying up to
517170091Srrs	 * length bytes out. We return the number of bytes copied.
518170091Srrs	 */
519170138Srrs	int tocopy, this_copy;
520170138Srrs	int *lenat;
521170138Srrs	int did_delay = 0;
522170091Srrs
523170091Srrs	tocopy = length;
524179783Srrs	if (length < (int)(2 * sizeof(int))) {
525170138Srrs		/* not enough room */
526170091Srrs		return (0);
527170091Srrs	}
528170138Srrs	if (SCTP_PKTLOG_WRITERS_NEED_LOCK) {
529179783Srrs		atomic_add_int(&SCTP_BASE_VAR(packet_log_writers), SCTP_PKTLOG_WRITERS_NEED_LOCK);
530170138Srrsagain:
531179783Srrs		if ((did_delay == 0) && (SCTP_BASE_VAR(packet_log_writers) != SCTP_PKTLOG_WRITERS_NEED_LOCK)) {
532170138Srrs			/*
533170138Srrs			 * we delay here for just a moment hoping the
534170138Srrs			 * writer(s) that were present when we entered will
535170138Srrs			 * have left and we only have locking ones that will
536170138Srrs			 * contend with us for the lock. This does not
537170138Srrs			 * assure 100% access, but its good enough for a
538170138Srrs			 * logging facility like this.
539170138Srrs			 */
540170138Srrs			did_delay = 1;
541170138Srrs			DELAY(10);
542170138Srrs			goto again;
543170091Srrs		}
544170091Srrs	}
545170138Srrs	SCTP_IP_PKTLOG_LOCK();
546170138Srrs	lenat = (int *)target;
547179783Srrs	*lenat = SCTP_BASE_VAR(packet_log_end);
548170138Srrs	lenat++;
549170899Srrs	this_copy = min((length - sizeof(int)), SCTP_PACKET_LOG_SIZE);
550179783Srrs	memcpy((void *)lenat, (void *)SCTP_BASE_VAR(packet_log_buffer), this_copy);
551170138Srrs	if (SCTP_PKTLOG_WRITERS_NEED_LOCK) {
552179783Srrs		atomic_subtract_int(&SCTP_BASE_VAR(packet_log_writers),
553170899Srrs		    SCTP_PKTLOG_WRITERS_NEED_LOCK);
554170138Srrs	}
555170138Srrs	SCTP_IP_PKTLOG_UNLOCK();
556170138Srrs	return (this_copy + sizeof(int));
557170091Srrs}
558170091Srrs
559170091Srrs#endif
560