~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/ncpfs/sock.c

Version: ~ [ linux-5.13-rc1 ] ~ [ linux-5.12.2 ] ~ [ linux-5.11.19 ] ~ [ linux-5.10.35 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.117 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.190 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.232 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.268 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.268 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/fs/ncpfs/sock.c
  3  *
  4  *  Copyright (C) 1992, 1993  Rick Sladkey
  5  *
  6  *  Modified 1995, 1996 by Volker Lendecke to be usable for ncp
  7  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
  8  *
  9  */
 10 
 11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 12 
 13 #include <linux/time.h>
 14 #include <linux/errno.h>
 15 #include <linux/socket.h>
 16 #include <linux/fcntl.h>
 17 #include <linux/stat.h>
 18 #include <linux/string.h>
 19 #include <asm/uaccess.h>
 20 #include <linux/in.h>
 21 #include <linux/net.h>
 22 #include <linux/mm.h>
 23 #include <linux/netdevice.h>
 24 #include <linux/signal.h>
 25 #include <linux/slab.h>
 26 #include <net/scm.h>
 27 #include <net/sock.h>
 28 #include <linux/ipx.h>
 29 #include <linux/poll.h>
 30 #include <linux/file.h>
 31 
 32 #include "ncp_fs.h"
 33 
 34 #include "ncpsign_kernel.h"
 35 
 36 static int _recv(struct socket *sock, void *buf, int size, unsigned flags)
 37 {
 38         struct msghdr msg = {NULL, };
 39         struct kvec iov = {buf, size};
 40         return kernel_recvmsg(sock, &msg, &iov, 1, size, flags);
 41 }
 42 
 43 static inline int do_send(struct socket *sock, struct kvec *vec, int count,
 44                           int len, unsigned flags)
 45 {
 46         struct msghdr msg = { .msg_flags = flags };
 47         return kernel_sendmsg(sock, &msg, vec, count, len);
 48 }
 49 
 50 static int _send(struct socket *sock, const void *buff, int len)
 51 {
 52         struct kvec vec;
 53         vec.iov_base = (void *) buff;
 54         vec.iov_len = len;
 55         return do_send(sock, &vec, 1, len, 0);
 56 }
 57 
 58 struct ncp_request_reply {
 59         struct list_head req;
 60         wait_queue_head_t wq;
 61         atomic_t refs;
 62         unsigned char* reply_buf;
 63         size_t datalen;
 64         int result;
 65         enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
 66         struct kvec* tx_ciov;
 67         size_t tx_totallen;
 68         size_t tx_iovlen;
 69         struct kvec tx_iov[3];
 70         u_int16_t tx_type;
 71         u_int32_t sign[6];
 72 };
 73 
 74 static inline struct ncp_request_reply* ncp_alloc_req(void)
 75 {
 76         struct ncp_request_reply *req;
 77 
 78         req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
 79         if (!req)
 80                 return NULL;
 81 
 82         init_waitqueue_head(&req->wq);
 83         atomic_set(&req->refs, (1));
 84         req->status = RQ_IDLE;
 85 
 86         return req;
 87 }
 88 
 89 static void ncp_req_get(struct ncp_request_reply *req)
 90 {
 91         atomic_inc(&req->refs);
 92 }
 93 
 94 static void ncp_req_put(struct ncp_request_reply *req)
 95 {
 96         if (atomic_dec_and_test(&req->refs))
 97                 kfree(req);
 98 }
 99 
100 void ncp_tcp_data_ready(struct sock *sk)
101 {
102         struct ncp_server *server = sk->sk_user_data;
103 
104         server->data_ready(sk);
105         schedule_work(&server->rcv.tq);
106 }
107 
108 void ncp_tcp_error_report(struct sock *sk)
109 {
110         struct ncp_server *server = sk->sk_user_data;
111         
112         server->error_report(sk);
113         schedule_work(&server->rcv.tq);
114 }
115 
116 void ncp_tcp_write_space(struct sock *sk)
117 {
118         struct ncp_server *server = sk->sk_user_data;
119         
120         /* We do not need any locking: we first set tx.creq, and then we do sendmsg,
121            not vice versa... */
122         server->write_space(sk);
123         if (server->tx.creq)
124                 schedule_work(&server->tx.tq);
125 }
126 
127 void ncpdgram_timeout_call(unsigned long v)
128 {
129         struct ncp_server *server = (void*)v;
130         
131         schedule_work(&server->timeout_tq);
132 }
133 
134 static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
135 {
136         req->result = result;
137         if (req->status != RQ_ABANDONED)
138                 memcpy(req->reply_buf, server->rxbuf, req->datalen);
139         req->status = RQ_DONE;
140         wake_up_all(&req->wq);
141         ncp_req_put(req);
142 }
143 
144 static void __abort_ncp_connection(struct ncp_server *server)
145 {
146         struct ncp_request_reply *req;
147 
148         ncp_invalidate_conn(server);
149         del_timer(&server->timeout_tm);
150         while (!list_empty(&server->tx.requests)) {
151                 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
152                 
153                 list_del_init(&req->req);
154                 ncp_finish_request(server, req, -EIO);
155         }
156         req = server->rcv.creq;
157         if (req) {
158                 server->rcv.creq = NULL;
159                 ncp_finish_request(server, req, -EIO);
160                 server->rcv.ptr = NULL;
161                 server->rcv.state = 0;
162         }
163         req = server->tx.creq;
164         if (req) {
165                 server->tx.creq = NULL;
166                 ncp_finish_request(server, req, -EIO);
167         }
168 }
169 
170 static inline int get_conn_number(struct ncp_reply_header *rp)
171 {
172         return rp->conn_low | (rp->conn_high << 8);
173 }
174 
175 static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
176 {
177         /* If req is done, we got signal, but we also received answer... */
178         switch (req->status) {
179                 case RQ_IDLE:
180                 case RQ_DONE:
181                         break;
182                 case RQ_QUEUED:
183                         list_del_init(&req->req);
184                         ncp_finish_request(server, req, err);
185                         break;
186                 case RQ_INPROGRESS:
187                         req->status = RQ_ABANDONED;
188                         break;
189                 case RQ_ABANDONED:
190                         break;
191         }
192 }
193 
194 static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
195 {
196         mutex_lock(&server->rcv.creq_mutex);
197         __ncp_abort_request(server, req, err);
198         mutex_unlock(&server->rcv.creq_mutex);
199 }
200 
201 static inline void __ncptcp_abort(struct ncp_server *server)
202 {
203         __abort_ncp_connection(server);
204 }
205 
206 static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
207 {
208         struct kvec vec[3];
209         /* sock_sendmsg updates iov pointers for us :-( */
210         memcpy(vec, req->tx_ciov, req->tx_iovlen * sizeof(vec[0]));
211         return do_send(sock, vec, req->tx_iovlen,
212                        req->tx_totallen, MSG_DONTWAIT);
213 }
214 
215 static void __ncptcp_try_send(struct ncp_server *server)
216 {
217         struct ncp_request_reply *rq;
218         struct kvec *iov;
219         struct kvec iovc[3];
220         int result;
221 
222         rq = server->tx.creq;
223         if (!rq)
224                 return;
225 
226         /* sock_sendmsg updates iov pointers for us :-( */
227         memcpy(iovc, rq->tx_ciov, rq->tx_iovlen * sizeof(iov[0]));
228         result = do_send(server->ncp_sock, iovc, rq->tx_iovlen,
229                          rq->tx_totallen, MSG_NOSIGNAL | MSG_DONTWAIT);
230 
231         if (result == -EAGAIN)
232                 return;
233 
234         if (result < 0) {
235                 pr_err("tcp: Send failed: %d\n", result);
236                 __ncp_abort_request(server, rq, result);
237                 return;
238         }
239         if (result >= rq->tx_totallen) {
240                 server->rcv.creq = rq;
241                 server->tx.creq = NULL;
242                 return;
243         }
244         rq->tx_totallen -= result;
245         iov = rq->tx_ciov;
246         while (iov->iov_len <= result) {
247                 result -= iov->iov_len;
248                 iov++;
249                 rq->tx_iovlen--;
250         }
251         iov->iov_base += result;
252         iov->iov_len -= result;
253         rq->tx_ciov = iov;
254 }
255 
256 static inline void ncp_init_header(struct ncp_server *server, struct ncp_request_reply *req, struct ncp_request_header *h)
257 {
258         req->status = RQ_INPROGRESS;
259         h->conn_low = server->connection;
260         h->conn_high = server->connection >> 8;
261         h->sequence = ++server->sequence;
262 }
263         
264 static void ncpdgram_start_request(struct ncp_server *server, struct ncp_request_reply *req)
265 {
266         size_t signlen;
267         struct ncp_request_header* h;
268         
269         req->tx_ciov = req->tx_iov + 1;
270 
271         h = req->tx_iov[1].iov_base;
272         ncp_init_header(server, req, h);
273         signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1, 
274                         req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
275                         cpu_to_le32(req->tx_totallen), req->sign);
276         if (signlen) {
277                 req->tx_ciov[1].iov_base = req->sign;
278                 req->tx_ciov[1].iov_len = signlen;
279                 req->tx_iovlen += 1;
280                 req->tx_totallen += signlen;
281         }
282         server->rcv.creq = req;
283         server->timeout_last = server->m.time_out;
284         server->timeout_retries = server->m.retry_count;
285         ncpdgram_send(server->ncp_sock, req);
286         mod_timer(&server->timeout_tm, jiffies + server->m.time_out);
287 }
288 
289 #define NCP_TCP_XMIT_MAGIC      (0x446D6454)
290 #define NCP_TCP_XMIT_VERSION    (1)
291 #define NCP_TCP_RCVD_MAGIC      (0x744E6350)
292 
293 static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
294 {
295         size_t signlen;
296         struct ncp_request_header* h;
297 
298         req->tx_ciov = req->tx_iov;
299         h = req->tx_iov[1].iov_base;
300         ncp_init_header(server, req, h);
301         signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
302                         req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
303                         cpu_to_be32(req->tx_totallen + 24), req->sign + 4) + 16;
304 
305         req->sign[0] = htonl(NCP_TCP_XMIT_MAGIC);
306         req->sign[1] = htonl(req->tx_totallen + signlen);
307         req->sign[2] = htonl(NCP_TCP_XMIT_VERSION);
308         req->sign[3] = htonl(req->datalen + 8);
309         req->tx_iov[0].iov_base = req->sign;
310         req->tx_iov[0].iov_len = signlen;
311         req->tx_iovlen += 1;
312         req->tx_totallen += signlen;
313 
314         server->tx.creq = req;
315         __ncptcp_try_send(server);
316 }
317 
318 static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
319 {
320         /* we copy the data so that we do not depend on the caller
321            staying alive */
322         memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
323         req->tx_iov[1].iov_base = server->txbuf;
324 
325         if (server->ncp_sock->type == SOCK_STREAM)
326                 ncptcp_start_request(server, req);
327         else
328                 ncpdgram_start_request(server, req);
329 }
330 
331 static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
332 {
333         mutex_lock(&server->rcv.creq_mutex);
334         if (!ncp_conn_valid(server)) {
335                 mutex_unlock(&server->rcv.creq_mutex);
336                 pr_err("tcp: Server died\n");
337                 return -EIO;
338         }
339         ncp_req_get(req);
340         if (server->tx.creq || server->rcv.creq) {
341                 req->status = RQ_QUEUED;
342                 list_add_tail(&req->req, &server->tx.requests);
343                 mutex_unlock(&server->rcv.creq_mutex);
344                 return 0;
345         }
346         __ncp_start_request(server, req);
347         mutex_unlock(&server->rcv.creq_mutex);
348         return 0;
349 }
350 
351 static void __ncp_next_request(struct ncp_server *server)
352 {
353         struct ncp_request_reply *req;
354 
355         server->rcv.creq = NULL;
356         if (list_empty(&server->tx.requests)) {
357                 return;
358         }
359         req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
360         list_del_init(&req->req);
361         __ncp_start_request(server, req);
362 }
363 
364 static void info_server(struct ncp_server *server, unsigned int id, const void * data, size_t len)
365 {
366         if (server->info_sock) {
367                 struct kvec iov[2];
368                 __be32 hdr[2];
369         
370                 hdr[0] = cpu_to_be32(len + 8);
371                 hdr[1] = cpu_to_be32(id);
372         
373                 iov[0].iov_base = hdr;
374                 iov[0].iov_len = 8;
375                 iov[1].iov_base = (void *) data;
376                 iov[1].iov_len = len;
377 
378                 do_send(server->info_sock, iov, 2, len + 8, MSG_NOSIGNAL);
379         }
380 }
381 
382 void ncpdgram_rcv_proc(struct work_struct *work)
383 {
384         struct ncp_server *server =
385                 container_of(work, struct ncp_server, rcv.tq);
386         struct socket* sock;
387         
388         sock = server->ncp_sock;
389         
390         while (1) {
391                 struct ncp_reply_header reply;
392                 int result;
393 
394                 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
395                 if (result < 0) {
396                         break;
397                 }
398                 if (result >= sizeof(reply)) {
399                         struct ncp_request_reply *req;
400         
401                         if (reply.type == NCP_WATCHDOG) {
402                                 unsigned char buf[10];
403 
404                                 if (server->connection != get_conn_number(&reply)) {
405                                         goto drop;
406                                 }
407                                 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
408                                 if (result < 0) {
409                                         ncp_dbg(1, "recv failed with %d\n", result);
410                                         continue;
411                                 }
412                                 if (result < 10) {
413                                         ncp_dbg(1, "too short (%u) watchdog packet\n", result);
414                                         continue;
415                                 }
416                                 if (buf[9] != '?') {
417                                         ncp_dbg(1, "bad signature (%02X) in watchdog packet\n", buf[9]);
418                                         continue;
419                                 }
420                                 buf[9] = 'Y';
421                                 _send(sock, buf, sizeof(buf));
422                                 continue;
423                         }
424                         if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
425                                 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
426                                 if (result < 0) {
427                                         continue;
428                                 }
429                                 info_server(server, 0, server->unexpected_packet.data, result);
430                                 continue;
431                         }
432                         mutex_lock(&server->rcv.creq_mutex);
433                         req = server->rcv.creq;
434                         if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence && 
435                                         server->connection == get_conn_number(&reply)))) {
436                                 if (reply.type == NCP_POSITIVE_ACK) {
437                                         server->timeout_retries = server->m.retry_count;
438                                         server->timeout_last = NCP_MAX_RPC_TIMEOUT;
439                                         mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
440                                 } else if (reply.type == NCP_REPLY) {
441                                         result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
442 #ifdef CONFIG_NCPFS_PACKET_SIGNING
443                                         if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
444                                                 if (result < 8 + 8) {
445                                                         result = -EIO;
446                                                 } else {
447                                                         unsigned int hdrl;
448                                                         
449                                                         result -= 8;
450                                                         hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
451                                                         if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
452                                                                 pr_info("Signature violation\n");
453                                                                 result = -EIO;
454                                                         }
455                                                 }
456                                         }
457 #endif
458                                         del_timer(&server->timeout_tm);
459                                         server->rcv.creq = NULL;
460                                         ncp_finish_request(server, req, result);
461                                         __ncp_next_request(server);
462                                         mutex_unlock(&server->rcv.creq_mutex);
463                                         continue;
464                                 }
465                         }
466                         mutex_unlock(&server->rcv.creq_mutex);
467                 }
468 drop:;          
469                 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
470         }
471 }
472 
473 static void __ncpdgram_timeout_proc(struct ncp_server *server)
474 {
475         /* If timer is pending, we are processing another request... */
476         if (!timer_pending(&server->timeout_tm)) {
477                 struct ncp_request_reply* req;
478                 
479                 req = server->rcv.creq;
480                 if (req) {
481                         int timeout;
482                         
483                         if (server->m.flags & NCP_MOUNT_SOFT) {
484                                 if (server->timeout_retries-- == 0) {
485                                         __ncp_abort_request(server, req, -ETIMEDOUT);
486                                         return;
487                                 }
488                         }
489                         /* Ignore errors */
490                         ncpdgram_send(server->ncp_sock, req);
491                         timeout = server->timeout_last << 1;
492                         if (timeout > NCP_MAX_RPC_TIMEOUT) {
493                                 timeout = NCP_MAX_RPC_TIMEOUT;
494                         }
495                         server->timeout_last = timeout;
496                         mod_timer(&server->timeout_tm, jiffies + timeout);
497                 }
498         }
499 }
500 
501 void ncpdgram_timeout_proc(struct work_struct *work)
502 {
503         struct ncp_server *server =
504                 container_of(work, struct ncp_server, timeout_tq);
505         mutex_lock(&server->rcv.creq_mutex);
506         __ncpdgram_timeout_proc(server);
507         mutex_unlock(&server->rcv.creq_mutex);
508 }
509 
510 static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
511 {
512         int result;
513         
514         if (buffer) {
515                 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
516         } else {
517                 static unsigned char dummy[1024];
518                         
519                 if (len > sizeof(dummy)) {
520                         len = sizeof(dummy);
521                 }
522                 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
523         }
524         if (result < 0) {
525                 return result;
526         }
527         if (result > len) {
528                 pr_err("tcp: bug in recvmsg (%u > %Zu)\n", result, len);
529                 return -EIO;                    
530         }
531         return result;
532 }       
533 
534 static int __ncptcp_rcv_proc(struct ncp_server *server)
535 {
536         /* We have to check the result, so store the complete header */
537         while (1) {
538                 int result;
539                 struct ncp_request_reply *req;
540                 int datalen;
541                 int type;
542 
543                 while (server->rcv.len) {
544                         result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
545                         if (result == -EAGAIN) {
546                                 return 0;
547                         }
548                         if (result <= 0) {
549                                 req = server->rcv.creq;
550                                 if (req) {
551                                         __ncp_abort_request(server, req, -EIO);
552                                 } else {
553                                         __ncptcp_abort(server);
554                                 }
555                                 if (result < 0) {
556                                         pr_err("tcp: error in recvmsg: %d\n", result);
557                                 } else {
558                                         ncp_dbg(1, "tcp: EOF\n");
559                                 }
560                                 return -EIO;
561                         }
562                         if (server->rcv.ptr) {
563                                 server->rcv.ptr += result;
564                         }
565                         server->rcv.len -= result;
566                 }
567                 switch (server->rcv.state) {
568                         case 0:
569                                 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
570                                         pr_err("tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
571                                         __ncptcp_abort(server);
572                                         return -EIO;
573                                 }
574                                 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
575                                 if (datalen < 10) {
576                                         pr_err("tcp: Unexpected reply len %d\n", datalen);
577                                         __ncptcp_abort(server);
578                                         return -EIO;
579                                 }
580 #ifdef CONFIG_NCPFS_PACKET_SIGNING                              
581                                 if (server->sign_active) {
582                                         if (datalen < 18) {
583                                                 pr_err("tcp: Unexpected reply len %d\n", datalen);
584                                                 __ncptcp_abort(server);
585                                                 return -EIO;
586                                         }
587                                         server->rcv.buf.len = datalen - 8;
588                                         server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
589                                         server->rcv.len = 8;
590                                         server->rcv.state = 4;
591                                         break;
592                                 }
593 #endif                          
594                                 type = ntohs(server->rcv.buf.type);
595 #ifdef CONFIG_NCPFS_PACKET_SIGNING                              
596 cont:;                          
597 #endif
598                                 if (type != NCP_REPLY) {
599                                         if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
600                                                 *(__u16*)(server->unexpected_packet.data) = htons(type);
601                                                 server->unexpected_packet.len = datalen - 8;
602 
603                                                 server->rcv.state = 5;
604                                                 server->rcv.ptr = server->unexpected_packet.data + 2;
605                                                 server->rcv.len = datalen - 10;
606                                                 break;
607                                         }                                       
608                                         ncp_dbg(1, "tcp: Unexpected NCP type %02X\n", type);
609 skipdata2:;
610                                         server->rcv.state = 2;
611 skipdata:;
612                                         server->rcv.ptr = NULL;
613                                         server->rcv.len = datalen - 10;
614                                         break;
615                                 }
616                                 req = server->rcv.creq;
617                                 if (!req) {
618                                         ncp_dbg(1, "Reply without appropriate request\n");
619                                         goto skipdata2;
620                                 }
621                                 if (datalen > req->datalen + 8) {
622                                         pr_err("tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
623                                         server->rcv.state = 3;
624                                         goto skipdata;
625                                 }
626                                 req->datalen = datalen - 8;
627                                 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
628                                 server->rcv.ptr = server->rxbuf + 2;
629                                 server->rcv.len = datalen - 10;
630                                 server->rcv.state = 1;
631                                 break;
632 #ifdef CONFIG_NCPFS_PACKET_SIGNING                              
633                         case 4:
634                                 datalen = server->rcv.buf.len;
635                                 type = ntohs(server->rcv.buf.type2);
636                                 goto cont;
637 #endif
638                         case 1:
639                                 req = server->rcv.creq;
640                                 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
641                                         if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
642                                                 pr_err("tcp: Bad sequence number\n");
643                                                 __ncp_abort_request(server, req, -EIO);
644                                                 return -EIO;
645                                         }
646                                         if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
647                                                 pr_err("tcp: Connection number mismatch\n");
648                                                 __ncp_abort_request(server, req, -EIO);
649                                                 return -EIO;
650                                         }
651                                 }
652 #ifdef CONFIG_NCPFS_PACKET_SIGNING                              
653                                 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
654                                         if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
655                                                 pr_err("tcp: Signature violation\n");
656                                                 __ncp_abort_request(server, req, -EIO);
657                                                 return -EIO;
658                                         }
659                                 }
660 #endif                          
661                                 ncp_finish_request(server, req, req->datalen);
662                         nextreq:;
663                                 __ncp_next_request(server);
664                         case 2:
665                         next:;
666                                 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
667                                 server->rcv.len = 10;
668                                 server->rcv.state = 0;
669                                 break;
670                         case 3:
671                                 ncp_finish_request(server, server->rcv.creq, -EIO);
672                                 goto nextreq;
673                         case 5:
674                                 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
675                                 goto next;
676                 }
677         }
678 }
679 
680 void ncp_tcp_rcv_proc(struct work_struct *work)
681 {
682         struct ncp_server *server =
683                 container_of(work, struct ncp_server, rcv.tq);
684 
685         mutex_lock(&server->rcv.creq_mutex);
686         __ncptcp_rcv_proc(server);
687         mutex_unlock(&server->rcv.creq_mutex);
688 }
689 
690 void ncp_tcp_tx_proc(struct work_struct *work)
691 {
692         struct ncp_server *server =
693                 container_of(work, struct ncp_server, tx.tq);
694         
695         mutex_lock(&server->rcv.creq_mutex);
696         __ncptcp_try_send(server);
697         mutex_unlock(&server->rcv.creq_mutex);
698 }
699 
700 static int do_ncp_rpc_call(struct ncp_server *server, int size,
701                 unsigned char* reply_buf, int max_reply_size)
702 {
703         int result;
704         struct ncp_request_reply *req;
705 
706         req = ncp_alloc_req();
707         if (!req)
708                 return -ENOMEM;
709 
710         req->reply_buf = reply_buf;
711         req->datalen = max_reply_size;
712         req->tx_iov[1].iov_base = server->packet;
713         req->tx_iov[1].iov_len = size;
714         req->tx_iovlen = 1;
715         req->tx_totallen = size;
716         req->tx_type = *(u_int16_t*)server->packet;
717 
718         result = ncp_add_request(server, req);
719         if (result < 0)
720                 goto out;
721 
722         if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
723                 ncp_abort_request(server, req, -EINTR);
724                 result = -EINTR;
725                 goto out;
726         }
727 
728         result = req->result;
729 
730 out:
731         ncp_req_put(req);
732 
733         return result;
734 }
735 
736 /*
737  * We need the server to be locked here, so check!
738  */
739 
740 static int ncp_do_request(struct ncp_server *server, int size,
741                 void* reply, int max_reply_size)
742 {
743         int result;
744 
745         if (server->lock == 0) {
746                 pr_err("Server not locked!\n");
747                 return -EIO;
748         }
749         if (!ncp_conn_valid(server)) {
750                 return -EIO;
751         }
752         {
753                 sigset_t old_set;
754                 unsigned long mask, flags;
755 
756                 spin_lock_irqsave(&current->sighand->siglock, flags);
757                 old_set = current->blocked;
758                 if (current->flags & PF_EXITING)
759                         mask = 0;
760                 else
761                         mask = sigmask(SIGKILL);
762                 if (server->m.flags & NCP_MOUNT_INTR) {
763                         /* FIXME: This doesn't seem right at all.  So, like,
764                            we can't handle SIGINT and get whatever to stop?
765                            What if we've blocked it ourselves?  What about
766                            alarms?  Why, in fact, are we mucking with the
767                            sigmask at all? -- r~ */
768                         if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
769                                 mask |= sigmask(SIGINT);
770                         if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
771                                 mask |= sigmask(SIGQUIT);
772                 }
773                 siginitsetinv(&current->blocked, mask);
774                 recalc_sigpending();
775                 spin_unlock_irqrestore(&current->sighand->siglock, flags);
776                 
777                 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
778 
779                 spin_lock_irqsave(&current->sighand->siglock, flags);
780                 current->blocked = old_set;
781                 recalc_sigpending();
782                 spin_unlock_irqrestore(&current->sighand->siglock, flags);
783         }
784 
785         ncp_dbg(2, "do_ncp_rpc_call returned %d\n", result);
786 
787         return result;
788 }
789 
790 /* ncp_do_request assures that at least a complete reply header is
791  * received. It assumes that server->current_size contains the ncp
792  * request size
793  */
794 int ncp_request2(struct ncp_server *server, int function, 
795                 void* rpl, int size)
796 {
797         struct ncp_request_header *h;
798         struct ncp_reply_header* reply = rpl;
799         int result;
800 
801         h = (struct ncp_request_header *) (server->packet);
802         if (server->has_subfunction != 0) {
803                 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
804         }
805         h->type = NCP_REQUEST;
806         /*
807          * The server shouldn't know or care what task is making a
808          * request, so we always use the same task number.
809          */
810         h->task = 2; /* (current->pid) & 0xff; */
811         h->function = function;
812 
813         result = ncp_do_request(server, server->current_size, reply, size);
814         if (result < 0) {
815                 ncp_dbg(1, "ncp_request_error: %d\n", result);
816                 goto out;
817         }
818         server->completion = reply->completion_code;
819         server->conn_status = reply->connection_state;
820         server->reply_size = result;
821         server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
822 
823         result = reply->completion_code;
824 
825         if (result != 0)
826                 ncp_vdbg("completion code=%x\n", result);
827 out:
828         return result;
829 }
830 
831 int ncp_connect(struct ncp_server *server)
832 {
833         struct ncp_request_header *h;
834         int result;
835 
836         server->connection = 0xFFFF;
837         server->sequence = 255;
838 
839         h = (struct ncp_request_header *) (server->packet);
840         h->type = NCP_ALLOC_SLOT_REQUEST;
841         h->task         = 2; /* see above */
842         h->function     = 0;
843 
844         result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
845         if (result < 0)
846                 goto out;
847         server->connection = h->conn_low + (h->conn_high * 256);
848         result = 0;
849 out:
850         return result;
851 }
852 
853 int ncp_disconnect(struct ncp_server *server)
854 {
855         struct ncp_request_header *h;
856 
857         h = (struct ncp_request_header *) (server->packet);
858         h->type = NCP_DEALLOC_SLOT_REQUEST;
859         h->task         = 2; /* see above */
860         h->function     = 0;
861 
862         return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
863 }
864 
865 void ncp_lock_server(struct ncp_server *server)
866 {
867         mutex_lock(&server->mutex);
868         if (server->lock)
869                 pr_warn("%s: was locked!\n", __func__);
870         server->lock = 1;
871 }
872 
873 void ncp_unlock_server(struct ncp_server *server)
874 {
875         if (!server->lock) {
876                 pr_warn("%s: was not locked!\n", __func__);
877                 return;
878         }
879         server->lock = 0;
880         mutex_unlock(&server->mutex);
881 }
882 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp