xref: /openbsd/usr.sbin/iscsid/util.c (revision dda190fa)
1 /*	$OpenBSD: util.c,v 1.10 2025/01/16 16:19:39 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Claudio Jeker <claudio@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/queue.h>
20 #include <sys/socket.h>
21 #include <sys/uio.h>
22 
23 #include <scsi/iscsi.h>
24 
25 #include <errno.h>
26 #include <event.h>
27 #include <fcntl.h>
28 #include <netdb.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include "iscsid.h"
35 #include "log.h"
36 
37 struct pdu *
pdu_new(void)38 pdu_new(void)
39 {
40 	struct pdu *p;
41 
42 	if (!(p = calloc(1, sizeof(*p))))
43 		return NULL;
44 	return p;
45 }
46 
47 void *
pdu_alloc(size_t len)48 pdu_alloc(size_t len)
49 {
50 	return malloc(PDU_LEN(len));
51 }
52 
53 void *
pdu_dup(void * data,size_t len)54 pdu_dup(void *data, size_t len)
55 {
56 	void *p;
57 
58 	if ((p = malloc(PDU_LEN(len))))
59 		memcpy(p, data, len);
60 	return p;
61 }
62 
63 int
pdu_addbuf(struct pdu * p,void * buf,size_t len,unsigned int elm)64 pdu_addbuf(struct pdu *p, void *buf, size_t len, unsigned int elm)
65 {
66 	if (len & 0x3) {
67 		bzero((char *)buf + len, 4 - (len & 0x3));
68 		len += 4 - (len & 0x3);
69 	}
70 
71 	if (elm < PDU_MAXIOV)
72 		if (!p->iov[elm].iov_base) {
73 			p->iov[elm].iov_base = buf;
74 			p->iov[elm].iov_len = len;
75 			return 0;
76 		}
77 
78 	/* no space left */
79 	return -1;
80 }
81 
82 void *
pdu_getbuf(struct pdu * p,size_t * len,unsigned int elm)83 pdu_getbuf(struct pdu *p, size_t *len, unsigned int elm)
84 {
85 	if (len)
86 		*len = 0;
87 	if (elm < PDU_MAXIOV)
88 		if (p->iov[elm].iov_base) {
89 			if (len)
90 				*len = p->iov[elm].iov_len;
91 			return p->iov[elm].iov_base;
92 		}
93 
94 	return NULL;
95 }
96 
97 void
pdu_free(struct pdu * p)98 pdu_free(struct pdu *p)
99 {
100 	unsigned int j;
101 
102 	for (j = 0; j < PDU_MAXIOV; j++)
103 		free(p->iov[j].iov_base);
104 	free(p);
105 }
106 
107 int
socket_setblockmode(int fd,int nonblocking)108 socket_setblockmode(int fd, int nonblocking)
109 {
110 	int flags;
111 
112 	if ((flags = fcntl(fd, F_GETFL)) == -1)
113 		return -1;
114 
115 	if (nonblocking)
116 		flags |= O_NONBLOCK;
117 	else
118 		flags &= ~O_NONBLOCK;
119 
120 	if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
121 		return -1;
122 	return 0;
123 }
124 
125 const char *
log_sockaddr(void * arg)126 log_sockaddr(void *arg)
127 {
128 	struct sockaddr *sa = arg;
129 	char port[6];
130 	char host[NI_MAXHOST];
131 	static char buf[NI_MAXHOST + 8];
132 
133 	if (getnameinfo(sa, sa->sa_len, host, sizeof(host), port, sizeof(port),
134 	    NI_NUMERICHOST))
135 		return "unknown";
136 	if (port[0] == '0')
137 		strlcpy(buf, host, sizeof(buf));
138 	else if (sa->sa_family == AF_INET)
139 		snprintf(buf, sizeof(buf), "%s:%s", host, port);
140 	else
141 		snprintf(buf, sizeof(buf), "[%s]:%s", host, port);
142 	return buf;
143 }
144 
145 int
control_compose(void * ch,u_int16_t type,void * buf,size_t len)146 control_compose(void *ch, u_int16_t type, void *buf, size_t len)
147 {
148 	return control_build(ch, type, 1, CTRLARGV({ buf, len }));
149 }
150 
151 int
control_build(void * ch,u_int16_t type,int argc,struct ctrldata * argv)152 control_build(void *ch, u_int16_t type, int argc, struct ctrldata *argv)
153 {
154 	struct pdu *pdu;
155 	struct ctrlmsghdr *cmh;
156 	size_t size = 0;
157 	int i;
158 
159 	if (argc > (int)nitems(cmh->len))
160 		return -1;
161 
162 	for (i = 0; i < argc; i++)
163 		size += argv[i].len;
164 	if (PDU_LEN(size) > CONTROL_READ_SIZE - PDU_LEN(sizeof(*cmh)))
165 		return -1;
166 
167 	if ((pdu = pdu_new()) == NULL)
168 		return -1;
169 	if ((cmh = pdu_alloc(sizeof(*cmh))) == NULL)
170 		goto fail;
171 	bzero(cmh, sizeof(*cmh));
172 	cmh->type = type;
173 	pdu_addbuf(pdu, cmh, sizeof(*cmh), 0);
174 
175 	for (i = 0; i < argc; i++)
176 		if (argv[i].len > 0) {
177 			void *ptr;
178 
179 			cmh->len[i] = argv[i].len;
180 			if ((ptr = pdu_alloc(argv[i].len)) == NULL)
181 				goto fail;
182 			memcpy(ptr, argv[i].buf, argv[i].len);
183 			pdu_addbuf(pdu, ptr, argv[i].len, i + 1);
184 		}
185 
186 	control_queue(ch, pdu);
187 	return 0;
188 fail:
189 	pdu_free(pdu);
190 	return -1;
191 }
192 
193 void
kvp_free(struct kvp * kvp)194 kvp_free(struct kvp *kvp)
195 {
196 	struct kvp *k;
197 
198 	if (kvp == NULL)
199 		return;
200 	for (k = kvp; k->key; k++) {
201 		if (k->flags & KVP_KEY_ALLOCED)
202 			free(k->key);
203 		if (k->flags & KVP_VALUE_ALLOCED)
204 			free(k->value);
205 	}
206 	free(kvp);
207 }
208