blob: a13c0b54f078e76c0558f5234561f4ab37719cc3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Joe Perchesb41f8b82014-04-08 16:04:14 -070011#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
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>
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010018#include <linux/string.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080019#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/in.h>
21#include <linux/net.h>
22#include <linux/mm.h>
23#include <linux/netdevice.h>
24#include <linux/signal.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#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
Al Viro32c419d2011-01-12 17:37:47 -050032#include "ncp_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34#include "ncpsign_kernel.h"
35
36static 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
43static 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
50static 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
58struct ncp_request_reply {
59 struct list_head req;
60 wait_queue_head_t wq;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010061 atomic_t refs;
62 unsigned char* reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 size_t datalen;
64 int result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010065 enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
Al Viro2cebcc72016-01-09 22:01:58 -050066 struct iov_iter from;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 struct kvec tx_iov[3];
68 u_int16_t tx_type;
69 u_int32_t sign[6];
70};
71
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010072static inline struct ncp_request_reply* ncp_alloc_req(void)
73{
74 struct ncp_request_reply *req;
75
76 req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
77 if (!req)
78 return NULL;
79
80 init_waitqueue_head(&req->wq);
81 atomic_set(&req->refs, (1));
82 req->status = RQ_IDLE;
83
84 return req;
85}
86
87static void ncp_req_get(struct ncp_request_reply *req)
88{
89 atomic_inc(&req->refs);
90}
91
92static void ncp_req_put(struct ncp_request_reply *req)
93{
94 if (atomic_dec_and_test(&req->refs))
95 kfree(req);
96}
97
David S. Miller676d2362014-04-11 16:15:36 -040098void ncp_tcp_data_ready(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -070099{
100 struct ncp_server *server = sk->sk_user_data;
101
David S. Miller676d2362014-04-11 16:15:36 -0400102 server->data_ready(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 schedule_work(&server->rcv.tq);
104}
105
106void ncp_tcp_error_report(struct sock *sk)
107{
108 struct ncp_server *server = sk->sk_user_data;
109
110 server->error_report(sk);
111 schedule_work(&server->rcv.tq);
112}
113
114void ncp_tcp_write_space(struct sock *sk)
115{
116 struct ncp_server *server = sk->sk_user_data;
117
118 /* We do not need any locking: we first set tx.creq, and then we do sendmsg,
119 not vice versa... */
120 server->write_space(sk);
121 if (server->tx.creq)
122 schedule_work(&server->tx.tq);
123}
124
125void ncpdgram_timeout_call(unsigned long v)
126{
127 struct ncp_server *server = (void*)v;
128
129 schedule_work(&server->timeout_tq);
130}
131
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100132static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
134 req->result = result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100135 if (req->status != RQ_ABANDONED)
136 memcpy(req->reply_buf, server->rxbuf, req->datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 req->status = RQ_DONE;
138 wake_up_all(&req->wq);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100139 ncp_req_put(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140}
141
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100142static void __abort_ncp_connection(struct ncp_server *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143{
144 struct ncp_request_reply *req;
145
146 ncp_invalidate_conn(server);
147 del_timer(&server->timeout_tm);
148 while (!list_empty(&server->tx.requests)) {
149 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
150
151 list_del_init(&req->req);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100152 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 }
154 req = server->rcv.creq;
155 if (req) {
156 server->rcv.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100157 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 server->rcv.ptr = NULL;
159 server->rcv.state = 0;
160 }
161 req = server->tx.creq;
162 if (req) {
163 server->tx.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100164 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 }
166}
167
168static inline int get_conn_number(struct ncp_reply_header *rp)
169{
170 return rp->conn_low | (rp->conn_high << 8);
171}
172
173static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
174{
175 /* If req is done, we got signal, but we also received answer... */
176 switch (req->status) {
177 case RQ_IDLE:
178 case RQ_DONE:
179 break;
180 case RQ_QUEUED:
181 list_del_init(&req->req);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100182 ncp_finish_request(server, req, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 break;
184 case RQ_INPROGRESS:
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100185 req->status = RQ_ABANDONED;
186 break;
187 case RQ_ABANDONED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 break;
189 }
190}
191
192static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
193{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800194 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 __ncp_abort_request(server, req, err);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800196 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197}
198
199static inline void __ncptcp_abort(struct ncp_server *server)
200{
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100201 __abort_ncp_connection(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202}
203
204static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
205{
Al Viro2cebcc72016-01-09 22:01:58 -0500206 struct msghdr msg = { .msg_iter = req->from, .msg_flags = MSG_DONTWAIT };
207 return sock_sendmsg(sock, &msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208}
209
210static void __ncptcp_try_send(struct ncp_server *server)
211{
212 struct ncp_request_reply *rq;
Al Viro2cebcc72016-01-09 22:01:58 -0500213 struct msghdr msg = { .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 int result;
215
216 rq = server->tx.creq;
217 if (!rq)
218 return;
219
Al Viro2cebcc72016-01-09 22:01:58 -0500220 msg.msg_iter = rq->from;
221 result = sock_sendmsg(server->ncp_sock, &msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
223 if (result == -EAGAIN)
224 return;
225
226 if (result < 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700227 pr_err("tcp: Send failed: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 __ncp_abort_request(server, rq, result);
229 return;
230 }
Al Viro2cebcc72016-01-09 22:01:58 -0500231 if (!msg_data_left(&msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 server->rcv.creq = rq;
233 server->tx.creq = NULL;
234 return;
235 }
Al Viro2cebcc72016-01-09 22:01:58 -0500236 rq->from = msg.msg_iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237}
238
239static inline void ncp_init_header(struct ncp_server *server, struct ncp_request_reply *req, struct ncp_request_header *h)
240{
241 req->status = RQ_INPROGRESS;
242 h->conn_low = server->connection;
243 h->conn_high = server->connection >> 8;
244 h->sequence = ++server->sequence;
245}
246
247static void ncpdgram_start_request(struct ncp_server *server, struct ncp_request_reply *req)
248{
Al Viro2cebcc72016-01-09 22:01:58 -0500249 size_t signlen, len = req->tx_iov[1].iov_len;
250 struct ncp_request_header *h = req->tx_iov[1].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 ncp_init_header(server, req, h);
Al Viro2cebcc72016-01-09 22:01:58 -0500253 signlen = sign_packet(server,
254 req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
255 len - sizeof(struct ncp_request_header) + 1,
256 cpu_to_le32(len), req->sign);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 if (signlen) {
Al Viro2cebcc72016-01-09 22:01:58 -0500258 /* NCP over UDP appends signature */
259 req->tx_iov[2].iov_base = req->sign;
260 req->tx_iov[2].iov_len = signlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 }
Al Viro2cebcc72016-01-09 22:01:58 -0500262 iov_iter_kvec(&req->from, WRITE | ITER_KVEC,
263 req->tx_iov + 1, signlen ? 2 : 1, len + signlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 server->rcv.creq = req;
265 server->timeout_last = server->m.time_out;
266 server->timeout_retries = server->m.retry_count;
267 ncpdgram_send(server->ncp_sock, req);
268 mod_timer(&server->timeout_tm, jiffies + server->m.time_out);
269}
270
271#define NCP_TCP_XMIT_MAGIC (0x446D6454)
272#define NCP_TCP_XMIT_VERSION (1)
273#define NCP_TCP_RCVD_MAGIC (0x744E6350)
274
275static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
276{
Al Viro2cebcc72016-01-09 22:01:58 -0500277 size_t signlen, len = req->tx_iov[1].iov_len;
278 struct ncp_request_header *h = req->tx_iov[1].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 ncp_init_header(server, req, h);
281 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
Al Viro2cebcc72016-01-09 22:01:58 -0500282 len - sizeof(struct ncp_request_header) + 1,
283 cpu_to_be32(len + 24), req->sign + 4) + 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
285 req->sign[0] = htonl(NCP_TCP_XMIT_MAGIC);
Al Viro2cebcc72016-01-09 22:01:58 -0500286 req->sign[1] = htonl(len + signlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 req->sign[2] = htonl(NCP_TCP_XMIT_VERSION);
288 req->sign[3] = htonl(req->datalen + 8);
Al Viro2cebcc72016-01-09 22:01:58 -0500289 /* NCP over TCP prepends signature */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 req->tx_iov[0].iov_base = req->sign;
291 req->tx_iov[0].iov_len = signlen;
Al Viro2cebcc72016-01-09 22:01:58 -0500292 iov_iter_kvec(&req->from, WRITE | ITER_KVEC,
293 req->tx_iov, 2, len + signlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 server->tx.creq = req;
296 __ncptcp_try_send(server);
297}
298
299static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
300{
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100301 /* we copy the data so that we do not depend on the caller
302 staying alive */
303 memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
304 req->tx_iov[1].iov_base = server->txbuf;
305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 if (server->ncp_sock->type == SOCK_STREAM)
307 ncptcp_start_request(server, req);
308 else
309 ncpdgram_start_request(server, req);
310}
311
312static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
313{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800314 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 if (!ncp_conn_valid(server)) {
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800316 mutex_unlock(&server->rcv.creq_mutex);
Joe Perchesb41f8b82014-04-08 16:04:14 -0700317 pr_err("tcp: Server died\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 return -EIO;
319 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100320 ncp_req_get(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 if (server->tx.creq || server->rcv.creq) {
322 req->status = RQ_QUEUED;
323 list_add_tail(&req->req, &server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800324 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 return 0;
326 }
327 __ncp_start_request(server, req);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800328 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 return 0;
330}
331
332static void __ncp_next_request(struct ncp_server *server)
333{
334 struct ncp_request_reply *req;
335
336 server->rcv.creq = NULL;
337 if (list_empty(&server->tx.requests)) {
338 return;
339 }
340 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
341 list_del_init(&req->req);
342 __ncp_start_request(server, req);
343}
344
345static void info_server(struct ncp_server *server, unsigned int id, const void * data, size_t len)
346{
347 if (server->info_sock) {
348 struct kvec iov[2];
349 __be32 hdr[2];
350
351 hdr[0] = cpu_to_be32(len + 8);
352 hdr[1] = cpu_to_be32(id);
353
354 iov[0].iov_base = hdr;
355 iov[0].iov_len = 8;
356 iov[1].iov_base = (void *) data;
357 iov[1].iov_len = len;
358
359 do_send(server->info_sock, iov, 2, len + 8, MSG_NOSIGNAL);
360 }
361}
362
David Howellsc4028952006-11-22 14:57:56 +0000363void ncpdgram_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
David Howellsc4028952006-11-22 14:57:56 +0000365 struct ncp_server *server =
366 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 struct socket* sock;
368
369 sock = server->ncp_sock;
370
371 while (1) {
372 struct ncp_reply_header reply;
373 int result;
374
375 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
376 if (result < 0) {
377 break;
378 }
379 if (result >= sizeof(reply)) {
380 struct ncp_request_reply *req;
381
382 if (reply.type == NCP_WATCHDOG) {
383 unsigned char buf[10];
384
385 if (server->connection != get_conn_number(&reply)) {
386 goto drop;
387 }
388 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
389 if (result < 0) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700390 ncp_dbg(1, "recv failed with %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 continue;
392 }
393 if (result < 10) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700394 ncp_dbg(1, "too short (%u) watchdog packet\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 continue;
396 }
397 if (buf[9] != '?') {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700398 ncp_dbg(1, "bad signature (%02X) in watchdog packet\n", buf[9]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 continue;
400 }
401 buf[9] = 'Y';
402 _send(sock, buf, sizeof(buf));
403 continue;
404 }
405 if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
406 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
407 if (result < 0) {
408 continue;
409 }
410 info_server(server, 0, server->unexpected_packet.data, result);
411 continue;
412 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800413 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 req = server->rcv.creq;
415 if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence &&
416 server->connection == get_conn_number(&reply)))) {
417 if (reply.type == NCP_POSITIVE_ACK) {
418 server->timeout_retries = server->m.retry_count;
419 server->timeout_last = NCP_MAX_RPC_TIMEOUT;
420 mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
421 } else if (reply.type == NCP_REPLY) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100422 result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423#ifdef CONFIG_NCPFS_PACKET_SIGNING
424 if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
425 if (result < 8 + 8) {
426 result = -EIO;
427 } else {
428 unsigned int hdrl;
429
430 result -= 8;
431 hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100432 if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700433 pr_info("Signature violation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 result = -EIO;
435 }
436 }
437 }
438#endif
439 del_timer(&server->timeout_tm);
440 server->rcv.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100441 ncp_finish_request(server, req, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 __ncp_next_request(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800443 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 continue;
445 }
446 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800447 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 }
449drop:;
450 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
451 }
452}
453
454static void __ncpdgram_timeout_proc(struct ncp_server *server)
455{
456 /* If timer is pending, we are processing another request... */
457 if (!timer_pending(&server->timeout_tm)) {
458 struct ncp_request_reply* req;
459
460 req = server->rcv.creq;
461 if (req) {
462 int timeout;
463
464 if (server->m.flags & NCP_MOUNT_SOFT) {
465 if (server->timeout_retries-- == 0) {
466 __ncp_abort_request(server, req, -ETIMEDOUT);
467 return;
468 }
469 }
470 /* Ignore errors */
471 ncpdgram_send(server->ncp_sock, req);
472 timeout = server->timeout_last << 1;
473 if (timeout > NCP_MAX_RPC_TIMEOUT) {
474 timeout = NCP_MAX_RPC_TIMEOUT;
475 }
476 server->timeout_last = timeout;
477 mod_timer(&server->timeout_tm, jiffies + timeout);
478 }
479 }
480}
481
David Howellsc4028952006-11-22 14:57:56 +0000482void ncpdgram_timeout_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
David Howellsc4028952006-11-22 14:57:56 +0000484 struct ncp_server *server =
485 container_of(work, struct ncp_server, timeout_tq);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800486 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 __ncpdgram_timeout_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800488 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489}
490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
492{
493 int result;
494
495 if (buffer) {
496 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
497 } else {
498 static unsigned char dummy[1024];
499
500 if (len > sizeof(dummy)) {
501 len = sizeof(dummy);
502 }
503 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
504 }
505 if (result < 0) {
506 return result;
507 }
508 if (result > len) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700509 pr_err("tcp: bug in recvmsg (%u > %Zu)\n", result, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 return -EIO;
511 }
512 return result;
513}
514
515static int __ncptcp_rcv_proc(struct ncp_server *server)
516{
517 /* We have to check the result, so store the complete header */
518 while (1) {
519 int result;
520 struct ncp_request_reply *req;
521 int datalen;
522 int type;
523
524 while (server->rcv.len) {
525 result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
526 if (result == -EAGAIN) {
527 return 0;
528 }
529 if (result <= 0) {
530 req = server->rcv.creq;
531 if (req) {
532 __ncp_abort_request(server, req, -EIO);
533 } else {
534 __ncptcp_abort(server);
535 }
536 if (result < 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700537 pr_err("tcp: error in recvmsg: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 } else {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700539 ncp_dbg(1, "tcp: EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 }
541 return -EIO;
542 }
543 if (server->rcv.ptr) {
544 server->rcv.ptr += result;
545 }
546 server->rcv.len -= result;
547 }
548 switch (server->rcv.state) {
549 case 0:
550 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700551 pr_err("tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 __ncptcp_abort(server);
553 return -EIO;
554 }
555 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
556 if (datalen < 10) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700557 pr_err("tcp: Unexpected reply len %d\n", datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 __ncptcp_abort(server);
559 return -EIO;
560 }
561#ifdef CONFIG_NCPFS_PACKET_SIGNING
562 if (server->sign_active) {
563 if (datalen < 18) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700564 pr_err("tcp: Unexpected reply len %d\n", datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 __ncptcp_abort(server);
566 return -EIO;
567 }
568 server->rcv.buf.len = datalen - 8;
569 server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
570 server->rcv.len = 8;
571 server->rcv.state = 4;
572 break;
573 }
574#endif
575 type = ntohs(server->rcv.buf.type);
576#ifdef CONFIG_NCPFS_PACKET_SIGNING
577cont:;
578#endif
579 if (type != NCP_REPLY) {
580 if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
581 *(__u16*)(server->unexpected_packet.data) = htons(type);
582 server->unexpected_packet.len = datalen - 8;
583
584 server->rcv.state = 5;
585 server->rcv.ptr = server->unexpected_packet.data + 2;
586 server->rcv.len = datalen - 10;
587 break;
588 }
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700589 ncp_dbg(1, "tcp: Unexpected NCP type %02X\n", type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590skipdata2:;
591 server->rcv.state = 2;
592skipdata:;
593 server->rcv.ptr = NULL;
594 server->rcv.len = datalen - 10;
595 break;
596 }
597 req = server->rcv.creq;
598 if (!req) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700599 ncp_dbg(1, "Reply without appropriate request\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 goto skipdata2;
601 }
602 if (datalen > req->datalen + 8) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700603 pr_err("tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 server->rcv.state = 3;
605 goto skipdata;
606 }
607 req->datalen = datalen - 8;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100608 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
609 server->rcv.ptr = server->rxbuf + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 server->rcv.len = datalen - 10;
611 server->rcv.state = 1;
612 break;
613#ifdef CONFIG_NCPFS_PACKET_SIGNING
614 case 4:
615 datalen = server->rcv.buf.len;
616 type = ntohs(server->rcv.buf.type2);
617 goto cont;
618#endif
619 case 1:
620 req = server->rcv.creq;
621 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100622 if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700623 pr_err("tcp: Bad sequence number\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 __ncp_abort_request(server, req, -EIO);
625 return -EIO;
626 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100627 if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700628 pr_err("tcp: Connection number mismatch\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 __ncp_abort_request(server, req, -EIO);
630 return -EIO;
631 }
632 }
633#ifdef CONFIG_NCPFS_PACKET_SIGNING
634 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100635 if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700636 pr_err("tcp: Signature violation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 __ncp_abort_request(server, req, -EIO);
638 return -EIO;
639 }
640 }
641#endif
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100642 ncp_finish_request(server, req, req->datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 nextreq:;
644 __ncp_next_request(server);
645 case 2:
646 next:;
647 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
648 server->rcv.len = 10;
649 server->rcv.state = 0;
650 break;
651 case 3:
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100652 ncp_finish_request(server, server->rcv.creq, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 goto nextreq;
654 case 5:
655 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
656 goto next;
657 }
658 }
659}
660
David Howellsc4028952006-11-22 14:57:56 +0000661void ncp_tcp_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
David Howellsc4028952006-11-22 14:57:56 +0000663 struct ncp_server *server =
664 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800666 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 __ncptcp_rcv_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800668 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669}
670
David Howellsc4028952006-11-22 14:57:56 +0000671void ncp_tcp_tx_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672{
David Howellsc4028952006-11-22 14:57:56 +0000673 struct ncp_server *server =
674 container_of(work, struct ncp_server, tx.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800676 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 __ncptcp_try_send(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800678 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679}
680
681static int do_ncp_rpc_call(struct ncp_server *server, int size,
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100682 unsigned char* reply_buf, int max_reply_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
684 int result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100685 struct ncp_request_reply *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100687 req = ncp_alloc_req();
688 if (!req)
689 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100691 req->reply_buf = reply_buf;
692 req->datalen = max_reply_size;
693 req->tx_iov[1].iov_base = server->packet;
694 req->tx_iov[1].iov_len = size;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100695 req->tx_type = *(u_int16_t*)server->packet;
696
697 result = ncp_add_request(server, req);
698 if (result < 0)
699 goto out;
700
701 if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
702 ncp_abort_request(server, req, -EINTR);
703 result = -EINTR;
704 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100706
707 result = req->result;
708
709out:
710 ncp_req_put(req);
711
712 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713}
714
715/*
716 * We need the server to be locked here, so check!
717 */
718
719static int ncp_do_request(struct ncp_server *server, int size,
720 void* reply, int max_reply_size)
721{
722 int result;
723
724 if (server->lock == 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700725 pr_err("Server not locked!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return -EIO;
727 }
728 if (!ncp_conn_valid(server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 return -EIO;
730 }
731 {
732 sigset_t old_set;
733 unsigned long mask, flags;
734
735 spin_lock_irqsave(&current->sighand->siglock, flags);
736 old_set = current->blocked;
737 if (current->flags & PF_EXITING)
738 mask = 0;
739 else
740 mask = sigmask(SIGKILL);
741 if (server->m.flags & NCP_MOUNT_INTR) {
742 /* FIXME: This doesn't seem right at all. So, like,
743 we can't handle SIGINT and get whatever to stop?
744 What if we've blocked it ourselves? What about
745 alarms? Why, in fact, are we mucking with the
746 sigmask at all? -- r~ */
747 if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
748 mask |= sigmask(SIGINT);
749 if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
750 mask |= sigmask(SIGQUIT);
751 }
752 siginitsetinv(&current->blocked, mask);
753 recalc_sigpending();
754 spin_unlock_irqrestore(&current->sighand->siglock, flags);
755
756 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
757
758 spin_lock_irqsave(&current->sighand->siglock, flags);
759 current->blocked = old_set;
760 recalc_sigpending();
761 spin_unlock_irqrestore(&current->sighand->siglock, flags);
762 }
763
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700764 ncp_dbg(2, "do_ncp_rpc_call returned %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return result;
767}
768
769/* ncp_do_request assures that at least a complete reply header is
770 * received. It assumes that server->current_size contains the ncp
771 * request size
772 */
773int ncp_request2(struct ncp_server *server, int function,
774 void* rpl, int size)
775{
776 struct ncp_request_header *h;
777 struct ncp_reply_header* reply = rpl;
778 int result;
779
780 h = (struct ncp_request_header *) (server->packet);
781 if (server->has_subfunction != 0) {
782 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
783 }
784 h->type = NCP_REQUEST;
785 /*
786 * The server shouldn't know or care what task is making a
787 * request, so we always use the same task number.
788 */
789 h->task = 2; /* (current->pid) & 0xff; */
790 h->function = function;
791
792 result = ncp_do_request(server, server->current_size, reply, size);
793 if (result < 0) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700794 ncp_dbg(1, "ncp_request_error: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 goto out;
796 }
797 server->completion = reply->completion_code;
798 server->conn_status = reply->connection_state;
799 server->reply_size = result;
800 server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
801
802 result = reply->completion_code;
803
804 if (result != 0)
Joe Perchese45ca8b2014-04-08 16:04:16 -0700805 ncp_vdbg("completion code=%x\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806out:
807 return result;
808}
809
810int ncp_connect(struct ncp_server *server)
811{
812 struct ncp_request_header *h;
813 int result;
814
815 server->connection = 0xFFFF;
816 server->sequence = 255;
817
818 h = (struct ncp_request_header *) (server->packet);
819 h->type = NCP_ALLOC_SLOT_REQUEST;
820 h->task = 2; /* see above */
821 h->function = 0;
822
823 result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
824 if (result < 0)
825 goto out;
826 server->connection = h->conn_low + (h->conn_high * 256);
827 result = 0;
828out:
829 return result;
830}
831
832int ncp_disconnect(struct ncp_server *server)
833{
834 struct ncp_request_header *h;
835
836 h = (struct ncp_request_header *) (server->packet);
837 h->type = NCP_DEALLOC_SLOT_REQUEST;
838 h->task = 2; /* see above */
839 h->function = 0;
840
841 return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
842}
843
844void ncp_lock_server(struct ncp_server *server)
845{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800846 mutex_lock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (server->lock)
Joe Perchesb41f8b82014-04-08 16:04:14 -0700848 pr_warn("%s: was locked!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 server->lock = 1;
850}
851
852void ncp_unlock_server(struct ncp_server *server)
853{
854 if (!server->lock) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700855 pr_warn("%s: was not locked!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 return;
857 }
858 server->lock = 0;
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800859 mutex_unlock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}