]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 LT |
2 | /* |
3 | * linux/fs/lockd/xdr.c | |
4 | * | |
5 | * XDR support for lockd and the lock client. | |
6 | * | |
7 | * Copyright (C) 1995, 1996 Olaf Kirch <[email protected]> | |
8 | */ | |
9 | ||
1da177e4 LT |
10 | #include <linux/types.h> |
11 | #include <linux/sched.h> | |
1da177e4 LT |
12 | #include <linux/nfs.h> |
13 | ||
14 | #include <linux/sunrpc/xdr.h> | |
15 | #include <linux/sunrpc/clnt.h> | |
16 | #include <linux/sunrpc/svc.h> | |
17 | #include <linux/sunrpc/stats.h> | |
18 | #include <linux/lockd/lockd.h> | |
1da177e4 | 19 | |
9c69de4c CH |
20 | #include <uapi/linux/nfs2.h> |
21 | ||
cc1029b5 CL |
22 | #include "svcxdr.h" |
23 | ||
1da177e4 LT |
24 | |
25 | static inline loff_t | |
26 | s32_to_loff_t(__s32 offset) | |
27 | { | |
28 | return (loff_t)offset; | |
29 | } | |
30 | ||
31 | static inline __s32 | |
32 | loff_t_to_s32(loff_t offset) | |
33 | { | |
34 | __s32 res; | |
35 | if (offset >= NLM_OFFSET_MAX) | |
36 | res = NLM_OFFSET_MAX; | |
37 | else if (offset <= -NLM_OFFSET_MAX) | |
38 | res = -NLM_OFFSET_MAX; | |
39 | else | |
40 | res = offset; | |
41 | return res; | |
42 | } | |
43 | ||
2fd0c67a CL |
44 | /* |
45 | * NLM file handles are defined by specification to be a variable-length | |
46 | * XDR opaque no longer than 1024 bytes. However, this implementation | |
47 | * constrains their length to exactly the length of an NFSv2 file | |
48 | * handle. | |
49 | */ | |
50 | static bool | |
51 | svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) | |
52 | { | |
53 | __be32 *p; | |
54 | u32 len; | |
55 | ||
56 | if (xdr_stream_decode_u32(xdr, &len) < 0) | |
57 | return false; | |
58 | if (len != NFS2_FHSIZE) | |
59 | return false; | |
60 | ||
61 | p = xdr_inline_decode(xdr, len); | |
62 | if (!p) | |
63 | return false; | |
64 | fh->size = NFS2_FHSIZE; | |
65 | memcpy(fh->data, p, len); | |
66 | memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE); | |
67 | ||
68 | return true; | |
69 | } | |
70 | ||
2fd0c67a CL |
71 | static bool |
72 | svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) | |
73 | { | |
74 | struct file_lock *fl = &lock->fl; | |
75 | s32 start, len, end; | |
76 | ||
77 | if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) | |
78 | return false; | |
79 | if (!svcxdr_decode_fhandle(xdr, &lock->fh)) | |
80 | return false; | |
81 | if (!svcxdr_decode_owner(xdr, &lock->oh)) | |
82 | return false; | |
83 | if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) | |
84 | return false; | |
85 | if (xdr_stream_decode_u32(xdr, &start) < 0) | |
86 | return false; | |
87 | if (xdr_stream_decode_u32(xdr, &len) < 0) | |
88 | return false; | |
89 | ||
90 | locks_init_lock(fl); | |
91 | fl->fl_flags = FL_POSIX; | |
92 | fl->fl_type = F_RDLCK; | |
93 | end = start + len - 1; | |
94 | fl->fl_start = s32_to_loff_t(start); | |
95 | if (len == 0 || end < 0) | |
96 | fl->fl_end = OFFSET_MAX; | |
97 | else | |
98 | fl->fl_end = s32_to_loff_t(end); | |
99 | ||
100 | return true; | |
101 | } | |
102 | ||
adf98a48 CL |
103 | static bool |
104 | svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock) | |
1da177e4 | 105 | { |
adf98a48 CL |
106 | const struct file_lock *fl = &lock->fl; |
107 | s32 start, len; | |
1da177e4 | 108 | |
adf98a48 CL |
109 | /* exclusive */ |
110 | if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0) | |
111 | return false; | |
112 | if (xdr_stream_encode_u32(xdr, lock->svid) < 0) | |
113 | return false; | |
114 | if (!svcxdr_encode_owner(xdr, &lock->oh)) | |
115 | return false; | |
116 | start = loff_t_to_s32(fl->fl_start); | |
117 | if (fl->fl_end == OFFSET_MAX) | |
118 | len = 0; | |
119 | else | |
120 | len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); | |
121 | if (xdr_stream_encode_u32(xdr, start) < 0) | |
122 | return false; | |
123 | if (xdr_stream_encode_u32(xdr, len) < 0) | |
124 | return false; | |
1da177e4 | 125 | |
adf98a48 CL |
126 | return true; |
127 | } | |
1da177e4 | 128 | |
adf98a48 CL |
129 | static bool |
130 | svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) | |
131 | { | |
132 | if (!svcxdr_encode_stats(xdr, resp->status)) | |
133 | return false; | |
134 | switch (resp->status) { | |
135 | case nlm_lck_denied: | |
136 | if (!svcxdr_encode_holder(xdr, &resp->lock)) | |
137 | return false; | |
1da177e4 LT |
138 | } |
139 | ||
adf98a48 | 140 | return true; |
1da177e4 LT |
141 | } |
142 | ||
143 | ||
144 | /* | |
cc1029b5 | 145 | * Decode Call arguments |
1da177e4 | 146 | */ |
cc1029b5 | 147 | |
c44b31c2 | 148 | bool |
16c66364 | 149 | nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
cc1029b5 | 150 | { |
c44b31c2 | 151 | return true; |
cc1029b5 CL |
152 | } |
153 | ||
c44b31c2 | 154 | bool |
16c66364 | 155 | nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
1da177e4 | 156 | { |
026fec7e | 157 | struct nlm_args *argp = rqstp->rq_argp; |
2fd0c67a | 158 | u32 exclusive; |
1da177e4 | 159 | |
2fd0c67a | 160 | if (!svcxdr_decode_cookie(xdr, &argp->cookie)) |
c44b31c2 | 161 | return false; |
2fd0c67a | 162 | if (xdr_stream_decode_bool(xdr, &exclusive) < 0) |
c44b31c2 | 163 | return false; |
2fd0c67a | 164 | if (!svcxdr_decode_lock(xdr, &argp->lock)) |
c44b31c2 | 165 | return false; |
1da177e4 LT |
166 | if (exclusive) |
167 | argp->lock.fl.fl_type = F_WRLCK; | |
168 | ||
c44b31c2 | 169 | return true; |
1da177e4 LT |
170 | } |
171 | ||
c44b31c2 | 172 | bool |
16c66364 | 173 | nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
1da177e4 | 174 | { |
026fec7e | 175 | struct nlm_args *argp = rqstp->rq_argp; |
c1adb8c6 | 176 | u32 exclusive; |
1da177e4 | 177 | |
c1adb8c6 | 178 | if (!svcxdr_decode_cookie(xdr, &argp->cookie)) |
c44b31c2 | 179 | return false; |
c1adb8c6 | 180 | if (xdr_stream_decode_bool(xdr, &argp->block) < 0) |
c44b31c2 | 181 | return false; |
c1adb8c6 | 182 | if (xdr_stream_decode_bool(xdr, &exclusive) < 0) |
c44b31c2 | 183 | return false; |
c1adb8c6 | 184 | if (!svcxdr_decode_lock(xdr, &argp->lock)) |
c44b31c2 | 185 | return false; |
1da177e4 LT |
186 | if (exclusive) |
187 | argp->lock.fl.fl_type = F_WRLCK; | |
c1adb8c6 | 188 | if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) |
c44b31c2 | 189 | return false; |
c1adb8c6 | 190 | if (xdr_stream_decode_u32(xdr, &argp->state) < 0) |
c44b31c2 | 191 | return false; |
1da177e4 LT |
192 | argp->monitor = 1; /* monitor client by default */ |
193 | ||
c44b31c2 | 194 | return true; |
c1adb8c6 CL |
195 | } |
196 | ||
c44b31c2 | 197 | bool |
16c66364 | 198 | nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
c1adb8c6 | 199 | { |
f4e08f3a CL |
200 | struct nlm_args *argp = rqstp->rq_argp; |
201 | u32 exclusive; | |
c1adb8c6 | 202 | |
f4e08f3a | 203 | if (!svcxdr_decode_cookie(xdr, &argp->cookie)) |
c44b31c2 | 204 | return false; |
f4e08f3a | 205 | if (xdr_stream_decode_bool(xdr, &argp->block) < 0) |
c44b31c2 | 206 | return false; |
f4e08f3a | 207 | if (xdr_stream_decode_bool(xdr, &exclusive) < 0) |
c44b31c2 | 208 | return false; |
f4e08f3a | 209 | if (!svcxdr_decode_lock(xdr, &argp->lock)) |
c44b31c2 | 210 | return false; |
f4e08f3a CL |
211 | if (exclusive) |
212 | argp->lock.fl.fl_type = F_WRLCK; | |
213 | ||
c44b31c2 | 214 | return true; |
1da177e4 LT |
215 | } |
216 | ||
c44b31c2 | 217 | bool |
16c66364 | 218 | nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
1da177e4 | 219 | { |
c27045d3 | 220 | struct nlm_args *argp = rqstp->rq_argp; |
1da177e4 | 221 | |
c27045d3 | 222 | if (!svcxdr_decode_cookie(xdr, &argp->cookie)) |
c44b31c2 | 223 | return false; |
c27045d3 | 224 | if (!svcxdr_decode_lock(xdr, &argp->lock)) |
c44b31c2 | 225 | return false; |
c27045d3 CL |
226 | argp->lock.fl.fl_type = F_UNLCK; |
227 | ||
c44b31c2 | 228 | return true; |
1da177e4 LT |
229 | } |
230 | ||
c44b31c2 | 231 | bool |
16c66364 | 232 | nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
16ddcabe | 233 | { |
16ddcabe CL |
234 | struct nlm_res *resp = rqstp->rq_argp; |
235 | ||
236 | if (!svcxdr_decode_cookie(xdr, &resp->cookie)) | |
c44b31c2 | 237 | return false; |
16ddcabe | 238 | if (!svcxdr_decode_stats(xdr, &resp->status)) |
c44b31c2 | 239 | return false; |
16ddcabe | 240 | |
c44b31c2 | 241 | return true; |
16ddcabe CL |
242 | } |
243 | ||
c44b31c2 | 244 | bool |
16c66364 | 245 | nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
137e05e2 | 246 | { |
137e05e2 | 247 | struct nlm_reboot *argp = rqstp->rq_argp; |
16c66364 | 248 | __be32 *p; |
137e05e2 CL |
249 | u32 len; |
250 | ||
251 | if (xdr_stream_decode_u32(xdr, &len) < 0) | |
c44b31c2 | 252 | return false; |
137e05e2 | 253 | if (len > SM_MAXSTRLEN) |
c44b31c2 | 254 | return false; |
137e05e2 CL |
255 | p = xdr_inline_decode(xdr, len); |
256 | if (!p) | |
c44b31c2 | 257 | return false; |
137e05e2 CL |
258 | argp->len = len; |
259 | argp->mon = (char *)p; | |
260 | if (xdr_stream_decode_u32(xdr, &argp->state) < 0) | |
c44b31c2 | 261 | return false; |
137e05e2 CL |
262 | p = xdr_inline_decode(xdr, SM_PRIV_SIZE); |
263 | if (!p) | |
c44b31c2 | 264 | return false; |
137e05e2 CL |
265 | memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); |
266 | ||
c44b31c2 | 267 | return true; |
137e05e2 CL |
268 | } |
269 | ||
c44b31c2 | 270 | bool |
16c66364 | 271 | nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
1da177e4 | 272 | { |
026fec7e | 273 | struct nlm_args *argp = rqstp->rq_argp; |
1da177e4 LT |
274 | struct nlm_lock *lock = &argp->lock; |
275 | ||
276 | memset(lock, 0, sizeof(*lock)); | |
277 | locks_init_lock(&lock->fl); | |
890939e1 | 278 | lock->svid = ~(u32)0; |
1da177e4 | 279 | |
890939e1 | 280 | if (!svcxdr_decode_cookie(xdr, &argp->cookie)) |
c44b31c2 | 281 | return false; |
890939e1 | 282 | if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) |
c44b31c2 | 283 | return false; |
890939e1 | 284 | if (!svcxdr_decode_fhandle(xdr, &lock->fh)) |
c44b31c2 | 285 | return false; |
890939e1 | 286 | if (!svcxdr_decode_owner(xdr, &lock->oh)) |
c44b31c2 | 287 | return false; |
890939e1 CL |
288 | /* XXX: Range checks are missing in the original code */ |
289 | if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) | |
c44b31c2 | 290 | return false; |
890939e1 | 291 | if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) |
c44b31c2 | 292 | return false; |
890939e1 | 293 | |
c44b31c2 | 294 | return true; |
890939e1 CL |
295 | } |
296 | ||
c44b31c2 | 297 | bool |
16c66364 | 298 | nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
14e10525 | 299 | { |
14e10525 CL |
300 | struct nlm_args *argp = rqstp->rq_argp; |
301 | struct nlm_lock *lock = &argp->lock; | |
302 | ||
303 | if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) | |
c44b31c2 | 304 | return false; |
14e10525 | 305 | if (xdr_stream_decode_u32(xdr, &argp->state) < 0) |
c44b31c2 | 306 | return false; |
14e10525 | 307 | |
c44b31c2 | 308 | return true; |
14e10525 CL |
309 | } |
310 | ||
e26ec898 CL |
311 | |
312 | /* | |
313 | * Encode Reply results | |
314 | */ | |
315 | ||
130e2054 | 316 | bool |
fda49441 | 317 | nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
e26ec898 | 318 | { |
130e2054 | 319 | return true; |
e26ec898 CL |
320 | } |
321 | ||
130e2054 | 322 | bool |
fda49441 | 323 | nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
890939e1 CL |
324 | { |
325 | struct nlm_res *resp = rqstp->rq_resp; | |
326 | ||
adf98a48 CL |
327 | return svcxdr_encode_cookie(xdr, &resp->cookie) && |
328 | svcxdr_encode_testrply(xdr, resp); | |
1da177e4 LT |
329 | } |
330 | ||
130e2054 | 331 | bool |
fda49441 | 332 | nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
1da177e4 | 333 | { |
63f8de37 CH |
334 | struct nlm_res *resp = rqstp->rq_resp; |
335 | ||
e96735a6 CL |
336 | return svcxdr_encode_cookie(xdr, &resp->cookie) && |
337 | svcxdr_encode_stats(xdr, resp->status); | |
1da177e4 LT |
338 | } |
339 | ||
130e2054 | 340 | bool |
fda49441 | 341 | nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr) |
1da177e4 | 342 | { |
63f8de37 CH |
343 | struct nlm_res *resp = rqstp->rq_resp; |
344 | ||
529ca3a1 | 345 | if (!svcxdr_encode_cookie(xdr, &resp->cookie)) |
130e2054 | 346 | return false; |
529ca3a1 | 347 | if (!svcxdr_encode_stats(xdr, resp->status)) |
130e2054 | 348 | return false; |
529ca3a1 CL |
349 | /* sequence */ |
350 | if (xdr_stream_encode_u32(xdr, 0) < 0) | |
130e2054 | 351 | return false; |
529ca3a1 | 352 | |
130e2054 | 353 | return true; |
1da177e4 | 354 | } |