Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / vera / niu_ippktgen / C / libnet / src / libnet_build_sctp.c
CommitLineData
86530b38
AT
1#if (HAVE_CONFIG_H)
2#include "../include/config.h"
3#endif
4#if (!(_WIN32) || (__CYGWIN__))
5#include "../include/libnet.h"
6#else
7#include "../include/win32/libnet.h"
8#endif
9
10libnet_ptag_t
11libnet_build_sctp(u_int16_t sp, u_int16_t dp, u_int32_t vtag, u_int32_t chksum, u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
12{
13 int n, offset;
14 libnet_pblock_t *p, *p_data, *p_temp;
15 libnet_ptag_t ptag_hold, ptag_data;
16 struct libnet_sctp_hdr sctp_hdr;
17 struct libnet_ipv4_hdr *ip_hdr;
18
19 if (l == NULL)
20 {
21 return (-1);
22 }
23
24 ptag_data = 0;
25
26 /*
27 * Find the existing protocol block if a ptag is specified, or create
28 * a new one.
29 */
30 p = libnet_pblock_probe(l, ptag, LIBNET_SCTP_H, LIBNET_PBLOCK_SCTP_H);
31 if (p == NULL)
32 {
33 return (-1);
34 }
35
36 memset(&sctp_hdr, 0, sizeof(sctp_hdr));
37 sctp_hdr.src_port = htons(sp); /* source port */
38 sctp_hdr.dst_port = htons(dp); /* destination port */
39 sctp_hdr.vtag = htonl(vtag); /* verification tag */
40 sctp_hdr.checksum = (chksum ? htonl(chksum) : 0); /* checksum */
41
42 n = libnet_pblock_append(l, p, (u_int8_t *)&sctp_hdr, LIBNET_SCTP_H);
43 if (n == -1)
44 {
45 goto bad;
46 }
47
48 ptag_hold = ptag;
49 if (ptag == LIBNET_PTAG_INITIALIZER)
50 {
51 ptag = libnet_pblock_update(l, p, LIBNET_SCTP_H + payload_s,
52 LIBNET_PBLOCK_SCTP_H);
53 }
54
55 /* find and set the appropriate ptag, or else use the default of 0 */
56 offset = payload_s;
57 if (ptag_hold && p->prev)
58 {
59 p_temp = p->prev;
60 while (p_temp->prev &&
61 (p_temp->type != LIBNET_PBLOCK_SCTP_CHNK_DATA) &&
62 (p_temp->type != LIBNET_PBLOCK_SCTP_H))
63 {
64 p_temp = p_temp->prev;
65 }
66
67 if (p_temp->type == LIBNET_PBLOCK_SCTP_CHNK_DATA)
68 {
69 ptag_data = p_temp->ptag;
70 offset -= p_temp->b_len;
71 p->h_len += offset;
72 }
73 else
74 {
75 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
76 "%s(): SCTP data pblock not found\n", __func__);
77 }
78 }
79
80 /* update ip_len if present */
81 if (ptag_hold && p->next)
82 {
83 p_temp = p->next;
84 while (p_temp->next && (p_temp->type != LIBNET_PBLOCK_IPV4_H))
85 {
86 p_temp = p_temp->next;
87 }
88 if (p_temp->type == LIBNET_PBLOCK_IPV4_H)
89 {
90 ip_hdr = (struct libnet_ipv4_hdr *)p_temp->buf;
91 n = ntohs(ip_hdr->ip_len) + offset;
92 ip_hdr->ip_len = htons(n);
93 }
94 }
95
96 if ((payload && !payload_s) || (!payload && payload_s))
97 {
98 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
99 "%s(): payload inconsistency\n", __func__);
100 goto bad;
101 }
102
103 /* if there is a payload, add it in the context */
104 if (payload && payload_s)
105 {
106 /* update ptag_data with the new payload */
107 p_data = libnet_pblock_probe(l, ptag_data, payload_s,
108 LIBNET_PBLOCK_SCTP_CHNK_DATA);
109 if (p_data == NULL)
110 {
111 return (-1);
112 }
113
114 if (libnet_pblock_append(l, p_data, payload, payload_s) == -1)
115 {
116 goto bad;
117 }
118
119 if (ptag_data == LIBNET_PTAG_INITIALIZER)
120 {
121 if (p_data->prev->type == LIBNET_PBLOCK_SCTP_H)
122 {
123 libnet_pblock_update(l, p_data, payload_s,
124 LIBNET_PBLOCK_SCTP_CHNK_DATA);
125 /* swap pblocks to correct the protocol order */
126 libnet_pblock_swap(l, p->ptag, p_data->ptag);
127 }
128 else
129 {
130 /* update without setting this as the final pblock */
131 p_data->type = LIBNET_PBLOCK_SCTP_CHNK_DATA;
132 p_data->ptag = ++(l->ptag_state);
133 p_data->h_len = payload_s;
134
135 /* Adjust h_len for checksum. */
136 p->h_len += payload_s;
137
138 /* data was added after the initial construction */
139 for (p_temp = l->protocol_blocks;
140 p_temp->type == LIBNET_PBLOCK_SCTP_H;
141 p_temp = p_temp->next)
142 {
143 libnet_pblock_insert_before(l, p_temp->ptag, p_data->ptag);
144 break;
145 }
146 /* The end block needs to have its next pointer cleared. */
147 l->pblock_end->next = NULL;
148 }
149 }
150 }
151 else
152 {
153 p_data = libnet_pblock_find(l, ptag_data);
154 if (p_data)
155 {
156 libnet_pblock_delete(l, p_data);
157 }
158 }
159
160 if (chksum == 0)
161 {
162 /*
163 * If checksum is zero, by default libnet will compute a checksum
164 * for the user. The programmer can override this by calling
165 * libnet_toggle_checksum(l, ptag, 1);
166 */
167 libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
168 }
169 return (ptag);
170bad:
171 libnet_pblock_delete(l, p);
172 return (-1);
173}
174
175/* EOF */