blob: 98b6db0ed63e0323477be82768f9c3c08a06de5d [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>
Ingo Molnar3f07c012017-02-08 18:51:30 +010019#include <linux/sched/signal.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080020#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/in.h>
22#include <linux/net.h>
23#include <linux/mm.h>
24#include <linux/netdevice.h>
25#include <linux/signal.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090026#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <net/scm.h>
28#include <net/sock.h>
29#include <linux/ipx.h>
30#include <linux/poll.h>
31#include <linux/file.h>
32
Al Viro32c419d2011-01-12 17:37:47 -050033#include "ncp_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35#include "ncpsign_kernel.h"
36
37static int _recv(struct socket *sock, void *buf, int size, unsigned flags)
38{
39 struct msghdr msg = {NULL, };
40 struct kvec iov = {buf, size};
41 return kernel_recvmsg(sock, &msg, &iov, 1, size, flags);
42}
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044static int _send(struct socket *sock, const void *buff, int len)
45{
Al Virob8e2df12016-01-09 22:12:55 -050046 struct msghdr msg = { .msg_flags = 0 };
47 struct kvec vec = {.iov_base = (void *)buff, .iov_len = len};
48 iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &vec, 1, len);
49 return sock_sendmsg(sock, &msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070050}
51
52struct ncp_request_reply {
53 struct list_head req;
54 wait_queue_head_t wq;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010055 atomic_t refs;
56 unsigned char* reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 size_t datalen;
58 int result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010059 enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
Al Viro2cebcc72016-01-09 22:01:58 -050060 struct iov_iter from;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 struct kvec tx_iov[3];
62 u_int16_t tx_type;
63 u_int32_t sign[6];
64};
65
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010066static inline struct ncp_request_reply* ncp_alloc_req(void)
67{
68 struct ncp_request_reply *req;
69
70 req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
71 if (!req)
72 return NULL;
73
74 init_waitqueue_head(&req->wq);
75 atomic_set(&req->refs, (1));
76 req->status = RQ_IDLE;
77
78 return req;
79}
80
81static void ncp_req_get(struct ncp_request_reply *req)
82{
83 atomic_inc(&req->refs);
84}
85
86static void ncp_req_put(struct ncp_request_reply *req)
87{
88 if (atomic_dec_and_test(&req->refs))
89 kfree(req);
90}
91
David S. Miller676d2362014-04-11 16:15:36 -040092void ncp_tcp_data_ready(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
94 struct ncp_server *server = sk->sk_user_data;
95
David S. Miller676d2362014-04-11 16:15:36 -040096 server->data_ready(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 schedule_work(&server->rcv.tq);
98}
99
100void ncp_tcp_error_report(struct sock *sk)
101{
102 struct ncp_server *server = sk->sk_user_data;
103
104 server->error_report(sk);
105 schedule_work(&server->rcv.tq);
106}
107
108void ncp_tcp_write_space(struct sock *sk)
109{
110 struct ncp_server *server = sk->sk_user_data;
111
112 /* We do not need any locking: we first set tx.creq, and then we do sendmsg,
113 not vice versa... */
114 server->write_space(sk);
115 if (server->tx.creq)
116 schedule_work(&server->tx.tq);
117}
118
119void ncpdgram_timeout_call(unsigned long v)
120{
121 struct ncp_server *server = (void*)v;
122
123 schedule_work(&server->timeout_tq);
124}
125
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100126static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
128 req->result = result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100129 if (req->status != RQ_ABANDONED)
130 memcpy(req->reply_buf, server->rxbuf, req->datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 req->status = RQ_DONE;
132 wake_up_all(&req->wq);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100133 ncp_req_put(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134}
135
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100136static void __abort_ncp_connection(struct ncp_server *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137{
138 struct ncp_request_reply *req;
139
140 ncp_invalidate_conn(server);
141 del_timer(&server->timeout_tm);
142 while (!list_empty(&server->tx.requests)) {
143 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
144
145 list_del_init(&req->req);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100146 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 }
148 req = server->rcv.creq;
149 if (req) {
150 server->rcv.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100151 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 server->rcv.ptr = NULL;
153 server->rcv.state = 0;
154 }
155 req = server->tx.creq;
156 if (req) {
157 server->tx.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100158 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 }
160}
161
162static inline int get_conn_number(struct ncp_reply_header *rp)
163{
164 return rp->conn_low | (rp->conn_high << 8);
165}
166
167static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
168{
169 /* If req is done, we got signal, but we also received answer... */
170 switch (req->status) {
171 case RQ_IDLE:
172 case RQ_DONE:
173 break;
174 case RQ_QUEUED:
175 list_del_init(&req->req);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100176 ncp_finish_request(server, req, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 break;
178 case RQ_INPROGRESS:
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100179 req->status = RQ_ABANDONED;
180 break;
181 case RQ_ABANDONED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 break;
183 }
184}
185
186static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
187{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800188 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 __ncp_abort_request(server, req, err);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800190 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191}
192
193static inline void __ncptcp_abort(struct ncp_server *server)
194{
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100195 __abort_ncp_connection(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196}
197
198static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
199{
Al Viro2cebcc72016-01-09 22:01:58 -0500200 struct msghdr msg = { .msg_iter = req->from, .msg_flags = MSG_DONTWAIT };
201 return sock_sendmsg(sock, &msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202}
203
204static void __ncptcp_try_send(struct ncp_server *server)
205{
206 struct ncp_request_reply *rq;
Al Viro2cebcc72016-01-09 22:01:58 -0500207 struct msghdr msg = { .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 int result;
209
210 rq = server->tx.creq;
211 if (!rq)
212 return;
213
Al Viro2cebcc72016-01-09 22:01:58 -0500214 msg.msg_iter = rq->from;
215 result = sock_sendmsg(server->ncp_sock, &msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
217 if (result == -EAGAIN)
218 return;
219
220 if (result < 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700221 pr_err("tcp: Send failed: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 __ncp_abort_request(server, rq, result);
223 return;
224 }
Al Viro2cebcc72016-01-09 22:01:58 -0500225 if (!msg_data_left(&msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 server->rcv.creq = rq;
227 server->tx.creq = NULL;
228 return;
229 }
Al Viro2cebcc72016-01-09 22:01:58 -0500230 rq->from = msg.msg_iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231}
232
233static inline void ncp_init_header(struct ncp_server *server, struct ncp_request_reply *req, struct ncp_request_header *h)
234{
235 req->status = RQ_INPROGRESS;
236 h->conn_low = server->connection;
237 h->conn_high = server->connection >> 8;
238 h->sequence = ++server->sequence;
239}
240
241static void ncpdgram_start_request(struct ncp_server *server, struct ncp_request_reply *req)
242{
Al Viro2cebcc72016-01-09 22:01:58 -0500243 size_t signlen, len = req->tx_iov[1].iov_len;
244 struct ncp_request_header *h = req->tx_iov[1].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 ncp_init_header(server, req, h);
Al Viro2cebcc72016-01-09 22:01:58 -0500247 signlen = sign_packet(server,
248 req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
249 len - sizeof(struct ncp_request_header) + 1,
250 cpu_to_le32(len), req->sign);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 if (signlen) {
Al Viro2cebcc72016-01-09 22:01:58 -0500252 /* NCP over UDP appends signature */
253 req->tx_iov[2].iov_base = req->sign;
254 req->tx_iov[2].iov_len = signlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 }
Al Viro2cebcc72016-01-09 22:01:58 -0500256 iov_iter_kvec(&req->from, WRITE | ITER_KVEC,
257 req->tx_iov + 1, signlen ? 2 : 1, len + signlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 server->rcv.creq = req;
259 server->timeout_last = server->m.time_out;
260 server->timeout_retries = server->m.retry_count;
261 ncpdgram_send(server->ncp_sock, req);
262 mod_timer(&server->timeout_tm, jiffies + server->m.time_out);
263}
264
265#define NCP_TCP_XMIT_MAGIC (0x446D6454)
266#define NCP_TCP_XMIT_VERSION (1)
267#define NCP_TCP_RCVD_MAGIC (0x744E6350)
268
269static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
270{
Al Viro2cebcc72016-01-09 22:01:58 -0500271 size_t signlen, len = req->tx_iov[1].iov_len;
272 struct ncp_request_header *h = req->tx_iov[1].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 ncp_init_header(server, req, h);
275 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
Al Viro2cebcc72016-01-09 22:01:58 -0500276 len - sizeof(struct ncp_request_header) + 1,
277 cpu_to_be32(len + 24), req->sign + 4) + 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279 req->sign[0] = htonl(NCP_TCP_XMIT_MAGIC);
Al Viro2cebcc72016-01-09 22:01:58 -0500280 req->sign[1] = htonl(len + signlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 req->sign[2] = htonl(NCP_TCP_XMIT_VERSION);
282 req->sign[3] = htonl(req->datalen + 8);
Al Viro2cebcc72016-01-09 22:01:58 -0500283 /* NCP over TCP prepends signature */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 req->tx_iov[0].iov_base = req->sign;
285 req->tx_iov[0].iov_len = signlen;
Al Viro2cebcc72016-01-09 22:01:58 -0500286 iov_iter_kvec(&req->from, WRITE | ITER_KVEC,
287 req->tx_iov, 2, len + signlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
289 server->tx.creq = req;
290 __ncptcp_try_send(server);
291}
292
293static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
294{
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100295 /* we copy the data so that we do not depend on the caller
296 staying alive */
297 memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
298 req->tx_iov[1].iov_base = server->txbuf;
299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 if (server->ncp_sock->type == SOCK_STREAM)
301 ncptcp_start_request(server, req);
302 else
303 ncpdgram_start_request(server, req);
304}
305
306static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
307{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800308 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 if (!ncp_conn_valid(server)) {
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800310 mutex_unlock(&server->rcv.creq_mutex);
Joe Perchesb41f8b82014-04-08 16:04:14 -0700311 pr_err("tcp: Server died\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 return -EIO;
313 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100314 ncp_req_get(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 if (server->tx.creq || server->rcv.creq) {
316 req->status = RQ_QUEUED;
317 list_add_tail(&req->req, &server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800318 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 return 0;
320 }
321 __ncp_start_request(server, req);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800322 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 return 0;
324}
325
326static void __ncp_next_request(struct ncp_server *server)
327{
328 struct ncp_request_reply *req;
329
330 server->rcv.creq = NULL;
331 if (list_empty(&server->tx.requests)) {
332 return;
333 }
334 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
335 list_del_init(&req->req);
336 __ncp_start_request(server, req);
337}
338
339static void info_server(struct ncp_server *server, unsigned int id, const void * data, size_t len)
340{
341 if (server->info_sock) {
Al Virob8e2df12016-01-09 22:12:55 -0500342 struct msghdr msg = { .msg_flags = MSG_NOSIGNAL };
343 __be32 hdr[2] = {cpu_to_be32(len + 8), cpu_to_be32(id)};
344 struct kvec iov[2] = {
345 {.iov_base = hdr, .iov_len = 8},
346 {.iov_base = (void *)data, .iov_len = len},
347 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Al Virob8e2df12016-01-09 22:12:55 -0500349 iov_iter_kvec(&msg.msg_iter, ITER_KVEC | WRITE,
350 iov, 2, len + 8);
351
352 sock_sendmsg(server->info_sock, &msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 }
354}
355
David Howellsc4028952006-11-22 14:57:56 +0000356void ncpdgram_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357{
David Howellsc4028952006-11-22 14:57:56 +0000358 struct ncp_server *server =
359 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 struct socket* sock;
361
362 sock = server->ncp_sock;
363
364 while (1) {
365 struct ncp_reply_header reply;
366 int result;
367
368 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
369 if (result < 0) {
370 break;
371 }
372 if (result >= sizeof(reply)) {
373 struct ncp_request_reply *req;
374
375 if (reply.type == NCP_WATCHDOG) {
376 unsigned char buf[10];
377
378 if (server->connection != get_conn_number(&reply)) {
379 goto drop;
380 }
381 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
382 if (result < 0) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700383 ncp_dbg(1, "recv failed with %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 continue;
385 }
386 if (result < 10) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700387 ncp_dbg(1, "too short (%u) watchdog packet\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 continue;
389 }
390 if (buf[9] != '?') {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700391 ncp_dbg(1, "bad signature (%02X) in watchdog packet\n", buf[9]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 continue;
393 }
394 buf[9] = 'Y';
395 _send(sock, buf, sizeof(buf));
396 continue;
397 }
398 if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
399 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
400 if (result < 0) {
401 continue;
402 }
403 info_server(server, 0, server->unexpected_packet.data, result);
404 continue;
405 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800406 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 req = server->rcv.creq;
408 if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence &&
409 server->connection == get_conn_number(&reply)))) {
410 if (reply.type == NCP_POSITIVE_ACK) {
411 server->timeout_retries = server->m.retry_count;
412 server->timeout_last = NCP_MAX_RPC_TIMEOUT;
413 mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
414 } else if (reply.type == NCP_REPLY) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100415 result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416#ifdef CONFIG_NCPFS_PACKET_SIGNING
417 if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
418 if (result < 8 + 8) {
419 result = -EIO;
420 } else {
421 unsigned int hdrl;
422
423 result -= 8;
424 hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100425 if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700426 pr_info("Signature violation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 result = -EIO;
428 }
429 }
430 }
431#endif
432 del_timer(&server->timeout_tm);
433 server->rcv.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100434 ncp_finish_request(server, req, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 __ncp_next_request(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800436 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 continue;
438 }
439 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800440 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 }
442drop:;
443 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
444 }
445}
446
447static void __ncpdgram_timeout_proc(struct ncp_server *server)
448{
449 /* If timer is pending, we are processing another request... */
450 if (!timer_pending(&server->timeout_tm)) {
451 struct ncp_request_reply* req;
452
453 req = server->rcv.creq;
454 if (req) {
455 int timeout;
456
457 if (server->m.flags & NCP_MOUNT_SOFT) {
458 if (server->timeout_retries-- == 0) {
459 __ncp_abort_request(server, req, -ETIMEDOUT);
460 return;
461 }
462 }
463 /* Ignore errors */
464 ncpdgram_send(server->ncp_sock, req);
465 timeout = server->timeout_last << 1;
466 if (timeout > NCP_MAX_RPC_TIMEOUT) {
467 timeout = NCP_MAX_RPC_TIMEOUT;
468 }
469 server->timeout_last = timeout;
470 mod_timer(&server->timeout_tm, jiffies + timeout);
471 }
472 }
473}
474
David Howellsc4028952006-11-22 14:57:56 +0000475void ncpdgram_timeout_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
David Howellsc4028952006-11-22 14:57:56 +0000477 struct ncp_server *server =
478 container_of(work, struct ncp_server, timeout_tq);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800479 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 __ncpdgram_timeout_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800481 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482}
483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
485{
486 int result;
487
488 if (buffer) {
489 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
490 } else {
491 static unsigned char dummy[1024];
492
493 if (len > sizeof(dummy)) {
494 len = sizeof(dummy);
495 }
496 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
497 }
498 if (result < 0) {
499 return result;
500 }
501 if (result > len) {
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -0800502 pr_err("tcp: bug in recvmsg (%u > %zu)\n", result, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 return -EIO;
504 }
505 return result;
506}
507
508static int __ncptcp_rcv_proc(struct ncp_server *server)
509{
510 /* We have to check the result, so store the complete header */
511 while (1) {
512 int result;
513 struct ncp_request_reply *req;
514 int datalen;
515 int type;
516
517 while (server->rcv.len) {
518 result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
519 if (result == -EAGAIN) {
520 return 0;
521 }
522 if (result <= 0) {
523 req = server->rcv.creq;
524 if (req) {
525 __ncp_abort_request(server, req, -EIO);
526 } else {
527 __ncptcp_abort(server);
528 }
529 if (result < 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700530 pr_err("tcp: error in recvmsg: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 } else {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700532 ncp_dbg(1, "tcp: EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 }
534 return -EIO;
535 }
536 if (server->rcv.ptr) {
537 server->rcv.ptr += result;
538 }
539 server->rcv.len -= result;
540 }
541 switch (server->rcv.state) {
542 case 0:
543 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700544 pr_err("tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 __ncptcp_abort(server);
546 return -EIO;
547 }
548 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
549 if (datalen < 10) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700550 pr_err("tcp: Unexpected reply len %d\n", datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 __ncptcp_abort(server);
552 return -EIO;
553 }
554#ifdef CONFIG_NCPFS_PACKET_SIGNING
555 if (server->sign_active) {
556 if (datalen < 18) {
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 server->rcv.buf.len = datalen - 8;
562 server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
563 server->rcv.len = 8;
564 server->rcv.state = 4;
565 break;
566 }
567#endif
568 type = ntohs(server->rcv.buf.type);
569#ifdef CONFIG_NCPFS_PACKET_SIGNING
570cont:;
571#endif
572 if (type != NCP_REPLY) {
573 if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
574 *(__u16*)(server->unexpected_packet.data) = htons(type);
575 server->unexpected_packet.len = datalen - 8;
576
577 server->rcv.state = 5;
578 server->rcv.ptr = server->unexpected_packet.data + 2;
579 server->rcv.len = datalen - 10;
580 break;
581 }
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700582 ncp_dbg(1, "tcp: Unexpected NCP type %02X\n", type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583skipdata2:;
584 server->rcv.state = 2;
585skipdata:;
586 server->rcv.ptr = NULL;
587 server->rcv.len = datalen - 10;
588 break;
589 }
590 req = server->rcv.creq;
591 if (!req) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700592 ncp_dbg(1, "Reply without appropriate request\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 goto skipdata2;
594 }
595 if (datalen > req->datalen + 8) {
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -0800596 pr_err("tcp: Unexpected reply len %d (expected at most %zd)\n", datalen, req->datalen + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 server->rcv.state = 3;
598 goto skipdata;
599 }
600 req->datalen = datalen - 8;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100601 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
602 server->rcv.ptr = server->rxbuf + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 server->rcv.len = datalen - 10;
604 server->rcv.state = 1;
605 break;
606#ifdef CONFIG_NCPFS_PACKET_SIGNING
607 case 4:
608 datalen = server->rcv.buf.len;
609 type = ntohs(server->rcv.buf.type2);
610 goto cont;
611#endif
612 case 1:
613 req = server->rcv.creq;
614 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100615 if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700616 pr_err("tcp: Bad sequence number\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 __ncp_abort_request(server, req, -EIO);
618 return -EIO;
619 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100620 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 -0700621 pr_err("tcp: Connection number mismatch\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 __ncp_abort_request(server, req, -EIO);
623 return -EIO;
624 }
625 }
626#ifdef CONFIG_NCPFS_PACKET_SIGNING
627 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100628 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 -0700629 pr_err("tcp: Signature violation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 __ncp_abort_request(server, req, -EIO);
631 return -EIO;
632 }
633 }
634#endif
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100635 ncp_finish_request(server, req, req->datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 nextreq:;
637 __ncp_next_request(server);
638 case 2:
639 next:;
640 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
641 server->rcv.len = 10;
642 server->rcv.state = 0;
643 break;
644 case 3:
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100645 ncp_finish_request(server, server->rcv.creq, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 goto nextreq;
647 case 5:
648 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
649 goto next;
650 }
651 }
652}
653
David Howellsc4028952006-11-22 14:57:56 +0000654void ncp_tcp_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655{
David Howellsc4028952006-11-22 14:57:56 +0000656 struct ncp_server *server =
657 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800659 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 __ncptcp_rcv_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800661 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662}
663
David Howellsc4028952006-11-22 14:57:56 +0000664void ncp_tcp_tx_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
David Howellsc4028952006-11-22 14:57:56 +0000666 struct ncp_server *server =
667 container_of(work, struct ncp_server, tx.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800669 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 __ncptcp_try_send(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800671 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672}
673
674static int do_ncp_rpc_call(struct ncp_server *server, int size,
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100675 unsigned char* reply_buf, int max_reply_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676{
677 int result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100678 struct ncp_request_reply *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100680 req = ncp_alloc_req();
681 if (!req)
682 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100684 req->reply_buf = reply_buf;
685 req->datalen = max_reply_size;
686 req->tx_iov[1].iov_base = server->packet;
687 req->tx_iov[1].iov_len = size;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100688 req->tx_type = *(u_int16_t*)server->packet;
689
690 result = ncp_add_request(server, req);
691 if (result < 0)
692 goto out;
693
694 if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
695 ncp_abort_request(server, req, -EINTR);
696 result = -EINTR;
697 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100699
700 result = req->result;
701
702out:
703 ncp_req_put(req);
704
705 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706}
707
708/*
709 * We need the server to be locked here, so check!
710 */
711
712static int ncp_do_request(struct ncp_server *server, int size,
713 void* reply, int max_reply_size)
714{
715 int result;
716
717 if (server->lock == 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700718 pr_err("Server not locked!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 return -EIO;
720 }
721 if (!ncp_conn_valid(server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return -EIO;
723 }
724 {
725 sigset_t old_set;
726 unsigned long mask, flags;
727
728 spin_lock_irqsave(&current->sighand->siglock, flags);
729 old_set = current->blocked;
730 if (current->flags & PF_EXITING)
731 mask = 0;
732 else
733 mask = sigmask(SIGKILL);
734 if (server->m.flags & NCP_MOUNT_INTR) {
735 /* FIXME: This doesn't seem right at all. So, like,
736 we can't handle SIGINT and get whatever to stop?
737 What if we've blocked it ourselves? What about
738 alarms? Why, in fact, are we mucking with the
739 sigmask at all? -- r~ */
740 if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
741 mask |= sigmask(SIGINT);
742 if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
743 mask |= sigmask(SIGQUIT);
744 }
745 siginitsetinv(&current->blocked, mask);
746 recalc_sigpending();
747 spin_unlock_irqrestore(&current->sighand->siglock, flags);
748
749 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
750
751 spin_lock_irqsave(&current->sighand->siglock, flags);
752 current->blocked = old_set;
753 recalc_sigpending();
754 spin_unlock_irqrestore(&current->sighand->siglock, flags);
755 }
756
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700757 ncp_dbg(2, "do_ncp_rpc_call returned %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return result;
760}
761
762/* ncp_do_request assures that at least a complete reply header is
763 * received. It assumes that server->current_size contains the ncp
764 * request size
765 */
766int ncp_request2(struct ncp_server *server, int function,
767 void* rpl, int size)
768{
769 struct ncp_request_header *h;
770 struct ncp_reply_header* reply = rpl;
771 int result;
772
773 h = (struct ncp_request_header *) (server->packet);
774 if (server->has_subfunction != 0) {
775 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
776 }
777 h->type = NCP_REQUEST;
778 /*
779 * The server shouldn't know or care what task is making a
780 * request, so we always use the same task number.
781 */
782 h->task = 2; /* (current->pid) & 0xff; */
783 h->function = function;
784
785 result = ncp_do_request(server, server->current_size, reply, size);
786 if (result < 0) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700787 ncp_dbg(1, "ncp_request_error: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 goto out;
789 }
790 server->completion = reply->completion_code;
791 server->conn_status = reply->connection_state;
792 server->reply_size = result;
793 server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
794
795 result = reply->completion_code;
796
797 if (result != 0)
Joe Perchese45ca8b2014-04-08 16:04:16 -0700798 ncp_vdbg("completion code=%x\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799out:
800 return result;
801}
802
803int ncp_connect(struct ncp_server *server)
804{
805 struct ncp_request_header *h;
806 int result;
807
808 server->connection = 0xFFFF;
809 server->sequence = 255;
810
811 h = (struct ncp_request_header *) (server->packet);
812 h->type = NCP_ALLOC_SLOT_REQUEST;
813 h->task = 2; /* see above */
814 h->function = 0;
815
816 result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
817 if (result < 0)
818 goto out;
819 server->connection = h->conn_low + (h->conn_high * 256);
820 result = 0;
821out:
822 return result;
823}
824
825int ncp_disconnect(struct ncp_server *server)
826{
827 struct ncp_request_header *h;
828
829 h = (struct ncp_request_header *) (server->packet);
830 h->type = NCP_DEALLOC_SLOT_REQUEST;
831 h->task = 2; /* see above */
832 h->function = 0;
833
834 return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
835}
836
837void ncp_lock_server(struct ncp_server *server)
838{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800839 mutex_lock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (server->lock)
Joe Perchesb41f8b82014-04-08 16:04:14 -0700841 pr_warn("%s: was locked!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 server->lock = 1;
843}
844
845void ncp_unlock_server(struct ncp_server *server)
846{
847 if (!server->lock) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700848 pr_warn("%s: was not locked!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 return;
850 }
851 server->lock = 0;
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800852 mutex_unlock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853}