cifs_swn.c (17349B)
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 19static DEFINE_IDR(cifs_swnreg_idr); 20static DEFINE_MUTEX(cifs_swnreg_idr_mutex); 21 22struct 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 struct cifs_tcon *tcon; 33}; 34 35static int cifs_swn_auth_info_krb(struct cifs_tcon *tcon, struct sk_buff *skb) 36{ 37 int ret; 38 39 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_KRB_AUTH); 40 if (ret < 0) 41 return ret; 42 43 return 0; 44} 45 46static int cifs_swn_auth_info_ntlm(struct cifs_tcon *tcon, struct sk_buff *skb) 47{ 48 int ret; 49 50 if (tcon->ses->user_name != NULL) { 51 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_USER_NAME, tcon->ses->user_name); 52 if (ret < 0) 53 return ret; 54 } 55 56 if (tcon->ses->password != NULL) { 57 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_PASSWORD, tcon->ses->password); 58 if (ret < 0) 59 return ret; 60 } 61 62 if (tcon->ses->domainName != NULL) { 63 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_DOMAIN_NAME, tcon->ses->domainName); 64 if (ret < 0) 65 return ret; 66 } 67 68 return 0; 69} 70 71/* 72 * Sends a register message to the userspace daemon based on the registration. 73 * The authentication information to connect to the witness service is bundled 74 * into the message. 75 */ 76static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg) 77{ 78 struct sk_buff *skb; 79 struct genlmsghdr *hdr; 80 enum securityEnum authtype; 81 struct sockaddr_storage *addr; 82 int ret; 83 84 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 85 if (skb == NULL) { 86 ret = -ENOMEM; 87 goto fail; 88 } 89 90 hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_REGISTER); 91 if (hdr == NULL) { 92 ret = -ENOMEM; 93 goto nlmsg_fail; 94 } 95 96 ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id); 97 if (ret < 0) 98 goto nlmsg_fail; 99 100 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name); 101 if (ret < 0) 102 goto nlmsg_fail; 103 104 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name); 105 if (ret < 0) 106 goto nlmsg_fail; 107 108 /* 109 * If there is an address stored use it instead of the server address, because we are 110 * in the process of reconnecting to it after a share has been moved or we have been 111 * told to switch to it (client move message). In these cases we unregister from the 112 * server address and register to the new address when we receive the notification. 113 */ 114 if (swnreg->tcon->ses->server->use_swn_dstaddr) 115 addr = &swnreg->tcon->ses->server->swn_dstaddr; 116 else 117 addr = &swnreg->tcon->ses->server->dstaddr; 118 119 ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), addr); 120 if (ret < 0) 121 goto nlmsg_fail; 122 123 if (swnreg->net_name_notify) { 124 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY); 125 if (ret < 0) 126 goto nlmsg_fail; 127 } 128 129 if (swnreg->share_name_notify) { 130 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY); 131 if (ret < 0) 132 goto nlmsg_fail; 133 } 134 135 if (swnreg->ip_notify) { 136 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY); 137 if (ret < 0) 138 goto nlmsg_fail; 139 } 140 141 authtype = cifs_select_sectype(swnreg->tcon->ses->server, swnreg->tcon->ses->sectype); 142 switch (authtype) { 143 case Kerberos: 144 ret = cifs_swn_auth_info_krb(swnreg->tcon, skb); 145 if (ret < 0) { 146 cifs_dbg(VFS, "%s: Failed to get kerberos auth info: %d\n", __func__, ret); 147 goto nlmsg_fail; 148 } 149 break; 150 case NTLMv2: 151 case RawNTLMSSP: 152 ret = cifs_swn_auth_info_ntlm(swnreg->tcon, skb); 153 if (ret < 0) { 154 cifs_dbg(VFS, "%s: Failed to get NTLM auth info: %d\n", __func__, ret); 155 goto nlmsg_fail; 156 } 157 break; 158 default: 159 cifs_dbg(VFS, "%s: secType %d not supported!\n", __func__, authtype); 160 ret = -EINVAL; 161 goto nlmsg_fail; 162 } 163 164 genlmsg_end(skb, hdr); 165 genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC); 166 167 cifs_dbg(FYI, "%s: Message to register for network name %s with id %d sent\n", __func__, 168 swnreg->net_name, swnreg->id); 169 170 return 0; 171 172nlmsg_fail: 173 genlmsg_cancel(skb, hdr); 174 nlmsg_free(skb); 175fail: 176 return ret; 177} 178 179/* 180 * Sends an uregister message to the userspace daemon based on the registration 181 */ 182static int cifs_swn_send_unregister_message(struct cifs_swn_reg *swnreg) 183{ 184 struct sk_buff *skb; 185 struct genlmsghdr *hdr; 186 int ret; 187 188 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 189 if (skb == NULL) 190 return -ENOMEM; 191 192 hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_UNREGISTER); 193 if (hdr == NULL) { 194 ret = -ENOMEM; 195 goto nlmsg_fail; 196 } 197 198 ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id); 199 if (ret < 0) 200 goto nlmsg_fail; 201 202 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name); 203 if (ret < 0) 204 goto nlmsg_fail; 205 206 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name); 207 if (ret < 0) 208 goto nlmsg_fail; 209 210 ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), 211 &swnreg->tcon->ses->server->dstaddr); 212 if (ret < 0) 213 goto nlmsg_fail; 214 215 if (swnreg->net_name_notify) { 216 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY); 217 if (ret < 0) 218 goto nlmsg_fail; 219 } 220 221 if (swnreg->share_name_notify) { 222 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY); 223 if (ret < 0) 224 goto nlmsg_fail; 225 } 226 227 if (swnreg->ip_notify) { 228 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY); 229 if (ret < 0) 230 goto nlmsg_fail; 231 } 232 233 genlmsg_end(skb, hdr); 234 genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC); 235 236 cifs_dbg(FYI, "%s: Message to unregister for network name %s with id %d sent\n", __func__, 237 swnreg->net_name, swnreg->id); 238 239 return 0; 240 241nlmsg_fail: 242 genlmsg_cancel(skb, hdr); 243 nlmsg_free(skb); 244 return ret; 245} 246 247/* 248 * Try to find a matching registration for the tcon's server name and share name. 249 * Calls to this function must be protected by cifs_swnreg_idr_mutex. 250 * TODO Try to avoid memory allocations 251 */ 252static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon) 253{ 254 struct cifs_swn_reg *swnreg; 255 int id; 256 const char *share_name; 257 const char *net_name; 258 259 net_name = extract_hostname(tcon->treeName); 260 if (IS_ERR(net_name)) { 261 int ret; 262 263 ret = PTR_ERR(net_name); 264 cifs_dbg(VFS, "%s: failed to extract host name from target '%s': %d\n", 265 __func__, tcon->treeName, ret); 266 return ERR_PTR(-EINVAL); 267 } 268 269 share_name = extract_sharename(tcon->treeName); 270 if (IS_ERR(share_name)) { 271 int ret; 272 273 ret = PTR_ERR(share_name); 274 cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n", 275 __func__, tcon->treeName, ret); 276 kfree(net_name); 277 return ERR_PTR(-EINVAL); 278 } 279 280 idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { 281 if (strcasecmp(swnreg->net_name, net_name) != 0 282 || strcasecmp(swnreg->share_name, share_name) != 0) { 283 continue; 284 } 285 286 cifs_dbg(FYI, "Existing swn registration for %s:%s found\n", swnreg->net_name, 287 swnreg->share_name); 288 289 kfree(net_name); 290 kfree(share_name); 291 292 return swnreg; 293 } 294 295 kfree(net_name); 296 kfree(share_name); 297 298 return ERR_PTR(-EEXIST); 299} 300 301/* 302 * Get a registration for the tcon's server and share name, allocating a new one if it does not 303 * exists 304 */ 305static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon) 306{ 307 struct cifs_swn_reg *reg = NULL; 308 int ret; 309 310 mutex_lock(&cifs_swnreg_idr_mutex); 311 312 /* Check if we are already registered for this network and share names */ 313 reg = cifs_find_swn_reg(tcon); 314 if (!IS_ERR(reg)) { 315 kref_get(®->ref_count); 316 mutex_unlock(&cifs_swnreg_idr_mutex); 317 return reg; 318 } else if (PTR_ERR(reg) != -EEXIST) { 319 mutex_unlock(&cifs_swnreg_idr_mutex); 320 return reg; 321 } 322 323 reg = kmalloc(sizeof(struct cifs_swn_reg), GFP_ATOMIC); 324 if (reg == NULL) { 325 mutex_unlock(&cifs_swnreg_idr_mutex); 326 return ERR_PTR(-ENOMEM); 327 } 328 329 kref_init(®->ref_count); 330 331 reg->id = idr_alloc(&cifs_swnreg_idr, reg, 1, 0, GFP_ATOMIC); 332 if (reg->id < 0) { 333 cifs_dbg(FYI, "%s: failed to allocate registration id\n", __func__); 334 ret = reg->id; 335 goto fail; 336 } 337 338 reg->net_name = extract_hostname(tcon->treeName); 339 if (IS_ERR(reg->net_name)) { 340 ret = PTR_ERR(reg->net_name); 341 cifs_dbg(VFS, "%s: failed to extract host name from target: %d\n", __func__, ret); 342 goto fail_idr; 343 } 344 345 reg->share_name = extract_sharename(tcon->treeName); 346 if (IS_ERR(reg->share_name)) { 347 ret = PTR_ERR(reg->share_name); 348 cifs_dbg(VFS, "%s: failed to extract share name from target: %d\n", __func__, ret); 349 goto fail_net_name; 350 } 351 352 reg->net_name_notify = true; 353 reg->share_name_notify = true; 354 reg->ip_notify = (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT); 355 356 reg->tcon = tcon; 357 358 mutex_unlock(&cifs_swnreg_idr_mutex); 359 360 return reg; 361 362fail_net_name: 363 kfree(reg->net_name); 364fail_idr: 365 idr_remove(&cifs_swnreg_idr, reg->id); 366fail: 367 kfree(reg); 368 mutex_unlock(&cifs_swnreg_idr_mutex); 369 return ERR_PTR(ret); 370} 371 372static void cifs_swn_reg_release(struct kref *ref) 373{ 374 struct cifs_swn_reg *swnreg = container_of(ref, struct cifs_swn_reg, ref_count); 375 int ret; 376 377 ret = cifs_swn_send_unregister_message(swnreg); 378 if (ret < 0) 379 cifs_dbg(VFS, "%s: Failed to send unregister message: %d\n", __func__, ret); 380 381 idr_remove(&cifs_swnreg_idr, swnreg->id); 382 kfree(swnreg->net_name); 383 kfree(swnreg->share_name); 384 kfree(swnreg); 385} 386 387static void cifs_put_swn_reg(struct cifs_swn_reg *swnreg) 388{ 389 mutex_lock(&cifs_swnreg_idr_mutex); 390 kref_put(&swnreg->ref_count, cifs_swn_reg_release); 391 mutex_unlock(&cifs_swnreg_idr_mutex); 392} 393 394static int cifs_swn_resource_state_changed(struct cifs_swn_reg *swnreg, const char *name, int state) 395{ 396 switch (state) { 397 case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE: 398 cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name); 399 cifs_signal_cifsd_for_reconnect(swnreg->tcon->ses->server, true); 400 break; 401 case CIFS_SWN_RESOURCE_STATE_AVAILABLE: 402 cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name); 403 cifs_signal_cifsd_for_reconnect(swnreg->tcon->ses->server, true); 404 break; 405 case CIFS_SWN_RESOURCE_STATE_UNKNOWN: 406 cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name); 407 break; 408 } 409 return 0; 410} 411 412static bool cifs_sockaddr_equal(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2) 413{ 414 if (addr1->ss_family != addr2->ss_family) 415 return false; 416 417 if (addr1->ss_family == AF_INET) { 418 return (memcmp(&((const struct sockaddr_in *)addr1)->sin_addr, 419 &((const struct sockaddr_in *)addr2)->sin_addr, 420 sizeof(struct in_addr)) == 0); 421 } 422 423 if (addr1->ss_family == AF_INET6) { 424 return (memcmp(&((const struct sockaddr_in6 *)addr1)->sin6_addr, 425 &((const struct sockaddr_in6 *)addr2)->sin6_addr, 426 sizeof(struct in6_addr)) == 0); 427 } 428 429 return false; 430} 431 432static int cifs_swn_store_swn_addr(const struct sockaddr_storage *new, 433 const struct sockaddr_storage *old, 434 struct sockaddr_storage *dst) 435{ 436 __be16 port = cpu_to_be16(CIFS_PORT); 437 438 if (old->ss_family == AF_INET) { 439 struct sockaddr_in *ipv4 = (struct sockaddr_in *)old; 440 441 port = ipv4->sin_port; 442 } else if (old->ss_family == AF_INET6) { 443 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)old; 444 445 port = ipv6->sin6_port; 446 } 447 448 if (new->ss_family == AF_INET) { 449 struct sockaddr_in *ipv4 = (struct sockaddr_in *)new; 450 451 ipv4->sin_port = port; 452 } else if (new->ss_family == AF_INET6) { 453 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)new; 454 455 ipv6->sin6_port = port; 456 } 457 458 *dst = *new; 459 460 return 0; 461} 462 463static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *addr) 464{ 465 int ret = 0; 466 467 /* Store the reconnect address */ 468 cifs_server_lock(tcon->ses->server); 469 if (cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr)) 470 goto unlock; 471 472 ret = cifs_swn_store_swn_addr(addr, &tcon->ses->server->dstaddr, 473 &tcon->ses->server->swn_dstaddr); 474 if (ret < 0) { 475 cifs_dbg(VFS, "%s: failed to store address: %d\n", __func__, ret); 476 goto unlock; 477 } 478 tcon->ses->server->use_swn_dstaddr = true; 479 480 /* 481 * Unregister to stop receiving notifications for the old IP address. 482 */ 483 ret = cifs_swn_unregister(tcon); 484 if (ret < 0) { 485 cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n", 486 __func__, ret); 487 goto unlock; 488 } 489 490 /* 491 * And register to receive notifications for the new IP address now that we have 492 * stored the new address. 493 */ 494 ret = cifs_swn_register(tcon); 495 if (ret < 0) { 496 cifs_dbg(VFS, "%s: Failed to register for witness notifications: %d\n", 497 __func__, ret); 498 goto unlock; 499 } 500 501 cifs_signal_cifsd_for_reconnect(tcon->ses->server, false); 502 503unlock: 504 cifs_server_unlock(tcon->ses->server); 505 506 return ret; 507} 508 509static int cifs_swn_client_move(struct cifs_swn_reg *swnreg, struct sockaddr_storage *addr) 510{ 511 struct sockaddr_in *ipv4 = (struct sockaddr_in *)addr; 512 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)addr; 513 514 if (addr->ss_family == AF_INET) 515 cifs_dbg(FYI, "%s: move to %pI4\n", __func__, &ipv4->sin_addr); 516 else if (addr->ss_family == AF_INET6) 517 cifs_dbg(FYI, "%s: move to %pI6\n", __func__, &ipv6->sin6_addr); 518 519 return cifs_swn_reconnect(swnreg->tcon, addr); 520} 521 522int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info) 523{ 524 struct cifs_swn_reg *swnreg; 525 char name[256]; 526 int type; 527 528 if (info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]) { 529 int swnreg_id; 530 531 swnreg_id = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]); 532 mutex_lock(&cifs_swnreg_idr_mutex); 533 swnreg = idr_find(&cifs_swnreg_idr, swnreg_id); 534 mutex_unlock(&cifs_swnreg_idr_mutex); 535 if (swnreg == NULL) { 536 cifs_dbg(FYI, "%s: registration id %d not found\n", __func__, swnreg_id); 537 return -EINVAL; 538 } 539 } else { 540 cifs_dbg(FYI, "%s: missing registration id attribute\n", __func__); 541 return -EINVAL; 542 } 543 544 if (info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]) { 545 type = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]); 546 } else { 547 cifs_dbg(FYI, "%s: missing notification type attribute\n", __func__); 548 return -EINVAL; 549 } 550 551 switch (type) { 552 case CIFS_SWN_NOTIFICATION_RESOURCE_CHANGE: { 553 int state; 554 555 if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME]) { 556 nla_strscpy(name, info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME], 557 sizeof(name)); 558 } else { 559 cifs_dbg(FYI, "%s: missing resource name attribute\n", __func__); 560 return -EINVAL; 561 } 562 if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]) { 563 state = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]); 564 } else { 565 cifs_dbg(FYI, "%s: missing resource state attribute\n", __func__); 566 return -EINVAL; 567 } 568 return cifs_swn_resource_state_changed(swnreg, name, state); 569 } 570 case CIFS_SWN_NOTIFICATION_CLIENT_MOVE: { 571 struct sockaddr_storage addr; 572 573 if (info->attrs[CIFS_GENL_ATTR_SWN_IP]) { 574 nla_memcpy(&addr, info->attrs[CIFS_GENL_ATTR_SWN_IP], sizeof(addr)); 575 } else { 576 cifs_dbg(FYI, "%s: missing IP address attribute\n", __func__); 577 return -EINVAL; 578 } 579 return cifs_swn_client_move(swnreg, &addr); 580 } 581 default: 582 cifs_dbg(FYI, "%s: unknown notification type %d\n", __func__, type); 583 break; 584 } 585 586 return 0; 587} 588 589int cifs_swn_register(struct cifs_tcon *tcon) 590{ 591 struct cifs_swn_reg *swnreg; 592 int ret; 593 594 swnreg = cifs_get_swn_reg(tcon); 595 if (IS_ERR(swnreg)) 596 return PTR_ERR(swnreg); 597 598 ret = cifs_swn_send_register_message(swnreg); 599 if (ret < 0) { 600 cifs_dbg(VFS, "%s: Failed to send swn register message: %d\n", __func__, ret); 601 /* Do not put the swnreg or return error, the echo task will retry */ 602 } 603 604 return 0; 605} 606 607int cifs_swn_unregister(struct cifs_tcon *tcon) 608{ 609 struct cifs_swn_reg *swnreg; 610 611 mutex_lock(&cifs_swnreg_idr_mutex); 612 613 swnreg = cifs_find_swn_reg(tcon); 614 if (IS_ERR(swnreg)) { 615 mutex_unlock(&cifs_swnreg_idr_mutex); 616 return PTR_ERR(swnreg); 617 } 618 619 mutex_unlock(&cifs_swnreg_idr_mutex); 620 621 cifs_put_swn_reg(swnreg); 622 623 return 0; 624} 625 626void cifs_swn_dump(struct seq_file *m) 627{ 628 struct cifs_swn_reg *swnreg; 629 struct sockaddr_in *sa; 630 struct sockaddr_in6 *sa6; 631 int id; 632 633 seq_puts(m, "Witness registrations:"); 634 635 mutex_lock(&cifs_swnreg_idr_mutex); 636 idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { 637 seq_printf(m, "\nId: %u Refs: %u Network name: '%s'%s Share name: '%s'%s Ip address: ", 638 id, kref_read(&swnreg->ref_count), 639 swnreg->net_name, swnreg->net_name_notify ? "(y)" : "(n)", 640 swnreg->share_name, swnreg->share_name_notify ? "(y)" : "(n)"); 641 switch (swnreg->tcon->ses->server->dstaddr.ss_family) { 642 case AF_INET: 643 sa = (struct sockaddr_in *) &swnreg->tcon->ses->server->dstaddr; 644 seq_printf(m, "%pI4", &sa->sin_addr.s_addr); 645 break; 646 case AF_INET6: 647 sa6 = (struct sockaddr_in6 *) &swnreg->tcon->ses->server->dstaddr; 648 seq_printf(m, "%pI6", &sa6->sin6_addr.s6_addr); 649 if (sa6->sin6_scope_id) 650 seq_printf(m, "%%%u", sa6->sin6_scope_id); 651 break; 652 default: 653 seq_puts(m, "(unknown)"); 654 } 655 seq_printf(m, "%s", swnreg->ip_notify ? "(y)" : "(n)"); 656 } 657 mutex_unlock(&cifs_swnreg_idr_mutex); 658 seq_puts(m, "\n"); 659} 660 661void cifs_swn_check(void) 662{ 663 struct cifs_swn_reg *swnreg; 664 int id; 665 int ret; 666 667 mutex_lock(&cifs_swnreg_idr_mutex); 668 idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { 669 ret = cifs_swn_send_register_message(swnreg); 670 if (ret < 0) 671 cifs_dbg(FYI, "%s: Failed to send register message: %d\n", __func__, ret); 672 } 673 mutex_unlock(&cifs_swnreg_idr_mutex); 674}