1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Witness Service client for CIFS
4 *
5 * Copyright (c) 2020 Samuel Cabrero <scabrero@suse.de>
6 */
7
8 #include <linux/kref.h>
9 #include <net/genetlink.h>
10 #include <uapi/linux/cifs/cifs_netlink.h>
11
12 #include "cifs_swn.h"
13 #include "cifsglob.h"
14 #include "cifsproto.h"
15 #include "fscache.h"
16 #include "cifs_debug.h"
17 #include "netlink.h"
18
19 static DEFINE_IDR(cifs_swnreg_idr);
20 static DEFINE_MUTEX(cifs_swnreg_idr_mutex);
21
22 struct cifs_swn_reg {
23 int id;
24 struct kref ref_count;
25
26 const char *net_name;
27 const char *share_name;
28 bool net_name_notify;
29 bool share_name_notify;
30 bool ip_notify;
31 };
32
33 struct cifs_swn_reg_info {
34 int id;
35 unsigned int ref_count;
36 const char *net_name;
37 const char *share_name;
38 bool net_name_notify;
39 bool share_name_notify;
40 bool ip_notify;
41 };
42
cifs_swn_snapshot_reg(struct cifs_swn_reg * swnreg,struct cifs_swn_reg_info * info)43 static void cifs_swn_snapshot_reg(struct cifs_swn_reg *swnreg,
44 struct cifs_swn_reg_info *info)
45 {
46 info->id = swnreg->id;
47 info->ref_count = kref_read(&swnreg->ref_count);
48 info->net_name = swnreg->net_name;
49 info->share_name = swnreg->share_name;
50 info->net_name_notify = swnreg->net_name_notify;
51 info->share_name_notify = swnreg->share_name_notify;
52 info->ip_notify = swnreg->ip_notify;
53 }
54
cifs_swn_dup_reg(struct cifs_swn_reg * swnreg,struct cifs_swn_reg_info * info)55 static int cifs_swn_dup_reg(struct cifs_swn_reg *swnreg,
56 struct cifs_swn_reg_info *info)
57 {
58 cifs_swn_snapshot_reg(swnreg, info);
59
60 info->net_name = kstrdup(swnreg->net_name, GFP_KERNEL);
61 if (!info->net_name)
62 return -ENOMEM;
63
64 info->share_name = kstrdup(swnreg->share_name, GFP_KERNEL);
65 if (!info->share_name) {
66 kfree(info->net_name);
67 return -ENOMEM;
68 }
69
70 return 0;
71 }
72
cifs_swn_free_reg_info(struct cifs_swn_reg_info * info)73 static void cifs_swn_free_reg_info(struct cifs_swn_reg_info *info)
74 {
75 kfree(info->net_name);
76 kfree(info->share_name);
77 }
78
cifs_swn_auth_info_krb(struct cifs_tcon * tcon,struct sk_buff * skb)79 static int cifs_swn_auth_info_krb(struct cifs_tcon *tcon, struct sk_buff *skb)
80 {
81 int ret;
82
83 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_KRB_AUTH);
84 if (ret < 0)
85 return ret;
86
87 return 0;
88 }
89
cifs_swn_auth_info_ntlm(struct cifs_tcon * tcon,struct sk_buff * skb)90 static int cifs_swn_auth_info_ntlm(struct cifs_tcon *tcon, struct sk_buff *skb)
91 {
92 int ret;
93
94 if (tcon->ses->user_name != NULL) {
95 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_USER_NAME, tcon->ses->user_name);
96 if (ret < 0)
97 return ret;
98 }
99
100 if (tcon->ses->password != NULL) {
101 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_PASSWORD, tcon->ses->password);
102 if (ret < 0)
103 return ret;
104 }
105
106 if (tcon->ses->domainName != NULL) {
107 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_DOMAIN_NAME, tcon->ses->domainName);
108 if (ret < 0)
109 return ret;
110 }
111
112 return 0;
113 }
114
115 /*
116 * Sends a register message to the userspace daemon based on the registration.
117 * The authentication information to connect to the witness service is bundled
118 * into the message.
119 */
cifs_swn_send_register_message(struct cifs_swn_reg_info * swnreg,struct cifs_tcon * tcon)120 static int cifs_swn_send_register_message(struct cifs_swn_reg_info *swnreg,
121 struct cifs_tcon *tcon)
122 {
123 struct sk_buff *skb;
124 struct genlmsghdr *hdr;
125 enum securityEnum authtype;
126 struct sockaddr_storage *addr;
127 int ret;
128
129 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
130 if (!skb)
131 return -ENOMEM;
132
133 hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_REGISTER);
134 if (hdr == NULL) {
135 ret = -ENOMEM;
136 goto nlmsg_fail;
137 }
138
139 ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id);
140 if (ret < 0)
141 goto nlmsg_fail;
142
143 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name);
144 if (ret < 0)
145 goto nlmsg_fail;
146
147 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name);
148 if (ret < 0)
149 goto nlmsg_fail;
150
151 /*
152 * If there is an address stored use it instead of the server address, because we are
153 * in the process of reconnecting to it after a share has been moved or we have been
154 * told to switch to it (client move message). In these cases we unregister from the
155 * server address and register to the new address when we receive the notification.
156 */
157 if (tcon->ses->server->use_swn_dstaddr)
158 addr = &tcon->ses->server->swn_dstaddr;
159 else
160 addr = &tcon->ses->server->dstaddr;
161
162 ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), addr);
163 if (ret < 0)
164 goto nlmsg_fail;
165
166 if (swnreg->net_name_notify) {
167 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY);
168 if (ret < 0)
169 goto nlmsg_fail;
170 }
171
172 if (swnreg->share_name_notify) {
173 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY);
174 if (ret < 0)
175 goto nlmsg_fail;
176 }
177
178 if (swnreg->ip_notify) {
179 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY);
180 if (ret < 0)
181 goto nlmsg_fail;
182 }
183
184 authtype = cifs_select_sectype(tcon->ses->server, tcon->ses->sectype);
185 switch (authtype) {
186 case Kerberos:
187 ret = cifs_swn_auth_info_krb(tcon, skb);
188 if (ret < 0) {
189 cifs_dbg(VFS, "%s: Failed to get kerberos auth info: %d\n", __func__, ret);
190 goto nlmsg_fail;
191 }
192 break;
193 case NTLMv2:
194 case RawNTLMSSP:
195 ret = cifs_swn_auth_info_ntlm(tcon, skb);
196 if (ret < 0) {
197 cifs_dbg(VFS, "%s: Failed to get NTLM auth info: %d\n", __func__, ret);
198 goto nlmsg_fail;
199 }
200 break;
201 default:
202 cifs_dbg(VFS, "%s: secType %d not supported!\n", __func__, authtype);
203 ret = -EINVAL;
204 goto nlmsg_fail;
205 }
206
207 genlmsg_end(skb, hdr);
208 genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC);
209
210 cifs_dbg(FYI, "%s: Message to register for network name %s with id %d sent\n", __func__,
211 swnreg->net_name, swnreg->id);
212
213 return 0;
214
215 nlmsg_fail:
216 genlmsg_cancel(skb, hdr);
217 nlmsg_free(skb);
218 return ret;
219 }
220
221 /*
222 * Sends an uregister message to the userspace daemon based on the registration
223 */
cifs_swn_send_unregister_message(struct cifs_swn_reg_info * swnreg,struct cifs_tcon * tcon)224 static int cifs_swn_send_unregister_message(struct cifs_swn_reg_info *swnreg,
225 struct cifs_tcon *tcon)
226 {
227 struct sk_buff *skb;
228 struct genlmsghdr *hdr;
229 int ret;
230
231 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
232 if (skb == NULL)
233 return -ENOMEM;
234
235 hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_UNREGISTER);
236 if (hdr == NULL) {
237 ret = -ENOMEM;
238 goto nlmsg_fail;
239 }
240
241 ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id);
242 if (ret < 0)
243 goto nlmsg_fail;
244
245 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name);
246 if (ret < 0)
247 goto nlmsg_fail;
248
249 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name);
250 if (ret < 0)
251 goto nlmsg_fail;
252
253 ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage),
254 &tcon->ses->server->dstaddr);
255 if (ret < 0)
256 goto nlmsg_fail;
257
258 if (swnreg->net_name_notify) {
259 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY);
260 if (ret < 0)
261 goto nlmsg_fail;
262 }
263
264 if (swnreg->share_name_notify) {
265 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY);
266 if (ret < 0)
267 goto nlmsg_fail;
268 }
269
270 if (swnreg->ip_notify) {
271 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY);
272 if (ret < 0)
273 goto nlmsg_fail;
274 }
275
276 genlmsg_end(skb, hdr);
277 genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC);
278
279 cifs_dbg(FYI, "%s: Message to unregister for network name %s with id %d sent\n", __func__,
280 swnreg->net_name, swnreg->id);
281
282 return 0;
283
284 nlmsg_fail:
285 genlmsg_cancel(skb, hdr);
286 nlmsg_free(skb);
287 return ret;
288 }
289
290 /*
291 * Allocation-free mirror of extract_hostname() + extract_sharename() from
292 * fs/smb/client/unc.c. Those helpers kmalloc(GFP_KERNEL); this runs under
293 * cifs_tcp_ses_lock and tcon->tc_lock, both spinlocks, so we mirror their
294 * parsing in place against the caller's stable net_name/share_name strings.
295 * Keep in sync with unc.c.
296 */
cifs_swn_tcon_matches(struct cifs_tcon * tcon,const char * net_name,const char * share_name)297 static bool cifs_swn_tcon_matches(struct cifs_tcon *tcon,
298 const char *net_name,
299 const char *share_name)
300 {
301 const char *unc = tcon->tree_name;
302 const char *host, *share, *delim;
303 size_t host_len, share_len;
304
305 if (!tcon->use_witness)
306 return false;
307
308 /* extract_hostname: require strlen(unc) >= 3 */
309 if (strnlen(unc, 3) < 3)
310 return false;
311 /* extract_hostname: skip all leading '\' characters */
312 for (host = unc; *host == '\\'; host++)
313 ;
314 if (!*host)
315 return false;
316 delim = strchr(host, '\\');
317 if (!delim)
318 return false;
319 host_len = delim - host;
320 if (strlen(net_name) != host_len ||
321 strncasecmp(host, net_name, host_len))
322 return false;
323
324 /* extract_sharename: start at unc + 2, then first '\' onward */
325 share = unc + 2;
326 delim = strchr(share, '\\');
327 if (!delim)
328 return false;
329 share = delim + 1;
330 share_len = strlen(share);
331
332 return strlen(share_name) == share_len &&
333 !strncasecmp(share, share_name, share_len);
334 }
335
336 /*
337 * One SWN registration id represents one net/share name pair. Multiple
338 * mounted tcons can therefore share the id. Pick a live representative at
339 * use time instead of caching the first tcon pointer in the registration.
340 */
cifs_swn_get_tcon(struct cifs_swn_reg_info * swnreg)341 static struct cifs_tcon *cifs_swn_get_tcon(struct cifs_swn_reg_info *swnreg)
342 {
343 struct TCP_Server_Info *server;
344 struct cifs_ses *ses;
345 struct cifs_tcon *tcon;
346
347 spin_lock(&cifs_tcp_ses_lock);
348 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
349 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
350 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
351 spin_lock(&tcon->tc_lock);
352 if (tcon->status == TID_EXITING ||
353 !cifs_swn_tcon_matches(tcon, swnreg->net_name,
354 swnreg->share_name)) {
355 spin_unlock(&tcon->tc_lock);
356 continue;
357 }
358 ++tcon->tc_count;
359 trace_smb3_tcon_ref(tcon->debug_id,
360 tcon->tc_count,
361 netfs_trace_tcon_ref_get_swn_notify);
362 spin_unlock(&tcon->tc_lock);
363 spin_unlock(&cifs_tcp_ses_lock);
364 return tcon;
365 }
366 }
367 }
368 spin_unlock(&cifs_tcp_ses_lock);
369 return NULL;
370 }
371
372 /*
373 * Try to find a matching registration for the tcon's server name and share name.
374 * Calls to this function must be protected by cifs_swnreg_idr_mutex.
375 * TODO Try to avoid memory allocations
376 */
cifs_find_swn_reg(struct cifs_tcon * tcon)377 static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon)
378 {
379 struct cifs_swn_reg *swnreg;
380 int id;
381 const char *share_name;
382 const char *net_name;
383
384 net_name = extract_hostname(tcon->tree_name);
385 if (IS_ERR(net_name)) {
386 int ret;
387
388 ret = PTR_ERR(net_name);
389 cifs_dbg(VFS, "%s: failed to extract host name from target '%s': %d\n",
390 __func__, tcon->tree_name, ret);
391 return ERR_PTR(-EINVAL);
392 }
393
394 share_name = extract_sharename(tcon->tree_name);
395 if (IS_ERR(share_name)) {
396 int ret;
397
398 ret = PTR_ERR(share_name);
399 cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n",
400 __func__, tcon->tree_name, ret);
401 kfree(net_name);
402 return ERR_PTR(-EINVAL);
403 }
404
405 idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) {
406 if (strcasecmp(swnreg->net_name, net_name) != 0
407 || strcasecmp(swnreg->share_name, share_name) != 0) {
408 continue;
409 }
410
411 cifs_dbg(FYI, "Existing swn registration for %s:%s found\n", swnreg->net_name,
412 swnreg->share_name);
413
414 kfree(net_name);
415 kfree(share_name);
416
417 return swnreg;
418 }
419
420 kfree(net_name);
421 kfree(share_name);
422
423 return ERR_PTR(-EEXIST);
424 }
425
426 /*
427 * Get a registration for the tcon's server and share name, allocating a new one if it does not
428 * exist.
429 */
cifs_get_swn_reg(struct cifs_tcon * tcon)430 static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon)
431 {
432 struct cifs_swn_reg *reg = NULL;
433 int ret;
434
435 mutex_lock(&cifs_swnreg_idr_mutex);
436
437 /* Check if we are already registered for this network and share names */
438 reg = cifs_find_swn_reg(tcon);
439 if (!IS_ERR(reg)) {
440 kref_get(®->ref_count);
441 goto unlock;
442 } else if (PTR_ERR(reg) != -EEXIST) {
443 goto unlock;
444 }
445
446 reg = kmalloc_obj(struct cifs_swn_reg, GFP_KERNEL);
447 if (reg == NULL) {
448 ret = -ENOMEM;
449 goto fail_unlock;
450 }
451
452 kref_init(®->ref_count);
453
454 reg->id = idr_alloc(&cifs_swnreg_idr, reg, 1, 0, GFP_KERNEL);
455 if (reg->id < 0) {
456 cifs_dbg(FYI, "%s: failed to allocate registration id\n", __func__);
457 ret = reg->id;
458 goto fail;
459 }
460
461 reg->net_name = extract_hostname(tcon->tree_name);
462 if (IS_ERR(reg->net_name)) {
463 ret = PTR_ERR(reg->net_name);
464 cifs_dbg(VFS, "%s: failed to extract host name from target: %d\n", __func__, ret);
465 goto fail_idr;
466 }
467
468 reg->share_name = extract_sharename(tcon->tree_name);
469 if (IS_ERR(reg->share_name)) {
470 ret = PTR_ERR(reg->share_name);
471 cifs_dbg(VFS, "%s: failed to extract share name from target: %d\n", __func__, ret);
472 goto fail_net_name;
473 }
474
475 reg->net_name_notify = true;
476 reg->share_name_notify = true;
477 reg->ip_notify = (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT);
478 unlock:
479 mutex_unlock(&cifs_swnreg_idr_mutex);
480
481 return reg;
482
483 fail_net_name:
484 kfree(reg->net_name);
485 fail_idr:
486 idr_remove(&cifs_swnreg_idr, reg->id);
487 fail:
488 kfree(reg);
489 fail_unlock:
490 mutex_unlock(&cifs_swnreg_idr_mutex);
491 return ERR_PTR(ret);
492 }
493
cifs_swn_reg_release(struct kref * ref)494 static void cifs_swn_reg_release(struct kref *ref)
495 {
496 struct cifs_swn_reg *swnreg = container_of(ref, struct cifs_swn_reg, ref_count);
497
498 idr_remove(&cifs_swnreg_idr, swnreg->id);
499 kfree(swnreg->net_name);
500 kfree(swnreg->share_name);
501 kfree(swnreg);
502 }
503
cifs_put_swn_reg_locked(struct cifs_swn_reg * swnreg,struct cifs_tcon * tcon)504 static void cifs_put_swn_reg_locked(struct cifs_swn_reg *swnreg,
505 struct cifs_tcon *tcon)
506 {
507 if (kref_read(&swnreg->ref_count) == 1) {
508 struct cifs_swn_reg_info swnreg_info;
509 int ret;
510
511 cifs_swn_snapshot_reg(swnreg, &swnreg_info);
512 ret = cifs_swn_send_unregister_message(&swnreg_info, tcon);
513 if (ret < 0)
514 cifs_dbg(VFS, "%s: Failed to send unregister message: %d\n",
515 __func__, ret);
516 }
517
518 kref_put(&swnreg->ref_count, cifs_swn_reg_release);
519 }
520
cifs_swn_resource_state_changed(struct cifs_tcon * tcon,const char * name,int state)521 static int cifs_swn_resource_state_changed(struct cifs_tcon *tcon, const char *name, int state)
522 {
523 switch (state) {
524 case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE:
525 cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name);
526 cifs_signal_cifsd_for_reconnect(tcon->ses->server, true);
527 break;
528 case CIFS_SWN_RESOURCE_STATE_AVAILABLE:
529 cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name);
530 cifs_signal_cifsd_for_reconnect(tcon->ses->server, true);
531 break;
532 case CIFS_SWN_RESOURCE_STATE_UNKNOWN:
533 cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name);
534 break;
535 }
536 return 0;
537 }
538
cifs_sockaddr_equal(struct sockaddr_storage * addr1,struct sockaddr_storage * addr2)539 static bool cifs_sockaddr_equal(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2)
540 {
541 if (addr1->ss_family != addr2->ss_family)
542 return false;
543
544 if (addr1->ss_family == AF_INET) {
545 return (memcmp(&((const struct sockaddr_in *)addr1)->sin_addr,
546 &((const struct sockaddr_in *)addr2)->sin_addr,
547 sizeof(struct in_addr)) == 0);
548 }
549
550 if (addr1->ss_family == AF_INET6) {
551 return (memcmp(&((const struct sockaddr_in6 *)addr1)->sin6_addr,
552 &((const struct sockaddr_in6 *)addr2)->sin6_addr,
553 sizeof(struct in6_addr)) == 0);
554 }
555
556 return false;
557 }
558
cifs_swn_store_swn_addr(const struct sockaddr_storage * new,const struct sockaddr_storage * old,struct sockaddr_storage * dst)559 static int cifs_swn_store_swn_addr(const struct sockaddr_storage *new,
560 const struct sockaddr_storage *old,
561 struct sockaddr_storage *dst)
562 {
563 __be16 port = cpu_to_be16(CIFS_PORT);
564
565 if (old->ss_family == AF_INET) {
566 struct sockaddr_in *ipv4 = (struct sockaddr_in *)old;
567
568 port = ipv4->sin_port;
569 } else if (old->ss_family == AF_INET6) {
570 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)old;
571
572 port = ipv6->sin6_port;
573 }
574
575 if (new->ss_family == AF_INET) {
576 struct sockaddr_in *ipv4 = (struct sockaddr_in *)new;
577
578 ipv4->sin_port = port;
579 } else if (new->ss_family == AF_INET6) {
580 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)new;
581
582 ipv6->sin6_port = port;
583 }
584
585 *dst = *new;
586
587 return 0;
588 }
589
cifs_swn_reconnect(struct cifs_tcon * tcon,struct sockaddr_storage * addr)590 static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *addr)
591 {
592 int ret = 0;
593
594 /* Store the reconnect address */
595 cifs_server_lock(tcon->ses->server);
596 if (cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr))
597 goto unlock;
598
599 ret = cifs_swn_store_swn_addr(addr, &tcon->ses->server->dstaddr,
600 &tcon->ses->server->swn_dstaddr);
601 if (ret < 0) {
602 cifs_dbg(VFS, "%s: failed to store address: %d\n", __func__, ret);
603 goto unlock;
604 }
605 tcon->ses->server->use_swn_dstaddr = true;
606
607 /*
608 * Unregister to stop receiving notifications for the old IP address.
609 */
610 ret = cifs_swn_unregister(tcon);
611 if (ret < 0) {
612 cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n",
613 __func__, ret);
614 goto unlock;
615 }
616
617 /*
618 * And register to receive notifications for the new IP address now that we have
619 * stored the new address.
620 */
621 ret = cifs_swn_register(tcon);
622 if (ret < 0) {
623 cifs_dbg(VFS, "%s: Failed to register for witness notifications: %d\n",
624 __func__, ret);
625 goto unlock;
626 }
627
628 cifs_signal_cifsd_for_reconnect(tcon->ses->server, false);
629
630 unlock:
631 cifs_server_unlock(tcon->ses->server);
632
633 return ret;
634 }
635
cifs_swn_client_move(struct cifs_tcon * tcon,struct sockaddr_storage * addr)636 static int cifs_swn_client_move(struct cifs_tcon *tcon, struct sockaddr_storage *addr)
637 {
638 struct sockaddr_in *ipv4 = (struct sockaddr_in *)addr;
639 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)addr;
640
641 if (addr->ss_family == AF_INET)
642 cifs_dbg(FYI, "%s: move to %pI4\n", __func__, &ipv4->sin_addr);
643 else if (addr->ss_family == AF_INET6)
644 cifs_dbg(FYI, "%s: move to %pI6\n", __func__, &ipv6->sin6_addr);
645
646 return cifs_swn_reconnect(tcon, addr);
647 }
648
cifs_swn_notify(struct sk_buff * skb,struct genl_info * info)649 int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info)
650 {
651 struct cifs_swn_reg *swnreg;
652 struct cifs_swn_reg_info swnreg_info;
653 struct cifs_tcon *tcon;
654 char name[256];
655 int type;
656 int ret = 0;
657
658 if (info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]) {
659 int swnreg_id;
660
661 swnreg_id = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]);
662 mutex_lock(&cifs_swnreg_idr_mutex);
663 swnreg = idr_find(&cifs_swnreg_idr, swnreg_id);
664 if (swnreg == NULL) {
665 mutex_unlock(&cifs_swnreg_idr_mutex);
666 cifs_dbg(FYI, "%s: registration id %d not found\n", __func__, swnreg_id);
667 return -EINVAL;
668 }
669 ret = cifs_swn_dup_reg(swnreg, &swnreg_info);
670 mutex_unlock(&cifs_swnreg_idr_mutex);
671 if (ret)
672 return ret;
673 } else {
674 cifs_dbg(FYI, "%s: missing registration id attribute\n", __func__);
675 return -EINVAL;
676 }
677
678 tcon = cifs_swn_get_tcon(&swnreg_info);
679 if (!tcon) {
680 cifs_dbg(FYI, "%s: registration id %d has no live tcon\n",
681 __func__, swnreg_info.id);
682 ret = -ENODEV;
683 goto free_info;
684 }
685
686 if (info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]) {
687 type = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]);
688 } else {
689 cifs_dbg(FYI, "%s: missing notification type attribute\n", __func__);
690 ret = -EINVAL;
691 goto out;
692 }
693
694 switch (type) {
695 case CIFS_SWN_NOTIFICATION_RESOURCE_CHANGE: {
696 int state;
697
698 if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME]) {
699 nla_strscpy(name, info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME],
700 sizeof(name));
701 } else {
702 cifs_dbg(FYI, "%s: missing resource name attribute\n", __func__);
703 ret = -EINVAL;
704 goto out;
705 }
706 if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]) {
707 state = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]);
708 } else {
709 cifs_dbg(FYI, "%s: missing resource state attribute\n", __func__);
710 ret = -EINVAL;
711 goto out;
712 }
713 ret = cifs_swn_resource_state_changed(tcon, name, state);
714 break;
715 }
716 case CIFS_SWN_NOTIFICATION_CLIENT_MOVE: {
717 struct sockaddr_storage addr;
718
719 if (info->attrs[CIFS_GENL_ATTR_SWN_IP]) {
720 nla_memcpy(&addr, info->attrs[CIFS_GENL_ATTR_SWN_IP], sizeof(addr));
721 } else {
722 cifs_dbg(FYI, "%s: missing IP address attribute\n", __func__);
723 ret = -EINVAL;
724 goto out;
725 }
726 ret = cifs_swn_client_move(tcon, &addr);
727 break;
728 }
729 default:
730 cifs_dbg(FYI, "%s: unknown notification type %d\n", __func__, type);
731 break;
732 }
733
734 out:
735 cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_swn_notify);
736 free_info:
737 cifs_swn_free_reg_info(&swnreg_info);
738 return ret;
739 }
740
cifs_swn_register(struct cifs_tcon * tcon)741 int cifs_swn_register(struct cifs_tcon *tcon)
742 {
743 struct cifs_swn_reg *swnreg;
744 struct cifs_swn_reg_info swnreg_info;
745 int ret;
746
747 swnreg = cifs_get_swn_reg(tcon);
748 if (IS_ERR(swnreg))
749 return PTR_ERR(swnreg);
750
751 cifs_swn_snapshot_reg(swnreg, &swnreg_info);
752 ret = cifs_swn_send_register_message(&swnreg_info, tcon);
753 if (ret < 0) {
754 cifs_dbg(VFS, "%s: Failed to send swn register message: %d\n", __func__, ret);
755 /* Do not put the swnreg or return error, the echo task will retry */
756 }
757
758 return 0;
759 }
760
cifs_swn_unregister(struct cifs_tcon * tcon)761 int cifs_swn_unregister(struct cifs_tcon *tcon)
762 {
763 struct cifs_swn_reg *swnreg;
764
765 mutex_lock(&cifs_swnreg_idr_mutex);
766
767 swnreg = cifs_find_swn_reg(tcon);
768 if (IS_ERR(swnreg)) {
769 mutex_unlock(&cifs_swnreg_idr_mutex);
770 return PTR_ERR(swnreg);
771 }
772
773 cifs_put_swn_reg_locked(swnreg, tcon);
774 mutex_unlock(&cifs_swnreg_idr_mutex);
775
776 return 0;
777 }
778
779 /*
780 * Snapshot one registration under cifs_swnreg_idr_mutex and return. Callers
781 * intentionally do the per-registration network/genlmsg work without the
782 * mutex held, both to keep the critical section short and to avoid nesting
783 * cifs_swnreg_idr_mutex inside the higher tc_lock when a live tcon is then
784 * pinned for the send.
785 */
cifs_swn_get_next_reg_info(int * id,struct cifs_swn_reg_info * info)786 static int cifs_swn_get_next_reg_info(int *id, struct cifs_swn_reg_info *info)
787 {
788 struct cifs_swn_reg *swnreg;
789 int ret = 0;
790
791 mutex_lock(&cifs_swnreg_idr_mutex);
792 swnreg = idr_get_next(&cifs_swnreg_idr, id);
793 if (swnreg) {
794 ret = cifs_swn_dup_reg(swnreg, info);
795 if (!ret) {
796 *id = swnreg->id + 1;
797 ret = 1;
798 }
799 }
800 mutex_unlock(&cifs_swnreg_idr_mutex);
801
802 return ret;
803 }
804
cifs_swn_dump(struct seq_file * m)805 void cifs_swn_dump(struct seq_file *m)
806 {
807 struct cifs_swn_reg_info swnreg_info;
808 struct cifs_tcon *tcon;
809 struct sockaddr_in *sa;
810 struct sockaddr_in6 *sa6;
811 int id = 0;
812 int ret;
813
814 seq_puts(m, "Witness registrations:");
815
816 while ((ret = cifs_swn_get_next_reg_info(&id, &swnreg_info)) > 0) {
817 seq_printf(m, "\nId: %u Refs: %u Network name: '%s'%s Share name: '%s'%s Ip address: ",
818 swnreg_info.id, swnreg_info.ref_count,
819 swnreg_info.net_name, swnreg_info.net_name_notify ? "(y)" : "(n)",
820 swnreg_info.share_name, swnreg_info.share_name_notify ? "(y)" : "(n)");
821
822 tcon = cifs_swn_get_tcon(&swnreg_info);
823 if (!tcon) {
824 seq_puts(m, "(no live tcon)");
825 goto next;
826 }
827
828 switch (tcon->ses->server->dstaddr.ss_family) {
829 case AF_INET:
830 sa = (struct sockaddr_in *)&tcon->ses->server->dstaddr;
831 seq_printf(m, "%pI4", &sa->sin_addr.s_addr);
832 break;
833 case AF_INET6:
834 sa6 = (struct sockaddr_in6 *)&tcon->ses->server->dstaddr;
835 seq_printf(m, "%pI6", &sa6->sin6_addr.s6_addr);
836 if (sa6->sin6_scope_id)
837 seq_printf(m, "%%%u", sa6->sin6_scope_id);
838 break;
839 default:
840 seq_puts(m, "(unknown)");
841 }
842 cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_swn_notify);
843 next:
844 seq_printf(m, "%s", swnreg_info.ip_notify ? "(y)" : "(n)");
845 cifs_swn_free_reg_info(&swnreg_info);
846 }
847 if (ret < 0)
848 seq_printf(m, "\nFailed to snapshot witness registration: %d", ret);
849 seq_puts(m, "\n");
850 }
851
cifs_swn_check(void)852 void cifs_swn_check(void)
853 {
854 struct cifs_swn_reg_info swnreg_info;
855 struct cifs_tcon *tcon;
856 int id = 0;
857 int ret;
858
859 while ((ret = cifs_swn_get_next_reg_info(&id, &swnreg_info)) > 0) {
860 tcon = cifs_swn_get_tcon(&swnreg_info);
861 if (!tcon) {
862 cifs_dbg(FYI, "%s: registration id %d has no live tcon\n",
863 __func__, swnreg_info.id);
864 goto free_info;
865 }
866
867 ret = cifs_swn_send_register_message(&swnreg_info, tcon);
868 if (ret < 0)
869 cifs_dbg(FYI, "%s: Failed to send register message: %d\n", __func__, ret);
870 cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_swn_notify);
871 free_info:
872 cifs_swn_free_reg_info(&swnreg_info);
873 }
874 if (ret < 0)
875 cifs_dbg(FYI, "%s: Failed to snapshot registration: %d\n", __func__, ret);
876 }
877