]> git.ozlabs.org Git - ccan/blob - ccan/iscsi/login.c
tdb2: compare the extra 11 hash bits in the header.
[ccan] / ccan / iscsi / login.c
1 /*
2    Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
3    
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8    
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13    
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #define _GNU_SOURCE
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <arpa/inet.h>
23 #include <ccan/compiler/compiler.h>
24 #include "iscsi.h"
25 #include "iscsi-private.h"
26
27 int iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data)
28 {
29         struct iscsi_pdu *pdu;
30         char *str;
31         int ret;
32
33         if (iscsi == NULL) {
34                 printf("trying to login on NULL context\n");
35                 return -1;
36         }
37
38         if (iscsi->is_loggedin != 0) {
39                 printf("trying to login while already logged in\n");
40                 return -2;
41         }
42
43         switch (iscsi->session_type) {
44         case ISCSI_SESSION_DISCOVERY:
45         case ISCSI_SESSION_NORMAL:
46                 break;
47         default:
48                 printf("trying to login without setting session type\n");
49                 return -3;
50         }
51
52         pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_LOGIN_REQUEST, ISCSI_PDU_LOGIN_RESPONSE);
53         if (pdu == NULL) {
54                 printf("Failed to allocate login pdu\n");
55                 return -4;
56         }
57
58         /* login request */
59         iscsi_pdu_set_immediate(pdu);
60
61         /* flags */
62         iscsi_pdu_set_pduflags(pdu, ISCSI_PDU_LOGIN_TRANSIT|ISCSI_PDU_LOGIN_CSG_OPNEG|ISCSI_PDU_LOGIN_NSG_FF);
63
64
65         /* initiator name */
66         if (asprintf(&str, "InitiatorName=%s", iscsi->initiator_name) == -1) {
67                 printf("asprintf failed\n");
68                 iscsi_free_pdu(iscsi, pdu);
69                 return -5;
70         }
71         ret = iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1);
72         free(str);
73         if (ret != 0) {
74                 printf("pdu add data failed\n");
75                 iscsi_free_pdu(iscsi, pdu);
76                 return -6;
77         }
78
79         /* optional alias */
80         if (iscsi->alias) {
81                 if (asprintf(&str, "InitiatorAlias=%s", iscsi->alias) == -1) {
82                         printf("asprintf failed\n");
83                         iscsi_free_pdu(iscsi, pdu);
84                         return -7;
85                 }
86                 ret = iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1);
87                 free(str);
88                 if (ret != 0) {
89                         printf("pdu add data failed\n");
90                         iscsi_free_pdu(iscsi, pdu);
91                         return -8;
92                 }
93         }
94
95         /* target name */
96         if (iscsi->session_type == ISCSI_SESSION_NORMAL) {
97                 if (iscsi->target_name == NULL) {
98                         printf("trying normal connect but target name not set\n");
99                         iscsi_free_pdu(iscsi, pdu);
100                         return -9;
101                 }
102
103                 if (asprintf(&str, "TargetName=%s", iscsi->target_name) == -1) {
104                         printf("asprintf failed\n");
105                         iscsi_free_pdu(iscsi, pdu);
106                         return -10;
107                 }
108                 ret = iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1);
109                 free(str);
110                 if (ret != 0) {
111                         printf("pdu add data failed\n");
112                         iscsi_free_pdu(iscsi, pdu);
113                         return -11;
114                 }
115         }
116
117         /* session type */
118         switch (iscsi->session_type) {
119         case ISCSI_SESSION_DISCOVERY:
120                 str = "SessionType=Discovery";
121                 break;
122         case ISCSI_SESSION_NORMAL:
123                 str = "SessionType=Normal";
124                 break;
125         default:
126                 printf("can not handle sessions %d yet\n", iscsi->session_type);
127                 return -12;
128         }
129         if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
130                 printf("pdu add data failed\n");
131                 iscsi_free_pdu(iscsi, pdu);
132                 return -13;
133         }
134
135         str = "HeaderDigest=None";
136         if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
137                 printf("pdu add data failed\n");
138                 iscsi_free_pdu(iscsi, pdu);
139                 return -14;
140         }
141         str = "DataDigest=None";
142         if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
143                 printf("pdu add data failed\n");
144                 iscsi_free_pdu(iscsi, pdu);
145                 return -15;
146         }
147         str = "InitialR2T=Yes";
148         if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
149                 printf("pdu add data failed\n");
150                 iscsi_free_pdu(iscsi, pdu);
151                 return -16;
152         }
153         str = "ImmediateData=Yes";
154         if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
155                 printf("pdu add data failed\n");
156                 iscsi_free_pdu(iscsi, pdu);
157                 return -17;
158         }
159         str = "MaxBurstLength=262144";
160         if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
161                 printf("pdu add data failed\n");
162                 iscsi_free_pdu(iscsi, pdu);
163                 return -18;
164         }
165         str = "FirstBurstLength=262144";
166         if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
167                 printf("pdu add data failed\n");
168                 iscsi_free_pdu(iscsi, pdu);
169                 return -19;
170         }
171         str = "MaxRecvDataSegmentLength=262144";
172         if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
173                 printf("pdu add data failed\n");
174                 iscsi_free_pdu(iscsi, pdu);
175                 return -20;
176         }
177         str = "DataPDUInOrder=Yes";
178         if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
179                 printf("pdu add data failed\n");
180                 iscsi_free_pdu(iscsi, pdu);
181                 return -21;
182         }
183         str = "DataSequenceInOrder=Yes";
184         if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
185                 printf("pdu add data failed\n");
186                 iscsi_free_pdu(iscsi, pdu);
187                 return -22;
188         }
189
190
191         pdu->callback     = cb;
192         pdu->private_data = private_data;
193
194         if (iscsi_queue_pdu(iscsi, pdu) != 0) {
195                 printf("failed to queue iscsi login pdu\n");
196                 iscsi_free_pdu(iscsi, pdu);
197                 return -23;
198         }
199
200         return 0;
201 }
202
203 int iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, const unsigned char *hdr, int size)
204 {
205         int status;
206
207         if (size < ISCSI_HEADER_SIZE) {
208                 printf("dont have enough data to read status from login reply\n");
209                 return -1;
210         }
211
212         /* XXX here we should parse the data returned in case the target renegotiated some
213          *     some parameters.
214          *     we should also do proper handshaking if the target is not yet prepared to transition
215          *     to the next stage
216          */
217         status = ntohs(*(uint16_t *)&hdr[36]);
218         if (status != 0) {
219                 pdu->callback(iscsi, ISCSI_STATUS_ERROR, NULL, pdu->private_data);
220                 return 0;
221         }
222
223         iscsi->statsn = ntohs(*(uint16_t *)&hdr[24]);
224
225         iscsi->is_loggedin = 1;
226         pdu->callback(iscsi, ISCSI_STATUS_GOOD, NULL, pdu->private_data);
227
228         return 0;
229 }
230
231
232 int iscsi_logout_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data)
233 {
234         struct iscsi_pdu *pdu;
235
236         if (iscsi == NULL) {
237                 printf("trying to logout on NULL context\n");
238                 return -1;
239         }
240
241         if (iscsi->is_loggedin == 0) {
242                 printf("trying to logout while not logged in\n");
243                 return -2;
244         }
245
246         pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_LOGOUT_REQUEST, ISCSI_PDU_LOGOUT_RESPONSE);
247         if (pdu == NULL) {
248                 printf("Failed to allocate logout pdu\n");
249                 return -3;
250         }
251
252         /* logout request has the immediate flag set */
253         iscsi_pdu_set_immediate(pdu);
254
255         /* flags : close the session */
256         iscsi_pdu_set_pduflags(pdu, 0x80);
257
258
259         pdu->callback     = cb;
260         pdu->private_data = private_data;
261
262         if (iscsi_queue_pdu(iscsi, pdu) != 0) {
263                 printf("failed to queue iscsi logout pdu\n");
264                 iscsi_free_pdu(iscsi, pdu);
265                 return -4;
266         }
267
268         return 0;
269 }
270
271 int iscsi_process_logout_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, const unsigned char *hdr, int size UNUSED)
272 {
273         iscsi->is_loggedin = 0;
274         pdu->callback(iscsi, ISCSI_STATUS_GOOD, NULL, pdu->private_data);
275
276         return 0;
277 }
278
279 int iscsi_set_session_type(struct iscsi_context *iscsi, enum iscsi_session_type session_type)
280 {
281         if (iscsi == NULL) {
282                 printf("Trying to set sesssion type on NULL context\n");
283                 return -1;
284         }
285         if (iscsi->is_loggedin) {
286                 printf("trying to set session type while logged in\n");
287                 return -2;
288         }
289         
290         iscsi->session_type = session_type;
291
292         return 0;
293 }