133965Sjdp/*-
233965Sjdp * Copyright (c) 2014 Alexander Motin <mav@FreeBSD.org>
377298Sobrien * All rights reserved.
477298Sobrien *
533965Sjdp * Redistribution and use in source and binary forms, with or without
633965Sjdp * modification, are permitted provided that the following conditions
733965Sjdp * are met:
833965Sjdp * 1. Redistributions of source code must retain the above copyright
933965Sjdp *    notice, this list of conditions and the following disclaimer.
1033965Sjdp * 2. Redistributions in binary form must reproduce the above copyright
1133965Sjdp *    notice, this list of conditions and the following disclaimer in the
1233965Sjdp *    documentation and/or other materials provided with the distribution.
1333965Sjdp *
1433965Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1533965Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1633965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1733965Sjdp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18218822Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19218822Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2033965Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2133965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2233965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2333965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2433965Sjdp * SUCH DAMAGE.
2533965Sjdp *
2633965Sjdp */
2733965Sjdp
2833965Sjdp#include <sys/cdefs.h>
2933965Sjdp__FBSDID("$FreeBSD$");
3033965Sjdp
3133965Sjdp#include <sys/types.h>
3233965Sjdp#include <sys/time.h>
3333965Sjdp#include <sys/socket.h>
3433965Sjdp#include <sys/wait.h>
3533965Sjdp#include <sys/endian.h>
3633965Sjdp#include <netinet/in.h>
3733965Sjdp#include <arpa/inet.h>
3833965Sjdp#include <netdb.h>
3933965Sjdp#include <stdbool.h>
4033965Sjdp#include <stdlib.h>
4133965Sjdp#include <string.h>
4233965Sjdp#include <unistd.h>
4333965Sjdp
4433965Sjdp#include "ctld.h"
4533965Sjdp#include "isns.h"
4633965Sjdp
4733965Sjdpstruct isns_req *
4877298Sobrienisns_req_alloc(void)
4933965Sjdp{
5033965Sjdp	struct isns_req *req;
5133965Sjdp
5233965Sjdp	req = calloc(sizeof(struct isns_req), 1);
5333965Sjdp	if (req == NULL) {
5433965Sjdp		log_err(1, "calloc");
5533965Sjdp		return (NULL);
5633965Sjdp	}
5733965Sjdp	req->ir_buflen = sizeof(struct isns_hdr);
5833965Sjdp	req->ir_usedlen = 0;
5933965Sjdp	req->ir_buf = calloc(req->ir_buflen, 1);
6033965Sjdp	if (req->ir_buf == NULL) {
6133965Sjdp		free(req);
6233965Sjdp		log_err(1, "calloc");
6333965Sjdp		return (NULL);
6433965Sjdp	}
6533965Sjdp	return (req);
6633965Sjdp}
6733965Sjdp
68218822Sdimstruct isns_req *
6933965Sjdpisns_req_create(uint16_t func, uint16_t flags)
7033965Sjdp{
7160484Sobrien	struct isns_req *req;
7233965Sjdp	struct isns_hdr *hdr;
7377298Sobrien
7433965Sjdp	req = isns_req_alloc();
7533965Sjdp	req->ir_usedlen = sizeof(struct isns_hdr);
7633965Sjdp	hdr = (struct isns_hdr *)req->ir_buf;
7733965Sjdp	be16enc(hdr->ih_version, ISNS_VERSION);
7833965Sjdp	be16enc(hdr->ih_function, func);
7933965Sjdp	be16enc(hdr->ih_flags, flags);
8033965Sjdp	return (req);
8133965Sjdp}
8233965Sjdp
8333965Sjdpvoid
8433965Sjdpisns_req_free(struct isns_req *req)
8533965Sjdp{
8633965Sjdp
8733965Sjdp	free(req->ir_buf);
8833965Sjdp	free(req);
8933965Sjdp}
9033965Sjdp
9133965Sjdpstatic int
9233965Sjdpisns_req_getspace(struct isns_req *req, uint32_t len)
9333965Sjdp{
9433965Sjdp	void *newbuf;
9533965Sjdp	int newlen;
9633965Sjdp
9760484Sobrien	if (req->ir_usedlen + len <= req->ir_buflen)
9833965Sjdp		return (0);
9933965Sjdp	newlen = 1 << flsl(req->ir_usedlen + len);
10033965Sjdp	newbuf = realloc(req->ir_buf, newlen);
10133965Sjdp	if (newbuf == NULL) {
10233965Sjdp		log_err(1, "realloc");
10333965Sjdp		return (1);
10433965Sjdp	}
10533965Sjdp	req->ir_buf = newbuf;
10633965Sjdp	req->ir_buflen = newlen;
10733965Sjdp	return (0);
10833965Sjdp}
10933965Sjdp
11033965Sjdpvoid
11133965Sjdpisns_req_add(struct isns_req *req, uint32_t tag, uint32_t len,
11233965Sjdp    const void *value)
11333965Sjdp{
11433965Sjdp	struct isns_tlv *tlv;
11560484Sobrien	uint32_t vlen;
11633965Sjdp
11733965Sjdp	vlen = len + ((len & 3) ? (4 - (len & 3)) : 0);
11860484Sobrien	isns_req_getspace(req, sizeof(*tlv) + vlen);
11933965Sjdp	tlv = (struct isns_tlv *)&req->ir_buf[req->ir_usedlen];
12033965Sjdp	be32enc(tlv->it_tag, tag);
12133965Sjdp	be32enc(tlv->it_length, vlen);
12233965Sjdp	memcpy(tlv->it_value, value, len);
12333965Sjdp	if (vlen != len)
12433965Sjdp		memset(&tlv->it_value[len], 0, vlen - len);
12533965Sjdp	req->ir_usedlen += sizeof(*tlv) + vlen;
12633965Sjdp}
127218822Sdim
12833965Sjdpvoid
12933965Sjdpisns_req_add_delim(struct isns_req *req)
13033965Sjdp{
13133965Sjdp
13233965Sjdp	isns_req_add(req, 0, 0, NULL);
13333965Sjdp}
13433965Sjdp
13533965Sjdpvoid
136218822Sdimisns_req_add_str(struct isns_req *req, uint32_t tag, const char *value)
137218822Sdim{
13833965Sjdp
13933965Sjdp	isns_req_add(req, tag, strlen(value) + 1, value);
14033965Sjdp}
14133965Sjdp
14233965Sjdpvoid
14360484Sobrienisns_req_add_32(struct isns_req *req, uint32_t tag, uint32_t value)
14433965Sjdp{
14533965Sjdp	uint32_t beval;
14633965Sjdp
14733965Sjdp	be32enc(&beval, value);
14833965Sjdp	isns_req_add(req, tag, sizeof(value), &beval);
14933965Sjdp}
15033965Sjdp
15133965Sjdpvoid
15233965Sjdpisns_req_add_addr(struct isns_req *req, uint32_t tag, struct addrinfo *ai)
15333965Sjdp{
15433965Sjdp	struct sockaddr_in *in4;
15533965Sjdp	struct sockaddr_in6 *in6;
15633965Sjdp	uint8_t buf[16];
15733965Sjdp
15833965Sjdp	switch (ai->ai_addr->sa_family) {
15933965Sjdp	case AF_INET:
16033965Sjdp		in4 = (struct sockaddr_in *)(void *)ai->ai_addr;
16133965Sjdp		memset(buf, 0, 10);
16233965Sjdp		buf[10] = 0xff;
16333965Sjdp		buf[11] = 0xff;
16433965Sjdp		memcpy(&buf[12], &in4->sin_addr, sizeof(in4->sin_addr));
16533965Sjdp		isns_req_add(req, tag, sizeof(buf), buf);
16633965Sjdp		break;
16733965Sjdp	case AF_INET6:
16833965Sjdp		in6 = (struct sockaddr_in6 *)(void *)ai->ai_addr;
16933965Sjdp		isns_req_add(req, tag, sizeof(in6->sin6_addr), &in6->sin6_addr);
17033965Sjdp		break;
17133965Sjdp	default:
17233965Sjdp		log_errx(1, "Unsupported address family %d",
17360484Sobrien		    ai->ai_addr->sa_family);
17460484Sobrien	}
17533965Sjdp}
17633965Sjdp
17733965Sjdpvoid
17833965Sjdpisns_req_add_port(struct isns_req *req, uint32_t tag, struct addrinfo *ai)
17933965Sjdp{
180218822Sdim	struct sockaddr_in *in4;
18133965Sjdp	struct sockaddr_in6 *in6;
18233965Sjdp	uint32_t buf;
18333965Sjdp
18433965Sjdp	switch (ai->ai_addr->sa_family) {
18533965Sjdp	case AF_INET:
18633965Sjdp		in4 = (struct sockaddr_in *)(void *)ai->ai_addr;
18733965Sjdp		be32enc(&buf, ntohs(in4->sin_port));
18833965Sjdp		isns_req_add(req, tag, sizeof(buf), &buf);
18933965Sjdp		break;
19033965Sjdp	case AF_INET6:
19133965Sjdp		in6 = (struct sockaddr_in6 *)(void *)ai->ai_addr;
19233965Sjdp		be32enc(&buf, ntohs(in6->sin6_port));
19333965Sjdp		isns_req_add(req, tag, sizeof(buf), &buf);
19433965Sjdp		break;
19533965Sjdp	default:
19633965Sjdp		log_errx(1, "Unsupported address family %d",
197218822Sdim		    ai->ai_addr->sa_family);
19833965Sjdp	}
19933965Sjdp}
20033965Sjdp
20133965Sjdpint
20233965Sjdpisns_req_send(int s, struct isns_req *req)
20360484Sobrien{
20433965Sjdp	struct isns_hdr *hdr;
20533965Sjdp	int res;
20633965Sjdp
20733965Sjdp	hdr = (struct isns_hdr *)req->ir_buf;
20833965Sjdp	be16enc(hdr->ih_length, req->ir_usedlen - sizeof(*hdr));
20933965Sjdp	be16enc(hdr->ih_flags, be16dec(hdr->ih_flags) |
21033965Sjdp	    ISNS_FLAG_LAST | ISNS_FLAG_FIRST);
21133965Sjdp	be16enc(hdr->ih_transaction, 0);
21233965Sjdp	be16enc(hdr->ih_sequence, 0);
21333965Sjdp
21433965Sjdp	res = write(s, req->ir_buf, req->ir_usedlen);
21533965Sjdp	return ((res < 0) ? -1 : 0);
21633965Sjdp}
21733965Sjdp
21833965Sjdpint
21933965Sjdpisns_req_receive(int s, struct isns_req *req)
22033965Sjdp{
221	struct isns_hdr *hdr;
222	ssize_t res, len;
223
224	req->ir_usedlen = 0;
225	isns_req_getspace(req, sizeof(*hdr));
226	res = read(s, req->ir_buf, sizeof(*hdr));
227	if (res < (ssize_t)sizeof(*hdr))
228		return (-1);
229	req->ir_usedlen = sizeof(*hdr);
230	hdr = (struct isns_hdr *)req->ir_buf;
231	if (be16dec(hdr->ih_version) != ISNS_VERSION)
232		return (-1);
233	if ((be16dec(hdr->ih_flags) & (ISNS_FLAG_LAST | ISNS_FLAG_FIRST)) !=
234	    (ISNS_FLAG_LAST | ISNS_FLAG_FIRST))
235		return (-1);
236	len = be16dec(hdr->ih_length);
237	isns_req_getspace(req, len);
238	res = read(s, &req->ir_buf[req->ir_usedlen], len);
239	if (res < len)
240		return (-1);
241	req->ir_usedlen += len;
242	return (0);
243}
244
245uint32_t
246isns_req_get_status(struct isns_req *req)
247{
248
249	if (req->ir_usedlen < sizeof(struct isns_hdr) + 4)
250		return (-1);
251	return (be32dec(&req->ir_buf[sizeof(struct isns_hdr)]));
252}
253