1273635Smav/*-
2273635Smav * Copyright (c) 2014 Alexander Motin <mav@FreeBSD.org>
3273635Smav * All rights reserved.
4273635Smav *
5273635Smav * Redistribution and use in source and binary forms, with or without
6273635Smav * modification, are permitted provided that the following conditions
7273635Smav * are met:
8273635Smav * 1. Redistributions of source code must retain the above copyright
9273635Smav *    notice, this list of conditions and the following disclaimer.
10273635Smav * 2. Redistributions in binary form must reproduce the above copyright
11273635Smav *    notice, this list of conditions and the following disclaimer in the
12273635Smav *    documentation and/or other materials provided with the distribution.
13273635Smav *
14273635Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15273635Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16273635Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17273635Smav * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18273635Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19273635Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20273635Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21273635Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22273635Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23273635Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24273635Smav * SUCH DAMAGE.
25273635Smav *
26273635Smav */
27273635Smav
28273635Smav#include <sys/cdefs.h>
29273635Smav__FBSDID("$FreeBSD: releng/11.0/usr.sbin/ctld/isns.c 281532 2015-04-14 18:13:55Z delphij $");
30273635Smav
31273635Smav#include <sys/types.h>
32273635Smav#include <sys/time.h>
33273635Smav#include <sys/socket.h>
34273635Smav#include <sys/wait.h>
35273635Smav#include <sys/endian.h>
36273635Smav#include <netinet/in.h>
37273635Smav#include <arpa/inet.h>
38273635Smav#include <netdb.h>
39273635Smav#include <stdbool.h>
40273635Smav#include <stdlib.h>
41273635Smav#include <string.h>
42273635Smav#include <unistd.h>
43273635Smav
44273635Smav#include "ctld.h"
45273635Smav#include "isns.h"
46273635Smav
47273635Smavstruct isns_req *
48273635Smavisns_req_alloc(void)
49273635Smav{
50273635Smav	struct isns_req *req;
51273635Smav
52273635Smav	req = calloc(sizeof(struct isns_req), 1);
53273635Smav	if (req == NULL) {
54273635Smav		log_err(1, "calloc");
55273635Smav		return (NULL);
56273635Smav	}
57273635Smav	req->ir_buflen = sizeof(struct isns_hdr);
58273635Smav	req->ir_usedlen = 0;
59273635Smav	req->ir_buf = calloc(req->ir_buflen, 1);
60274797Strasz	if (req->ir_buf == NULL) {
61273635Smav		free(req);
62273635Smav		log_err(1, "calloc");
63273635Smav		return (NULL);
64273635Smav	}
65273635Smav	return (req);
66273635Smav}
67273635Smav
68273635Smavstruct isns_req *
69273635Smavisns_req_create(uint16_t func, uint16_t flags)
70273635Smav{
71273635Smav	struct isns_req *req;
72273635Smav	struct isns_hdr *hdr;
73273635Smav
74273635Smav	req = isns_req_alloc();
75273635Smav	req->ir_usedlen = sizeof(struct isns_hdr);
76273635Smav	hdr = (struct isns_hdr *)req->ir_buf;
77273635Smav	be16enc(hdr->ih_version, ISNS_VERSION);
78273635Smav	be16enc(hdr->ih_function, func);
79273635Smav	be16enc(hdr->ih_flags, flags);
80273635Smav	return (req);
81273635Smav}
82273635Smav
83273635Smavvoid
84273635Smavisns_req_free(struct isns_req *req)
85273635Smav{
86273635Smav
87273635Smav	free(req->ir_buf);
88273635Smav	free(req);
89273635Smav}
90273635Smav
91273635Smavstatic int
92273635Smavisns_req_getspace(struct isns_req *req, uint32_t len)
93273635Smav{
94273635Smav	void *newbuf;
95273635Smav	int newlen;
96273635Smav
97273635Smav	if (req->ir_usedlen + len <= req->ir_buflen)
98273635Smav		return (0);
99273635Smav	newlen = 1 << flsl(req->ir_usedlen + len);
100273635Smav	newbuf = realloc(req->ir_buf, newlen);
101273635Smav	if (newbuf == NULL) {
102273635Smav		log_err(1, "realloc");
103273635Smav		return (1);
104273635Smav	}
105273635Smav	req->ir_buf = newbuf;
106273635Smav	req->ir_buflen = newlen;
107273635Smav	return (0);
108273635Smav}
109273635Smav
110273635Smavvoid
111273635Smavisns_req_add(struct isns_req *req, uint32_t tag, uint32_t len,
112273635Smav    const void *value)
113273635Smav{
114273635Smav	struct isns_tlv *tlv;
115273635Smav	uint32_t vlen;
116273635Smav
117273635Smav	vlen = len + ((len & 3) ? (4 - (len & 3)) : 0);
118273635Smav	isns_req_getspace(req, sizeof(*tlv) + vlen);
119273635Smav	tlv = (struct isns_tlv *)&req->ir_buf[req->ir_usedlen];
120273635Smav	be32enc(tlv->it_tag, tag);
121273635Smav	be32enc(tlv->it_length, vlen);
122273635Smav	memcpy(tlv->it_value, value, len);
123273635Smav	if (vlen != len)
124273635Smav		memset(&tlv->it_value[len], 0, vlen - len);
125273635Smav	req->ir_usedlen += sizeof(*tlv) + vlen;
126273635Smav}
127273635Smav
128273635Smavvoid
129273635Smavisns_req_add_delim(struct isns_req *req)
130273635Smav{
131273635Smav
132273635Smav	isns_req_add(req, 0, 0, NULL);
133273635Smav}
134273635Smav
135273635Smavvoid
136273635Smavisns_req_add_str(struct isns_req *req, uint32_t tag, const char *value)
137273635Smav{
138273635Smav
139273635Smav	isns_req_add(req, tag, strlen(value) + 1, value);
140273635Smav}
141273635Smav
142273635Smavvoid
143273635Smavisns_req_add_32(struct isns_req *req, uint32_t tag, uint32_t value)
144273635Smav{
145273635Smav	uint32_t beval;
146273635Smav
147273635Smav	be32enc(&beval, value);
148273635Smav	isns_req_add(req, tag, sizeof(value), &beval);
149273635Smav}
150273635Smav
151273635Smavvoid
152273635Smavisns_req_add_addr(struct isns_req *req, uint32_t tag, struct addrinfo *ai)
153273635Smav{
154273635Smav	struct sockaddr_in *in4;
155273635Smav	struct sockaddr_in6 *in6;
156273635Smav	uint8_t buf[16];
157273635Smav
158273635Smav	switch (ai->ai_addr->sa_family) {
159273635Smav	case AF_INET:
160273635Smav		in4 = (struct sockaddr_in *)(void *)ai->ai_addr;
161273635Smav		memset(buf, 0, 10);
162273635Smav		buf[10] = 0xff;
163273635Smav		buf[11] = 0xff;
164273635Smav		memcpy(&buf[12], &in4->sin_addr, sizeof(in4->sin_addr));
165273635Smav		isns_req_add(req, tag, sizeof(buf), buf);
166273635Smav		break;
167273635Smav	case AF_INET6:
168273635Smav		in6 = (struct sockaddr_in6 *)(void *)ai->ai_addr;
169273635Smav		isns_req_add(req, tag, sizeof(in6->sin6_addr), &in6->sin6_addr);
170273635Smav		break;
171273635Smav	default:
172273635Smav		log_errx(1, "Unsupported address family %d",
173273635Smav		    ai->ai_addr->sa_family);
174273635Smav	}
175273635Smav}
176273635Smav
177273635Smavvoid
178273635Smavisns_req_add_port(struct isns_req *req, uint32_t tag, struct addrinfo *ai)
179273635Smav{
180273635Smav	struct sockaddr_in *in4;
181273635Smav	struct sockaddr_in6 *in6;
182273635Smav	uint32_t buf;
183273635Smav
184273635Smav	switch (ai->ai_addr->sa_family) {
185273635Smav	case AF_INET:
186273635Smav		in4 = (struct sockaddr_in *)(void *)ai->ai_addr;
187273635Smav		be32enc(&buf, ntohs(in4->sin_port));
188273635Smav		isns_req_add(req, tag, sizeof(buf), &buf);
189273635Smav		break;
190273635Smav	case AF_INET6:
191273635Smav		in6 = (struct sockaddr_in6 *)(void *)ai->ai_addr;
192273635Smav		be32enc(&buf, ntohs(in6->sin6_port));
193273635Smav		isns_req_add(req, tag, sizeof(buf), &buf);
194273635Smav		break;
195273635Smav	default:
196273635Smav		log_errx(1, "Unsupported address family %d",
197273635Smav		    ai->ai_addr->sa_family);
198273635Smav	}
199273635Smav}
200273635Smav
201273635Smavint
202273635Smavisns_req_send(int s, struct isns_req *req)
203273635Smav{
204273635Smav	struct isns_hdr *hdr;
205273635Smav	int res;
206273635Smav
207273635Smav	hdr = (struct isns_hdr *)req->ir_buf;
208273635Smav	be16enc(hdr->ih_length, req->ir_usedlen - sizeof(*hdr));
209273635Smav	be16enc(hdr->ih_flags, be16dec(hdr->ih_flags) |
210273635Smav	    ISNS_FLAG_LAST | ISNS_FLAG_FIRST);
211273635Smav	be16enc(hdr->ih_transaction, 0);
212273635Smav	be16enc(hdr->ih_sequence, 0);
213273635Smav
214273635Smav	res = write(s, req->ir_buf, req->ir_usedlen);
215273635Smav	return ((res < 0) ? -1 : 0);
216273635Smav}
217273635Smav
218273635Smavint
219273635Smavisns_req_receive(int s, struct isns_req *req)
220273635Smav{
221273635Smav	struct isns_hdr *hdr;
222273635Smav	ssize_t res, len;
223273635Smav
224273635Smav	req->ir_usedlen = 0;
225273635Smav	isns_req_getspace(req, sizeof(*hdr));
226273635Smav	res = read(s, req->ir_buf, sizeof(*hdr));
227273635Smav	if (res < (ssize_t)sizeof(*hdr))
228273635Smav		return (-1);
229273635Smav	req->ir_usedlen = sizeof(*hdr);
230273635Smav	hdr = (struct isns_hdr *)req->ir_buf;
231273635Smav	if (be16dec(hdr->ih_version) != ISNS_VERSION)
232273635Smav		return (-1);
233273635Smav	if ((be16dec(hdr->ih_flags) & (ISNS_FLAG_LAST | ISNS_FLAG_FIRST)) !=
234273635Smav	    (ISNS_FLAG_LAST | ISNS_FLAG_FIRST))
235273635Smav		return (-1);
236273635Smav	len = be16dec(hdr->ih_length);
237273635Smav	isns_req_getspace(req, len);
238273635Smav	res = read(s, &req->ir_buf[req->ir_usedlen], len);
239273635Smav	if (res < len)
240273635Smav		return (-1);
241273635Smav	req->ir_usedlen += len;
242273635Smav	return (0);
243273635Smav}
244273635Smav
245273635Smavuint32_t
246273635Smavisns_req_get_status(struct isns_req *req)
247273635Smav{
248273635Smav
249273635Smav	if (req->ir_usedlen < sizeof(struct isns_hdr) + 4)
250273635Smav		return (-1);
251273635Smav	return (be32dec(&req->ir_buf[sizeof(struct isns_hdr)]));
252273635Smav}
253