Commit | Line | Data |
---|---|---|
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 | ||
10 | libnet_ptag_t | |
11 | libnet_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); | |
170 | bad: | |
171 | libnet_pblock_delete(l, p); | |
172 | return (-1); | |
173 | } | |
174 | ||
175 | /* EOF */ |