Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / vera / niu_ippktgen / C / libnet / src / libnet_pblock.c
CommitLineData
86530b38
AT
1/*
2 * $Id: libnet_pblock.c,v 1.20 2005/11/29 22:34:37 carlosc Exp $
3 *
4 * libnet
5 * libnet_pblock.c - Memory protocol block routines.
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_pblock_t *
43libnet_pblock_probe(libnet_t *l, libnet_ptag_t ptag, u_int32_t n, u_int8_t type)
44{
45 int offset;
46 libnet_pblock_t *p;
47
48 if (ptag == LIBNET_PTAG_INITIALIZER)
49 {
50 /*
51 * Create a new pblock and enough buffer space for the packet.
52 */
53 p = libnet_pblock_new(l, n);
54 if (p == NULL)
55 {
56 /* err msg set in libnet_pblock_new() */
57 return (NULL);
58 }
59 }
60 else
61 {
62 /*
63 * Update this pblock, don't create a new one. Note that if the
64 * new packet size is larger than the old one we will do a malloc.
65 */
66 p = libnet_pblock_find(l, ptag);
67
68 if (p == NULL)
69 {
70 /* err msg set in libnet_pblock_find() */
71 return (NULL);
72 }
73 if (p->type != type)
74 {
75 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
76 "%s(): ptag refers to different type than expected (%d != %d)",
77 __func__, p->type, type);
78 return (NULL);
79 }
80 /*
81 * If size is greater than the original block of memory, we need
82 * to malloc more memory. Should we use realloc?
83 */
84 if (n > p->b_len)
85 {
86 offset = n - p->b_len; /* how many bytes larger new pblock is */
87 free(p->buf);
88 p->buf = malloc(n);
89 if (p->buf == NULL)
90 {
91 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
92 "%s(): can't resize pblock buffer: %s\n", __func__,
93 strerror(errno));
94 return (NULL);
95 }
96 memset(p->buf, 0, n);
97 p->h_len += offset; /* new length for checksums */
98 p->b_len = n; /* new buf len */
99 l->total_size += offset;
100 }
101 else
102 {
103 offset = p->b_len - n;
104 p->h_len -= offset; /* new length for checksums */
105 p->b_len = n; /* new buf len */
106 l->total_size -= offset;
107 }
108 p->copied = 0; /* reset copied counter */
109 }
110 return (p);
111}
112
113libnet_pblock_t *
114libnet_pblock_new(libnet_t *l, u_int32_t size)
115{
116 libnet_pblock_t *p;
117 /*
118 * Should we do error checking the size of the pblock here, or
119 * should we rely on the underlying operating system to complain when
120 * the user tries to write some ridiculously huge packet?
121 */
122
123 /* make the head node if it doesn't exist */
124 if (l->protocol_blocks == NULL)
125 {
126 p = l->protocol_blocks = malloc(sizeof (libnet_pblock_t));
127 if (p == NULL)
128 {
129 goto bad;
130 }
131 memset(p, 0, sizeof (libnet_pblock_t));
132 }
133 else
134 {
135 p = l->pblock_end;
136 p->next = malloc(sizeof (libnet_pblock_t));
137
138 if (p->next == NULL)
139 {
140 goto bad;
141 }
142 memset(p->next, 0, sizeof (libnet_pblock_t));
143 p->next->prev = p;
144 p = p->next;
145 }
146
147 p->buf = malloc(size);
148 if (p->buf == NULL)
149 {
150 free(p);
151 p = NULL;
152 goto bad;
153 }
154 memset(p->buf, 0, size);
155 p->b_len = size;
156 l->total_size += size;
157 l->n_pblocks++;
158 return (p);
159
160 bad:
161 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n", __func__,
162 strerror(errno));
163 return (NULL);
164}
165
166int
167libnet_pblock_swap(libnet_t *l, libnet_ptag_t ptag1, libnet_ptag_t ptag2)
168{
169 libnet_pblock_t *p1, *p2;
170
171 p1 = libnet_pblock_find(l, ptag1);
172 p2 = libnet_pblock_find(l, ptag2);
173 if (p1 == NULL || p2 == NULL)
174 {
175 /* error set elsewhere */
176 return (-1);
177 }
178
179 p2->prev = p1->prev;
180 p1->next = p2->next;
181 p2->next = p1;
182 p1->prev = p2;
183
184 if (p1->next)
185 {
186 p1->next->prev = p1;
187 }
188
189 if (p2->prev)
190 {
191 p2->prev->next = p2;
192 }
193 else
194 {
195 /* first node on the list */
196 l->protocol_blocks = p2;
197 }
198
199 if (l->pblock_end == p2)
200 {
201 l->pblock_end = p1;
202 }
203 return (1);
204}
205
206int
207libnet_pblock_insert_before(libnet_t *l, libnet_ptag_t ptag1,
208 libnet_ptag_t ptag2)
209{
210 libnet_pblock_t *p1, *p2;
211
212 p1 = libnet_pblock_find(l, ptag1);
213 p2 = libnet_pblock_find(l, ptag2);
214 if (p1 == NULL || p2 == NULL)
215 {
216 /* error set elsewhere */
217 return (-1);
218 }
219
220 p2->prev = p1->prev;
221 p2->next = p1;
222 p1->prev = p2;
223
224 if (p2->prev)
225 {
226 p2->prev->next = p2;
227 }
228 else
229 {
230 /* first node on the list */
231 l->protocol_blocks = p2;
232 }
233
234 return (1);
235}
236
237libnet_pblock_t *
238libnet_pblock_find(libnet_t *l, libnet_ptag_t ptag)
239{
240 libnet_pblock_t *p;
241
242 for (p = l->protocol_blocks; p; p = p->next)
243 {
244 if (p->ptag == ptag)
245 {
246 return (p);
247 }
248 }
249 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
250 "%s(): couldn't find protocol block\n", __func__);
251 return (NULL);
252}
253
254int
255libnet_pblock_append(libnet_t *l, libnet_pblock_t *p, u_int8_t *buf,
256 u_int32_t len)
257{
258 if (p->copied + len > p->b_len)
259 {
260 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
261 "%s(): memcpy would overflow buffer\n", __func__);
262 return (-1);
263 }
264 memcpy(p->buf + p->copied, buf, len);
265 p->copied += len;
266 return (1);
267}
268
269void
270libnet_pblock_setflags(libnet_pblock_t *p, u_int8_t flags)
271{
272 p->flags = flags;
273}
274
275libnet_ptag_t
276libnet_pblock_update(libnet_t *l, libnet_pblock_t *p, u_int32_t h,
277u_int8_t type)
278{
279 p->type = type;
280 p->ptag = ++(l->ptag_state);
281 p->h_len = h;
282 l->pblock_end = p; /* point end of pblock list here */
283
284 return (p->ptag);
285}
286
287int
288libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet, u_int32_t *size)
289{
290 libnet_pblock_t *p, *q;
291 u_int32_t c, n;
292
293 /*
294 * Determine the offset required to keep memory aligned (strict
295 * architectures like solaris enforce this, but's a good practice
296 * either way). This is only required on the link layer with the
297 * 14 byte ethernet offset (others are similarly unkind).
298 */
299 if (l->injection_type == LIBNET_LINK ||
300 l->injection_type == LIBNET_LINK_ADV)
301 {
302 /* 8 byte alignment should work */
303 l->aligner = 8 - (l->link_offset % 8);
304 }
305 else
306 {
307 l->aligner = 0;
308 }
309
310 *packet = malloc(l->aligner + l->total_size);
311 if (*packet == NULL)
312 {
313 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n",
314 __func__, strerror(errno));
315 return (-1);
316 }
317
318 memset(*packet, 0, l->aligner + l->total_size);
319
320 if (l->injection_type == LIBNET_RAW4 &&
321 l->pblock_end->type == LIBNET_PBLOCK_IPV4_H)
322 {
323 libnet_pblock_setflags(l->pblock_end, LIBNET_PBLOCK_DO_CHECKSUM);
324 }
325
326 /* additional sanity checks to perform if we're not in advanced mode */
327 if (!(l->injection_type & LIBNET_ADV_MASK))
328 {
329 switch (l->injection_type)
330 {
331 case LIBNET_LINK:
332 if ((l->pblock_end->type != LIBNET_PBLOCK_TOKEN_RING_H) &&
333 (l->pblock_end->type != LIBNET_PBLOCK_FDDI_H) &&
334 (l->pblock_end->type != LIBNET_PBLOCK_ETH_H) &&
335 (l->pblock_end->type != LIBNET_PBLOCK_802_1Q_H) &&
336 (l->pblock_end->type != LIBNET_PBLOCK_ISL_H) &&
337 (l->pblock_end->type != LIBNET_PBLOCK_802_3_H))
338 {
339 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
340 "%s(): packet assembly cannot find a layer 2 header\n",
341 __func__);
342 return (-1);
343 }
344 break;
345 case LIBNET_RAW4:
346 if ((l->pblock_end->type != LIBNET_PBLOCK_IPV4_H))
347 {
348 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
349 "%s(): packet assembly cannot find an IPv4 header\n",
350 __func__);
351 return (-1);
352 }
353 break;
354 case LIBNET_RAW6:
355 if ((l->pblock_end->type != LIBNET_PBLOCK_IPV6_H))
356 {
357 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
358 "%s(): packet assembly cannot find an IPv6 header\n",
359 __func__);
360 return (-1);
361 }
362 break;
363 default:
364 /* we should not end up here ever */
365 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
366 "%s(): suddenly the dungeon collapses -- you die\n",
367 __func__);
368 return (-1);
369 break;
370 }
371 }
372
373 q = NULL;
374 for (n = l->aligner + l->total_size, p = l->protocol_blocks; p || q; )
375 {
376 if (q)
377 {
378 p = p->next;
379 }
380 if (p)
381 {
382 n -= p->b_len;
383 /* copy over the packet chunk */
384 memcpy(*packet + n, p->buf, p->b_len);
385 }
386 if (q)
387 {
388 if (p == NULL || ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM))
389 {
390 if ((q->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
391 {
392 int offset = (l->total_size + l->aligner) - q->ip_offset;
393 c = libnet_do_checksum(l, *packet + offset,
394 libnet_pblock_p2p(q->type), q->h_len);
395 if (c == -1)
396 {
397 /* err msg set in libnet_do_checksum() */
398 return (-1);
399 }
400 }
401 q = p;
402 }
403 }
404 else
405 {
406 q = p;
407 }
408 }
409 *size = l->aligner + l->total_size;
410
411 /*
412 * Set the packet pointer to the true beginning of the packet and set
413 * the size for transmission.
414 */
415 if ((l->injection_type == LIBNET_LINK ||
416 l->injection_type == LIBNET_LINK_ADV) && l->aligner)
417 {
418 *packet += l->aligner;
419 *size -= l->aligner;
420 }
421 return (1);
422}
423
424void
425libnet_pblock_delete(libnet_t *l, libnet_pblock_t *p)
426{
427 if (p)
428 {
429 l->total_size -= p->b_len;
430 l->n_pblocks--;
431 if (p->prev)
432 {
433 p->prev->next = p->next;
434 }
435 else
436 {
437 l->protocol_blocks = p->next;
438 }
439
440 if (p->next)
441 {
442 p->next->prev = p->prev;
443 }
444 else
445 {
446 l->pblock_end = p->prev;
447 }
448
449 if (p->buf)
450 {
451 free(p->buf);
452 }
453
454 free(p);
455 p = NULL;
456 }
457}
458
459int
460libnet_pblock_p2p(u_int8_t type)
461{
462 /* for checksum; return the protocol number given a pblock type*/
463 switch (type)
464 {
465 case LIBNET_PBLOCK_CDP_H:
466 return (LIBNET_PROTO_CDP);
467 case LIBNET_PBLOCK_ICMPV4_H:
468 case LIBNET_PBLOCK_ICMPV4_ECHO_H:
469 case LIBNET_PBLOCK_ICMPV4_MASK_H:
470 case LIBNET_PBLOCK_ICMPV4_UNREACH_H:
471 case LIBNET_PBLOCK_ICMPV4_TIMXCEED_H:
472 case LIBNET_PBLOCK_ICMPV4_REDIRECT_H:
473 case LIBNET_PBLOCK_ICMPV4_TS_H:
474 return (IPPROTO_ICMP);
475 case LIBNET_PBLOCK_IGMP_H:
476 return (IPPROTO_IGMP);
477 case LIBNET_PBLOCK_IPV4_H:
478 return (IPPROTO_IP);
479 case LIBNET_ISL_H:
480 return (LIBNET_PROTO_ISL);
481 case LIBNET_PBLOCK_OSPF_H:
482 return (IPPROTO_OSPF);
483 case LIBNET_PBLOCK_LS_RTR_H:
484 return (IPPROTO_OSPF_LSA);
485 case LIBNET_PBLOCK_TCP_H:
486 return (IPPROTO_TCP);
487 case LIBNET_PBLOCK_UDP_H:
488 return (IPPROTO_UDP);
489 case LIBNET_PBLOCK_VRRP_H:
490 return (IPPROTO_VRRP);
491 case LIBNET_PBLOCK_GRE_H:
492 return (IPPROTO_GRE);
493 case LIBNET_PBLOCK_SCTP_H:
494 return (IPPROTO_SCTP);
495 case LIBNET_PBLOCK_PIM_H:
496 return (IPPROTO_PIM);
497 case LIBNET_PBLOCK_RSVP_H:
498 return (IPPROTO_RSVP);
499 default:
500 return (-1);
501 }
502}
503
504void
505libnet_pblock_record_ip_offset(libnet_t *l, u_int32_t offset)
506{
507 libnet_pblock_t *p = l->pblock_end;
508
509 do
510 {
511 p->ip_offset = offset;
512 p = p->prev;
513 } while (p && p->type != LIBNET_PBLOCK_IPV4_H && p->type != LIBNET_PBLOCK_IPV6_H);
514}
515
516
517/* EOF */