iscsid_main.c revision 1.8 1 1.8 mlelstv /* $NetBSD: iscsid_main.c,v 1.8 2012/12/29 08:28:20 mlelstv Exp $ */
2 1.1 agc
3 1.1 agc /*-
4 1.1 agc * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
5 1.1 agc * All rights reserved.
6 1.1 agc *
7 1.1 agc * This code is derived from software contributed to The NetBSD Foundation
8 1.1 agc * by Wasabi Systems, Inc.
9 1.1 agc *
10 1.1 agc * Redistribution and use in source and binary forms, with or without
11 1.1 agc * modification, are permitted provided that the following conditions
12 1.1 agc * are met:
13 1.1 agc * 1. Redistributions of source code must retain the above copyright
14 1.1 agc * notice, this list of conditions and the following disclaimer.
15 1.1 agc * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 agc * notice, this list of conditions and the following disclaimer in the
17 1.1 agc * documentation and/or other materials provided with the distribution.
18 1.1 agc *
19 1.1 agc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 agc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 agc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 agc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 agc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 agc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 agc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 agc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 agc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 agc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 agc * POSSIBILITY OF SUCH DAMAGE.
30 1.1 agc */
31 1.1 agc
32 1.1 agc #include "iscsid_globals.h"
33 1.1 agc
34 1.1 agc #include <sys/types.h>
35 1.1 agc #include <sys/socket.h>
36 1.1 agc #include <sys/un.h>
37 1.1 agc #include <sys/sysctl.h>
38 1.1 agc
39 1.1 agc #include <ctype.h>
40 1.7 riz #include <err.h>
41 1.1 agc #include <fcntl.h>
42 1.1 agc
43 1.1 agc #define DEVICE "/dev/iscsi0"
44 1.1 agc
45 1.1 agc /* -------------------------------------------------------------------------- */
46 1.1 agc
47 1.1 agc list_head_t list[NUM_DAEMON_LISTS]; /* the lists this daemon keeps */
48 1.1 agc
49 1.1 agc pthread_mutex_t sesslist_lock; /* session list lock */
50 1.1 agc pthread_t event_thread; /* event thread handle */
51 1.1 agc
52 1.1 agc int driver = -1; /* the driver's file desc */
53 1.1 agc int client_sock; /* the client communication socket */
54 1.1 agc
55 1.4 christos #ifndef ISCSI_DEBUG
56 1.4 christos #define ISCSI_DEBUG 0
57 1.4 christos #endif
58 1.1 agc int debug_level = ISCSI_DEBUG; /* How much info to display */
59 1.5 christos int nothreads;
60 1.1 agc
61 1.1 agc /*
62 1.1 agc To avoid memory fragmentation (and speed things up a bit), we use the
63 1.1 agc static bufs unless the request or response exceeds the buffer size
64 1.1 agc (which it normally shouldn't, assuming we don't have thousands
65 1.1 agc of list entries).
66 1.1 agc */
67 1.3 agc static uint8_t req_buf[REQ_BUFFER_SIZE]; /* default buffer for requests */
68 1.3 agc static uint8_t rsp_buf[RSP_BUFFER_SIZE]; /* default buffer for responses */
69 1.1 agc
70 1.1 agc /* -------------------------------------------------------------------------- */
71 1.1 agc
72 1.4 christos static void __dead
73 1.4 christos usage(void)
74 1.4 christos {
75 1.7 riz fprintf(stderr, "Usage: %s [-d <lvl>] [-n]\n", getprogname());
76 1.4 christos exit(EXIT_FAILURE);
77 1.4 christos }
78 1.4 christos
79 1.1 agc
80 1.1 agc /*
81 1.1 agc * create_node_name:
82 1.1 agc * Create and set default node name.
83 1.1 agc *
84 1.1 agc * Returns 0 on success, else an error code.
85 1.1 agc */
86 1.1 agc
87 1.3 agc static int
88 1.1 agc create_node_name(void)
89 1.1 agc {
90 1.1 agc iscsi_set_node_name_parameters_t snp;
91 1.1 agc uint32_t hid = 0;
92 1.1 agc size_t siz;
93 1.1 agc int mib[2];
94 1.1 agc unsigned char *s;
95 1.1 agc
96 1.1 agc (void) memset(&snp, 0x0, sizeof(snp));
97 1.1 agc mib[0] = CTL_KERN;
98 1.1 agc mib[1] = KERN_HOSTID;
99 1.1 agc siz = sizeof(hid);
100 1.1 agc sysctl(mib, 2, &hid, &siz, NULL, 0);
101 1.1 agc mib[1] = KERN_HOSTNAME;
102 1.1 agc siz = ISCSI_STRING_LENGTH - 45;
103 1.1 agc sysctl(mib, 2, snp.InitiatorAlias, &siz, NULL, 0);
104 1.1 agc
105 1.1 agc DEB(1, ("Host Name: <%s>, Host ID: %u\n", snp.InitiatorAlias, hid));
106 1.1 agc if (!snp.InitiatorAlias[0]) {
107 1.1 agc printf("Warning: iSCSI Node Name not set (No Host Name)!\n");
108 1.1 agc return ISCSID_STATUS_NO_INITIATOR_NAME;
109 1.1 agc }
110 1.1 agc for (s = snp.InitiatorAlias; *s; s++)
111 1.1 agc if (!isalnum((unsigned char) *s) && *s != '-' && *s != '.' && *s != ':')
112 1.1 agc *s = '-';
113 1.1 agc snprintf((char *)snp.InitiatorName, sizeof(snp.InitiatorName),
114 1.1 agc "iqn.1994-04.org.netbsd:iscsi.%s:%u", snp.InitiatorAlias, hid);
115 1.1 agc
116 1.1 agc ioctl(driver, ISCSI_SET_NODE_NAME, &snp);
117 1.1 agc return snp.status;
118 1.1 agc }
119 1.1 agc
120 1.1 agc
121 1.1 agc /*
122 1.1 agc * init_daemon:
123 1.1 agc * Open driver, create communication socket.
124 1.1 agc *
125 1.1 agc * Returns: <0 on error
126 1.1 agc */
127 1.1 agc
128 1.3 agc static int
129 1.1 agc init_daemon(void)
130 1.1 agc {
131 1.1 agc int sock, i;
132 1.1 agc struct sockaddr_un name;
133 1.1 agc iscsid_request_t req;
134 1.1 agc
135 1.1 agc if ((driver = open(DEVICE, O_RDONLY)) < 0) {
136 1.1 agc perror("opening " DEVICE);
137 1.1 agc #ifndef ISCSI_DEBUG /* DEBUG ONLY: Allow daemon to operate w/o driver */
138 1.1 agc return -1;
139 1.1 agc #endif
140 1.1 agc }
141 1.1 agc
142 1.1 agc sock = socket(AF_UNIX, SOCK_DGRAM, 0);
143 1.1 agc if (sock < 0) {
144 1.1 agc perror("opening datagram socket");
145 1.1 agc return -1;
146 1.1 agc }
147 1.1 agc
148 1.1 agc name.sun_family = AF_UNIX;
149 1.1 agc strlcpy(name.sun_path, ISCSID_SOCK_NAME, sizeof(name.sun_path));
150 1.1 agc
151 1.1 agc req.request = ISCSID_DAEMON_TEST;
152 1.1 agc req.parameter_length = 0;
153 1.1 agc
154 1.2 christos i = sendto(sock, &req, sizeof(req), 0, (struct sockaddr *)(void *)&name,
155 1.2 christos (socklen_t)sizeof(struct sockaddr_un));
156 1.1 agc if (i == sizeof(req)) {
157 1.1 agc printf("Daemon already loaded!\n");
158 1.1 agc close(sock);
159 1.1 agc return -1;
160 1.1 agc }
161 1.1 agc
162 1.1 agc unlink(ISCSID_SOCK_NAME);
163 1.2 christos if (bind(sock, (struct sockaddr *)(void *)&name, (socklen_t)sizeof(struct sockaddr_un))) {
164 1.1 agc perror("binding name to socket");
165 1.1 agc return -1;
166 1.1 agc }
167 1.1 agc
168 1.1 agc for (i = 0; i < NUM_DAEMON_LISTS; i++) {
169 1.1 agc TAILQ_INIT(&list[i].list);
170 1.1 agc list[i].num_entries = 0;
171 1.1 agc }
172 1.1 agc
173 1.5 christos if (!nothreads && (i = pthread_mutex_init(&sesslist_lock, NULL)) != 0) {
174 1.1 agc printf("Mutex init failed (%d)\n", i);
175 1.1 agc close(sock);
176 1.1 agc return -1;
177 1.1 agc }
178 1.1 agc
179 1.1 agc if (!register_event_handler()) {
180 1.1 agc printf("Couldn't register event handler\n");
181 1.1 agc close(sock);
182 1.1 agc unlink(ISCSID_SOCK_NAME);
183 1.5 christos if (!nothreads)
184 1.5 christos pthread_mutex_destroy(&sesslist_lock);
185 1.1 agc return -1;
186 1.1 agc }
187 1.1 agc
188 1.1 agc create_node_name();
189 1.1 agc
190 1.1 agc return sock;
191 1.1 agc }
192 1.1 agc
193 1.1 agc
194 1.1 agc /*
195 1.1 agc * make_rsp:
196 1.1 agc * Allocate a response buffer if the static buffer is insufficient, set
197 1.1 agc * the response parameter length.
198 1.1 agc *
199 1.1 agc * Parameter:
200 1.1 agc * len Response parameter size (not counting header)
201 1.1 agc * prsp Pointer to address of response buffer
202 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
203 1.1 agc * for static buffer.
204 1.1 agc *
205 1.1 agc * Returns: Pointer to response buffer, NULL if allocation failed.
206 1.1 agc */
207 1.1 agc
208 1.1 agc iscsid_response_t *
209 1.2 christos make_rsp(size_t len, iscsid_response_t ** prsp, int *prsp_temp)
210 1.1 agc {
211 1.1 agc iscsid_response_t *rsp;
212 1.1 agc
213 1.1 agc if ((len + sizeof(iscsid_response_t)) > RSP_BUFFER_SIZE) {
214 1.1 agc if ((rsp = calloc(1, len)) == NULL) {
215 1.1 agc (*prsp)->status = ISCSID_STATUS_NO_RESOURCES;
216 1.1 agc return NULL;
217 1.1 agc }
218 1.1 agc *prsp_temp = TRUE;
219 1.1 agc *prsp = rsp;
220 1.1 agc } else
221 1.1 agc rsp = *prsp;
222 1.1 agc
223 1.1 agc memset (rsp, 0, len + sizeof(iscsid_response_t));
224 1.2 christos rsp->parameter_length = (uint32_t)len;
225 1.1 agc return rsp;
226 1.1 agc }
227 1.1 agc
228 1.1 agc
229 1.1 agc /*
230 1.1 agc * process_message:
231 1.1 agc * minimal parameter check and dispatch for the daemon functions.
232 1.1 agc *
233 1.1 agc * Parameter:
234 1.1 agc * req The request
235 1.1 agc * prsp Pointer to address of response buffer
236 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
237 1.1 agc * for static buffer.
238 1.1 agc */
239 1.1 agc
240 1.3 agc static void
241 1.1 agc process_message(iscsid_request_t *req, iscsid_response_t **prsp, int *prsp_temp)
242 1.1 agc {
243 1.1 agc iscsid_response_t *rsp;
244 1.2 christos void *p = req->parameter;
245 1.1 agc
246 1.1 agc *prsp_temp = FALSE;
247 1.2 christos *prsp = rsp = (iscsid_response_t *)(void *)rsp_buf;
248 1.1 agc rsp->parameter_length = 0;
249 1.1 agc rsp->status = ISCSID_STATUS_SUCCESS;
250 1.1 agc
251 1.1 agc switch (req->request) {
252 1.1 agc case ISCSID_ADD_TARGET:
253 1.1 agc if (req->parameter_length < sizeof(iscsid_add_target_req_t)) {
254 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
255 1.1 agc break;
256 1.1 agc }
257 1.2 christos add_target((iscsid_add_target_req_t *)p, prsp, prsp_temp);
258 1.1 agc break;
259 1.1 agc
260 1.1 agc case ISCSID_ADD_PORTAL:
261 1.1 agc if (req->parameter_length != sizeof(iscsid_add_portal_req_t)) {
262 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
263 1.1 agc break;
264 1.1 agc }
265 1.2 christos add_portal((iscsid_add_portal_req_t *)p, prsp, prsp_temp);
266 1.1 agc break;
267 1.1 agc
268 1.1 agc case ISCSID_SET_TARGET_OPTIONS:
269 1.1 agc if (req->parameter_length != sizeof(iscsid_get_set_target_options_t)) {
270 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
271 1.1 agc break;
272 1.1 agc }
273 1.2 christos rsp->status = set_target_options((iscsid_get_set_target_options_t *)p);
274 1.1 agc break;
275 1.1 agc
276 1.1 agc case ISCSID_GET_TARGET_OPTIONS:
277 1.1 agc if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
278 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
279 1.1 agc break;
280 1.1 agc }
281 1.1 agc rsp->status = ISCSID_STATUS_NOTIMPL;
282 1.1 agc break;
283 1.1 agc
284 1.1 agc case ISCSID_SET_TARGET_AUTHENTICATION:
285 1.1 agc if (req->parameter_length !=
286 1.1 agc sizeof(iscsid_set_target_authentication_req_t)) {
287 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
288 1.1 agc break;
289 1.1 agc }
290 1.2 christos rsp->status = set_target_auth((iscsid_set_target_authentication_req_t *)p);
291 1.1 agc break;
292 1.1 agc
293 1.1 agc case ISCSID_SLP_FIND_TARGETS:
294 1.1 agc rsp->status = ISCSID_STATUS_NOTIMPL;
295 1.1 agc break;
296 1.1 agc
297 1.1 agc case ISCSID_REFRESH_TARGETS:
298 1.1 agc if (req->parameter_length < sizeof(iscsid_refresh_req_t)) {
299 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
300 1.1 agc break;
301 1.1 agc }
302 1.2 christos rsp->status = refresh_targets((iscsid_refresh_req_t *)p);
303 1.1 agc break;
304 1.1 agc
305 1.1 agc case ISCSID_REMOVE_TARGET:
306 1.1 agc if (req->parameter_length != sizeof(iscsid_list_id_t)) {
307 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
308 1.1 agc break;
309 1.1 agc }
310 1.2 christos rsp->status = remove_target((iscsid_list_id_t *)p);
311 1.1 agc break;
312 1.1 agc
313 1.1 agc case ISCSID_SEARCH_LIST:
314 1.1 agc if (req->parameter_length != sizeof(iscsid_search_list_req_t)) {
315 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
316 1.1 agc break;
317 1.1 agc }
318 1.2 christos search_list((iscsid_search_list_req_t *)p, prsp, prsp_temp);
319 1.1 agc break;
320 1.1 agc
321 1.1 agc case ISCSID_GET_LIST:
322 1.1 agc if (req->parameter_length != sizeof(iscsid_get_list_req_t)) {
323 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
324 1.1 agc break;
325 1.1 agc }
326 1.2 christos get_list((iscsid_get_list_req_t *)p, prsp, prsp_temp);
327 1.1 agc break;
328 1.1 agc
329 1.1 agc case ISCSID_GET_TARGET_INFO:
330 1.1 agc if (req->parameter_length != sizeof(iscsid_list_id_t)) {
331 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
332 1.1 agc break;
333 1.1 agc }
334 1.2 christos get_target_info((iscsid_list_id_t *)p, prsp, prsp_temp);
335 1.1 agc break;
336 1.1 agc
337 1.1 agc case ISCSID_GET_PORTAL_INFO:
338 1.1 agc if (req->parameter_length != sizeof(iscsid_list_id_t)) {
339 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
340 1.1 agc break;
341 1.1 agc }
342 1.2 christos get_portal_info((iscsid_list_id_t *)p, prsp, prsp_temp);
343 1.1 agc break;
344 1.1 agc
345 1.1 agc #ifndef ISCSI_MINIMAL
346 1.1 agc case ISCSID_ADD_ISNS_SERVER:
347 1.1 agc if (req->parameter_length != sizeof(iscsid_add_isns_server_req_t)) {
348 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
349 1.1 agc break;
350 1.1 agc }
351 1.2 christos add_isns_server((iscsid_add_isns_server_req_t *)p,
352 1.1 agc prsp, prsp_temp);
353 1.1 agc break;
354 1.1 agc
355 1.1 agc case ISCSID_GET_ISNS_SERVER:
356 1.1 agc if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
357 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
358 1.1 agc break;
359 1.1 agc }
360 1.2 christos get_isns_server((iscsid_sym_id_t *)p, prsp, prsp_temp);
361 1.1 agc break;
362 1.1 agc
363 1.1 agc case ISCSID_SLP_FIND_ISNS_SERVERS:
364 1.1 agc rsp->status = ISCSID_STATUS_NOTIMPL;
365 1.1 agc break;
366 1.1 agc
367 1.1 agc case ISCSID_REMOVE_ISNS_SERVER:
368 1.1 agc if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
369 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
370 1.1 agc break;
371 1.1 agc }
372 1.2 christos rsp->status = remove_isns_server((iscsid_sym_id_t *)p);
373 1.1 agc break;
374 1.1 agc #endif
375 1.1 agc
376 1.1 agc case ISCSID_ADD_INITIATOR_PORTAL:
377 1.1 agc if (req->parameter_length != sizeof(iscsid_add_initiator_req_t)) {
378 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
379 1.1 agc break;
380 1.1 agc }
381 1.2 christos add_initiator_portal((iscsid_add_initiator_req_t *)p,
382 1.1 agc prsp, prsp_temp);
383 1.1 agc break;
384 1.1 agc
385 1.1 agc case ISCSID_GET_INITIATOR_PORTAL:
386 1.1 agc if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
387 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
388 1.1 agc break;
389 1.1 agc }
390 1.2 christos get_initiator_portal((iscsid_sym_id_t *)p, prsp, prsp_temp);
391 1.1 agc break;
392 1.1 agc
393 1.1 agc case ISCSID_REMOVE_INITIATOR_PORTAL:
394 1.1 agc if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
395 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
396 1.1 agc break;
397 1.1 agc }
398 1.2 christos rsp->status = remove_initiator_portal((iscsid_sym_id_t *)p);
399 1.1 agc break;
400 1.1 agc
401 1.1 agc case ISCSID_LOGIN:
402 1.1 agc if (req->parameter_length != sizeof(iscsid_login_req_t)) {
403 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
404 1.1 agc break;
405 1.1 agc }
406 1.2 christos login((iscsid_login_req_t *)p, rsp);
407 1.1 agc break;
408 1.1 agc
409 1.1 agc case ISCSID_ADD_CONNECTION:
410 1.1 agc if (req->parameter_length != sizeof(iscsid_login_req_t)) {
411 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
412 1.1 agc break;
413 1.1 agc }
414 1.2 christos add_connection((iscsid_login_req_t *)p, rsp);
415 1.1 agc break;
416 1.1 agc
417 1.1 agc case ISCSID_LOGOUT:
418 1.1 agc if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
419 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
420 1.1 agc break;
421 1.1 agc }
422 1.2 christos rsp->status = logout((iscsid_sym_id_t *)p);
423 1.1 agc break;
424 1.1 agc
425 1.1 agc case ISCSID_REMOVE_CONNECTION:
426 1.1 agc if (req->parameter_length != sizeof(iscsid_remove_connection_req_t)) {
427 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
428 1.1 agc break;
429 1.1 agc }
430 1.2 christos rsp->status = remove_connection((iscsid_remove_connection_req_t *)p);
431 1.1 agc break;
432 1.1 agc
433 1.1 agc case ISCSID_GET_SESSION_LIST:
434 1.1 agc get_session_list(prsp, prsp_temp);
435 1.1 agc break;
436 1.1 agc
437 1.1 agc case ISCSID_GET_CONNECTION_LIST:
438 1.1 agc if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
439 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
440 1.1 agc break;
441 1.1 agc }
442 1.2 christos get_connection_list((iscsid_sym_id_t *)p, prsp, prsp_temp);
443 1.1 agc break;
444 1.1 agc
445 1.1 agc case ISCSID_GET_CONNECTION_INFO:
446 1.1 agc if (req->parameter_length != sizeof(iscsid_get_connection_info_req_t)) {
447 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
448 1.1 agc break;
449 1.1 agc }
450 1.2 christos get_connection_info((iscsid_get_connection_info_req_t *)p,
451 1.1 agc prsp, prsp_temp);
452 1.1 agc break;
453 1.1 agc
454 1.1 agc case ISCSID_SET_NODE_NAME:
455 1.1 agc if (req->parameter_length != sizeof(iscsid_set_node_name_req_t)) {
456 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
457 1.1 agc break;
458 1.1 agc }
459 1.2 christos rsp->status = set_node_name((iscsid_set_node_name_req_t *)p);
460 1.1 agc break;
461 1.1 agc
462 1.1 agc case ISCSID_GET_VERSION:
463 1.1 agc get_version(prsp, prsp_temp);
464 1.1 agc break;
465 1.1 agc
466 1.1 agc default:
467 1.1 agc rsp->status = ISCSID_STATUS_INVALID_REQUEST;
468 1.1 agc break;
469 1.1 agc }
470 1.1 agc }
471 1.1 agc
472 1.1 agc
473 1.1 agc /*
474 1.1 agc * exit_daemon:
475 1.1 agc * Deregister the event handler, deregister isns servers, then exit program.
476 1.1 agc */
477 1.1 agc
478 1.1 agc void
479 1.1 agc exit_daemon(void)
480 1.1 agc {
481 1.6 riz LOCK_SESSIONS;
482 1.1 agc deregister_event_handler();
483 1.1 agc
484 1.1 agc #ifndef ISCSI_MINIMAL
485 1.1 agc dereg_all_isns_servers();
486 1.1 agc #endif
487 1.1 agc
488 1.1 agc printf("iSCSI Daemon Exits\n");
489 1.1 agc exit(0);
490 1.1 agc }
491 1.1 agc
492 1.1 agc
493 1.1 agc /*
494 1.1 agc * main:
495 1.1 agc * init, go daemon, then loop reading requests, processing them,
496 1.1 agc * and sending responses.
497 1.1 agc * Stops on receiving a terminate message (no response to that one is sent),
498 1.1 agc * or when an error occurs reading or writing the socket.
499 1.1 agc *
500 1.1 agc * Parameter: argc, argv currently ignored.
501 1.1 agc */
502 1.1 agc
503 1.1 agc int
504 1.2 christos /*ARGSUSED*/
505 1.1 agc main(int argc, char **argv)
506 1.1 agc {
507 1.4 christos int req_temp, rsp_temp, c;
508 1.2 christos ssize_t ret;
509 1.2 christos size_t len;
510 1.1 agc struct sockaddr_un from;
511 1.1 agc socklen_t fromlen;
512 1.1 agc iscsid_request_t *req;
513 1.1 agc iscsid_response_t *rsp;
514 1.1 agc struct timeval seltout = { 2, 0 }; /* 2 second poll interval */
515 1.7 riz char *p;
516 1.1 agc
517 1.7 riz while ((c = getopt(argc, argv, "d:n")) != -1)
518 1.4 christos switch (c) {
519 1.5 christos case 'n':
520 1.5 christos nothreads++;
521 1.5 christos break;
522 1.4 christos case 'd':
523 1.7 riz debug_level=(int)strtol(optarg, &p, 10);
524 1.7 riz if (*p)
525 1.7 riz errx(EXIT_FAILURE, "illegal debug level -- %s",
526 1.7 riz optarg);
527 1.4 christos break;
528 1.4 christos default:
529 1.4 christos usage();
530 1.4 christos }
531 1.4 christos
532 1.7 riz client_sock = init_daemon();
533 1.7 riz if (client_sock < 0)
534 1.7 riz exit(1);
535 1.7 riz
536 1.7 riz printf("iSCSI Daemon loaded\n");
537 1.7 riz
538 1.4 christos if (!debug_level)
539 1.4 christos daemon(0, 1);
540 1.1 agc
541 1.5 christos if (nothreads)
542 1.5 christos setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &seltout,
543 1.5 christos sizeof(seltout));
544 1.5 christos else {
545 1.5 christos ret = pthread_create(&event_thread, NULL, event_handler, NULL);
546 1.5 christos if (ret) {
547 1.5 christos printf("Thread creation failed (%zd)\n", ret);
548 1.5 christos close(client_sock);
549 1.5 christos unlink(ISCSID_SOCK_NAME);
550 1.5 christos deregister_event_handler();
551 1.5 christos pthread_mutex_destroy(&sesslist_lock);
552 1.5 christos return -1;
553 1.5 christos }
554 1.1 agc }
555 1.1 agc
556 1.1 agc /* ---------------------------------------------------------------------- */
557 1.1 agc
558 1.1 agc for (;;) {
559 1.1 agc /* First, get size of request */
560 1.2 christos req = (iscsid_request_t *)(void *)req_buf;
561 1.1 agc fromlen = sizeof(from);
562 1.1 agc len = sizeof(iscsid_request_t);
563 1.1 agc
564 1.5 christos if (nothreads) {
565 1.6 riz do {
566 1.6 riz ret = recvfrom(client_sock, req, len, MSG_PEEK |
567 1.6 riz MSG_WAITALL, (struct sockaddr *)(void *)&from,
568 1.6 riz &fromlen);
569 1.6 riz if (ret == -1)
570 1.6 riz event_handler(NULL);
571 1.6 riz } while (ret == -1 && errno == EAGAIN);
572 1.5 christos } else {
573 1.5 christos do {
574 1.5 christos ret = recvfrom(client_sock, req, len, MSG_PEEK |
575 1.5 christos MSG_WAITALL, (struct sockaddr *) &from,
576 1.5 christos &fromlen);
577 1.5 christos if (ret == -1)
578 1.5 christos event_handler(NULL);
579 1.5 christos } while (ret == -1 && errno == EAGAIN);
580 1.5 christos }
581 1.1 agc
582 1.2 christos if ((size_t)ret != len) {
583 1.1 agc perror("Receiving from socket");
584 1.1 agc break;
585 1.1 agc }
586 1.7 riz DEB(98, ("Request %d, parlen %d\n",
587 1.1 agc req->request, req->parameter_length));
588 1.1 agc
589 1.1 agc len += req->parameter_length;
590 1.1 agc
591 1.1 agc /* now that we know the size, get the buffer for it */
592 1.1 agc req_temp = (len > REQ_BUFFER_SIZE);
593 1.1 agc
594 1.1 agc if (req_temp) {
595 1.1 agc req = malloc(len);
596 1.1 agc if (!req) {
597 1.2 christos printf("Can't alloc %zu bytes\n", len);
598 1.1 agc break;
599 1.1 agc }
600 1.1 agc }
601 1.1 agc /* read the complete request */
602 1.1 agc fromlen = sizeof(from);
603 1.1 agc ret = recvfrom(client_sock, req, len, MSG_WAITALL,
604 1.2 christos (struct sockaddr *)(void *)&from, &fromlen);
605 1.2 christos if ((size_t)ret != len) {
606 1.1 agc DEBOUT(("Error receiving from socket!\n"));
607 1.1 agc if (req_temp)
608 1.1 agc free(req);
609 1.1 agc continue;
610 1.1 agc }
611 1.1 agc /* terminate? then go die. */
612 1.1 agc if (req->request == ISCSID_DAEMON_TERMINATE)
613 1.1 agc break;
614 1.1 agc
615 1.1 agc /* No reply required to test message */
616 1.1 agc if (req->request == ISCSID_DAEMON_TEST) {
617 1.1 agc if (req_temp)
618 1.1 agc free(req);
619 1.1 agc continue;
620 1.1 agc }
621 1.1 agc /* no return path? then we can't send a reply, */
622 1.1 agc /* so don't process the command */
623 1.1 agc if (!from.sun_path[0]) {
624 1.8 mlelstv if (req_temp)
625 1.8 mlelstv free(req);
626 1.1 agc DEBOUT(("No Return Address!\n"));
627 1.1 agc continue;
628 1.1 agc }
629 1.1 agc /* process the request */
630 1.1 agc process_message(req, &rsp, &rsp_temp);
631 1.8 mlelstv if (rsp == NULL) {
632 1.8 mlelstv if (req_temp)
633 1.8 mlelstv free(req);
634 1.8 mlelstv DEBOUT(("Invalid message!\n"));
635 1.8 mlelstv continue;
636 1.8 mlelstv }
637 1.1 agc
638 1.7 riz DEB(98, ("Sending reply: status %d, len %d\n",
639 1.1 agc rsp->status, rsp->parameter_length));
640 1.1 agc
641 1.1 agc /* send the response */
642 1.1 agc len = sizeof(iscsid_response_t) + rsp->parameter_length;
643 1.1 agc ret = sendto(client_sock, rsp, len, 0,
644 1.2 christos (struct sockaddr *)(void *)&from, fromlen);
645 1.2 christos if (len != (size_t)ret) {
646 1.1 agc DEBOUT(("Error sending reply!\n"));
647 1.1 agc }
648 1.1 agc /* free temp buffers if we needed them */
649 1.1 agc if (req_temp)
650 1.1 agc free(req);
651 1.1 agc if (rsp_temp)
652 1.1 agc free(rsp);
653 1.1 agc }
654 1.1 agc
655 1.1 agc exit_daemon();
656 1.1 agc
657 1.1 agc /* we never get here */
658 1.1 agc return 0;
659 1.1 agc }
660