Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / vera / niu_ippktgen / C / libnet / src / libnet_build_tcp.c
CommitLineData
86530b38
AT
1/*
2 * $Id: libnet_build_tcp.c,v 1.20 2005/11/29 22:14:06 carlosc Exp $
3 *
4 * libnet
5 * libnet_build_tcp.c - TCP packet assembler
6 *
7 * Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 */
32
33#if (HAVE_CONFIG_H)
34#include "../include/config.h"
35#endif
36#if (!(_WIN32) || (__CYGWIN__))
37#include "../include/libnet.h"
38#else
39#include "../include/win32/libnet.h"
40#endif
41
42libnet_ptag_t
43libnet_build_tcp(u_int16_t sp, u_int16_t dp, u_int32_t seq, u_int32_t ack,
44u_int8_t control, u_int16_t win, u_int16_t sum, u_int16_t urg, u_int16_t len,
45u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
46{
47 int n, offset;
48 u_int32_t i, j;
49 libnet_pblock_t *p, *p_data, *p_temp;
50 libnet_ptag_t ptag_hold, ptag_data;
51 struct libnet_tcp_hdr tcp_hdr;
52 struct libnet_ipv4_hdr *ip_hdr;
53
54 if (l == NULL)
55 {
56 return (-1);
57 }
58
59 ptag_data = 0; /* for possible options */
60
61 /*
62 * Find the existing protocol block if a ptag is specified, or create
63 * a new one.
64 */
65 p = libnet_pblock_probe(l, ptag, LIBNET_TCP_H, LIBNET_PBLOCK_TCP_H);
66 if (p == NULL)
67 {
68 return (-1);
69 }
70
71 memset(&tcp_hdr, 0, sizeof(tcp_hdr));
72 tcp_hdr.th_sport = htons(sp); /* source port */
73 tcp_hdr.th_dport = htons(dp); /* destination port */
74 tcp_hdr.th_seq = htonl(seq); /* sequence number */
75 tcp_hdr.th_ack = htonl(ack); /* acknowledgement number */
76 tcp_hdr.th_flags = control; /* control flags */
77 tcp_hdr.th_x2 = 0; /* UNUSED */
78 tcp_hdr.th_off = 5; /* 20 byte header */
79
80 /* check to see if there are TCP options to include */
81 if (p->prev)
82 {
83 p_temp = p->prev;
84 while ((p_temp->prev) && (p_temp->type != LIBNET_PBLOCK_TCPO_H))
85 {
86 p_temp = p_temp->prev;
87 }
88 if (p_temp->type == LIBNET_PBLOCK_TCPO_H)
89 {
90 /*
91 * Count up number of 32-bit words in options list, padding if
92 * neccessary.
93 */
94 for (i = 0, j = 0; i < p_temp->b_len; i++)
95 {
96 (i % 4) ? j : j++;
97 }
98 tcp_hdr.th_off += j;
99 }
100 }
101
102 tcp_hdr.th_win = htons(win); /* window size */
103 tcp_hdr.th_sum = (sum ? htons(sum) : 0); /* checksum */
104 tcp_hdr.th_urp = htons(urg); /* urgent pointer */
105
106 n = libnet_pblock_append(l, p, (u_int8_t *)&tcp_hdr, LIBNET_TCP_H);
107 if (n == -1)
108 {
109 goto bad;
110 }
111
112 ptag_hold = ptag;
113 if (ptag == LIBNET_PTAG_INITIALIZER)
114 {
115 ptag = libnet_pblock_update(l, p, len, LIBNET_PBLOCK_TCP_H);
116 }
117
118 /* find and set the appropriate ptag, or else use the default of 0 */
119 offset = payload_s;
120 if (ptag_hold && p->prev)
121 {
122 p_temp = p->prev;
123 while (p_temp->prev &&
124 (p_temp->type != LIBNET_PBLOCK_TCPDATA) &&
125 (p_temp->type != LIBNET_PBLOCK_TCP_H))
126 {
127 p_temp = p_temp->prev;
128 }
129
130 if (p_temp->type == LIBNET_PBLOCK_TCPDATA)
131 {
132 ptag_data = p_temp->ptag;
133 offset -= p_temp->b_len;
134 p->h_len += offset;
135 }
136 else
137 {
138 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
139 "%s(): TCP data pblock not found\n", __func__);
140 }
141 }
142
143 /* update ip_len if present */
144 if (ptag_hold && p->next)
145 {
146 p_temp = p->next;
147 while (p_temp->next && (p_temp->type != LIBNET_PBLOCK_IPV4_H))
148 {
149 p_temp = p_temp->next;
150 }
151 if (p_temp->type == LIBNET_PBLOCK_IPV4_H)
152 {
153 ip_hdr = (struct libnet_ipv4_hdr *)p_temp->buf;
154 n = ntohs(ip_hdr->ip_len) + offset;
155 ip_hdr->ip_len = htons(n);
156 }
157 }
158
159 if ((payload && !payload_s) || (!payload && payload_s))
160 {
161 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
162 "%s(): payload inconsistency\n", __func__);
163 goto bad;
164 }
165
166 /* if there is a payload, add it in the context */
167 if (payload && payload_s)
168 {
169 /* update ptag_data with the new payload */
170 p_data = libnet_pblock_probe(l, ptag_data, payload_s,
171 LIBNET_PBLOCK_TCPDATA);
172 if (p_data == NULL)
173 {
174 return (-1);
175 }
176
177 if (libnet_pblock_append(l, p_data, payload, payload_s) == -1)
178 {
179 goto bad;
180 }
181
182 if (ptag_data == LIBNET_PTAG_INITIALIZER)
183 {
184 if (p_data->prev->type == LIBNET_PBLOCK_TCP_H)
185 {
186 libnet_pblock_update(l, p_data, payload_s,
187 LIBNET_PBLOCK_TCPDATA);
188 /* swap pblocks to correct the protocol order */
189 libnet_pblock_swap(l, p->ptag, p_data->ptag);
190 }
191 else
192 {
193 /* update without setting this as the final pblock */
194 p_data->type = LIBNET_PBLOCK_TCPDATA;
195 p_data->ptag = ++(l->ptag_state);
196 p_data->h_len = payload_s;
197
198 /* Adjust h_len for checksum. */
199 p->h_len += payload_s;
200
201 /* data was added after the initial construction */
202 for (p_temp = l->protocol_blocks;
203 p_temp->type == LIBNET_PBLOCK_TCP_H ||
204 p_temp->type == LIBNET_PBLOCK_TCPO_H;
205 p_temp = p_temp->next)
206 {
207 libnet_pblock_insert_before(l, p_temp->ptag, p_data->ptag);
208 break;
209 }
210 /* The end block needs to have its next pointer cleared. */
211 l->pblock_end->next = NULL;
212 }
213
214 if (p_data->prev && p_data->prev->type == LIBNET_PBLOCK_TCPO_H)
215 {
216 libnet_pblock_swap(l, p_data->prev->ptag, p_data->ptag);
217 }
218 }
219 }
220 else
221 {
222 p_data = libnet_pblock_find(l, ptag_data);
223 if (p_data)
224 {
225 libnet_pblock_delete(l, p_data);
226 }
227 }
228
229 if (sum == 0)
230 {
231 /*
232 * If checksum is zero, by default libnet will compute a checksum
233 * for the user. The programmer can override this by calling
234 * libnet_toggle_checksum(l, ptag, 1);
235 */
236 libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
237 }
238 return (ptag);
239bad:
240 libnet_pblock_delete(l, p);
241 return (-1);
242}
243
244
245libnet_ptag_t
246libnet_build_tcp_options(u_int8_t *options, u_int32_t options_s, libnet_t *l,
247libnet_ptag_t ptag)
248{
249 int offset, underflow;
250 u_int32_t i, j, n, adj_size;
251 libnet_pblock_t *p, *p_temp;
252 struct libnet_ipv4_hdr *ip_hdr;
253 struct libnet_tcp_hdr *tcp_hdr;
254
255 if (l == NULL)
256 {
257 return (-1);
258 }
259
260 underflow = 0;
261 offset = 0;
262
263 /* check options list size */
264 if (options_s > LIBNET_MAXOPTION_SIZE)
265 {
266 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
267 "%s(): options list is too large %d\n", __func__, options_s);
268 return (-1);
269 }
270
271 adj_size = options_s;
272 if (adj_size % 4)
273 {
274 /* size of memory block with padding */
275 adj_size += 4 - (options_s % 4);
276 }
277
278 /* if this pblock already exists, determine if there is a size diff */
279 if (ptag)
280 {
281 p_temp = libnet_pblock_find(l, ptag);
282 if (p_temp)
283 {
284 if (adj_size >= p_temp->b_len)
285 {
286 offset = adj_size - p_temp->b_len;
287 }
288 else
289 {
290 offset = p_temp->b_len - adj_size;
291 underflow = 1;
292 }
293 }
294 }
295
296 /*
297 * Find the existing protocol block if a ptag is specified, or create
298 * a new one.
299 */
300 p = libnet_pblock_probe(l, ptag, adj_size, LIBNET_PBLOCK_TCPO_H);
301 if (p == NULL)
302 {
303 return (-1);
304 }
305
306 n = libnet_pblock_append(l, p, options, adj_size);
307 if (n == -1)
308 {
309 goto bad;
310 }
311
312 if (ptag && p->next)
313 {
314 p_temp = p->next;
315 while ((p_temp->next) && (p_temp->type != LIBNET_PBLOCK_TCP_H))
316 {
317 p_temp = p_temp->next;
318 }
319 if (p_temp->type == LIBNET_PBLOCK_TCP_H)
320 {
321 /*
322 * Count up number of 32-bit words in options list, padding if
323 * neccessary.
324 */
325 for (i = 0, j = 0; i < p->b_len; i++)
326 {
327 (i % 4) ? j : j++;
328 }
329 tcp_hdr = (struct libnet_tcp_hdr *)p_temp->buf;
330 tcp_hdr->th_off = j + 5;
331 if (!underflow)
332 {
333 p_temp->h_len += offset;
334 }
335 else
336 {
337 p_temp->h_len -= offset;
338 }
339 }
340 while ((p_temp->next) && (p_temp->type != LIBNET_PBLOCK_IPV4_H))
341 {
342 p_temp = p_temp->next;
343 }
344 if (p_temp->type == LIBNET_PBLOCK_IPV4_H)
345 {
346 ip_hdr = (struct libnet_ipv4_hdr *)p_temp->buf;
347 if (!underflow)
348 {
349 ip_hdr->ip_len += htons(offset);
350 }
351 else
352 {
353 ip_hdr->ip_len -= htons(offset);
354 }
355 }
356 }
357
358 return (ptag ? ptag : libnet_pblock_update(l, p, adj_size,
359 LIBNET_PBLOCK_TCPO_H));
360bad:
361 libnet_pblock_delete(l, p);
362 return (-1);
363}
364
365/* EOF */