]>
Commit | Line | Data |
---|---|---|
ec26815a | 1 | /* AFS Cache Manager Service |
1da177e4 LT |
2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | |
4 | * Written by David Howells ([email protected]) | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the License, or (at your option) any later version. | |
10 | */ | |
11 | ||
12 | #include <linux/module.h> | |
13 | #include <linux/init.h> | |
5a0e3ad6 | 14 | #include <linux/slab.h> |
1da177e4 | 15 | #include <linux/sched.h> |
08e0e7c8 | 16 | #include <linux/ip.h> |
1da177e4 | 17 | #include "internal.h" |
08e0e7c8 | 18 | #include "afs_cm.h" |
1da177e4 | 19 | |
d001648e DH |
20 | static int afs_deliver_cb_init_call_back_state(struct afs_call *); |
21 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *); | |
22 | static int afs_deliver_cb_probe(struct afs_call *); | |
23 | static int afs_deliver_cb_callback(struct afs_call *); | |
24 | static int afs_deliver_cb_probe_uuid(struct afs_call *); | |
25 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *); | |
08e0e7c8 | 26 | static void afs_cm_destructor(struct afs_call *); |
341f741f DH |
27 | static void SRXAFSCB_CallBack(struct work_struct *); |
28 | static void SRXAFSCB_InitCallBackState(struct work_struct *); | |
29 | static void SRXAFSCB_Probe(struct work_struct *); | |
30 | static void SRXAFSCB_ProbeUuid(struct work_struct *); | |
31 | static void SRXAFSCB_TellMeAboutYourself(struct work_struct *); | |
1da177e4 | 32 | |
8e8d7f13 DH |
33 | #define CM_NAME(name) \ |
34 | const char afs_SRXCB##name##_name[] __tracepoint_string = \ | |
35 | "CB." #name | |
36 | ||
1da177e4 | 37 | /* |
08e0e7c8 | 38 | * CB.CallBack operation type |
1da177e4 | 39 | */ |
8e8d7f13 | 40 | static CM_NAME(CallBack); |
08e0e7c8 | 41 | static const struct afs_call_type afs_SRXCBCallBack = { |
8e8d7f13 | 42 | .name = afs_SRXCBCallBack_name, |
08e0e7c8 | 43 | .deliver = afs_deliver_cb_callback, |
08e0e7c8 | 44 | .destructor = afs_cm_destructor, |
341f741f | 45 | .work = SRXAFSCB_CallBack, |
08e0e7c8 | 46 | }; |
1da177e4 | 47 | |
1da177e4 | 48 | /* |
08e0e7c8 | 49 | * CB.InitCallBackState operation type |
1da177e4 | 50 | */ |
8e8d7f13 | 51 | static CM_NAME(InitCallBackState); |
08e0e7c8 | 52 | static const struct afs_call_type afs_SRXCBInitCallBackState = { |
8e8d7f13 | 53 | .name = afs_SRXCBInitCallBackState_name, |
08e0e7c8 | 54 | .deliver = afs_deliver_cb_init_call_back_state, |
08e0e7c8 | 55 | .destructor = afs_cm_destructor, |
341f741f | 56 | .work = SRXAFSCB_InitCallBackState, |
08e0e7c8 | 57 | }; |
1da177e4 | 58 | |
c35eccb1 DH |
59 | /* |
60 | * CB.InitCallBackState3 operation type | |
61 | */ | |
8e8d7f13 | 62 | static CM_NAME(InitCallBackState3); |
c35eccb1 | 63 | static const struct afs_call_type afs_SRXCBInitCallBackState3 = { |
8e8d7f13 | 64 | .name = afs_SRXCBInitCallBackState3_name, |
c35eccb1 | 65 | .deliver = afs_deliver_cb_init_call_back_state3, |
c35eccb1 | 66 | .destructor = afs_cm_destructor, |
341f741f | 67 | .work = SRXAFSCB_InitCallBackState, |
c35eccb1 DH |
68 | }; |
69 | ||
1da177e4 | 70 | /* |
08e0e7c8 | 71 | * CB.Probe operation type |
1da177e4 | 72 | */ |
8e8d7f13 | 73 | static CM_NAME(Probe); |
08e0e7c8 | 74 | static const struct afs_call_type afs_SRXCBProbe = { |
8e8d7f13 | 75 | .name = afs_SRXCBProbe_name, |
08e0e7c8 | 76 | .deliver = afs_deliver_cb_probe, |
08e0e7c8 | 77 | .destructor = afs_cm_destructor, |
341f741f | 78 | .work = SRXAFSCB_Probe, |
08e0e7c8 | 79 | }; |
1da177e4 | 80 | |
9396d496 DH |
81 | /* |
82 | * CB.ProbeUuid operation type | |
83 | */ | |
8e8d7f13 | 84 | static CM_NAME(ProbeUuid); |
9396d496 | 85 | static const struct afs_call_type afs_SRXCBProbeUuid = { |
8e8d7f13 | 86 | .name = afs_SRXCBProbeUuid_name, |
9396d496 | 87 | .deliver = afs_deliver_cb_probe_uuid, |
9396d496 | 88 | .destructor = afs_cm_destructor, |
341f741f | 89 | .work = SRXAFSCB_ProbeUuid, |
9396d496 DH |
90 | }; |
91 | ||
b908fe6b | 92 | /* |
7c80bcce | 93 | * CB.TellMeAboutYourself operation type |
b908fe6b | 94 | */ |
8e8d7f13 | 95 | static CM_NAME(TellMeAboutYourself); |
7c80bcce | 96 | static const struct afs_call_type afs_SRXCBTellMeAboutYourself = { |
8e8d7f13 | 97 | .name = afs_SRXCBTellMeAboutYourself_name, |
7c80bcce | 98 | .deliver = afs_deliver_cb_tell_me_about_yourself, |
b908fe6b | 99 | .destructor = afs_cm_destructor, |
341f741f | 100 | .work = SRXAFSCB_TellMeAboutYourself, |
b908fe6b DH |
101 | }; |
102 | ||
1da177e4 | 103 | /* |
08e0e7c8 DH |
104 | * route an incoming cache manager call |
105 | * - return T if supported, F if not | |
1da177e4 | 106 | */ |
08e0e7c8 | 107 | bool afs_cm_incoming_call(struct afs_call *call) |
1da177e4 | 108 | { |
50a2c953 | 109 | _enter("{CB.OP %u}", call->operation_ID); |
08e0e7c8 | 110 | |
50a2c953 | 111 | switch (call->operation_ID) { |
08e0e7c8 DH |
112 | case CBCallBack: |
113 | call->type = &afs_SRXCBCallBack; | |
114 | return true; | |
115 | case CBInitCallBackState: | |
116 | call->type = &afs_SRXCBInitCallBackState; | |
117 | return true; | |
c35eccb1 DH |
118 | case CBInitCallBackState3: |
119 | call->type = &afs_SRXCBInitCallBackState3; | |
120 | return true; | |
08e0e7c8 DH |
121 | case CBProbe: |
122 | call->type = &afs_SRXCBProbe; | |
123 | return true; | |
f4b3526d DH |
124 | case CBProbeUuid: |
125 | call->type = &afs_SRXCBProbeUuid; | |
126 | return true; | |
7c80bcce DH |
127 | case CBTellMeAboutYourself: |
128 | call->type = &afs_SRXCBTellMeAboutYourself; | |
b908fe6b | 129 | return true; |
08e0e7c8 DH |
130 | default: |
131 | return false; | |
1da177e4 | 132 | } |
ec26815a | 133 | } |
1da177e4 | 134 | |
1da177e4 | 135 | /* |
428edade | 136 | * Clean up a cache manager call. |
1da177e4 | 137 | */ |
08e0e7c8 | 138 | static void afs_cm_destructor(struct afs_call *call) |
1da177e4 | 139 | { |
08e0e7c8 DH |
140 | kfree(call->buffer); |
141 | call->buffer = NULL; | |
ec26815a | 142 | } |
1da177e4 | 143 | |
1da177e4 | 144 | /* |
c435ee34 | 145 | * The server supplied a list of callbacks that it wanted to break. |
1da177e4 | 146 | */ |
08e0e7c8 | 147 | static void SRXAFSCB_CallBack(struct work_struct *work) |
1da177e4 | 148 | { |
08e0e7c8 | 149 | struct afs_call *call = container_of(work, struct afs_call, work); |
1da177e4 | 150 | |
08e0e7c8 | 151 | _enter(""); |
1da177e4 | 152 | |
428edade DH |
153 | /* We need to break the callbacks before sending the reply as the |
154 | * server holds up change visibility till it receives our reply so as | |
155 | * to maintain cache coherency. | |
156 | */ | |
a86b06d1 DH |
157 | if (call->cm_server) |
158 | afs_break_callbacks(call->cm_server, call->count, call->request); | |
428edade DH |
159 | |
160 | afs_send_empty_reply(call); | |
341f741f | 161 | afs_put_call(call); |
08e0e7c8 | 162 | _leave(""); |
ec26815a | 163 | } |
1da177e4 | 164 | |
1da177e4 | 165 | /* |
08e0e7c8 | 166 | * deliver request data to a CB.CallBack call |
1da177e4 | 167 | */ |
d001648e | 168 | static int afs_deliver_cb_callback(struct afs_call *call) |
1da177e4 | 169 | { |
5cf9dd55 | 170 | struct afs_callback_break *cb; |
8324f0bc | 171 | struct sockaddr_rxrpc srx; |
08e0e7c8 | 172 | __be32 *bp; |
08e0e7c8 DH |
173 | int ret, loop; |
174 | ||
d001648e | 175 | _enter("{%u}", call->unmarshall); |
08e0e7c8 DH |
176 | |
177 | switch (call->unmarshall) { | |
178 | case 0: | |
179 | call->offset = 0; | |
180 | call->unmarshall++; | |
181 | ||
182 | /* extract the FID array and its count in two steps */ | |
183 | case 1: | |
184 | _debug("extract FID count"); | |
d001648e | 185 | ret = afs_extract_data(call, &call->tmp, 4, true); |
372ee163 DH |
186 | if (ret < 0) |
187 | return ret; | |
1da177e4 | 188 | |
08e0e7c8 DH |
189 | call->count = ntohl(call->tmp); |
190 | _debug("FID count: %u", call->count); | |
191 | if (call->count > AFSCBMAX) | |
5f702c8e | 192 | return afs_protocol_error(call, -EBADMSG); |
08e0e7c8 | 193 | |
6da2ec56 KC |
194 | call->buffer = kmalloc(array3_size(call->count, 3, 4), |
195 | GFP_KERNEL); | |
08e0e7c8 DH |
196 | if (!call->buffer) |
197 | return -ENOMEM; | |
198 | call->offset = 0; | |
199 | call->unmarshall++; | |
200 | ||
201 | case 2: | |
202 | _debug("extract FID array"); | |
d001648e DH |
203 | ret = afs_extract_data(call, call->buffer, |
204 | call->count * 3 * 4, true); | |
372ee163 DH |
205 | if (ret < 0) |
206 | return ret; | |
1da177e4 | 207 | |
08e0e7c8 DH |
208 | _debug("unmarshall FID array"); |
209 | call->request = kcalloc(call->count, | |
5cf9dd55 | 210 | sizeof(struct afs_callback_break), |
08e0e7c8 DH |
211 | GFP_KERNEL); |
212 | if (!call->request) | |
213 | return -ENOMEM; | |
214 | ||
215 | cb = call->request; | |
216 | bp = call->buffer; | |
217 | for (loop = call->count; loop > 0; loop--, cb++) { | |
218 | cb->fid.vid = ntohl(*bp++); | |
219 | cb->fid.vnode = ntohl(*bp++); | |
220 | cb->fid.unique = ntohl(*bp++); | |
5cf9dd55 | 221 | cb->cb.type = AFSCM_CB_UNTYPED; |
1da177e4 LT |
222 | } |
223 | ||
08e0e7c8 DH |
224 | call->offset = 0; |
225 | call->unmarshall++; | |
226 | ||
227 | /* extract the callback array and its count in two steps */ | |
228 | case 3: | |
229 | _debug("extract CB count"); | |
d001648e | 230 | ret = afs_extract_data(call, &call->tmp, 4, true); |
372ee163 DH |
231 | if (ret < 0) |
232 | return ret; | |
1da177e4 | 233 | |
bcd89270 MD |
234 | call->count2 = ntohl(call->tmp); |
235 | _debug("CB count: %u", call->count2); | |
236 | if (call->count2 != call->count && call->count2 != 0) | |
5f702c8e | 237 | return afs_protocol_error(call, -EBADMSG); |
08e0e7c8 DH |
238 | call->offset = 0; |
239 | call->unmarshall++; | |
08e0e7c8 DH |
240 | |
241 | case 4: | |
242 | _debug("extract CB array"); | |
d001648e | 243 | ret = afs_extract_data(call, call->buffer, |
bcd89270 | 244 | call->count2 * 3 * 4, false); |
372ee163 DH |
245 | if (ret < 0) |
246 | return ret; | |
1da177e4 | 247 | |
08e0e7c8 DH |
248 | _debug("unmarshall CB array"); |
249 | cb = call->request; | |
250 | bp = call->buffer; | |
bcd89270 | 251 | for (loop = call->count2; loop > 0; loop--, cb++) { |
5cf9dd55 DH |
252 | cb->cb.version = ntohl(*bp++); |
253 | cb->cb.expiry = ntohl(*bp++); | |
254 | cb->cb.type = ntohl(*bp++); | |
08e0e7c8 | 255 | } |
1da177e4 | 256 | |
08e0e7c8 DH |
257 | call->offset = 0; |
258 | call->unmarshall++; | |
d001648e | 259 | case 5: |
1da177e4 LT |
260 | break; |
261 | } | |
262 | ||
98bf40cd DH |
263 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
264 | return -EIO; | |
1da177e4 | 265 | |
08e0e7c8 DH |
266 | /* we'll need the file server record as that tells us which set of |
267 | * vnodes to operate upon */ | |
98bf40cd | 268 | rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx); |
a86b06d1 DH |
269 | call->cm_server = afs_find_server(call->net, &srx); |
270 | if (!call->cm_server) | |
3709a399 | 271 | trace_afs_cm_no_server(call, &srx); |
08e0e7c8 | 272 | |
341f741f | 273 | return afs_queue_call_work(call); |
ec26815a | 274 | } |
1da177e4 | 275 | |
1da177e4 | 276 | /* |
08e0e7c8 | 277 | * allow the fileserver to request callback state (re-)initialisation |
1da177e4 | 278 | */ |
08e0e7c8 | 279 | static void SRXAFSCB_InitCallBackState(struct work_struct *work) |
1da177e4 | 280 | { |
08e0e7c8 | 281 | struct afs_call *call = container_of(work, struct afs_call, work); |
1da177e4 | 282 | |
d0676a16 | 283 | _enter("{%p}", call->cm_server); |
1da177e4 | 284 | |
a86b06d1 DH |
285 | if (call->cm_server) |
286 | afs_init_callback_state(call->cm_server); | |
08e0e7c8 | 287 | afs_send_empty_reply(call); |
341f741f | 288 | afs_put_call(call); |
08e0e7c8 | 289 | _leave(""); |
ec26815a | 290 | } |
1da177e4 | 291 | |
1da177e4 | 292 | /* |
08e0e7c8 | 293 | * deliver request data to a CB.InitCallBackState call |
1da177e4 | 294 | */ |
d001648e | 295 | static int afs_deliver_cb_init_call_back_state(struct afs_call *call) |
1da177e4 | 296 | { |
8324f0bc | 297 | struct sockaddr_rxrpc srx; |
372ee163 | 298 | int ret; |
1da177e4 | 299 | |
d001648e | 300 | _enter(""); |
1da177e4 | 301 | |
f044c884 | 302 | rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx); |
8324f0bc | 303 | |
d001648e | 304 | ret = afs_extract_data(call, NULL, 0, false); |
372ee163 DH |
305 | if (ret < 0) |
306 | return ret; | |
1da177e4 | 307 | |
08e0e7c8 DH |
308 | /* we'll need the file server record as that tells us which set of |
309 | * vnodes to operate upon */ | |
a86b06d1 DH |
310 | call->cm_server = afs_find_server(call->net, &srx); |
311 | if (!call->cm_server) | |
3709a399 | 312 | trace_afs_cm_no_server(call, &srx); |
1da177e4 | 313 | |
341f741f | 314 | return afs_queue_call_work(call); |
08e0e7c8 | 315 | } |
1da177e4 | 316 | |
c35eccb1 DH |
317 | /* |
318 | * deliver request data to a CB.InitCallBackState3 call | |
319 | */ | |
d001648e | 320 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) |
c35eccb1 | 321 | { |
41bb26f8 | 322 | struct afs_uuid *r; |
d001648e DH |
323 | unsigned loop; |
324 | __be32 *b; | |
325 | int ret; | |
c35eccb1 | 326 | |
d001648e | 327 | _enter(""); |
c35eccb1 | 328 | |
d001648e DH |
329 | _enter("{%u}", call->unmarshall); |
330 | ||
331 | switch (call->unmarshall) { | |
332 | case 0: | |
333 | call->offset = 0; | |
6da2ec56 | 334 | call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL); |
d001648e DH |
335 | if (!call->buffer) |
336 | return -ENOMEM; | |
337 | call->unmarshall++; | |
338 | ||
339 | case 1: | |
340 | _debug("extract UUID"); | |
341 | ret = afs_extract_data(call, call->buffer, | |
342 | 11 * sizeof(__be32), false); | |
343 | switch (ret) { | |
344 | case 0: break; | |
345 | case -EAGAIN: return 0; | |
346 | default: return ret; | |
347 | } | |
348 | ||
349 | _debug("unmarshall UUID"); | |
41bb26f8 | 350 | call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL); |
d001648e DH |
351 | if (!call->request) |
352 | return -ENOMEM; | |
353 | ||
354 | b = call->buffer; | |
355 | r = call->request; | |
ff548773 DH |
356 | r->time_low = b[0]; |
357 | r->time_mid = htons(ntohl(b[1])); | |
358 | r->time_hi_and_version = htons(ntohl(b[2])); | |
d001648e DH |
359 | r->clock_seq_hi_and_reserved = ntohl(b[3]); |
360 | r->clock_seq_low = ntohl(b[4]); | |
361 | ||
362 | for (loop = 0; loop < 6; loop++) | |
363 | r->node[loop] = ntohl(b[loop + 5]); | |
364 | ||
365 | call->offset = 0; | |
366 | call->unmarshall++; | |
367 | ||
368 | case 2: | |
369 | break; | |
370 | } | |
c35eccb1 | 371 | |
98bf40cd DH |
372 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
373 | return -EIO; | |
c35eccb1 DH |
374 | |
375 | /* we'll need the file server record as that tells us which set of | |
376 | * vnodes to operate upon */ | |
001ab5a6 | 377 | rcu_read_lock(); |
a86b06d1 | 378 | call->cm_server = afs_find_server_by_uuid(call->net, call->request); |
001ab5a6 | 379 | rcu_read_unlock(); |
a86b06d1 | 380 | if (!call->cm_server) |
3709a399 | 381 | trace_afs_cm_no_server_u(call, call->request); |
c35eccb1 | 382 | |
341f741f | 383 | return afs_queue_call_work(call); |
c35eccb1 DH |
384 | } |
385 | ||
08e0e7c8 DH |
386 | /* |
387 | * allow the fileserver to see if the cache manager is still alive | |
388 | */ | |
389 | static void SRXAFSCB_Probe(struct work_struct *work) | |
390 | { | |
391 | struct afs_call *call = container_of(work, struct afs_call, work); | |
1da177e4 | 392 | |
08e0e7c8 DH |
393 | _enter(""); |
394 | afs_send_empty_reply(call); | |
341f741f | 395 | afs_put_call(call); |
08e0e7c8 DH |
396 | _leave(""); |
397 | } | |
1da177e4 | 398 | |
08e0e7c8 DH |
399 | /* |
400 | * deliver request data to a CB.Probe call | |
401 | */ | |
d001648e | 402 | static int afs_deliver_cb_probe(struct afs_call *call) |
08e0e7c8 | 403 | { |
372ee163 DH |
404 | int ret; |
405 | ||
d001648e | 406 | _enter(""); |
1da177e4 | 407 | |
d001648e | 408 | ret = afs_extract_data(call, NULL, 0, false); |
372ee163 DH |
409 | if (ret < 0) |
410 | return ret; | |
1da177e4 | 411 | |
98bf40cd DH |
412 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
413 | return -EIO; | |
1da177e4 | 414 | |
341f741f | 415 | return afs_queue_call_work(call); |
ec26815a | 416 | } |
b908fe6b | 417 | |
9396d496 DH |
418 | /* |
419 | * allow the fileserver to quickly find out if the fileserver has been rebooted | |
420 | */ | |
421 | static void SRXAFSCB_ProbeUuid(struct work_struct *work) | |
422 | { | |
423 | struct afs_call *call = container_of(work, struct afs_call, work); | |
41bb26f8 | 424 | struct afs_uuid *r = call->request; |
9396d496 DH |
425 | |
426 | struct { | |
427 | __be32 match; | |
428 | } reply; | |
429 | ||
430 | _enter(""); | |
431 | ||
f044c884 | 432 | if (memcmp(r, &call->net->uuid, sizeof(call->net->uuid)) == 0) |
9396d496 DH |
433 | reply.match = htonl(0); |
434 | else | |
435 | reply.match = htonl(1); | |
436 | ||
437 | afs_send_simple_reply(call, &reply, sizeof(reply)); | |
341f741f | 438 | afs_put_call(call); |
9396d496 DH |
439 | _leave(""); |
440 | } | |
441 | ||
442 | /* | |
443 | * deliver request data to a CB.ProbeUuid call | |
444 | */ | |
d001648e | 445 | static int afs_deliver_cb_probe_uuid(struct afs_call *call) |
9396d496 | 446 | { |
41bb26f8 | 447 | struct afs_uuid *r; |
9396d496 DH |
448 | unsigned loop; |
449 | __be32 *b; | |
450 | int ret; | |
451 | ||
d001648e | 452 | _enter("{%u}", call->unmarshall); |
9396d496 DH |
453 | |
454 | switch (call->unmarshall) { | |
455 | case 0: | |
456 | call->offset = 0; | |
6da2ec56 | 457 | call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL); |
9396d496 DH |
458 | if (!call->buffer) |
459 | return -ENOMEM; | |
460 | call->unmarshall++; | |
461 | ||
462 | case 1: | |
463 | _debug("extract UUID"); | |
d001648e DH |
464 | ret = afs_extract_data(call, call->buffer, |
465 | 11 * sizeof(__be32), false); | |
9396d496 DH |
466 | switch (ret) { |
467 | case 0: break; | |
468 | case -EAGAIN: return 0; | |
469 | default: return ret; | |
470 | } | |
471 | ||
472 | _debug("unmarshall UUID"); | |
41bb26f8 | 473 | call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL); |
9396d496 DH |
474 | if (!call->request) |
475 | return -ENOMEM; | |
476 | ||
477 | b = call->buffer; | |
478 | r = call->request; | |
fe342cf7 DH |
479 | r->time_low = b[0]; |
480 | r->time_mid = htons(ntohl(b[1])); | |
481 | r->time_hi_and_version = htons(ntohl(b[2])); | |
9396d496 DH |
482 | r->clock_seq_hi_and_reserved = ntohl(b[3]); |
483 | r->clock_seq_low = ntohl(b[4]); | |
484 | ||
485 | for (loop = 0; loop < 6; loop++) | |
486 | r->node[loop] = ntohl(b[loop + 5]); | |
487 | ||
488 | call->offset = 0; | |
489 | call->unmarshall++; | |
490 | ||
491 | case 2: | |
9396d496 DH |
492 | break; |
493 | } | |
494 | ||
98bf40cd DH |
495 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
496 | return -EIO; | |
9396d496 | 497 | |
341f741f | 498 | return afs_queue_call_work(call); |
9396d496 DH |
499 | } |
500 | ||
b908fe6b DH |
501 | /* |
502 | * allow the fileserver to ask about the cache manager's capabilities | |
503 | */ | |
7c80bcce | 504 | static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work) |
b908fe6b DH |
505 | { |
506 | struct afs_interface *ifs; | |
507 | struct afs_call *call = container_of(work, struct afs_call, work); | |
508 | int loop, nifs; | |
509 | ||
510 | struct { | |
511 | struct /* InterfaceAddr */ { | |
512 | __be32 nifs; | |
513 | __be32 uuid[11]; | |
514 | __be32 ifaddr[32]; | |
515 | __be32 netmask[32]; | |
516 | __be32 mtu[32]; | |
517 | } ia; | |
518 | struct /* Capabilities */ { | |
519 | __be32 capcount; | |
520 | __be32 caps[1]; | |
521 | } cap; | |
522 | } reply; | |
523 | ||
524 | _enter(""); | |
525 | ||
526 | nifs = 0; | |
527 | ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL); | |
528 | if (ifs) { | |
5b86d4ff | 529 | nifs = afs_get_ipv4_interfaces(call->net, ifs, 32, false); |
b908fe6b DH |
530 | if (nifs < 0) { |
531 | kfree(ifs); | |
532 | ifs = NULL; | |
533 | nifs = 0; | |
534 | } | |
535 | } | |
536 | ||
537 | memset(&reply, 0, sizeof(reply)); | |
538 | reply.ia.nifs = htonl(nifs); | |
539 | ||
f044c884 DH |
540 | reply.ia.uuid[0] = call->net->uuid.time_low; |
541 | reply.ia.uuid[1] = htonl(ntohs(call->net->uuid.time_mid)); | |
542 | reply.ia.uuid[2] = htonl(ntohs(call->net->uuid.time_hi_and_version)); | |
543 | reply.ia.uuid[3] = htonl((s8) call->net->uuid.clock_seq_hi_and_reserved); | |
544 | reply.ia.uuid[4] = htonl((s8) call->net->uuid.clock_seq_low); | |
b908fe6b | 545 | for (loop = 0; loop < 6; loop++) |
f044c884 | 546 | reply.ia.uuid[loop + 5] = htonl((s8) call->net->uuid.node[loop]); |
b908fe6b DH |
547 | |
548 | if (ifs) { | |
549 | for (loop = 0; loop < nifs; loop++) { | |
550 | reply.ia.ifaddr[loop] = ifs[loop].address.s_addr; | |
551 | reply.ia.netmask[loop] = ifs[loop].netmask.s_addr; | |
552 | reply.ia.mtu[loop] = htonl(ifs[loop].mtu); | |
553 | } | |
5b35fad9 | 554 | kfree(ifs); |
b908fe6b DH |
555 | } |
556 | ||
557 | reply.cap.capcount = htonl(1); | |
558 | reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); | |
559 | afs_send_simple_reply(call, &reply, sizeof(reply)); | |
341f741f | 560 | afs_put_call(call); |
b908fe6b DH |
561 | _leave(""); |
562 | } | |
563 | ||
564 | /* | |
7c80bcce | 565 | * deliver request data to a CB.TellMeAboutYourself call |
b908fe6b | 566 | */ |
d001648e | 567 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call) |
b908fe6b | 568 | { |
372ee163 DH |
569 | int ret; |
570 | ||
d001648e | 571 | _enter(""); |
b908fe6b | 572 | |
d001648e | 573 | ret = afs_extract_data(call, NULL, 0, false); |
372ee163 DH |
574 | if (ret < 0) |
575 | return ret; | |
b908fe6b | 576 | |
98bf40cd DH |
577 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
578 | return -EIO; | |
b908fe6b | 579 | |
341f741f | 580 | return afs_queue_call_work(call); |
b908fe6b | 581 | } |