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