OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [fs/] [smbfs/] [sock.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  sock.c
3
 *
4
 *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
5
 *
6
 */
7
 
8
#include <linux/sched.h>
9
#include <linux/smb_fs.h>
10
#include <linux/errno.h>
11
#include <linux/socket.h>
12
#include <linux/fcntl.h>
13
#include <linux/stat.h>
14
#include <asm/segment.h>
15
#include <linux/in.h>
16
#include <linux/net.h>
17
#include <linux/mm.h>
18
#include <linux/netdevice.h>
19
#include <net/ip.h>
20
 
21
#include <linux/smb.h>
22
#include <linux/smbno.h>
23
 
24
 
25
#define _S(nr) (1<<((nr)-1))
26
 
27
static int
28
_recvfrom(struct socket *sock, unsigned char *ubuf, int size,
29
          int noblock, unsigned flags, struct sockaddr_in *sa, int *addr_len)
30
{
31
        struct iovec iov;
32
        struct msghdr msg;
33
 
34
        iov.iov_base = ubuf;
35
        iov.iov_len = size;
36
 
37
        msg.msg_name = (void *) sa;
38
        msg.msg_namelen = 0;
39
        if (addr_len)
40
                msg.msg_namelen = *addr_len;
41
        msg.msg_control = NULL;
42
        msg.msg_iov = &iov;
43
        msg.msg_iovlen = 1;
44
 
45
        return sock->ops->recvmsg(sock, &msg, size, noblock, flags, addr_len);
46
}
47
 
48
static int
49
_send(struct socket *sock, const void *buff, int len,
50
      int nonblock, unsigned flags)
51
{
52
        struct iovec iov;
53
        struct msghdr msg;
54
 
55
        iov.iov_base = (void *) buff;
56
        iov.iov_len = len;
57
 
58
        msg.msg_name = NULL;
59
        msg.msg_namelen = 0;
60
        msg.msg_control = NULL;
61
        msg.msg_iov = &iov;
62
        msg.msg_iovlen = 1;
63
 
64
        return sock->ops->sendmsg(sock, &msg, len, nonblock, flags);
65
}
66
 
67
static void
68
smb_data_callback(struct sock *sk, int len)
69
{
70
        struct socket *sock = sk->socket;
71
 
72
        if (!sk->dead)
73
        {
74
                unsigned char peek_buf[4];
75
                int result;
76
                unsigned short fs;
77
 
78
                fs = get_fs();
79
                set_fs(get_ds());
80
 
81
                result = _recvfrom(sock, (void *) peek_buf, 1, 1,
82
                                   MSG_PEEK, NULL, NULL);
83
 
84
                while ((result != -EAGAIN) && (peek_buf[0] == 0x85))
85
                {
86
                        /* got SESSION KEEP ALIVE */
87
                        result = _recvfrom(sock, (void *) peek_buf,
88
                                           4, 1, 0, NULL, NULL);
89
 
90
                        DDPRINTK("smb_data_callback:"
91
                                 " got SESSION KEEP ALIVE\n");
92
 
93
                        if (result == -EAGAIN)
94
                        {
95
                                break;
96
                        }
97
                        result = _recvfrom(sock, (void *) peek_buf,
98
                                           1, 1, MSG_PEEK,
99
                                           NULL, NULL);
100
                }
101
                set_fs(fs);
102
 
103
                if (result != -EAGAIN)
104
                {
105
                        wake_up_interruptible(sk->sleep);
106
                }
107
        }
108
}
109
 
110
int
111
smb_catch_keepalive(struct smb_server *server)
112
{
113
        struct file *file;
114
        struct inode *inode;
115
        struct socket *sock;
116
        struct sock *sk;
117
 
118
        if ((server == NULL)
119
            || ((file = server->sock_file) == NULL)
120
            || ((inode = file->f_inode) == NULL)
121
            || (!S_ISSOCK(inode->i_mode)))
122
        {
123
                printk("smb_catch_keepalive: did not get valid server!\n");
124
                server->data_ready = NULL;
125
                return -EINVAL;
126
        }
127
        sock = &(inode->u.socket_i);
128
 
129
        if (sock->type != SOCK_STREAM)
130
        {
131
                printk("smb_catch_keepalive: did not get SOCK_STREAM\n");
132
                server->data_ready = NULL;
133
                return -EINVAL;
134
        }
135
        sk = (struct sock *) (sock->data);
136
 
137
        if (sk == NULL)
138
        {
139
                printk("smb_catch_keepalive: sk == NULL");
140
                server->data_ready = NULL;
141
                return -EINVAL;
142
        }
143
        DDPRINTK("smb_catch_keepalive.: sk->d_r = %x, server->d_r = %x\n",
144
                 (unsigned int) (sk->data_ready),
145
                 (unsigned int) (server->data_ready));
146
 
147
        if (sk->data_ready == smb_data_callback)
148
        {
149
                printk("smb_catch_keepalive: already done\n");
150
                return -EINVAL;
151
        }
152
        server->data_ready = sk->data_ready;
153
        sk->data_ready = smb_data_callback;
154
        return 0;
155
}
156
 
157
int
158
smb_dont_catch_keepalive(struct smb_server *server)
159
{
160
        struct file *file;
161
        struct inode *inode;
162
        struct socket *sock;
163
        struct sock *sk;
164
 
165
        if ((server == NULL)
166
            || ((file = server->sock_file) == NULL)
167
            || ((inode = file->f_inode) == NULL)
168
            || (!S_ISSOCK(inode->i_mode)))
169
        {
170
                printk("smb_dont_catch_keepalive: "
171
                       "did not get valid server!\n");
172
                return -EINVAL;
173
        }
174
        sock = &(inode->u.socket_i);
175
 
176
        if (sock->type != SOCK_STREAM)
177
        {
178
                printk("smb_dont_catch_keepalive: did not get SOCK_STREAM\n");
179
                return -EINVAL;
180
        }
181
        sk = (struct sock *) (sock->data);
182
 
183
        if (sk == NULL)
184
        {
185
                printk("smb_dont_catch_keepalive: sk == NULL");
186
                return -EINVAL;
187
        }
188
        if (server->data_ready == NULL)
189
        {
190
                printk("smb_dont_catch_keepalive: "
191
                       "server->data_ready == NULL\n");
192
                return -EINVAL;
193
        }
194
        if (sk->data_ready != smb_data_callback)
195
        {
196
                printk("smb_dont_catch_keepalive: "
197
                       "sk->data_callback != smb_data_callback\n");
198
                return -EINVAL;
199
        }
200
        DDPRINTK("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
201
                 (unsigned int) (sk->data_ready),
202
                 (unsigned int) (server->data_ready));
203
 
204
        sk->data_ready = server->data_ready;
205
        server->data_ready = NULL;
206
        return 0;
207
}
208
 
209
static int
210
smb_send_raw(struct socket *sock, unsigned char *source, int length)
211
{
212
        int result;
213
        int already_sent = 0;
214
 
215
        while (already_sent < length)
216
        {
217
                result = _send(sock,
218
                               (void *) (source + already_sent),
219
                               length - already_sent, 0, 0);
220
 
221
                if (result < 0)
222
                {
223
                        DPRINTK("smb_send_raw: sendto error = %d\n",
224
                                -result);
225
                        return result;
226
                }
227
                already_sent += result;
228
        }
229
        return already_sent;
230
}
231
 
232
static int
233
smb_receive_raw(struct socket *sock, unsigned char *target, int length)
234
{
235
        int result;
236
        int already_read = 0;
237
 
238
        while (already_read < length)
239
        {
240
                result = _recvfrom(sock,
241
                                   (void *) (target + already_read),
242
                                   length - already_read, 0, 0,
243
                                   NULL, NULL);
244
 
245
                if (result == 0)
246
                {
247
                        return -EIO;
248
                }
249
                if (result < 0)
250
                {
251
                        DPRINTK("smb_receive_raw: recvfrom error = %d\n",
252
                                -result);
253
                        return result;
254
                }
255
                already_read += result;
256
        }
257
        return already_read;
258
}
259
 
260
static int
261
smb_get_length(struct socket *sock, unsigned char *header)
262
{
263
        int result;
264
        unsigned char peek_buf[4];
265
        unsigned short fs;
266
 
267
      re_recv:
268
        fs = get_fs();
269
        set_fs(get_ds());
270
        result = smb_receive_raw(sock, peek_buf, 4);
271
        set_fs(fs);
272
 
273
        if (result < 0)
274
        {
275
                DPRINTK("smb_get_length: recv error = %d\n", -result);
276
                return result;
277
        }
278
        switch (peek_buf[0])
279
        {
280
        case 0x00:
281
        case 0x82:
282
                break;
283
 
284
        case 0x85:
285
                DPRINTK("smb_get_length: Got SESSION KEEP ALIVE\n");
286
                goto re_recv;
287
 
288
        default:
289
                printk("smb_get_length: Invalid NBT packet\n");
290
                return -EIO;
291
        }
292
 
293
        if (header != NULL)
294
        {
295
                memcpy(header, peek_buf, 4);
296
        }
297
        /* The length in the RFC NB header is the raw data length */
298
        return smb_len(peek_buf);
299
}
300
 
301
static struct socket *
302
server_sock(struct smb_server *server)
303
{
304
        struct file *file;
305
        struct inode *inode;
306
 
307
        if (server == NULL)
308
                return NULL;
309
        if ((file = server->sock_file) == NULL)
310
                return NULL;
311
        if ((inode = file->f_inode) == NULL)
312
                return NULL;
313
        return &(inode->u.socket_i);
314
}
315
 
316
/*
317
 * smb_receive
318
 * fs points to the correct segment
319
 */
320
static int
321
smb_receive(struct smb_server *server)
322
{
323
        struct socket *sock = server_sock(server);
324
        int len;
325
        int result;
326
        unsigned char peek_buf[4];
327
 
328
        len = smb_get_length(sock, peek_buf);
329
 
330
        if (len < 0)
331
        {
332
                return len;
333
        }
334
        if (len + 4 > server->packet_size)
335
        {
336
                /* Some servers do not care about our max_xmit. They
337
                   send larger packets */
338
                DPRINTK("smb_receive: Increase packet size from %d to %d\n",
339
                        server->packet_size, len + 4);
340
                smb_vfree(server->packet);
341
                server->packet = NULL;
342
 
343
                server->packet_size = 0;
344
                server->packet = smb_vmalloc(len + 4);
345
                if (server->packet == NULL)
346
                {
347
                        return -ENOMEM;
348
                }
349
                server->packet_size = len + 4;
350
        }
351
        memcpy(server->packet, peek_buf, 4);
352
        result = smb_receive_raw(sock, server->packet + 4, len);
353
 
354
        if (result < 0)
355
        {
356
                printk("smb_receive: receive error: %d\n", result);
357
                return result;
358
        }
359
        server->rcls = BVAL(server->packet, 9);
360
        server->err = WVAL(server->packet, 11);
361
 
362
        if (server->rcls != 0)
363
        {
364
                DPRINTK("smb_receive: rcls=%d, err=%d\n",
365
                        server->rcls, server->err);
366
        }
367
        return result;
368
}
369
 
370
static int
371
smb_receive_trans2(struct smb_server *server,
372
                   int *ldata, unsigned char **data,
373
                   int *lparam, unsigned char **param)
374
{
375
        int total_data = 0;
376
        int total_param = 0;
377
        int result;
378
        unsigned char *rcv_buf;
379
        int buf_len;
380
        int data_len = 0;
381
        int param_len = 0;
382
 
383
        if ((result = smb_receive(server)) < 0)
384
        {
385
                return result;
386
        }
387
        if (server->rcls != 0)
388
        {
389
                *param = *data = server->packet;
390
                *ldata = *lparam = 0;
391
                return 0;
392
        }
393
        total_data = WVAL(server->packet, smb_tdrcnt);
394
        total_param = WVAL(server->packet, smb_tprcnt);
395
 
396
        DDPRINTK("smb_receive_trans2: td=%d,tp=%d\n", total_data, total_param);
397
 
398
        if ((total_data > TRANS2_MAX_TRANSFER)
399
            || (total_param > TRANS2_MAX_TRANSFER))
400
        {
401
                DPRINTK("smb_receive_trans2: data/param too long\n");
402
                return -EIO;
403
        }
404
        buf_len = total_data + total_param;
405
        if (server->packet_size > buf_len)
406
        {
407
                buf_len = server->packet_size;
408
        }
409
        if ((rcv_buf = smb_vmalloc(buf_len)) == NULL)
410
        {
411
                DPRINTK("smb_receive_trans2: could not alloc data area\n");
412
                return -ENOMEM;
413
        }
414
        *param = rcv_buf;
415
        *data = rcv_buf + total_param;
416
 
417
        while (1)
418
        {
419
                unsigned char *inbuf = server->packet;
420
 
421
                if (WVAL(inbuf, smb_prdisp) + WVAL(inbuf, smb_prcnt)
422
                    > total_param)
423
                {
424
                        DPRINTK("smb_receive_trans2: invalid parameters\n");
425
                        result = -EIO;
426
                        goto fail;
427
                }
428
                memcpy(*param + WVAL(inbuf, smb_prdisp),
429
                       smb_base(inbuf) + WVAL(inbuf, smb_proff),
430
                       WVAL(inbuf, smb_prcnt));
431
                param_len += WVAL(inbuf, smb_prcnt);
432
 
433
                if (WVAL(inbuf, smb_drdisp) + WVAL(inbuf, smb_drcnt)
434
                    > total_data)
435
                {
436
                        DPRINTK("smb_receive_trans2: invalid data block\n");
437
                        result = -EIO;
438
                        goto fail;
439
                }
440
                DDPRINTK("target: %X\n",
441
                         (unsigned int) *data + WVAL(inbuf, smb_drdisp));
442
                DDPRINTK("source: %X\n",
443
                         (unsigned int)
444
                         smb_base(inbuf) + WVAL(inbuf, smb_droff));
445
                DDPRINTK("disp: %d, off: %d, cnt: %d\n",
446
                         WVAL(inbuf, smb_drdisp), WVAL(inbuf, smb_droff),
447
                         WVAL(inbuf, smb_drcnt));
448
 
449
                memcpy(*data + WVAL(inbuf, smb_drdisp),
450
                       smb_base(inbuf) + WVAL(inbuf, smb_droff),
451
                       WVAL(inbuf, smb_drcnt));
452
                data_len += WVAL(inbuf, smb_drcnt);
453
 
454
                if ((WVAL(inbuf, smb_tdrcnt) > total_data)
455
                    || (WVAL(inbuf, smb_tprcnt) > total_param))
456
                {
457
                        printk("smb_receive_trans2: data/params grew!\n");
458
                        result = -EIO;
459
                        goto fail;
460
                }
461
                /* the total lengths might shrink! */
462
                total_data = WVAL(inbuf, smb_tdrcnt);
463
                total_param = WVAL(inbuf, smb_tprcnt);
464
 
465
                if ((data_len >= total_data) && (param_len >= total_param))
466
                {
467
                        break;
468
                }
469
                if ((result = smb_receive(server)) < 0)
470
                {
471
                        goto fail;
472
                }
473
                if (server->rcls != 0)
474
                {
475
                        result = -EIO;
476
                        goto fail;
477
                }
478
        }
479
        *ldata = data_len;
480
        *lparam = param_len;
481
 
482
        smb_vfree(server->packet);
483
        server->packet = rcv_buf;
484
        server->packet_size = buf_len;
485
        return 0;
486
 
487
      fail:
488
        smb_vfree(rcv_buf);
489
        return result;
490
}
491
 
492
int
493
smb_release(struct smb_server *server)
494
{
495
        struct socket *sock = server_sock(server);
496
        int result;
497
 
498
        if (sock == NULL)
499
        {
500
                return -EINVAL;
501
        }
502
        result = sock->ops->release(sock, NULL);
503
        DPRINTK("smb_release: sock->ops->release = %d\n", result);
504
 
505
        /* inet_release does not set sock->state.  Maybe someone is
506
           confused about sock->state being SS_CONNECTED while there
507
           is nothing behind it, so I set it to SS_UNCONNECTED. */
508
        sock->state = SS_UNCONNECTED;
509
 
510
        result = sock->ops->create(sock, 0);
511
        DPRINTK("smb_release: sock->ops->create = %d\n", result);
512
        return result;
513
}
514
 
515
int
516
smb_connect(struct smb_server *server)
517
{
518
        struct socket *sock = server_sock(server);
519
        if (sock == NULL)
520
        {
521
                return -EINVAL;
522
        }
523
        if (sock->state != SS_UNCONNECTED)
524
        {
525
                DPRINTK("smb_connect: socket is not unconnected: %d\n",
526
                        sock->state);
527
        }
528
        return sock->ops->connect(sock, (struct sockaddr *) &(server->m.addr),
529
                                  sizeof(struct sockaddr_in), 0);
530
}
531
 
532
int
533
smb_request(struct smb_server *server)
534
{
535
        unsigned long old_mask;
536
        unsigned short fs;
537
        int len, result;
538
 
539
        unsigned char *buffer = (server == NULL) ? NULL : server->packet;
540
 
541
        if (buffer == NULL)
542
        {
543
                printk("smb_request: Bad server!\n");
544
                return -EBADF;
545
        }
546
        if (server->state != CONN_VALID)
547
        {
548
                return -EIO;
549
        }
550
        if ((result = smb_dont_catch_keepalive(server)) != 0)
551
        {
552
                server->state = CONN_INVALID;
553
                smb_invalidate_all_inodes(server);
554
                return result;
555
        }
556
        len = smb_len(buffer) + 4;
557
 
558
        DPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
559
 
560
        old_mask = current->blocked;
561
        current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
562
        fs = get_fs();
563
        set_fs(get_ds());
564
 
565
        result = smb_send_raw(server_sock(server), (void *) buffer, len);
566
        if (result > 0)
567
        {
568
                result = smb_receive(server);
569
        }
570
        /* read/write errors are handled by errno */
571
        current->signal &= ~_S(SIGPIPE);
572
        current->blocked = old_mask;
573
        set_fs(fs);
574
 
575
        if (result >= 0)
576
        {
577
                int result2 = smb_catch_keepalive(server);
578
                if (result2 < 0)
579
                {
580
                        result = result2;
581
                }
582
        }
583
        if (result < 0)
584
        {
585
                server->state = CONN_INVALID;
586
                smb_invalidate_all_inodes(server);
587
        }
588
        DDPRINTK("smb_request: result = %d\n", result);
589
 
590
        return result;
591
}
592
 
593
#define ROUND_UP(x) (((x)+3) & ~3)
594
static int
595
smb_send_trans2(struct smb_server *server, __u16 trans2_command,
596
                int ldata, unsigned char *data,
597
                int lparam, unsigned char *param)
598
{
599
        struct socket *sock = server_sock(server);
600
 
601
        /* I know the following is very ugly, but I want to build the
602
           smb packet as efficiently as possible. */
603
 
604
        const int smb_parameters = 15;
605
        const int oparam =
606
        ROUND_UP(SMB_HEADER_LEN + 2 * smb_parameters + 2 + 3);
607
        const int odata =
608
        ROUND_UP(oparam + lparam);
609
        const int bcc =
610
        odata + ldata - (SMB_HEADER_LEN + 2 * smb_parameters + 2);
611
        const int packet_length =
612
        SMB_HEADER_LEN + 2 * smb_parameters + bcc + 2;
613
 
614
        unsigned char padding[4] =
615
        {0,};
616
        char *p;
617
 
618
        struct iovec iov[4];
619
        struct msghdr msg;
620
 
621
        if ((bcc + oparam) > server->max_xmit)
622
        {
623
                return -ENOMEM;
624
        }
625
        p = smb_setup_header(server, SMBtrans2, smb_parameters, bcc);
626
 
627
        WSET(server->packet, smb_tpscnt, lparam);
628
        WSET(server->packet, smb_tdscnt, ldata);
629
        WSET(server->packet, smb_mprcnt, TRANS2_MAX_TRANSFER);
630
        WSET(server->packet, smb_mdrcnt, TRANS2_MAX_TRANSFER);
631
        WSET(server->packet, smb_msrcnt, 0);
632
        WSET(server->packet, smb_flags, 0);
633
        DSET(server->packet, smb_timeout, 0);
634
        WSET(server->packet, smb_pscnt, lparam);
635
        WSET(server->packet, smb_psoff, oparam - 4);
636
        WSET(server->packet, smb_dscnt, ldata);
637
        WSET(server->packet, smb_dsoff, odata - 4);
638
        WSET(server->packet, smb_suwcnt, 1);
639
        WSET(server->packet, smb_setup0, trans2_command);
640
        *p++ = 0;                /* null smb_name for trans2 */
641
        *p++ = 'D';             /* this was added because OS/2 does it */
642
        *p++ = ' ';
643
 
644
        iov[0].iov_base = (void *) server->packet;
645
        iov[0].iov_len = oparam;
646
        iov[1].iov_base = (param == NULL) ? padding : param;
647
        iov[1].iov_len = lparam;
648
        iov[2].iov_base = padding;
649
        iov[2].iov_len = odata - oparam - lparam;
650
        iov[3].iov_base = (data == NULL) ? padding : data;
651
        iov[3].iov_len = ldata;
652
 
653
        msg.msg_name = NULL;
654
        msg.msg_namelen = 0;
655
        msg.msg_control = NULL;
656
        msg.msg_iov = iov;
657
        msg.msg_iovlen = 4;
658
 
659
        return sock->ops->sendmsg(sock, &msg, packet_length, 0, 0);
660
}
661
 
662
/*
663
 * This is not really a trans2 request, we assume that you only have
664
 * one packet to send.
665
 */
666
int
667
smb_trans2_request(struct smb_server *server, __u16 trans2_command,
668
                   int ldata, unsigned char *data,
669
                   int lparam, unsigned char *param,
670
                   int *lrdata, unsigned char **rdata,
671
                   int *lrparam, unsigned char **rparam)
672
{
673
        unsigned long old_mask;
674
        unsigned short fs;
675
        int result;
676
 
677
        DPRINTK("smb_trans2_request: com=%d, ld=%d, lp=%d\n",
678
                trans2_command, ldata, lparam);
679
 
680
        if (server->state != CONN_VALID)
681
        {
682
                return -EIO;
683
        }
684
        if ((result = smb_dont_catch_keepalive(server)) != 0)
685
        {
686
                server->state = CONN_INVALID;
687
                smb_invalidate_all_inodes(server);
688
                return result;
689
        }
690
        old_mask = current->blocked;
691
        current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
692
        fs = get_fs();
693
        set_fs(get_ds());
694
 
695
        result = smb_send_trans2(server, trans2_command,
696
                                 ldata, data, lparam, param);
697
        if (result >= 0)
698
        {
699
                result = smb_receive_trans2(server,
700
                                            lrdata, rdata, lrparam, rparam);
701
        }
702
        /* read/write errors are handled by errno */
703
        current->signal &= ~_S(SIGPIPE);
704
        current->blocked = old_mask;
705
        set_fs(fs);
706
 
707
        if (result >= 0)
708
        {
709
                int result2 = smb_catch_keepalive(server);
710
                if (result2 < 0)
711
                {
712
                        result = result2;
713
                }
714
        }
715
        if (result < 0)
716
        {
717
                server->state = CONN_INVALID;
718
                smb_invalidate_all_inodes(server);
719
        }
720
        DDPRINTK("smb_trans2_request: result = %d\n", result);
721
 
722
        return result;
723
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.