tools/adflib: build only host variant which is used by Sam440 target
[AROS.git] / workbench / network / smbfs / source_code / sock.c
bloba49c64c633a4ad7bac81c7083102bba3cf69a42b
1 /*
2 * $Id$
4 * :ts=4
6 * sock.c
8 * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
9 * Modified by Christian Starkjohann <cs -at- hal -dot- kph -dot- tuwien -dot- ac -dot- at>
10 * Modified for use with AmigaOS by Olaf Barthel <obarthel -at- gmx -dot- net>
13 #include "smbfs.h"
15 /*****************************************************************************/
17 #include <smb/smb_fs.h>
18 #include <smb/smb.h>
19 #include <smb/smbno.h>
21 /*****************************************************************************/
23 #include "smb_abstraction.h"
24 #include "dump_smb.h"
26 /*****************************************************************************/
28 /* smb_receive_raw
29 fs points to the correct segment, sock != NULL, target != NULL
30 The smb header is only stored if want_header != 0. */
31 static int
32 smb_receive_raw (const struct smb_server *server, int sock_fd, unsigned char *target, int max_raw_length, int want_header)
34 int len, result;
35 int already_read;
36 unsigned char netbios_session_buf[256];
37 int netbios_session_payload_size;
39 re_recv:
41 /* Read the NetBIOS session header (rfc-1002, section 4.3.1) */
42 result = recvfrom (sock_fd, netbios_session_buf, 4, 0, NULL, NULL);
43 if (result < 0)
45 LOG (("smb_receive_raw: recv error = %ld\n", errno));
46 result = (-errno);
47 goto out;
50 if (result < 4)
52 LOG (("smb_receive_raw: got less than 4 bytes\n"));
53 result = -EIO;
54 goto out;
57 netbios_session_payload_size = (int)smb_len (netbios_session_buf);
59 #if defined(DUMP_SMB)
61 if(netbios_session_buf[0] != 0x00 && netbios_session_payload_size > 0)
63 if(netbios_session_payload_size > 256 - 4)
64 netbios_session_payload_size = 256 - 4;
66 result = recvfrom (sock_fd, &netbios_session_buf[4], netbios_session_payload_size - 4, 0, NULL, NULL);
67 if (result < 0)
69 LOG (("smb_receive_raw: recv error = %ld\n", errno));
70 result = (-errno);
71 goto out;
74 if(result < netbios_session_payload_size - 4)
76 result = -EIO;
77 goto out;
80 dump_netbios_header(__FILE__,__LINE__,netbios_session_buf,&netbios_session_buf[4],netbios_session_payload_size);
82 else
84 dump_netbios_header(__FILE__,__LINE__,netbios_session_buf,NULL,0);
87 #endif /* defined(DUMP_SMB) */
89 /* Check the session type. */
90 switch (netbios_session_buf[0])
92 /* 0x00 == session message */
93 case 0x00:
95 break;
97 /* 0x85 == session keepalive */
98 case 0x85:
100 LOG (("smb_receive_raw: Got SESSION KEEP ALIVE\n"));
101 goto re_recv;
103 /* 0x81 == session request */
104 /* 0x82 == positive session response */
105 /* 0x83 == negative session response */
106 /* 0x84 == retarget session response */
107 default:
109 LOG (("smb_receive_raw: Invalid session header type 0x%02lx\n", netbios_session_buf[0]));
110 result = -EIO;
111 goto out;
114 /* The length in the RFC NB header is the raw data length (17 bits) */
115 len = netbios_session_payload_size;
116 if (len > max_raw_length)
118 LOG (("smb_receive_raw: Received length (%ld) > max_xmit (%ld)!\n", len, max_raw_length));
119 result = -EIO;
120 goto out;
123 /* Prepend the NetBIOS header to what is read? */
124 if (want_header)
126 /* Check for buffer overflow. */
127 if(len + 4 > max_raw_length)
129 LOG (("smb_receive_raw: Received length (%ld) > max_xmit (%ld)!\n", len, max_raw_length));
130 result = -EIO;
131 goto out;
134 memcpy (target, netbios_session_buf, 4);
135 target += 4;
138 for(already_read = 0 ; already_read < len ; already_read += result)
140 result = recvfrom (sock_fd, (void *) (target + already_read), len - already_read, 0, NULL, NULL);
141 if (result < 0)
143 LOG (("smb_receive_raw: recvfrom error = %ld\n", errno));
145 result = (-errno);
147 goto out;
151 #if defined(DUMP_SMB)
153 /* If want_header==0 then this is the data returned by SMB_COM_READ_RAW. */
154 dump_smb(__FILE__,__LINE__,!want_header,target,already_read,smb_packet_to_consumer,server->max_recv);
156 #endif /* defined(DUMP_SMB) */
158 result = already_read;
160 out:
162 return result;
165 /* smb_receive
166 fs points to the correct segment, server != NULL, sock!=NULL */
168 smb_receive (struct smb_server *server, int sock_fd)
170 byte * packet = server->packet;
171 int result;
173 result = smb_receive_raw (server, sock_fd, packet,
174 server->max_recv - 4, /* max_xmit in server includes NB header */
175 1); /* We want the header */
176 if (result < 0)
178 LOG (("smb_receive: receive error: %ld\n", result));
179 goto out;
182 server->rcls = *((unsigned char *) (packet + 9));
183 server->err = WVAL (packet, 11);
185 if (server->rcls != 0)
186 LOG (("smb_receive: rcls=%ld, err=%ld\n", server->rcls, server->err));
188 out:
190 return result;
193 /* smb_receive's preconditions also apply here. */
194 static int
195 smb_receive_trans2 (struct smb_server *server, int sock_fd, int *data_len, int *param_len, char **data, char **param)
197 unsigned char *inbuf = server->packet;
198 int total_data;
199 int total_param;
200 int result;
202 LOG (("smb_receive_trans2: enter\n"));
204 (*data_len) = (*param_len) = 0;
205 (*param) = (*data) = NULL;
207 result = smb_receive (server, sock_fd);
208 if (result < 0)
209 goto fail;
211 if (server->rcls != 0)
212 goto fail;
214 /* parse out the lengths */
215 total_data = WVAL (inbuf, smb_tdrcnt);
216 total_param = WVAL (inbuf, smb_tprcnt);
218 if ((total_data > server->max_buffer_size) || (total_param > server->max_buffer_size))
220 LOG (("smb_receive_trans2: data/param too long\n"));
222 result = -EIO;
223 goto fail;
226 /* Allocate it, but only if there is something to allocate
227 in the first place. ZZZ this may not be the proper approach,
228 and we should return an error for 'no data'. */
229 if(total_data > 0)
231 (*data) = malloc (total_data);
232 if ((*data) == NULL)
234 LOG (("smb_receive_trans2: could not alloc data area\n"));
236 result = -ENOMEM;
237 goto fail;
240 else
242 (*data) = NULL;
245 /* Allocate it, but only if there is something to allocate
246 in the first place. ZZZ this may not be the proper approach,
247 and we should return an error for 'no parameters'. */
248 if(total_param > 0)
250 (*param) = malloc(total_param);
251 if ((*param) == NULL)
253 LOG (("smb_receive_trans2: could not alloc param area\n"));
255 result = -ENOMEM;
256 goto fail;
259 else
261 (*param) = NULL;
264 LOG (("smb_rec_trans2: total_data/param: %ld/%ld\n", total_data, total_param));
266 while (1)
268 if (WVAL (inbuf, smb_prdisp) + WVAL (inbuf, smb_prcnt) > total_param)
270 LOG (("smb_receive_trans2: invalid parameters\n"));
271 result = -EIO;
272 goto fail;
275 if((*param) != NULL)
276 memcpy ((*param) + WVAL (inbuf, smb_prdisp), smb_base (inbuf) + WVAL (inbuf, smb_proff), WVAL (inbuf, smb_prcnt));
278 (*param_len) += WVAL (inbuf, smb_prcnt);
280 if (WVAL (inbuf, smb_drdisp) + WVAL (inbuf, smb_drcnt) > total_data)
282 LOG (("smb_receive_trans2: invalid data block\n"));
283 result = -EIO;
284 goto fail;
287 if((*data) != NULL)
288 memcpy ((*data) + WVAL (inbuf, smb_drdisp), smb_base (inbuf) + WVAL (inbuf, smb_droff), WVAL (inbuf, smb_drcnt));
290 (*data_len) += WVAL (inbuf, smb_drcnt);
292 LOG (("smb_rec_trans2: drcnt/prcnt: %ld/%ld\n", WVAL (inbuf, smb_drcnt), WVAL (inbuf, smb_prcnt)));
294 /* parse out the total lengths again - they can shrink! */
295 if ((WVAL (inbuf, smb_tdrcnt) > total_data) || (WVAL (inbuf, smb_tprcnt) > total_param))
297 LOG (("smb_receive_trans2: data/params grew!\n"));
298 result = -EIO;
299 goto fail;
302 total_data = WVAL (inbuf, smb_tdrcnt);
303 total_param = WVAL (inbuf, smb_tprcnt);
304 if (total_data <= (*data_len) && total_param <= (*param_len))
305 break;
307 result = smb_receive (server, sock_fd);
308 if (result < 0)
309 goto fail;
311 if (server->rcls != 0)
313 /* smb_trans2_request() will check server->rcls, etc. and
314 * produce a matching error code value.
316 result = -EIO;
317 goto fail;
321 LOG (("smb_receive_trans2: normal exit\n"));
322 return 0;
324 fail:
326 LOG (("smb_receive_trans2: failed exit\n"));
328 if((*param) != NULL)
329 free (*param);
331 if((*data) != NULL)
332 free (*data);
334 (*param) = (*data) = NULL;
336 return result;
340 smb_release (struct smb_server *server)
342 int result;
344 if (server->mount_data.fd >= 0)
345 CloseSocket (server->mount_data.fd);
347 server->mount_data.fd = socket (AF_INET, SOCK_STREAM, 0);
348 if (server->mount_data.fd < 0)
350 result = (-errno);
351 goto out;
354 result = 0;
356 out:
358 return result;
362 smb_connect (struct smb_server *server)
364 int sock_fd = server->mount_data.fd;
365 int result;
367 if (sock_fd < 0)
369 result = (-EBADF);
370 goto out;
373 result = connect (sock_fd, (struct sockaddr *)&server->mount_data.addr, sizeof(struct sockaddr_in));
374 if(result < 0)
375 result = (-errno);
377 out:
379 return(result);
382 /*****************************************************************************
384 * This routine was once taken from nfs, which is for udp. Here TCP does
385 * most of the ugly stuff for us (thanks, Alan!)
387 ****************************************************************************/
389 /* Returns number of bytes received (>= 0) or a negative value in
390 * case of error.
393 smb_request (struct smb_server *server)
395 int len, result;
396 int sock_fd = server->mount_data.fd;
397 unsigned char *buffer = server->packet;
399 if ((sock_fd < 0) || (buffer == NULL))
401 LOG (("smb_request: Bad server!\n"));
402 result = -EBADF;
403 goto out;
406 if (server->state != CONN_VALID)
408 result = -EIO;
409 goto out;
412 /* Length includes the NetBIOS session header (4 bytes), which
413 * is prepended to the packet to be sent.
415 len = smb_len (buffer) + 4;
417 LOG (("smb_request: len = %ld cmd = 0x%lx\n", len, buffer[8]));
419 #if defined(DUMP_SMB)
420 dump_netbios_header(__FILE__,__LINE__,buffer,&buffer[4],len);
421 dump_smb(__FILE__,__LINE__,0,buffer+4,len-4,smb_packet_from_consumer,server->max_recv);
422 #endif /* defined(DUMP_SMB) */
424 result = send (sock_fd, (void *) buffer, len, 0);
425 if (result < 0)
427 LOG (("smb_request: send error = %ld\n", errno));
429 result = (-errno);
431 else
433 result = smb_receive (server, sock_fd);
436 out:
438 if (result < 0)
440 server->state = CONN_INVALID;
441 smb_invalidate_all_inodes (server);
444 LOG (("smb_request: result = %ld\n", result));
446 return (result);
449 /* This is not really a trans2 request, we assume that you only have
450 one packet to send. */
452 smb_trans2_request (struct smb_server *server, int *data_len, int *param_len, char **data, char **param)
454 int len, result;
455 int sock_fd = server->mount_data.fd;
456 unsigned char *buffer = server->packet;
458 if (server->state != CONN_VALID)
460 result = -EIO;
461 goto out;
464 /* Length includes the NetBIOS session header (4 bytes), which
465 * is prepended to the packet to be sent.
467 len = smb_len (buffer) + 4;
469 LOG (("smb_request: len = %ld cmd = 0x%02lx\n", len, buffer[8]));
471 #if defined(DUMP_SMB)
472 dump_netbios_header(__FILE__,__LINE__,buffer,NULL,0);
473 dump_smb(__FILE__,__LINE__,0,buffer+4,len-4,smb_packet_from_consumer,server->max_recv);
474 #endif /* defined(DUMP_SMB) */
476 result = send (sock_fd, (void *) buffer, len, 0);
477 if (result < 0)
479 LOG (("smb_trans2_request: send error = %ld\n", errno));
481 result = (-errno);
483 else
485 result = smb_receive_trans2 (server, sock_fd, data_len, param_len, data, param);
488 out:
490 if (result < 0)
492 server->state = CONN_INVALID;
493 smb_invalidate_all_inodes (server);
496 LOG (("smb_trans2_request: result = %ld\n", result));
498 return result;
501 /* target must be in user space */
503 smb_request_read_raw (struct smb_server *server, unsigned char *target, int max_len)
505 int len, result;
506 int sock_fd = server->mount_data.fd;
507 unsigned char *buffer = server->packet;
509 if (server->state != CONN_VALID)
511 result = -EIO;
512 goto out;
515 /* Length includes the NetBIOS session header (4 bytes), which
516 * is prepended to the packet to be sent.
518 len = smb_len (buffer) + 4;
520 LOG (("smb_request_read_raw: len = %ld cmd = 0x%02lx\n", len, buffer[8]));
521 LOG (("smb_request_read_raw: target=%lx, max_len=%ld\n", (unsigned int) target, max_len));
522 LOG (("smb_request_read_raw: buffer=%lx, sock=%lx\n", (unsigned int) buffer, (unsigned int) sock_fd));
524 #if defined(DUMP_SMB)
525 dump_netbios_header(__FILE__,__LINE__,buffer,NULL,0);
526 dump_smb(__FILE__,__LINE__,0,buffer+4,len-4,smb_packet_from_consumer,server->max_recv);
527 #endif /* defined(DUMP_SMB) */
529 /* Request that data should be read in raw mode. */
530 result = send (sock_fd, (void *) buffer, len, 0);
532 LOG (("smb_request_read_raw: send returned %ld\n", result));
534 if (result < 0)
536 LOG (("smb_request_read_raw: send error = %ld\n", errno));
538 result = (-errno);
540 else
542 /* Wait for the raw data to be sent by the server. */
543 result = smb_receive_raw (server, sock_fd, target, max_len, 0);
546 out:
548 if (result < 0)
550 server->state = CONN_INVALID;
551 smb_invalidate_all_inodes (server);
554 LOG (("smb_request_read_raw: result = %ld\n", result));
556 return result;
559 /* Source must be in user space. smb_request_write_raw assumes that
560 the request SMBwriteBraw has been completed successfully, so that
561 we can send the raw data now. */
563 smb_request_write_raw (struct smb_server *server, unsigned const char *source, int length)
565 int result;
566 byte nb_header[4];
567 int sock_fd = server->mount_data.fd;
569 if (server->state != CONN_VALID)
571 result = -EIO;
572 goto out;
575 /* Send the NetBIOS header. */
576 smb_encode_smb_length (nb_header, length);
578 result = send (sock_fd, (void *) nb_header, 4, 0);
579 if (result == 4)
581 /* Now send the data to be written. */
582 result = send (sock_fd, (void *) source, length, 0);
583 if(result < 0)
584 result = (-errno);
586 else
588 if(result < 0)
589 result = (-errno);
590 else
591 result = -EIO;
594 LOG (("smb_request_write_raw: send returned %ld\n", result));
596 /* If the write operation succeeded, wait for the
597 * server to confirm it.
599 if (result == length)
600 result = smb_receive (server, sock_fd);
602 out:
604 if (result < 0)
606 server->state = CONN_INVALID;
608 smb_invalidate_all_inodes (server);
611 if (result > 0)
612 result = length;
614 LOG (("smb_request_write_raw: result = %ld\n", result));
616 return result;