summaryrefslogtreecommitdiffstats
path: root/3rdparty/openpgm-svn-r1085/pgm/include/pgm/skbuff.h
blob: 0701dfb7920a29052dcc300b712030ff654035a3 (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
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
 * 
 * PGM socket buffers
 *
 * Copyright (c) 2006-2009 Miru Limited.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __PGM_SKBUFF_H__
#define __PGM_SKBUFF_H__

#include <string.h>

struct pgm_sk_buff_t;

#include <pgm/types.h>
#include <pgm/atomic.h>
#include <pgm/mem.h>
#include <pgm/list.h>
#include <pgm/time.h>
#include <pgm/packet.h>
#include <pgm/tsi.h>
#include <pgm/socket.h>

PGM_BEGIN_DECLS

struct pgm_sk_buff_t {
	pgm_list_t			link_;

	pgm_sock_t* restrict		sock;
	pgm_time_t			tstamp;
	pgm_tsi_t			tsi;

	uint32_t			sequence;
	uint32_t			__padding;	/* push alignment of pgm_sk_buff_t::cb to 8 bytes */

	char				cb[48];		/* control buffer */

	uint16_t			len;		/* actual data */
	unsigned			zero_padded:1;

	struct pgm_header*		pgm_header;
	struct pgm_opt_fragment* 	pgm_opt_fragment;
#define of_apdu_first_sqn		pgm_opt_fragment->opt_sqn
#define of_frag_offset			pgm_opt_fragment->opt_frag_off
#define of_apdu_len			pgm_opt_fragment->opt_frag_len
	struct pgm_opt_pgmcc_data*	pgm_opt_pgmcc_data;
	struct pgm_data*		pgm_data;

	void			       *head,		/* all may-alias */
				       *data,
				       *tail,
				       *end;
	uint32_t			truesize;
	volatile uint32_t		users;		/* atomic */
};

void pgm_skb_over_panic (const struct pgm_sk_buff_t*const, const uint16_t) PGM_GNUC_NORETURN;
void pgm_skb_under_panic (const struct pgm_sk_buff_t*const, const uint16_t) PGM_GNUC_NORETURN;
bool pgm_skb_is_valid (const struct pgm_sk_buff_t*const) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT;

/* attribute __pure__ only valid for platforms with atomic ops.
 * attribute __malloc__ not used as only part of the memory should be aliased.
 * attribute __alloc_size__ does not allow headroom.
 */
static inline struct pgm_sk_buff_t* pgm_alloc_skb (const uint16_t) PGM_GNUC_WARN_UNUSED_RESULT;

static inline
struct pgm_sk_buff_t*
pgm_alloc_skb (
	const uint16_t		size
	)
{
	struct pgm_sk_buff_t* skb;

	skb = (struct pgm_sk_buff_t*)pgm_malloc (size + sizeof(struct pgm_sk_buff_t));
	if (PGM_UNLIKELY(pgm_mem_gc_friendly)) {
		memset (skb, 0, size + sizeof(struct pgm_sk_buff_t));
		skb->zero_padded = 1;
	} else {
		memset (skb, 0, sizeof(struct pgm_sk_buff_t));
	}
	skb->truesize = size + sizeof(struct pgm_sk_buff_t);
	pgm_atomic_write32 (&skb->users, 1);
	skb->head = skb + 1;
	skb->data = skb->tail = skb->head;
	skb->end  = (char*)skb->data + size;
	return skb;
}

/* increase reference count */
static inline
struct pgm_sk_buff_t*
pgm_skb_get (
	struct pgm_sk_buff_t*const skb
	)
{
	pgm_atomic_inc32 (&skb->users);
	return skb;
}

static inline
void
pgm_free_skb (
	struct pgm_sk_buff_t*const skb
	)
{
	if (pgm_atomic_exchange_and_add32 (&skb->users, (uint32_t)-1) == 1)
		pgm_free (skb);
}

/* add data */
static inline
void*
pgm_skb_put (
	struct pgm_sk_buff_t* const skb,
	const uint16_t		len
	)
{
	void* tmp = skb->tail;
	skb->tail = (char*)skb->tail + len;
	skb->len  += len;
	if (PGM_UNLIKELY(skb->tail > skb->end))
		pgm_skb_over_panic (skb, len);
	return tmp;
}

static inline
void*
__pgm_skb_pull (
	struct pgm_sk_buff_t*const skb,
	const uint16_t		len
	)
{
	skb->len -= len;
	return skb->data = (char*)skb->data + len;
}

/* remove data from start of buffer */
static inline
void*
pgm_skb_pull (
	struct pgm_sk_buff_t*const skb,
	const uint16_t		len
	)
{
	return PGM_UNLIKELY(len > skb->len) ? NULL : __pgm_skb_pull (skb, len);
}

static inline uint16_t pgm_skb_headroom (const struct pgm_sk_buff_t*const) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT;
static inline uint16_t pgm_skb_tailroom (const struct pgm_sk_buff_t*const) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT;

static inline
uint16_t
pgm_skb_headroom (
	const struct pgm_sk_buff_t*const skb
	)
{
	return (char*)skb->data - (char*)skb->head;
}

static inline
uint16_t
pgm_skb_tailroom (
	const struct pgm_sk_buff_t*const skb
	)
{
	return (char*)skb->end - (char*)skb->tail;
}

/* reserve space to add data */
static inline
void
pgm_skb_reserve (
	struct pgm_sk_buff_t*const skb,
	const uint16_t		len
	)
{
	skb->data = (char*)skb->data + len;
	skb->tail = (char*)skb->tail + len;
	if (PGM_UNLIKELY(skb->tail > skb->end))
		pgm_skb_over_panic (skb, len);
	if (PGM_UNLIKELY(skb->data < skb->head))
		pgm_skb_under_panic (skb, len);
}

static inline struct pgm_sk_buff_t* pgm_skb_copy (const struct pgm_sk_buff_t* const) PGM_GNUC_WARN_UNUSED_RESULT;

static inline
struct pgm_sk_buff_t*
pgm_skb_copy (
	const struct pgm_sk_buff_t* const skb
	)
{
	struct pgm_sk_buff_t* newskb;
	newskb = (struct pgm_sk_buff_t*)pgm_malloc (skb->truesize);
	memcpy (newskb, skb, PGM_OFFSETOF(struct pgm_sk_buff_t, pgm_header));
	newskb->zero_padded = 0;
	newskb->truesize = skb->truesize;
	pgm_atomic_write32 (&newskb->users, 1);
	newskb->head = newskb + 1;
	newskb->end  = (char*)newskb->head + ((char*)skb->end  - (char*)skb->head);
	newskb->data = (char*)newskb->head + ((char*)skb->data - (char*)skb->head);
	newskb->tail = (char*)newskb->head + ((char*)skb->tail - (char*)skb->head);
	newskb->pgm_header = skb->pgm_header ? (struct pgm_header*)((char*)newskb->head + ((char*)skb->pgm_header - (char*)skb->head)) : skb->pgm_header;
	newskb->pgm_opt_fragment = skb->pgm_opt_fragment ? (struct pgm_opt_fragment*)((char*)newskb->head + ((char*)skb->pgm_opt_fragment - (char*)skb->head)) : skb->pgm_opt_fragment;
	newskb->pgm_data = skb->pgm_data ? (struct pgm_data*)((char*)newskb->head + ((char*)skb->pgm_data - (char*)skb->head)) : skb->pgm_data;
	memcpy (newskb->head, skb->head, (char*)skb->end - (char*)skb->head);
	return newskb;
}

static inline
void
pgm_skb_zero_pad (
	struct pgm_sk_buff_t* const	skb,
	const uint16_t			len
	)
{
	if (skb->zero_padded)
		return;

	const uint16_t tailroom = MIN(pgm_skb_tailroom (skb), len);
	if (tailroom > 0)
		memset (skb->tail, 0, tailroom);
	skb->zero_padded = 1;
}

PGM_END_DECLS

#endif /* __PGM_SKBUFF_H__ */