aboutsummaryrefslogtreecommitdiff
path: root/sys/sys/sockbuf.h
blob: a1fd65d1a9e56d384be1319d6460b1f57bd6e328 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/*-
 * SPDX-License-Identifier: BSD-3-Clause
 *
 * Copyright (c) 1982, 1986, 1990, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)socketvar.h	8.3 (Berkeley) 2/19/95
 *
 * $FreeBSD$
 */
#ifndef _SYS_SOCKBUF_H_
#define _SYS_SOCKBUF_H_

/*
 * Constants for sb_flags field of struct sockbuf/xsockbuf.
 */
#define	SB_TLS_RX	0x01		/* using KTLS on RX */
#define	SB_TLS_RX_RUNNING 0x02		/* KTLS RX operation running */
#define	SB_WAIT		0x04		/* someone is waiting for data/space */
#define	SB_SEL		0x08		/* someone is selecting */
#define	SB_ASYNC	0x10		/* ASYNC I/O, need signals */
#define	SB_UPCALL	0x20		/* someone wants an upcall */
#define	SB_NOINTR	0x40		/* operations not interruptible */
#define	SB_AIO		0x80		/* AIO operations queued */
#define	SB_KNOTE	0x100		/* kernel note attached */
#define	SB_NOCOALESCE	0x200		/* don't coalesce new data into existing mbufs */
#define	SB_IN_TOE	0x400		/* socket buffer is in the middle of an operation */
#define	SB_AUTOSIZE	0x800		/* automatically size socket buffer */
#define	SB_STOP		0x1000		/* backpressure indicator */
#define	SB_AIO_RUNNING	0x2000		/* AIO operation running */
#define	SB_TLS_IFNET	0x4000		/* has used / is using ifnet KTLS */
#define	SB_TLS_RX_RESYNC 0x8000		/* KTLS RX lost HW sync */

#define	SBS_CANTSENDMORE	0x0010	/* can't send more data to peer */
#define	SBS_CANTRCVMORE		0x0020	/* can't receive more data from peer */
#define	SBS_RCVATMARK		0x0040	/* at mark on input */

#if defined(_KERNEL) || defined(_WANT_SOCKET)
#include <sys/_lock.h>
#include <sys/_mutex.h>
#include <sys/_sx.h>
#include <sys/_task.h>

#define	SB_MAX		(2*1024*1024)	/* default for max chars in sockbuf */

struct ktls_session;
struct mbuf;
struct sockaddr;
struct socket;
struct thread;
struct selinfo;

/*
 * Socket buffer
 *
 * A buffer starts with the fields that are accessed by I/O multiplexing
 * APIs like select(2), kevent(2) or AIO and thus are shared between different
 * buffer implementations.  They are protected by the SOCK_RECVBUF_LOCK()
 * or SOCK_SENDBUF_LOCK() of the owning socket.
 *
 * XXX: sb_acc, sb_ccc and sb_mbcnt shall become implementation specific
 * methods.
 *
 * Protocol specific implementations follow in a union.
 */
struct sockbuf {
	struct	selinfo *sb_sel;	/* process selecting read/write */
	short	sb_state;		/* socket state on sockbuf */
	short	sb_flags;		/* flags, see above */
	u_int	sb_acc;			/* available chars in buffer */
	u_int	sb_ccc;			/* claimed chars in buffer */
	u_int	sb_mbcnt;		/* chars of mbufs used */
	u_int	sb_ctl;			/* non-data chars in buffer */
	u_int	sb_hiwat;		/* max actual char count */
	u_int	sb_lowat;		/* low water mark */
	u_int	sb_mbmax;		/* max chars of mbufs to use */
	sbintime_t sb_timeo;		/* timeout for read/write */
	int	(*sb_upcall)(struct socket *, void *, int);
	void	*sb_upcallarg;
	TAILQ_HEAD(, kaiocb) sb_aiojobq;	/* pending AIO ops */
	struct	task sb_aiotask;		/* AIO task */
	union {
		/*
		 * Classic BSD one-size-fits-all socket buffer, capable of
		 * doing streams and datagrams. The stream part is able
		 * to perform special features:
		 * - not ready data (sendfile)
		 * - TLS
		 */
		struct {
			/* compat: sockbuf lock pointer */
			struct	mtx *sb_mtx;
			/* first and last mbufs in the chain */
			struct	mbuf *sb_mb;
			struct	mbuf *sb_mbtail;
			/* first mbuf of last record in socket buffer */
			struct	mbuf *sb_lastrecord;
			/* pointer to data to send next (TCP */
			struct	mbuf *sb_sndptr;
			/* pointer to first not ready buffer */
			struct	mbuf *sb_fnrdy;
			/* byte offset of ptr into chain, used with sb_sndptr */
			u_int	sb_sndptroff;
			/* TLS */
			u_int	sb_tlscc;	/* TLS chain characters */
			u_int	sb_tlsdcc;	/* characters being decrypted */
			struct	mbuf *sb_mtls;	/*  TLS mbuf chain */
			struct	mbuf *sb_mtlstail; /* last mbuf in TLS chain */
			uint64_t sb_tls_seqno;	/* TLS seqno */
			struct	ktls_session *sb_tls_info; /* TLS state */
		};
		/*
		 * PF_UNIX/SOCK_DGRAM
		 *
		 * Local protocol, thus any socket buffer is a receive buffer.
		 */
		struct {
			STAILQ_HEAD(, mbuf)	uxdg_mb;
		};
	};
};

#endif	/* defined(_KERNEL) || defined(_WANT_SOCKET) */
#ifdef _KERNEL

/* 'which' values for KPIs that operate on one buffer of a socket. */
typedef enum { SO_RCV, SO_SND } sb_which;

/*
 * Per-socket buffer mutex used to protect most fields in the socket buffer.
 * These make use of the mutex pointer embedded in struct sockbuf, which
 * currently just references mutexes in the containing socket.  The
 * SOCK_SENDBUF_LOCK() etc. macros can be used instead of or in combination with
 * these locking macros.
 */
#define	SOCKBUF_MTX(_sb)		((_sb)->sb_mtx)
#define	SOCKBUF_LOCK(_sb)		mtx_lock(SOCKBUF_MTX(_sb))
#define	SOCKBUF_OWNED(_sb)		mtx_owned(SOCKBUF_MTX(_sb))
#define	SOCKBUF_UNLOCK(_sb)		mtx_unlock(SOCKBUF_MTX(_sb))
#define	SOCKBUF_LOCK_ASSERT(_sb)	mtx_assert(SOCKBUF_MTX(_sb), MA_OWNED)
#define	SOCKBUF_UNLOCK_ASSERT(_sb)	mtx_assert(SOCKBUF_MTX(_sb), MA_NOTOWNED)

/*
 * Socket buffer private mbuf(9) flags.
 */
#define	M_NOTREADY	M_PROTO1	/* m_data not populated yet */
#define	M_BLOCKED	M_PROTO2	/* M_NOTREADY in front of m */
#define	M_NOTAVAIL	(M_NOTREADY | M_BLOCKED)

void	sbappend(struct sockbuf *sb, struct mbuf *m, int flags);
void	sbappend_locked(struct sockbuf *sb, struct mbuf *m, int flags);
void	sbappendstream(struct sockbuf *sb, struct mbuf *m, int flags);
void	sbappendstream_locked(struct sockbuf *sb, struct mbuf *m, int flags);
int	sbappendaddr(struct sockbuf *sb, const struct sockaddr *asa,
	    struct mbuf *m0, struct mbuf *control);
int	sbappendaddr_locked(struct sockbuf *sb, const struct sockaddr *asa,
	    struct mbuf *m0, struct mbuf *control);
int	sbappendaddr_nospacecheck_locked(struct sockbuf *sb,
	    const struct sockaddr *asa, struct mbuf *m0, struct mbuf *control);
void	sbappendcontrol(struct sockbuf *sb, struct mbuf *m0,
	    struct mbuf *control, int flags);
void	sbappendcontrol_locked(struct sockbuf *sb, struct mbuf *m0,
	    struct mbuf *control, int flags);
void	sbappendrecord(struct sockbuf *sb, struct mbuf *m0);
void	sbappendrecord_locked(struct sockbuf *sb, struct mbuf *m0);
void	sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n);
struct mbuf *
	sbcreatecontrol(const void *p, u_int size, int type, int level,
	    int wait);
void	sbdestroy(struct socket *, sb_which);
void	sbdrop(struct sockbuf *sb, int len);
void	sbdrop_locked(struct sockbuf *sb, int len);
struct mbuf *
	sbcut_locked(struct sockbuf *sb, int len);
void	sbdroprecord(struct sockbuf *sb);
void	sbdroprecord_locked(struct sockbuf *sb);
void	sbflush(struct sockbuf *sb);
void	sbflush_locked(struct sockbuf *sb);
void	sbrelease(struct socket *, sb_which);
void	sbrelease_locked(struct socket *, sb_which);
int	sbsetopt(struct socket *so, int cmd, u_long cc);
bool	sbreserve_locked(struct socket *so, sb_which which, u_long cc,
	    struct thread *td);
void	sbsndptr_adv(struct sockbuf *sb, struct mbuf *mb, u_int len);
struct mbuf *
	sbsndptr_noadv(struct sockbuf *sb, u_int off, u_int *moff);
struct mbuf *
	sbsndmbuf(struct sockbuf *sb, u_int off, u_int *moff);
int	sbwait(struct socket *, sb_which);
void	sballoc(struct sockbuf *, struct mbuf *);
void	sbfree(struct sockbuf *, struct mbuf *);
void	sballoc_ktls_rx(struct sockbuf *sb, struct mbuf *m);
void	sbfree_ktls_rx(struct sockbuf *sb, struct mbuf *m);
int	sbready(struct sockbuf *, struct mbuf *, int);

/*
 * Return how much data is available to be taken out of socket
 * buffer right now.
 */
static inline u_int
sbavail(struct sockbuf *sb)
{

#if 0
	SOCKBUF_LOCK_ASSERT(sb);
#endif
	return (sb->sb_acc);
}

/*
 * Return how much data sits there in the socket buffer
 * It might be that some data is not yet ready to be read.
 */
static inline u_int
sbused(struct sockbuf *sb)
{

#if 0
	SOCKBUF_LOCK_ASSERT(sb);
#endif
	return (sb->sb_ccc);
}

/*
 * How much space is there in a socket buffer (so->so_snd or so->so_rcv)?
 * This is problematical if the fields are unsigned, as the space might
 * still be negative (ccc > hiwat or mbcnt > mbmax).
 */
static inline long
sbspace(struct sockbuf *sb)
{
	int bleft, mleft;		/* size should match sockbuf fields */

#if 0
	SOCKBUF_LOCK_ASSERT(sb);
#endif

	if (sb->sb_flags & SB_STOP)
		return(0);

	bleft = sb->sb_hiwat - sb->sb_ccc;
	mleft = sb->sb_mbmax - sb->sb_mbcnt;

	return ((bleft < mleft) ? bleft : mleft);
}

#define SB_EMPTY_FIXUP(sb) do {						\
	if ((sb)->sb_mb == NULL) {					\
		(sb)->sb_mbtail = NULL;					\
		(sb)->sb_lastrecord = NULL;				\
	}								\
} while (/*CONSTCOND*/0)

#ifdef SOCKBUF_DEBUG
void	sblastrecordchk(struct sockbuf *, const char *, int);
void	sblastmbufchk(struct sockbuf *, const char *, int);
void	sbcheck(struct sockbuf *, const char *, int);
#define	SBLASTRECORDCHK(sb)	sblastrecordchk((sb), __FILE__, __LINE__)
#define	SBLASTMBUFCHK(sb)	sblastmbufchk((sb), __FILE__, __LINE__)
#define	SBCHECK(sb)		sbcheck((sb), __FILE__, __LINE__)
#else
#define	SBLASTRECORDCHK(sb)	do {} while (0)
#define	SBLASTMBUFCHK(sb)	do {} while (0)
#define	SBCHECK(sb)		do {} while (0)
#endif /* SOCKBUF_DEBUG */

#endif /* _KERNEL */

#endif /* _SYS_SOCKBUF_H_ */