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
296296052Stuexen	if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
297296052Stuexen		return;
298296052Stuexen	}
299163953Srrs	/*
300167598Srrs	 * BSD only has one VRF, if this changes we will need to hook in the
301167598Srrs	 * right things here to get the id to pass to the address managment
302167598Srrs	 * routine.
303163953Srrs	 */
304179783Srrs	if (SCTP_BASE_VAR(first_time) == 0) {
305167598Srrs		/* Special test to see if my ::1 will showup with this */
306179783Srrs		SCTP_BASE_VAR(first_time) = 1;
307167598Srrs		sctp_init_ifns_for_vrf(SCTP_DEFAULT_VRFID);
308163953Srrs	}
309167598Srrs	if ((cmd != RTM_ADD) && (cmd != RTM_DELETE)) {
310167598Srrs		/* don't know what to do with this */
311167598Srrs		return;
312163953Srrs	}
313167598Srrs	if (ifa->ifa_addr == NULL) {
314167598Srrs		return;
315163953Srrs	}
316239035Stuexen	if (sctp_is_desired_interface_type(ifa->ifa_ifp) == 0) {
317239035Stuexen		/* non desired type */
318239035Stuexen		return;
319239035Stuexen	}
320221249Stuexen	switch (ifa->ifa_addr->sa_family) {
321221249Stuexen#ifdef INET
322221249Stuexen	case AF_INET:
323221249Stuexen		if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == 0) {
324221249Stuexen			return;
325221249Stuexen		}
326221249Stuexen		break;
327221249Stuexen#endif
328221249Stuexen#ifdef INET6
329221249Stuexen	case AF_INET6:
330179783Srrs		ifa_flags = ((struct in6_ifaddr *)ifa)->ia6_flags;
331167598Srrs		if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) {
332167598Srrs			/* skip unspecifed addresses */
333167598Srrs			return;
334163953Srrs		}
335221249Stuexen		break;
336221249Stuexen#endif
337221249Stuexen	default:
338221249Stuexen		/* non inet/inet6 skip */
339221249Stuexen		return;
340163953Srrs	}
341167598Srrs	if (cmd == RTM_ADD) {
342212707Stuexen		(void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, (void *)ifa->ifa_ifp,
343239035Stuexen		    ifa->ifa_ifp->if_index, ifa->ifa_ifp->if_type, ifa->ifa_ifp->if_xname,
344169208Srrs		    (void *)ifa, ifa->ifa_addr, ifa_flags, 1);
345179783Srrs	} else {
346167598Srrs
347172091Srrs		sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr,
348172091Srrs		    ifa->ifa_ifp->if_index,
349239035Stuexen		    ifa->ifa_ifp->if_xname);
350239035Stuexen
351163953Srrs		/*
352167598Srrs		 * We don't bump refcount here so when it completes the
353167598Srrs		 * final delete will happen.
354163953Srrs		 */
355163953Srrs	}
356169208Srrs}
357167598Srrs
358179783Srrsvoid
359179783Srrs     sctp_add_or_del_interfaces(int (*pred) (struct ifnet *), int add){
360179783Srrs	struct ifnet *ifn;
361179783Srrs	struct ifaddr *ifa;
362179783Srrs
363197326Stuexen	IFNET_RLOCK();
364197288Srrs	TAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_list) {
365179783Srrs		if (!(*pred) (ifn)) {
366179783Srrs			continue;
367179783Srrs		}
368179783Srrs		TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
369179783Srrs			sctp_addr_change(ifa, add ? RTM_ADD : RTM_DELETE);
370179783Srrs		}
371179783Srrs	}
372197326Stuexen	IFNET_RUNLOCK();
373179783Srrs}
374179783Srrs
375169208Srrsstruct mbuf *
376169208Srrssctp_get_mbuf_for_msg(unsigned int space_needed, int want_header,
377169208Srrs    int how, int allonebuf, int type)
378169208Srrs{
379169208Srrs	struct mbuf *m = NULL;
380163953Srrs
381169208Srrs	m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0);
382169208Srrs	if (m == NULL) {
383169208Srrs		/* bad, no memory */
384169208Srrs		return (m);
385163953Srrs	}
386169208Srrs	if (allonebuf) {
387169208Srrs		int siz;
388169208Srrs
389169208Srrs		if (SCTP_BUF_IS_EXTENDED(m)) {
390169208Srrs			siz = SCTP_BUF_EXTEND_SIZE(m);
391169208Srrs		} else {
392169208Srrs			if (want_header)
393169208Srrs				siz = MHLEN;
394169208Srrs			else
395169208Srrs				siz = MLEN;
396169208Srrs		}
397169208Srrs		if (siz < space_needed) {
398169208Srrs			m_freem(m);
399169208Srrs			return (NULL);
400169208Srrs		}
401163953Srrs	}
402169208Srrs	if (SCTP_BUF_NEXT(m)) {
403169208Srrs		sctp_m_freem(SCTP_BUF_NEXT(m));
404169208Srrs		SCTP_BUF_NEXT(m) = NULL;
405169208Srrs	}
406169208Srrs#ifdef SCTP_MBUF_LOGGING
407179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
408283708Stuexen		sctp_log_mb(m, SCTP_MBUF_IALLOC);
409169208Srrs	}
410169208Srrs#endif
411169208Srrs	return (m);
412163953Srrs}
413170091Srrs
414170091Srrs
415170091Srrs#ifdef SCTP_PACKET_LOGGING
416170091Srrsvoid
417237540Stuexensctp_packet_log(struct mbuf *m)
418170091Srrs{
419170138Srrs	int *lenat, thisone;
420170091Srrs	void *copyto;
421170091Srrs	uint32_t *tick_tock;
422237540Stuexen	int length;
423170138Srrs	int total_len;
424170138Srrs	int grabbed_lock = 0;
425170138Srrs	int value, newval, thisend, thisbegin;
426170091Srrs
427170138Srrs	/*
428170138Srrs	 * Buffer layout. -sizeof this entry (total_len) -previous end
429170138Srrs	 * (value) -ticks of log      (ticks) o -ip packet o -as logged -
430170138Srrs	 * where this started (thisbegin) x <--end points here
431170138Srrs	 */
432237540Stuexen	length = SCTP_HEADER_LEN(m);
433170138Srrs	total_len = SCTP_SIZE32((length + (4 * sizeof(int))));
434170091Srrs	/* Log a packet to the buffer. */
435170091Srrs	if (total_len > SCTP_PACKET_LOG_SIZE) {
436170091Srrs		/* Can't log this packet I have not a buffer big enough */
437170091Srrs		return;
438170091Srrs	}
439179783Srrs	if (length < (int)(SCTP_MIN_V4_OVERHEAD + sizeof(struct sctp_cookie_ack_chunk))) {
440170091Srrs		return;
441170091Srrs	}
442179783Srrs	atomic_add_int(&SCTP_BASE_VAR(packet_log_writers), 1);
443170138Srrstry_again:
444179783Srrs	if (SCTP_BASE_VAR(packet_log_writers) > SCTP_PKTLOG_WRITERS_NEED_LOCK) {
445170138Srrs		SCTP_IP_PKTLOG_LOCK();
446170138Srrs		grabbed_lock = 1;
447170138Srrsagain_locked:
448179783Srrs		value = SCTP_BASE_VAR(packet_log_end);
449179783Srrs		newval = SCTP_BASE_VAR(packet_log_end) + total_len;
450170138Srrs		if (newval >= SCTP_PACKET_LOG_SIZE) {
451170138Srrs			/* we wrapped */
452170138Srrs			thisbegin = 0;
453170138Srrs			thisend = total_len;
454170091Srrs		} else {
455179783Srrs			thisbegin = SCTP_BASE_VAR(packet_log_end);
456170138Srrs			thisend = newval;
457170091Srrs		}
458179783Srrs		if (!(atomic_cmpset_int(&SCTP_BASE_VAR(packet_log_end), value, thisend))) {
459170138Srrs			goto again_locked;
460170091Srrs		}
461170091Srrs	} else {
462179783Srrs		value = SCTP_BASE_VAR(packet_log_end);
463179783Srrs		newval = SCTP_BASE_VAR(packet_log_end) + total_len;
464170138Srrs		if (newval >= SCTP_PACKET_LOG_SIZE) {
465170138Srrs			/* we wrapped */
466170138Srrs			thisbegin = 0;
467170138Srrs			thisend = total_len;
468170138Srrs		} else {
469179783Srrs			thisbegin = SCTP_BASE_VAR(packet_log_end);
470170138Srrs			thisend = newval;
471170091Srrs		}
472179783Srrs		if (!(atomic_cmpset_int(&SCTP_BASE_VAR(packet_log_end), value, thisend))) {
473170138Srrs			goto try_again;
474170138Srrs		}
475170091Srrs	}
476170138Srrs	/* Sanity check */
477170138Srrs	if (thisend >= SCTP_PACKET_LOG_SIZE) {
478234995Stuexen		SCTP_PRINTF("Insanity stops a log thisbegin:%d thisend:%d writers:%d lock:%d end:%d\n",
479170138Srrs		    thisbegin,
480170138Srrs		    thisend,
481179783Srrs		    SCTP_BASE_VAR(packet_log_writers),
482170138Srrs		    grabbed_lock,
483179783Srrs		    SCTP_BASE_VAR(packet_log_end));
484179783Srrs		SCTP_BASE_VAR(packet_log_end) = 0;
485170138Srrs		goto no_log;
486170138Srrs
487170091Srrs	}
488179783Srrs	lenat = (int *)&SCTP_BASE_VAR(packet_log_buffer)[thisbegin];
489170091Srrs	*lenat = total_len;
490170091Srrs	lenat++;
491170138Srrs	*lenat = value;
492170138Srrs	lenat++;
493170091Srrs	tick_tock = (uint32_t *) lenat;
494170091Srrs	lenat++;
495170091Srrs	*tick_tock = sctp_get_tick_count();
496170091Srrs	copyto = (void *)lenat;
497170138Srrs	thisone = thisend - sizeof(int);
498179783Srrs	lenat = (int *)&SCTP_BASE_VAR(packet_log_buffer)[thisone];
499170138Srrs	*lenat = thisbegin;
500170138Srrs	if (grabbed_lock) {
501170138Srrs		SCTP_IP_PKTLOG_UNLOCK();
502170138Srrs		grabbed_lock = 0;
503170138Srrs	}
504170091Srrs	m_copydata(m, 0, length, (caddr_t)copyto);
505170138Srrsno_log:
506170138Srrs	if (grabbed_lock) {
507170138Srrs		SCTP_IP_PKTLOG_UNLOCK();
508170138Srrs	}
509179783Srrs	atomic_subtract_int(&SCTP_BASE_VAR(packet_log_writers), 1);
510170091Srrs}
511170091Srrs
512170091Srrs
513170091Srrsint
514170091Srrssctp_copy_out_packet_log(uint8_t * target, int length)
515170091Srrs{
516170091Srrs	/*
517170091Srrs	 * We wind through the packet log starting at start copying up to
518170091Srrs	 * length bytes out. We return the number of bytes copied.
519170091Srrs	 */
520170138Srrs	int tocopy, this_copy;
521170138Srrs	int *lenat;
522170138Srrs	int did_delay = 0;
523170091Srrs
524170091Srrs	tocopy = length;
525179783Srrs	if (length < (int)(2 * sizeof(int))) {
526170138Srrs		/* not enough room */
527170091Srrs		return (0);
528170091Srrs	}
529170138Srrs	if (SCTP_PKTLOG_WRITERS_NEED_LOCK) {
530179783Srrs		atomic_add_int(&SCTP_BASE_VAR(packet_log_writers), SCTP_PKTLOG_WRITERS_NEED_LOCK);
531170138Srrsagain:
532179783Srrs		if ((did_delay == 0) && (SCTP_BASE_VAR(packet_log_writers) != SCTP_PKTLOG_WRITERS_NEED_LOCK)) {
533170138Srrs			/*
534170138Srrs			 * we delay here for just a moment hoping the
535170138Srrs			 * writer(s) that were present when we entered will
536170138Srrs			 * have left and we only have locking ones that will
537170138Srrs			 * contend with us for the lock. This does not
538170138Srrs			 * assure 100% access, but its good enough for a
539170138Srrs			 * logging facility like this.
540170138Srrs			 */
541170138Srrs			did_delay = 1;
542170138Srrs			DELAY(10);
543170138Srrs			goto again;
544170091Srrs		}
545170091Srrs	}
546170138Srrs	SCTP_IP_PKTLOG_LOCK();
547170138Srrs	lenat = (int *)target;
548179783Srrs	*lenat = SCTP_BASE_VAR(packet_log_end);
549170138Srrs	lenat++;
550170899Srrs	this_copy = min((length - sizeof(int)), SCTP_PACKET_LOG_SIZE);
551179783Srrs	memcpy((void *)lenat, (void *)SCTP_BASE_VAR(packet_log_buffer), this_copy);
552170138Srrs	if (SCTP_PKTLOG_WRITERS_NEED_LOCK) {
553179783Srrs		atomic_subtract_int(&SCTP_BASE_VAR(packet_log_writers),
554170899Srrs		    SCTP_PKTLOG_WRITERS_NEED_LOCK);
555170138Srrs	}
556170138Srrs	SCTP_IP_PKTLOG_UNLOCK();
557170138Srrs	return (this_copy + sizeof(int));
558170091Srrs}
559170091Srrs
560170091Srrs#endif
561