xref: /freebsd/lib/libiscsiutil/text.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
1b4068979SJohn Baldwin /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3b4068979SJohn Baldwin  *
4b4068979SJohn Baldwin  * Copyright (c) 2012 The FreeBSD Foundation
5b4068979SJohn Baldwin  *
6b4068979SJohn Baldwin  * This software was developed by Edward Tomasz Napierala under sponsorship
7b4068979SJohn Baldwin  * from the FreeBSD Foundation.
8b4068979SJohn Baldwin  *
9b4068979SJohn Baldwin  * Redistribution and use in source and binary forms, with or without
10b4068979SJohn Baldwin  * modification, are permitted provided that the following conditions
11b4068979SJohn Baldwin  * are met:
12b4068979SJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
13b4068979SJohn Baldwin  *    notice, this list of conditions and the following disclaimer.
14b4068979SJohn Baldwin  * 2. Redistributions in binary form must reproduce the above copyright
15b4068979SJohn Baldwin  *    notice, this list of conditions and the following disclaimer in the
16b4068979SJohn Baldwin  *    documentation and/or other materials provided with the distribution.
17b4068979SJohn Baldwin  *
18b4068979SJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19b4068979SJohn Baldwin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20b4068979SJohn Baldwin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21b4068979SJohn Baldwin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22b4068979SJohn Baldwin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23b4068979SJohn Baldwin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24b4068979SJohn Baldwin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25b4068979SJohn Baldwin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26b4068979SJohn Baldwin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27b4068979SJohn Baldwin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28b4068979SJohn Baldwin  * SUCH DAMAGE.
29b4068979SJohn Baldwin  */
30b4068979SJohn Baldwin 
31b4068979SJohn Baldwin #include <sys/types.h>
32b4068979SJohn Baldwin #include <netinet/in.h>
33b4068979SJohn Baldwin 
34b4068979SJohn Baldwin #include <stdlib.h>
35b4068979SJohn Baldwin #include <string.h>
36b4068979SJohn Baldwin 
37b4068979SJohn Baldwin #include <iscsi_proto.h>
38b4068979SJohn Baldwin #include "libiscsiutil.h"
39b4068979SJohn Baldwin 
40b4068979SJohn Baldwin /* Construct a new TextRequest PDU. */
41b4068979SJohn Baldwin static struct pdu *
text_new_request(struct connection * conn,uint32_t ttt)42b4068979SJohn Baldwin text_new_request(struct connection *conn, uint32_t ttt)
43b4068979SJohn Baldwin {
44b4068979SJohn Baldwin 	struct pdu *request;
45b4068979SJohn Baldwin 	struct iscsi_bhs_text_request *bhstr;
46b4068979SJohn Baldwin 
47b4068979SJohn Baldwin 	request = pdu_new(conn);
48b4068979SJohn Baldwin 	bhstr = (struct iscsi_bhs_text_request *)request->pdu_bhs;
49b4068979SJohn Baldwin 	bhstr->bhstr_opcode = ISCSI_BHS_OPCODE_TEXT_REQUEST |
50b4068979SJohn Baldwin 	    ISCSI_BHS_OPCODE_IMMEDIATE;
51b4068979SJohn Baldwin 	bhstr->bhstr_flags = BHSTR_FLAGS_FINAL;
52b4068979SJohn Baldwin 	bhstr->bhstr_initiator_task_tag = 0;
53b4068979SJohn Baldwin 	bhstr->bhstr_target_transfer_tag = ttt;
54b4068979SJohn Baldwin 
55b4068979SJohn Baldwin 	bhstr->bhstr_cmdsn = conn->conn_cmdsn;
56b4068979SJohn Baldwin 	bhstr->bhstr_expstatsn = htonl(conn->conn_statsn + 1);
57b4068979SJohn Baldwin 
58b4068979SJohn Baldwin 	return (request);
59b4068979SJohn Baldwin }
60b4068979SJohn Baldwin 
61b4068979SJohn Baldwin /* Receive a TextRequest PDU from a connection. */
62b4068979SJohn Baldwin static struct pdu *
text_receive_request(struct connection * conn)63b4068979SJohn Baldwin text_receive_request(struct connection *conn)
64b4068979SJohn Baldwin {
65b4068979SJohn Baldwin 	struct pdu *request;
66b4068979SJohn Baldwin 	struct iscsi_bhs_text_request *bhstr;
67b4068979SJohn Baldwin 
68b4068979SJohn Baldwin 	request = pdu_new(conn);
69b4068979SJohn Baldwin 	pdu_receive(request);
70b4068979SJohn Baldwin 	if ((request->pdu_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) !=
71b4068979SJohn Baldwin 	    ISCSI_BHS_OPCODE_TEXT_REQUEST)
72b4068979SJohn Baldwin 		log_errx(1, "protocol error: received invalid opcode 0x%x",
73b4068979SJohn Baldwin 		    request->pdu_bhs->bhs_opcode);
74b4068979SJohn Baldwin 	bhstr = (struct iscsi_bhs_text_request *)request->pdu_bhs;
75b4068979SJohn Baldwin 
76b4068979SJohn Baldwin 	/*
77b4068979SJohn Baldwin 	 * XXX: Implement the C flag some day.
78b4068979SJohn Baldwin 	 */
79b4068979SJohn Baldwin 	if ((bhstr->bhstr_flags & (BHSTR_FLAGS_FINAL | BHSTR_FLAGS_CONTINUE)) !=
80b4068979SJohn Baldwin 	    BHSTR_FLAGS_FINAL)
81b4068979SJohn Baldwin 		log_errx(1, "received TextRequest PDU with invalid "
82b4068979SJohn Baldwin 		    "flags: %u", bhstr->bhstr_flags);
83b4068979SJohn Baldwin 	if (ISCSI_SNLT(ntohl(bhstr->bhstr_cmdsn), conn->conn_cmdsn)) {
84b4068979SJohn Baldwin 		log_errx(1, "received TextRequest PDU with decreasing CmdSN: "
85b4068979SJohn Baldwin 		    "was %u, is %u", conn->conn_cmdsn, ntohl(bhstr->bhstr_cmdsn));
86b4068979SJohn Baldwin 	}
87b4068979SJohn Baldwin 	conn->conn_cmdsn = ntohl(bhstr->bhstr_cmdsn);
88b4068979SJohn Baldwin 	if ((bhstr->bhstr_opcode & ISCSI_BHS_OPCODE_IMMEDIATE) == 0)
89b4068979SJohn Baldwin 		conn->conn_cmdsn++;
90b4068979SJohn Baldwin 
91b4068979SJohn Baldwin 	return (request);
92b4068979SJohn Baldwin }
93b4068979SJohn Baldwin 
94b4068979SJohn Baldwin /* Construct a new TextResponse PDU in reply to a request. */
95b4068979SJohn Baldwin static struct pdu *
text_new_response(struct pdu * request,uint32_t ttt,bool final)96b4068979SJohn Baldwin text_new_response(struct pdu *request, uint32_t ttt, bool final)
97b4068979SJohn Baldwin {
98b4068979SJohn Baldwin 	struct pdu *response;
99b4068979SJohn Baldwin 	struct connection *conn;
100b4068979SJohn Baldwin 	struct iscsi_bhs_text_request *bhstr;
101b4068979SJohn Baldwin 	struct iscsi_bhs_text_response *bhstr2;
102b4068979SJohn Baldwin 
103b4068979SJohn Baldwin 	bhstr = (struct iscsi_bhs_text_request *)request->pdu_bhs;
104b4068979SJohn Baldwin 	conn = request->pdu_connection;
105b4068979SJohn Baldwin 
106b4068979SJohn Baldwin 	response = pdu_new_response(request);
107b4068979SJohn Baldwin 	bhstr2 = (struct iscsi_bhs_text_response *)response->pdu_bhs;
108b4068979SJohn Baldwin 	bhstr2->bhstr_opcode = ISCSI_BHS_OPCODE_TEXT_RESPONSE;
109b4068979SJohn Baldwin 	if (final)
110b4068979SJohn Baldwin 		bhstr2->bhstr_flags = BHSTR_FLAGS_FINAL;
111b4068979SJohn Baldwin 	else
112b4068979SJohn Baldwin 		bhstr2->bhstr_flags = BHSTR_FLAGS_CONTINUE;
113b4068979SJohn Baldwin 	bhstr2->bhstr_lun = bhstr->bhstr_lun;
114b4068979SJohn Baldwin 	bhstr2->bhstr_initiator_task_tag = bhstr->bhstr_initiator_task_tag;
115b4068979SJohn Baldwin 	bhstr2->bhstr_target_transfer_tag = ttt;
116b4068979SJohn Baldwin 	bhstr2->bhstr_statsn = htonl(conn->conn_statsn++);
117b4068979SJohn Baldwin 	bhstr2->bhstr_expcmdsn = htonl(conn->conn_cmdsn);
118b4068979SJohn Baldwin 	bhstr2->bhstr_maxcmdsn = htonl(conn->conn_cmdsn);
119b4068979SJohn Baldwin 
120b4068979SJohn Baldwin 	return (response);
121b4068979SJohn Baldwin }
122b4068979SJohn Baldwin 
123b4068979SJohn Baldwin /* Receive a TextResponse PDU from a connection. */
124b4068979SJohn Baldwin static struct pdu *
text_receive_response(struct connection * conn)125b4068979SJohn Baldwin text_receive_response(struct connection *conn)
126b4068979SJohn Baldwin {
127b4068979SJohn Baldwin 	struct pdu *response;
128b4068979SJohn Baldwin 	struct iscsi_bhs_text_response *bhstr;
129b4068979SJohn Baldwin 	uint8_t flags;
130b4068979SJohn Baldwin 
131b4068979SJohn Baldwin 	response = pdu_new(conn);
132b4068979SJohn Baldwin 	pdu_receive(response);
133b4068979SJohn Baldwin 	if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_TEXT_RESPONSE)
134b4068979SJohn Baldwin 		log_errx(1, "protocol error: received invalid opcode 0x%x",
135b4068979SJohn Baldwin 		    response->pdu_bhs->bhs_opcode);
136b4068979SJohn Baldwin 	bhstr = (struct iscsi_bhs_text_response *)response->pdu_bhs;
137b4068979SJohn Baldwin 	flags = bhstr->bhstr_flags & (BHSTR_FLAGS_FINAL | BHSTR_FLAGS_CONTINUE);
138b4068979SJohn Baldwin 	switch (flags) {
139b4068979SJohn Baldwin 	case BHSTR_FLAGS_CONTINUE:
140b4068979SJohn Baldwin 		if (bhstr->bhstr_target_transfer_tag == 0xffffffff)
141b4068979SJohn Baldwin 			log_errx(1, "received continue TextResponse PDU with "
142b4068979SJohn Baldwin 			    "invalid TTT 0x%x",
143b4068979SJohn Baldwin 			    bhstr->bhstr_target_transfer_tag);
144b4068979SJohn Baldwin 		break;
145b4068979SJohn Baldwin 	case BHSTR_FLAGS_FINAL:
146b4068979SJohn Baldwin 		if (bhstr->bhstr_target_transfer_tag != 0xffffffff)
147b4068979SJohn Baldwin 			log_errx(1, "received final TextResponse PDU with "
148b4068979SJohn Baldwin 			    "invalid TTT 0x%x",
149b4068979SJohn Baldwin 			    bhstr->bhstr_target_transfer_tag);
150b4068979SJohn Baldwin 		break;
151b4068979SJohn Baldwin 	default:
152b4068979SJohn Baldwin 		log_errx(1, "received TextResponse PDU with invalid "
153b4068979SJohn Baldwin 		    "flags: %u", bhstr->bhstr_flags);
154b4068979SJohn Baldwin 	}
155b4068979SJohn Baldwin 	if (ntohl(bhstr->bhstr_statsn) != conn->conn_statsn + 1) {
156b4068979SJohn Baldwin 		log_errx(1, "received TextResponse PDU with wrong StatSN: "
157b4068979SJohn Baldwin 		    "is %u, should be %u", ntohl(bhstr->bhstr_statsn),
158b4068979SJohn Baldwin 		    conn->conn_statsn + 1);
159b4068979SJohn Baldwin 	}
160b4068979SJohn Baldwin 	conn->conn_statsn = ntohl(bhstr->bhstr_statsn);
161b4068979SJohn Baldwin 
162b4068979SJohn Baldwin 	return (response);
163b4068979SJohn Baldwin }
164b4068979SJohn Baldwin 
165b4068979SJohn Baldwin /*
166b4068979SJohn Baldwin  * Send a list of keys from the initiator to the target in a
167b4068979SJohn Baldwin  * TextRequest PDU.
168b4068979SJohn Baldwin  */
169b4068979SJohn Baldwin void
text_send_request(struct connection * conn,struct keys * request_keys)170b4068979SJohn Baldwin text_send_request(struct connection *conn, struct keys *request_keys)
171b4068979SJohn Baldwin {
172b4068979SJohn Baldwin 	struct pdu *request;
173b4068979SJohn Baldwin 
174b4068979SJohn Baldwin 	request = text_new_request(conn, 0xffffffff);
175b4068979SJohn Baldwin 	keys_save_pdu(request_keys, request);
176b4068979SJohn Baldwin 	if (request->pdu_data_len == 0)
177b4068979SJohn Baldwin 		log_errx(1, "No keys to send in a TextRequest");
178b4068979SJohn Baldwin 	if (request->pdu_data_len >
179b4068979SJohn Baldwin 	    (size_t)conn->conn_max_send_data_segment_length)
180b4068979SJohn Baldwin 		log_errx(1, "Keys to send in TextRequest are too long");
181b4068979SJohn Baldwin 
182b4068979SJohn Baldwin 	pdu_send(request);
183b4068979SJohn Baldwin 	pdu_delete(request);
184b4068979SJohn Baldwin }
185b4068979SJohn Baldwin 
186b4068979SJohn Baldwin /*
187b4068979SJohn Baldwin  * Read a list of keys from the target in a series of TextResponse
188b4068979SJohn Baldwin  * PDUs.
189b4068979SJohn Baldwin  */
190b4068979SJohn Baldwin struct keys *
text_read_response(struct connection * conn)191b4068979SJohn Baldwin text_read_response(struct connection *conn)
192b4068979SJohn Baldwin {
193b4068979SJohn Baldwin 	struct keys *response_keys;
194b4068979SJohn Baldwin 	char *keys_data;
195b4068979SJohn Baldwin 	size_t keys_len;
196b4068979SJohn Baldwin 	uint32_t ttt;
197b4068979SJohn Baldwin 
198b4068979SJohn Baldwin 	keys_data = NULL;
199b4068979SJohn Baldwin 	keys_len = 0;
200b4068979SJohn Baldwin 	ttt = 0xffffffff;
201b4068979SJohn Baldwin 	for (;;) {
202b4068979SJohn Baldwin 		struct pdu *request, *response;
203b4068979SJohn Baldwin 		struct iscsi_bhs_text_response *bhstr;
204b4068979SJohn Baldwin 
205b4068979SJohn Baldwin 		response = text_receive_response(conn);
206b4068979SJohn Baldwin 		bhstr = (struct iscsi_bhs_text_response *)response->pdu_bhs;
207b4068979SJohn Baldwin 		if (keys_data == NULL) {
208b4068979SJohn Baldwin 			ttt = bhstr->bhstr_target_transfer_tag;
209b4068979SJohn Baldwin 			keys_data = response->pdu_data;
210b4068979SJohn Baldwin 			keys_len = response->pdu_data_len;
211b4068979SJohn Baldwin 			response->pdu_data = NULL;
212b4068979SJohn Baldwin 		} else {
213b4068979SJohn Baldwin 			keys_data = realloc(keys_data,
214b4068979SJohn Baldwin 			    keys_len + response->pdu_data_len);
215b4068979SJohn Baldwin 			if (keys_data == NULL)
216b4068979SJohn Baldwin 				log_err(1, "failed to grow keys block");
217b4068979SJohn Baldwin 			memcpy(keys_data + keys_len, response->pdu_data,
218b4068979SJohn Baldwin 			    response->pdu_data_len);
219b4068979SJohn Baldwin 			keys_len += response->pdu_data_len;
220b4068979SJohn Baldwin 		}
221b4068979SJohn Baldwin 		if ((bhstr->bhstr_flags & BHSTR_FLAGS_FINAL) != 0) {
222b4068979SJohn Baldwin 			pdu_delete(response);
223b4068979SJohn Baldwin 			break;
224b4068979SJohn Baldwin 		}
225b4068979SJohn Baldwin 		if (bhstr->bhstr_target_transfer_tag != ttt)
226b4068979SJohn Baldwin 			log_errx(1, "received non-final TextRequest PDU with "
227b4068979SJohn Baldwin 			    "invalid TTT 0x%x",
228b4068979SJohn Baldwin 			    bhstr->bhstr_target_transfer_tag);
229b4068979SJohn Baldwin 		pdu_delete(response);
230b4068979SJohn Baldwin 
231b4068979SJohn Baldwin 		/* Send an empty request. */
232b4068979SJohn Baldwin 		request = text_new_request(conn, ttt);
233b4068979SJohn Baldwin 		pdu_send(request);
234b4068979SJohn Baldwin 		pdu_delete(request);
235b4068979SJohn Baldwin 	}
236b4068979SJohn Baldwin 
237b4068979SJohn Baldwin 	response_keys = keys_new();
238b4068979SJohn Baldwin 	keys_load(response_keys, keys_data, keys_len);
239b4068979SJohn Baldwin 	free(keys_data);
240b4068979SJohn Baldwin 	return (response_keys);
241b4068979SJohn Baldwin }
242b4068979SJohn Baldwin 
243b4068979SJohn Baldwin /*
244b4068979SJohn Baldwin  * Read a list of keys from the initiator in a TextRequest PDU.
245b4068979SJohn Baldwin  */
246b4068979SJohn Baldwin struct keys *
text_read_request(struct connection * conn,struct pdu ** requestp)247b4068979SJohn Baldwin text_read_request(struct connection *conn, struct pdu **requestp)
248b4068979SJohn Baldwin {
249b4068979SJohn Baldwin 	struct iscsi_bhs_text_request *bhstr;
250b4068979SJohn Baldwin 	struct pdu *request;
251b4068979SJohn Baldwin 	struct keys *request_keys;
252b4068979SJohn Baldwin 
253b4068979SJohn Baldwin 	request = text_receive_request(conn);
254b4068979SJohn Baldwin 	bhstr = (struct iscsi_bhs_text_request *)request->pdu_bhs;
255b4068979SJohn Baldwin 	if (bhstr->bhstr_target_transfer_tag != 0xffffffff)
256b4068979SJohn Baldwin 		log_errx(1, "received TextRequest PDU with invalid TTT 0x%x",
257b4068979SJohn Baldwin 		    bhstr->bhstr_target_transfer_tag);
258b4068979SJohn Baldwin 	if (ntohl(bhstr->bhstr_expstatsn) != conn->conn_statsn) {
259b4068979SJohn Baldwin 		log_errx(1, "received TextRequest PDU with wrong ExpStatSN: "
260b4068979SJohn Baldwin 		    "is %u, should be %u", ntohl(bhstr->bhstr_expstatsn),
261b4068979SJohn Baldwin 		    conn->conn_statsn);
262b4068979SJohn Baldwin 	}
263b4068979SJohn Baldwin 
264b4068979SJohn Baldwin 	request_keys = keys_new();
265b4068979SJohn Baldwin 	keys_load_pdu(request_keys, request);
266b4068979SJohn Baldwin 	*requestp = request;
267b4068979SJohn Baldwin 	return (request_keys);
268b4068979SJohn Baldwin }
269b4068979SJohn Baldwin 
270b4068979SJohn Baldwin /*
271b4068979SJohn Baldwin  * Send a response back to the initiator as a series of TextResponse
272b4068979SJohn Baldwin  * PDUs.
273b4068979SJohn Baldwin  */
274b4068979SJohn Baldwin void
text_send_response(struct pdu * request,struct keys * response_keys)275b4068979SJohn Baldwin text_send_response(struct pdu *request, struct keys *response_keys)
276b4068979SJohn Baldwin {
277b4068979SJohn Baldwin 	struct connection *conn = request->pdu_connection;
278b4068979SJohn Baldwin 	char *keys_data;
279b4068979SJohn Baldwin 	size_t keys_len;
280b4068979SJohn Baldwin 	size_t keys_offset;
281b4068979SJohn Baldwin 	uint32_t ttt;
282b4068979SJohn Baldwin 
283b4068979SJohn Baldwin 	keys_save(response_keys, &keys_data, &keys_len);
284b4068979SJohn Baldwin 	keys_offset = 0;
285b4068979SJohn Baldwin 	ttt = keys_len;
286b4068979SJohn Baldwin 	for (;;) {
287b4068979SJohn Baldwin 		struct pdu *request2, *response;
288b4068979SJohn Baldwin 		struct iscsi_bhs_text_request *bhstr;
289b4068979SJohn Baldwin 		size_t todo;
290b4068979SJohn Baldwin 		bool final;
291b4068979SJohn Baldwin 
292b4068979SJohn Baldwin 		todo = keys_len - keys_offset;
293b4068979SJohn Baldwin 		if (todo > (size_t)conn->conn_max_send_data_segment_length) {
294b4068979SJohn Baldwin 			final = false;
295b4068979SJohn Baldwin 			todo = conn->conn_max_send_data_segment_length;
296b4068979SJohn Baldwin 		} else {
297b4068979SJohn Baldwin 			final = true;
298b4068979SJohn Baldwin 			ttt = 0xffffffff;
299b4068979SJohn Baldwin 		}
300b4068979SJohn Baldwin 
301b4068979SJohn Baldwin 		response = text_new_response(request, ttt, final);
302b4068979SJohn Baldwin 		response->pdu_data = keys_data + keys_offset;
303b4068979SJohn Baldwin 		response->pdu_data_len = todo;
304b4068979SJohn Baldwin 		keys_offset += todo;
305b4068979SJohn Baldwin 
306b4068979SJohn Baldwin 		pdu_send(response);
307b4068979SJohn Baldwin 		response->pdu_data = NULL;
308b4068979SJohn Baldwin 		pdu_delete(response);
309b4068979SJohn Baldwin 
310b4068979SJohn Baldwin 		if (final)
311b4068979SJohn Baldwin 			break;
312b4068979SJohn Baldwin 
313b4068979SJohn Baldwin 		/*
314b4068979SJohn Baldwin 		 * Wait for an empty request.
315b4068979SJohn Baldwin 		 *
316b4068979SJohn Baldwin 		 * XXX: Linux's Open-iSCSI initiator doesn't update
317b4068979SJohn Baldwin 		 * ExpStatSN when receiving a TextResponse PDU.
318b4068979SJohn Baldwin 		 */
319b4068979SJohn Baldwin 		request2 = text_receive_request(conn);
320b4068979SJohn Baldwin 		bhstr = (struct iscsi_bhs_text_request *)request2->pdu_bhs;
321b4068979SJohn Baldwin 		if ((bhstr->bhstr_flags & BHSTR_FLAGS_FINAL) == 0)
322b4068979SJohn Baldwin 			log_errx(1, "received continuation TextRequest PDU "
323b4068979SJohn Baldwin 			    "without F set");
324b4068979SJohn Baldwin 		if (pdu_data_segment_length(request2) != 0)
325b4068979SJohn Baldwin 			log_errx(1, "received non-empty continuation "
326b4068979SJohn Baldwin 			    "TextRequest PDU");
327b4068979SJohn Baldwin 		if (bhstr->bhstr_target_transfer_tag != ttt)
328b4068979SJohn Baldwin 			log_errx(1, "received TextRequest PDU with invalid "
329b4068979SJohn Baldwin 			    "TTT 0x%x", bhstr->bhstr_target_transfer_tag);
330b4068979SJohn Baldwin 		pdu_delete(request2);
331b4068979SJohn Baldwin 	}
332b4068979SJohn Baldwin 	free(keys_data);
333b4068979SJohn Baldwin }
334