| .. | .. |
|---|
| 50 | 50 | #include "cifs_spnego.h" |
|---|
| 51 | 51 | #include "smbdirect.h" |
|---|
| 52 | 52 | #include "trace.h" |
|---|
| 53 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
|---|
| 54 | +#include "dfs_cache.h" |
|---|
| 55 | +#endif |
|---|
| 53 | 56 | |
|---|
| 54 | 57 | /* |
|---|
| 55 | 58 | * The following table defines the expected "StructureSize" of SMB2 requests |
|---|
| .. | .. |
|---|
| 82 | 85 | |
|---|
| 83 | 86 | int smb3_encryption_required(const struct cifs_tcon *tcon) |
|---|
| 84 | 87 | { |
|---|
| 85 | | - if (!tcon) |
|---|
| 88 | + if (!tcon || !tcon->ses) |
|---|
| 86 | 89 | return 0; |
|---|
| 87 | 90 | if ((tcon->ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) || |
|---|
| 88 | 91 | (tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA)) |
|---|
| .. | .. |
|---|
| 95 | 98 | |
|---|
| 96 | 99 | static void |
|---|
| 97 | 100 | smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd, |
|---|
| 98 | | - const struct cifs_tcon *tcon) |
|---|
| 101 | + const struct cifs_tcon *tcon, |
|---|
| 102 | + struct TCP_Server_Info *server) |
|---|
| 99 | 103 | { |
|---|
| 100 | 104 | shdr->ProtocolId = SMB2_PROTO_NUMBER; |
|---|
| 101 | 105 | shdr->StructureSize = cpu_to_le16(64); |
|---|
| 102 | 106 | shdr->Command = smb2_cmd; |
|---|
| 103 | | - if (tcon && tcon->ses && tcon->ses->server) { |
|---|
| 104 | | - struct TCP_Server_Info *server = tcon->ses->server; |
|---|
| 105 | | - |
|---|
| 107 | + if (server) { |
|---|
| 106 | 108 | spin_lock(&server->req_lock); |
|---|
| 107 | | - /* Request up to 2 credits but don't go over the limit. */ |
|---|
| 109 | + /* Request up to 10 credits but don't go over the limit. */ |
|---|
| 108 | 110 | if (server->credits >= server->max_credits) |
|---|
| 109 | 111 | shdr->CreditRequest = cpu_to_le16(0); |
|---|
| 110 | 112 | else |
|---|
| 111 | 113 | shdr->CreditRequest = cpu_to_le16( |
|---|
| 112 | 114 | min_t(int, server->max_credits - |
|---|
| 113 | | - server->credits, 2)); |
|---|
| 115 | + server->credits, 10)); |
|---|
| 114 | 116 | spin_unlock(&server->req_lock); |
|---|
| 115 | 117 | } else { |
|---|
| 116 | 118 | shdr->CreditRequest = cpu_to_le16(2); |
|---|
| .. | .. |
|---|
| 122 | 124 | |
|---|
| 123 | 125 | /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */ |
|---|
| 124 | 126 | /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */ |
|---|
| 125 | | - if ((tcon->ses) && (tcon->ses->server) && |
|---|
| 126 | | - (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) |
|---|
| 127 | + if (server && (server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) |
|---|
| 127 | 128 | shdr->CreditCharge = cpu_to_le16(1); |
|---|
| 128 | 129 | /* else CreditCharge MBZ */ |
|---|
| 129 | 130 | |
|---|
| .. | .. |
|---|
| 145 | 146 | /* if (tcon->share_flags & SHI1005_FLAGS_DFS) |
|---|
| 146 | 147 | shdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */ |
|---|
| 147 | 148 | |
|---|
| 148 | | - if (tcon->ses && tcon->ses->server && tcon->ses->server->sign && |
|---|
| 149 | | - !smb3_encryption_required(tcon)) |
|---|
| 149 | + if (server && server->sign && !smb3_encryption_required(tcon)) |
|---|
| 150 | 150 | shdr->Flags |= SMB2_FLAGS_SIGNED; |
|---|
| 151 | 151 | out: |
|---|
| 152 | 152 | return; |
|---|
| 153 | 153 | } |
|---|
| 154 | 154 | |
|---|
| 155 | 155 | static int |
|---|
| 156 | | -smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) |
|---|
| 156 | +smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, |
|---|
| 157 | + struct TCP_Server_Info *server) |
|---|
| 157 | 158 | { |
|---|
| 158 | 159 | int rc; |
|---|
| 159 | 160 | struct nls_table *nls_codepage; |
|---|
| 160 | 161 | struct cifs_ses *ses; |
|---|
| 161 | | - struct TCP_Server_Info *server; |
|---|
| 162 | + int retries; |
|---|
| 162 | 163 | |
|---|
| 163 | 164 | /* |
|---|
| 164 | 165 | * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so |
|---|
| .. | .. |
|---|
| 186 | 187 | } |
|---|
| 187 | 188 | } |
|---|
| 188 | 189 | if ((!tcon->ses) || (tcon->ses->status == CifsExiting) || |
|---|
| 189 | | - (!tcon->ses->server)) |
|---|
| 190 | + (!tcon->ses->server) || !server) |
|---|
| 190 | 191 | return -EIO; |
|---|
| 191 | 192 | |
|---|
| 192 | 193 | ses = tcon->ses; |
|---|
| 193 | | - server = ses->server; |
|---|
| 194 | + retries = server->nr_targets; |
|---|
| 194 | 195 | |
|---|
| 195 | 196 | /* |
|---|
| 196 | | - * Give demultiplex thread up to 10 seconds to reconnect, should be |
|---|
| 197 | | - * greater than cifs socket timeout which is 7 seconds |
|---|
| 197 | + * Give demultiplex thread up to 10 seconds to each target available for |
|---|
| 198 | + * reconnect -- should be greater than cifs socket timeout which is 7 |
|---|
| 199 | + * seconds. |
|---|
| 198 | 200 | */ |
|---|
| 199 | 201 | while (server->tcpStatus == CifsNeedReconnect) { |
|---|
| 200 | 202 | /* |
|---|
| .. | .. |
|---|
| 216 | 218 | (server->tcpStatus != CifsNeedReconnect), |
|---|
| 217 | 219 | 10 * HZ); |
|---|
| 218 | 220 | if (rc < 0) { |
|---|
| 219 | | - cifs_dbg(FYI, "%s: aborting reconnect due to a received" |
|---|
| 220 | | - " signal by the process\n", __func__); |
|---|
| 221 | + cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n", |
|---|
| 222 | + __func__); |
|---|
| 221 | 223 | return -ERESTARTSYS; |
|---|
| 222 | 224 | } |
|---|
| 223 | 225 | |
|---|
| 224 | 226 | /* are we still trying to reconnect? */ |
|---|
| 225 | 227 | if (server->tcpStatus != CifsNeedReconnect) |
|---|
| 226 | 228 | break; |
|---|
| 229 | + |
|---|
| 230 | + if (retries && --retries) |
|---|
| 231 | + continue; |
|---|
| 227 | 232 | |
|---|
| 228 | 233 | /* |
|---|
| 229 | 234 | * on "soft" mounts we wait once. Hard mounts keep |
|---|
| .. | .. |
|---|
| 234 | 239 | cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n"); |
|---|
| 235 | 240 | return -EHOSTDOWN; |
|---|
| 236 | 241 | } |
|---|
| 242 | + retries = server->nr_targets; |
|---|
| 237 | 243 | } |
|---|
| 238 | 244 | |
|---|
| 239 | 245 | if (!tcon->ses->need_reconnect && !tcon->need_reconnect) |
|---|
| .. | .. |
|---|
| 258 | 264 | goto out; |
|---|
| 259 | 265 | } |
|---|
| 260 | 266 | |
|---|
| 267 | + /* |
|---|
| 268 | + * If we are reconnecting an extra channel, bind |
|---|
| 269 | + */ |
|---|
| 270 | + if (server->is_channel) { |
|---|
| 271 | + ses->binding = true; |
|---|
| 272 | + ses->binding_chan = cifs_ses_find_chan(ses, server); |
|---|
| 273 | + } |
|---|
| 274 | + |
|---|
| 261 | 275 | rc = cifs_negotiate_protocol(0, tcon->ses); |
|---|
| 262 | 276 | if (!rc && tcon->ses->need_reconnect) { |
|---|
| 263 | 277 | rc = cifs_setup_session(0, tcon->ses, nls_codepage); |
|---|
| 264 | 278 | if ((rc == -EACCES) && !tcon->retry) { |
|---|
| 265 | 279 | rc = -EHOSTDOWN; |
|---|
| 280 | + ses->binding = false; |
|---|
| 281 | + ses->binding_chan = NULL; |
|---|
| 266 | 282 | mutex_unlock(&tcon->ses->session_mutex); |
|---|
| 267 | 283 | goto failed; |
|---|
| 284 | + } else if (rc) { |
|---|
| 285 | + mutex_unlock(&ses->session_mutex); |
|---|
| 286 | + goto out; |
|---|
| 268 | 287 | } |
|---|
| 269 | 288 | } |
|---|
| 289 | + /* |
|---|
| 290 | + * End of channel binding |
|---|
| 291 | + */ |
|---|
| 292 | + ses->binding = false; |
|---|
| 293 | + ses->binding_chan = NULL; |
|---|
| 294 | + |
|---|
| 270 | 295 | if (rc || !tcon->need_reconnect) { |
|---|
| 271 | 296 | mutex_unlock(&tcon->ses->session_mutex); |
|---|
| 272 | 297 | goto out; |
|---|
| .. | .. |
|---|
| 276 | 301 | if (tcon->use_persistent) |
|---|
| 277 | 302 | tcon->need_reopen_files = true; |
|---|
| 278 | 303 | |
|---|
| 279 | | - rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); |
|---|
| 304 | + rc = cifs_tree_connect(0, tcon, nls_codepage); |
|---|
| 280 | 305 | mutex_unlock(&tcon->ses->session_mutex); |
|---|
| 281 | 306 | |
|---|
| 282 | 307 | cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc); |
|---|
| 283 | 308 | if (rc) { |
|---|
| 284 | 309 | /* If sess reconnected but tcon didn't, something strange ... */ |
|---|
| 285 | | - printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc); |
|---|
| 310 | + pr_warn_once("reconnect tcon failed rc = %d\n", rc); |
|---|
| 286 | 311 | goto out; |
|---|
| 287 | 312 | } |
|---|
| 288 | 313 | |
|---|
| 289 | 314 | if (smb2_command != SMB2_INTERNAL_CMD) |
|---|
| 290 | | - queue_delayed_work(cifsiod_wq, &server->reconnect, 0); |
|---|
| 315 | + mod_delayed_work(cifsiod_wq, &server->reconnect, 0); |
|---|
| 291 | 316 | |
|---|
| 292 | 317 | atomic_inc(&tconInfoReconnectCount); |
|---|
| 293 | 318 | out: |
|---|
| .. | .. |
|---|
| 317 | 342 | } |
|---|
| 318 | 343 | |
|---|
| 319 | 344 | static void |
|---|
| 320 | | -fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon, void *buf, |
|---|
| 345 | +fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon, |
|---|
| 346 | + struct TCP_Server_Info *server, |
|---|
| 347 | + void *buf, |
|---|
| 321 | 348 | unsigned int *total_len) |
|---|
| 322 | 349 | { |
|---|
| 323 | 350 | struct smb2_sync_pdu *spdu = (struct smb2_sync_pdu *)buf; |
|---|
| .. | .. |
|---|
| 330 | 357 | */ |
|---|
| 331 | 358 | memset(buf, 0, 256); |
|---|
| 332 | 359 | |
|---|
| 333 | | - smb2_hdr_assemble(&spdu->sync_hdr, smb2_command, tcon); |
|---|
| 360 | + smb2_hdr_assemble(&spdu->sync_hdr, smb2_command, tcon, server); |
|---|
| 334 | 361 | spdu->StructureSize2 = cpu_to_le16(parmsize); |
|---|
| 335 | 362 | |
|---|
| 336 | 363 | *total_len = parmsize + sizeof(struct smb2_sync_hdr); |
|---|
| .. | .. |
|---|
| 342 | 369 | * function must have filled in request_buf pointer. |
|---|
| 343 | 370 | */ |
|---|
| 344 | 371 | static int __smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon, |
|---|
| 345 | | - void **request_buf, unsigned int *total_len) |
|---|
| 372 | + struct TCP_Server_Info *server, |
|---|
| 373 | + void **request_buf, unsigned int *total_len) |
|---|
| 346 | 374 | { |
|---|
| 347 | 375 | /* BB eventually switch this to SMB2 specific small buf size */ |
|---|
| 348 | 376 | if (smb2_command == SMB2_SET_INFO) |
|---|
| .. | .. |
|---|
| 354 | 382 | return -ENOMEM; |
|---|
| 355 | 383 | } |
|---|
| 356 | 384 | |
|---|
| 357 | | - fill_small_buf(smb2_command, tcon, |
|---|
| 385 | + fill_small_buf(smb2_command, tcon, server, |
|---|
| 358 | 386 | (struct smb2_sync_hdr *)(*request_buf), |
|---|
| 359 | 387 | total_len); |
|---|
| 360 | 388 | |
|---|
| .. | .. |
|---|
| 368 | 396 | } |
|---|
| 369 | 397 | |
|---|
| 370 | 398 | static int smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon, |
|---|
| 399 | + struct TCP_Server_Info *server, |
|---|
| 371 | 400 | void **request_buf, unsigned int *total_len) |
|---|
| 372 | 401 | { |
|---|
| 373 | 402 | int rc; |
|---|
| 374 | 403 | |
|---|
| 375 | | - rc = smb2_reconnect(smb2_command, tcon); |
|---|
| 404 | + rc = smb2_reconnect(smb2_command, tcon, server); |
|---|
| 376 | 405 | if (rc) |
|---|
| 377 | 406 | return rc; |
|---|
| 378 | 407 | |
|---|
| 379 | | - return __smb2_plain_req_init(smb2_command, tcon, request_buf, |
|---|
| 408 | + return __smb2_plain_req_init(smb2_command, tcon, server, request_buf, |
|---|
| 380 | 409 | total_len); |
|---|
| 381 | 410 | } |
|---|
| 382 | 411 | |
|---|
| 383 | 412 | static int smb2_ioctl_req_init(u32 opcode, struct cifs_tcon *tcon, |
|---|
| 413 | + struct TCP_Server_Info *server, |
|---|
| 384 | 414 | void **request_buf, unsigned int *total_len) |
|---|
| 385 | 415 | { |
|---|
| 386 | 416 | /* Skip reconnect only for FSCTL_VALIDATE_NEGOTIATE_INFO IOCTLs */ |
|---|
| 387 | 417 | if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO) { |
|---|
| 388 | | - return __smb2_plain_req_init(SMB2_IOCTL, tcon, request_buf, |
|---|
| 389 | | - total_len); |
|---|
| 418 | + return __smb2_plain_req_init(SMB2_IOCTL, tcon, server, |
|---|
| 419 | + request_buf, total_len); |
|---|
| 390 | 420 | } |
|---|
| 391 | | - return smb2_plain_req_init(SMB2_IOCTL, tcon, request_buf, total_len); |
|---|
| 421 | + return smb2_plain_req_init(SMB2_IOCTL, tcon, server, |
|---|
| 422 | + request_buf, total_len); |
|---|
| 392 | 423 | } |
|---|
| 393 | 424 | |
|---|
| 394 | | - |
|---|
| 395 | | -/* offset is sizeof smb2_negotiate_req but rounded up to 8 bytes */ |
|---|
| 396 | | -#define OFFSET_OF_NEG_CONTEXT 0x68 /* sizeof(struct smb2_negotiate_req) */ |
|---|
| 397 | | - |
|---|
| 398 | | - |
|---|
| 399 | | -#define SMB2_PREAUTH_INTEGRITY_CAPABILITIES cpu_to_le16(1) |
|---|
| 400 | | -#define SMB2_ENCRYPTION_CAPABILITIES cpu_to_le16(2) |
|---|
| 401 | | -#define SMB2_POSIX_EXTENSIONS_AVAILABLE cpu_to_le16(0x100) |
|---|
| 425 | +/* For explanation of negotiate contexts see MS-SMB2 section 2.2.3.1 */ |
|---|
| 402 | 426 | |
|---|
| 403 | 427 | static void |
|---|
| 404 | 428 | build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt) |
|---|
| .. | .. |
|---|
| 412 | 436 | } |
|---|
| 413 | 437 | |
|---|
| 414 | 438 | static void |
|---|
| 439 | +build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_ctxt) |
|---|
| 440 | +{ |
|---|
| 441 | + pneg_ctxt->ContextType = SMB2_COMPRESSION_CAPABILITIES; |
|---|
| 442 | + pneg_ctxt->DataLength = |
|---|
| 443 | + cpu_to_le16(sizeof(struct smb2_compression_capabilities_context) |
|---|
| 444 | + - sizeof(struct smb2_neg_context)); |
|---|
| 445 | + pneg_ctxt->CompressionAlgorithmCount = cpu_to_le16(3); |
|---|
| 446 | + pneg_ctxt->CompressionAlgorithms[0] = SMB3_COMPRESS_LZ77; |
|---|
| 447 | + pneg_ctxt->CompressionAlgorithms[1] = SMB3_COMPRESS_LZ77_HUFF; |
|---|
| 448 | + pneg_ctxt->CompressionAlgorithms[2] = SMB3_COMPRESS_LZNT1; |
|---|
| 449 | +} |
|---|
| 450 | + |
|---|
| 451 | +static void |
|---|
| 415 | 452 | build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt) |
|---|
| 416 | 453 | { |
|---|
| 417 | 454 | pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES; |
|---|
| 418 | | - pneg_ctxt->DataLength = cpu_to_le16(4); /* Cipher Count + le16 cipher */ |
|---|
| 419 | | - pneg_ctxt->CipherCount = cpu_to_le16(1); |
|---|
| 420 | | -/* pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM;*/ /* not supported yet */ |
|---|
| 421 | | - pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_CCM; |
|---|
| 455 | + if (require_gcm_256) { |
|---|
| 456 | + pneg_ctxt->DataLength = cpu_to_le16(4); /* Cipher Count + 1 cipher */ |
|---|
| 457 | + pneg_ctxt->CipherCount = cpu_to_le16(1); |
|---|
| 458 | + pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES256_GCM; |
|---|
| 459 | + } else if (enable_gcm_256) { |
|---|
| 460 | + pneg_ctxt->DataLength = cpu_to_le16(8); /* Cipher Count + 3 ciphers */ |
|---|
| 461 | + pneg_ctxt->CipherCount = cpu_to_le16(3); |
|---|
| 462 | + pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM; |
|---|
| 463 | + pneg_ctxt->Ciphers[1] = SMB2_ENCRYPTION_AES256_GCM; |
|---|
| 464 | + pneg_ctxt->Ciphers[2] = SMB2_ENCRYPTION_AES128_CCM; |
|---|
| 465 | + } else { |
|---|
| 466 | + pneg_ctxt->DataLength = cpu_to_le16(6); /* Cipher Count + 2 ciphers */ |
|---|
| 467 | + pneg_ctxt->CipherCount = cpu_to_le16(2); |
|---|
| 468 | + pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM; |
|---|
| 469 | + pneg_ctxt->Ciphers[1] = SMB2_ENCRYPTION_AES128_CCM; |
|---|
| 470 | + } |
|---|
| 471 | +} |
|---|
| 472 | + |
|---|
| 473 | +static unsigned int |
|---|
| 474 | +build_netname_ctxt(struct smb2_netname_neg_context *pneg_ctxt, char *hostname) |
|---|
| 475 | +{ |
|---|
| 476 | + struct nls_table *cp = load_nls_default(); |
|---|
| 477 | + |
|---|
| 478 | + pneg_ctxt->ContextType = SMB2_NETNAME_NEGOTIATE_CONTEXT_ID; |
|---|
| 479 | + |
|---|
| 480 | + /* copy up to max of first 100 bytes of server name to NetName field */ |
|---|
| 481 | + pneg_ctxt->DataLength = cpu_to_le16(2 * cifs_strtoUTF16(pneg_ctxt->NetName, hostname, 100, cp)); |
|---|
| 482 | + /* context size is DataLength + minimal smb2_neg_context */ |
|---|
| 483 | + return DIV_ROUND_UP(le16_to_cpu(pneg_ctxt->DataLength) + |
|---|
| 484 | + sizeof(struct smb2_neg_context), 8) * 8; |
|---|
| 422 | 485 | } |
|---|
| 423 | 486 | |
|---|
| 424 | 487 | static void |
|---|
| .. | .. |
|---|
| 426 | 489 | { |
|---|
| 427 | 490 | pneg_ctxt->ContextType = SMB2_POSIX_EXTENSIONS_AVAILABLE; |
|---|
| 428 | 491 | pneg_ctxt->DataLength = cpu_to_le16(POSIX_CTXT_DATA_LEN); |
|---|
| 492 | + /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */ |
|---|
| 493 | + pneg_ctxt->Name[0] = 0x93; |
|---|
| 494 | + pneg_ctxt->Name[1] = 0xAD; |
|---|
| 495 | + pneg_ctxt->Name[2] = 0x25; |
|---|
| 496 | + pneg_ctxt->Name[3] = 0x50; |
|---|
| 497 | + pneg_ctxt->Name[4] = 0x9C; |
|---|
| 498 | + pneg_ctxt->Name[5] = 0xB4; |
|---|
| 499 | + pneg_ctxt->Name[6] = 0x11; |
|---|
| 500 | + pneg_ctxt->Name[7] = 0xE7; |
|---|
| 501 | + pneg_ctxt->Name[8] = 0xB4; |
|---|
| 502 | + pneg_ctxt->Name[9] = 0x23; |
|---|
| 503 | + pneg_ctxt->Name[10] = 0x83; |
|---|
| 504 | + pneg_ctxt->Name[11] = 0xDE; |
|---|
| 505 | + pneg_ctxt->Name[12] = 0x96; |
|---|
| 506 | + pneg_ctxt->Name[13] = 0x8B; |
|---|
| 507 | + pneg_ctxt->Name[14] = 0xCD; |
|---|
| 508 | + pneg_ctxt->Name[15] = 0x7C; |
|---|
| 429 | 509 | } |
|---|
| 430 | 510 | |
|---|
| 431 | 511 | static void |
|---|
| 432 | 512 | assemble_neg_contexts(struct smb2_negotiate_req *req, |
|---|
| 433 | | - unsigned int *total_len) |
|---|
| 513 | + struct TCP_Server_Info *server, unsigned int *total_len) |
|---|
| 434 | 514 | { |
|---|
| 435 | | - char *pneg_ctxt = (char *)req + OFFSET_OF_NEG_CONTEXT; |
|---|
| 515 | + char *pneg_ctxt; |
|---|
| 436 | 516 | unsigned int ctxt_len; |
|---|
| 437 | 517 | |
|---|
| 438 | | - *total_len += 2; /* Add 2 due to round to 8 byte boundary for 1st ctxt */ |
|---|
| 518 | + if (*total_len > 200) { |
|---|
| 519 | + /* In case length corrupted don't want to overrun smb buffer */ |
|---|
| 520 | + cifs_server_dbg(VFS, "Bad frame length assembling neg contexts\n"); |
|---|
| 521 | + return; |
|---|
| 522 | + } |
|---|
| 523 | + |
|---|
| 524 | + /* |
|---|
| 525 | + * round up total_len of fixed part of SMB3 negotiate request to 8 |
|---|
| 526 | + * byte boundary before adding negotiate contexts |
|---|
| 527 | + */ |
|---|
| 528 | + *total_len = roundup(*total_len, 8); |
|---|
| 529 | + |
|---|
| 530 | + pneg_ctxt = (*total_len) + (char *)req; |
|---|
| 531 | + req->NegotiateContextOffset = cpu_to_le32(*total_len); |
|---|
| 532 | + |
|---|
| 439 | 533 | build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt); |
|---|
| 440 | 534 | ctxt_len = DIV_ROUND_UP(sizeof(struct smb2_preauth_neg_context), 8) * 8; |
|---|
| 441 | 535 | *total_len += ctxt_len; |
|---|
| .. | .. |
|---|
| 446 | 540 | *total_len += ctxt_len; |
|---|
| 447 | 541 | pneg_ctxt += ctxt_len; |
|---|
| 448 | 542 | |
|---|
| 543 | + if (server->compress_algorithm) { |
|---|
| 544 | + build_compression_ctxt((struct smb2_compression_capabilities_context *) |
|---|
| 545 | + pneg_ctxt); |
|---|
| 546 | + ctxt_len = DIV_ROUND_UP( |
|---|
| 547 | + sizeof(struct smb2_compression_capabilities_context), |
|---|
| 548 | + 8) * 8; |
|---|
| 549 | + *total_len += ctxt_len; |
|---|
| 550 | + pneg_ctxt += ctxt_len; |
|---|
| 551 | + req->NegotiateContextCount = cpu_to_le16(5); |
|---|
| 552 | + } else |
|---|
| 553 | + req->NegotiateContextCount = cpu_to_le16(4); |
|---|
| 554 | + |
|---|
| 555 | + ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt, |
|---|
| 556 | + server->hostname); |
|---|
| 557 | + *total_len += ctxt_len; |
|---|
| 558 | + pneg_ctxt += ctxt_len; |
|---|
| 559 | + |
|---|
| 449 | 560 | build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt); |
|---|
| 450 | 561 | *total_len += sizeof(struct smb2_posix_neg_context); |
|---|
| 451 | | - |
|---|
| 452 | | - req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT); |
|---|
| 453 | | - req->NegotiateContextCount = cpu_to_le16(3); |
|---|
| 454 | 562 | } |
|---|
| 455 | 563 | |
|---|
| 456 | 564 | static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt) |
|---|
| .. | .. |
|---|
| 459 | 567 | |
|---|
| 460 | 568 | /* If invalid preauth context warn but use what we requested, SHA-512 */ |
|---|
| 461 | 569 | if (len < MIN_PREAUTH_CTXT_DATA_LEN) { |
|---|
| 462 | | - printk_once(KERN_WARNING "server sent bad preauth context\n"); |
|---|
| 570 | + pr_warn_once("server sent bad preauth context\n"); |
|---|
| 463 | 571 | return; |
|---|
| 464 | 572 | } else if (len < MIN_PREAUTH_CTXT_DATA_LEN + le16_to_cpu(ctxt->SaltLength)) { |
|---|
| 465 | 573 | pr_warn_once("server sent invalid SaltLength\n"); |
|---|
| 466 | 574 | return; |
|---|
| 467 | 575 | } |
|---|
| 468 | 576 | if (le16_to_cpu(ctxt->HashAlgorithmCount) != 1) |
|---|
| 469 | | - printk_once(KERN_WARNING "illegal SMB3 hash algorithm count\n"); |
|---|
| 577 | + pr_warn_once("Invalid SMB3 hash algorithm count\n"); |
|---|
| 470 | 578 | if (ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512) |
|---|
| 471 | | - printk_once(KERN_WARNING "unknown SMB3 hash algorithm\n"); |
|---|
| 579 | + pr_warn_once("unknown SMB3 hash algorithm\n"); |
|---|
| 580 | +} |
|---|
| 581 | + |
|---|
| 582 | +static void decode_compress_ctx(struct TCP_Server_Info *server, |
|---|
| 583 | + struct smb2_compression_capabilities_context *ctxt) |
|---|
| 584 | +{ |
|---|
| 585 | + unsigned int len = le16_to_cpu(ctxt->DataLength); |
|---|
| 586 | + |
|---|
| 587 | + /* sizeof compress context is a one element compression capbility struct */ |
|---|
| 588 | + if (len < 10) { |
|---|
| 589 | + pr_warn_once("server sent bad compression cntxt\n"); |
|---|
| 590 | + return; |
|---|
| 591 | + } |
|---|
| 592 | + if (le16_to_cpu(ctxt->CompressionAlgorithmCount) != 1) { |
|---|
| 593 | + pr_warn_once("Invalid SMB3 compress algorithm count\n"); |
|---|
| 594 | + return; |
|---|
| 595 | + } |
|---|
| 596 | + if (le16_to_cpu(ctxt->CompressionAlgorithms[0]) > 3) { |
|---|
| 597 | + pr_warn_once("unknown compression algorithm\n"); |
|---|
| 598 | + return; |
|---|
| 599 | + } |
|---|
| 600 | + server->compress_algorithm = ctxt->CompressionAlgorithms[0]; |
|---|
| 472 | 601 | } |
|---|
| 473 | 602 | |
|---|
| 474 | 603 | static int decode_encrypt_ctx(struct TCP_Server_Info *server, |
|---|
| .. | .. |
|---|
| 478 | 607 | |
|---|
| 479 | 608 | cifs_dbg(FYI, "decode SMB3.11 encryption neg context of len %d\n", len); |
|---|
| 480 | 609 | if (len < MIN_ENCRYPT_CTXT_DATA_LEN) { |
|---|
| 481 | | - printk_once(KERN_WARNING "server sent bad crypto ctxt len\n"); |
|---|
| 610 | + pr_warn_once("server sent bad crypto ctxt len\n"); |
|---|
| 482 | 611 | return -EINVAL; |
|---|
| 483 | 612 | } |
|---|
| 484 | 613 | |
|---|
| 485 | 614 | if (le16_to_cpu(ctxt->CipherCount) != 1) { |
|---|
| 486 | | - printk_once(KERN_WARNING "illegal SMB3.11 cipher count\n"); |
|---|
| 615 | + pr_warn_once("Invalid SMB3.11 cipher count\n"); |
|---|
| 487 | 616 | return -EINVAL; |
|---|
| 488 | 617 | } |
|---|
| 489 | 618 | cifs_dbg(FYI, "SMB311 cipher type:%d\n", le16_to_cpu(ctxt->Ciphers[0])); |
|---|
| 490 | | - if ((ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES128_CCM) && |
|---|
| 491 | | - (ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES128_GCM)) { |
|---|
| 492 | | - printk_once(KERN_WARNING "invalid SMB3.11 cipher returned\n"); |
|---|
| 619 | + if (require_gcm_256) { |
|---|
| 620 | + if (ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES256_GCM) { |
|---|
| 621 | + cifs_dbg(VFS, "Server does not support requested encryption type (AES256 GCM)\n"); |
|---|
| 622 | + return -EOPNOTSUPP; |
|---|
| 623 | + } |
|---|
| 624 | + } else if (ctxt->Ciphers[0] == 0) { |
|---|
| 625 | + /* |
|---|
| 626 | + * e.g. if server only supported AES256_CCM (very unlikely) |
|---|
| 627 | + * or server supported no encryption types or had all disabled. |
|---|
| 628 | + * Since GLOBAL_CAP_ENCRYPTION will be not set, in the case |
|---|
| 629 | + * in which mount requested encryption ("seal") checks later |
|---|
| 630 | + * on during tree connection will return proper rc, but if |
|---|
| 631 | + * seal not requested by client, since server is allowed to |
|---|
| 632 | + * return 0 to indicate no supported cipher, we can't fail here |
|---|
| 633 | + */ |
|---|
| 634 | + server->cipher_type = 0; |
|---|
| 635 | + server->capabilities &= ~SMB2_GLOBAL_CAP_ENCRYPTION; |
|---|
| 636 | + pr_warn_once("Server does not support requested encryption types\n"); |
|---|
| 637 | + return 0; |
|---|
| 638 | + } else if ((ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES128_CCM) && |
|---|
| 639 | + (ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES128_GCM) && |
|---|
| 640 | + (ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES256_GCM)) { |
|---|
| 641 | + /* server returned a cipher we didn't ask for */ |
|---|
| 642 | + pr_warn_once("Invalid SMB3.11 cipher returned\n"); |
|---|
| 493 | 643 | return -EINVAL; |
|---|
| 494 | 644 | } |
|---|
| 495 | 645 | server->cipher_type = ctxt->Ciphers[0]; |
|---|
| .. | .. |
|---|
| 509 | 659 | |
|---|
| 510 | 660 | cifs_dbg(FYI, "decoding %d negotiate contexts\n", ctxt_cnt); |
|---|
| 511 | 661 | if (len_of_smb <= offset) { |
|---|
| 512 | | - cifs_dbg(VFS, "Invalid response: negotiate context offset\n"); |
|---|
| 662 | + cifs_server_dbg(VFS, "Invalid response: negotiate context offset\n"); |
|---|
| 513 | 663 | return -EINVAL; |
|---|
| 514 | 664 | } |
|---|
| 515 | 665 | |
|---|
| .. | .. |
|---|
| 535 | 685 | else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) |
|---|
| 536 | 686 | rc = decode_encrypt_ctx(server, |
|---|
| 537 | 687 | (struct smb2_encryption_neg_context *)pctx); |
|---|
| 688 | + else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES) |
|---|
| 689 | + decode_compress_ctx(server, |
|---|
| 690 | + (struct smb2_compression_capabilities_context *)pctx); |
|---|
| 538 | 691 | else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE) |
|---|
| 539 | 692 | server->posix_ext_supported = true; |
|---|
| 540 | 693 | else |
|---|
| 541 | | - cifs_dbg(VFS, "unknown negcontext of type %d ignored\n", |
|---|
| 694 | + cifs_server_dbg(VFS, "unknown negcontext of type %d ignored\n", |
|---|
| 542 | 695 | le16_to_cpu(pctx->ContextType)); |
|---|
| 543 | 696 | |
|---|
| 544 | 697 | if (rc) |
|---|
| .. | .. |
|---|
| 586 | 739 | buf->Name[14] = 0xCD; |
|---|
| 587 | 740 | buf->Name[15] = 0x7C; |
|---|
| 588 | 741 | buf->Mode = cpu_to_le32(mode); |
|---|
| 589 | | - cifs_dbg(FYI, "mode on posix create 0%o", mode); |
|---|
| 742 | + cifs_dbg(FYI, "mode on posix create 0%o\n", mode); |
|---|
| 590 | 743 | return buf; |
|---|
| 591 | 744 | } |
|---|
| 592 | 745 | |
|---|
| .. | .. |
|---|
| 597 | 750 | unsigned int num = *num_iovec; |
|---|
| 598 | 751 | |
|---|
| 599 | 752 | iov[num].iov_base = create_posix_buf(mode); |
|---|
| 753 | + if (mode == ACL_NO_MODE) |
|---|
| 754 | + cifs_dbg(FYI, "Invalid mode\n"); |
|---|
| 600 | 755 | if (iov[num].iov_base == NULL) |
|---|
| 601 | 756 | return -ENOMEM; |
|---|
| 602 | 757 | iov[num].iov_len = sizeof(struct create_posix); |
|---|
| .. | .. |
|---|
| 635 | 790 | struct kvec rsp_iov; |
|---|
| 636 | 791 | int rc = 0; |
|---|
| 637 | 792 | int resp_buftype; |
|---|
| 638 | | - struct TCP_Server_Info *server = ses->server; |
|---|
| 793 | + struct TCP_Server_Info *server = cifs_ses_server(ses); |
|---|
| 639 | 794 | int blob_offset, blob_length; |
|---|
| 640 | 795 | char *security_blob; |
|---|
| 641 | 796 | int flags = CIFS_NEG_OP; |
|---|
| .. | .. |
|---|
| 648 | 803 | return -EIO; |
|---|
| 649 | 804 | } |
|---|
| 650 | 805 | |
|---|
| 651 | | - rc = smb2_plain_req_init(SMB2_NEGOTIATE, NULL, (void **) &req, &total_len); |
|---|
| 806 | + rc = smb2_plain_req_init(SMB2_NEGOTIATE, NULL, server, |
|---|
| 807 | + (void **) &req, &total_len); |
|---|
| 652 | 808 | if (rc) |
|---|
| 653 | 809 | return rc; |
|---|
| 654 | 810 | |
|---|
| .. | .. |
|---|
| 657 | 813 | memset(server->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE); |
|---|
| 658 | 814 | memset(ses->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE); |
|---|
| 659 | 815 | |
|---|
| 660 | | - if (strcmp(ses->server->vals->version_string, |
|---|
| 816 | + if (strcmp(server->vals->version_string, |
|---|
| 661 | 817 | SMB3ANY_VERSION_STRING) == 0) { |
|---|
| 662 | 818 | req->Dialects[0] = cpu_to_le16(SMB30_PROT_ID); |
|---|
| 663 | 819 | req->Dialects[1] = cpu_to_le16(SMB302_PROT_ID); |
|---|
| 664 | 820 | req->DialectCount = cpu_to_le16(2); |
|---|
| 665 | 821 | total_len += 4; |
|---|
| 666 | | - } else if (strcmp(ses->server->vals->version_string, |
|---|
| 822 | + } else if (strcmp(server->vals->version_string, |
|---|
| 667 | 823 | SMBDEFAULT_VERSION_STRING) == 0) { |
|---|
| 668 | 824 | req->Dialects[0] = cpu_to_le16(SMB21_PROT_ID); |
|---|
| 669 | 825 | req->Dialects[1] = cpu_to_le16(SMB30_PROT_ID); |
|---|
| 670 | 826 | req->Dialects[2] = cpu_to_le16(SMB302_PROT_ID); |
|---|
| 671 | | - req->DialectCount = cpu_to_le16(3); |
|---|
| 672 | | - total_len += 6; |
|---|
| 827 | + req->Dialects[3] = cpu_to_le16(SMB311_PROT_ID); |
|---|
| 828 | + req->DialectCount = cpu_to_le16(4); |
|---|
| 829 | + total_len += 8; |
|---|
| 673 | 830 | } else { |
|---|
| 674 | 831 | /* otherwise send specific dialect */ |
|---|
| 675 | | - req->Dialects[0] = cpu_to_le16(ses->server->vals->protocol_id); |
|---|
| 832 | + req->Dialects[0] = cpu_to_le16(server->vals->protocol_id); |
|---|
| 676 | 833 | req->DialectCount = cpu_to_le16(1); |
|---|
| 677 | 834 | total_len += 2; |
|---|
| 678 | 835 | } |
|---|
| .. | .. |
|---|
| 685 | 842 | else |
|---|
| 686 | 843 | req->SecurityMode = 0; |
|---|
| 687 | 844 | |
|---|
| 688 | | - req->Capabilities = cpu_to_le32(ses->server->vals->req_capabilities); |
|---|
| 845 | + req->Capabilities = cpu_to_le32(server->vals->req_capabilities); |
|---|
| 846 | + if (ses->chan_max > 1) |
|---|
| 847 | + req->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL); |
|---|
| 689 | 848 | |
|---|
| 690 | 849 | /* ClientGUID must be zero for SMB2.02 dialect */ |
|---|
| 691 | | - if (ses->server->vals->protocol_id == SMB20_PROT_ID) |
|---|
| 850 | + if (server->vals->protocol_id == SMB20_PROT_ID) |
|---|
| 692 | 851 | memset(req->ClientGUID, 0, SMB2_CLIENT_GUID_SIZE); |
|---|
| 693 | 852 | else { |
|---|
| 694 | 853 | memcpy(req->ClientGUID, server->client_guid, |
|---|
| 695 | 854 | SMB2_CLIENT_GUID_SIZE); |
|---|
| 696 | | - if (ses->server->vals->protocol_id == SMB311_PROT_ID) |
|---|
| 697 | | - assemble_neg_contexts(req, &total_len); |
|---|
| 855 | + if ((server->vals->protocol_id == SMB311_PROT_ID) || |
|---|
| 856 | + (strcmp(server->vals->version_string, |
|---|
| 857 | + SMBDEFAULT_VERSION_STRING) == 0)) |
|---|
| 858 | + assemble_neg_contexts(req, server, &total_len); |
|---|
| 698 | 859 | } |
|---|
| 699 | 860 | iov[0].iov_base = (char *)req; |
|---|
| 700 | 861 | iov[0].iov_len = total_len; |
|---|
| .. | .. |
|---|
| 703 | 864 | rqst.rq_iov = iov; |
|---|
| 704 | 865 | rqst.rq_nvec = 1; |
|---|
| 705 | 866 | |
|---|
| 706 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 867 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 868 | + &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 707 | 869 | cifs_small_buf_release(req); |
|---|
| 708 | 870 | rsp = (struct smb2_negotiate_rsp *)rsp_iov.iov_base; |
|---|
| 709 | 871 | /* |
|---|
| .. | .. |
|---|
| 711 | 873 | * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); |
|---|
| 712 | 874 | */ |
|---|
| 713 | 875 | if (rc == -EOPNOTSUPP) { |
|---|
| 714 | | - cifs_dbg(VFS, "Dialect not supported by server. Consider " |
|---|
| 715 | | - "specifying vers=1.0 or vers=2.0 on mount for accessing" |
|---|
| 716 | | - " older servers\n"); |
|---|
| 876 | + cifs_server_dbg(VFS, "Dialect not supported by server. Consider specifying vers=1.0 or vers=2.0 on mount for accessing older servers\n"); |
|---|
| 717 | 877 | goto neg_exit; |
|---|
| 718 | 878 | } else if (rc != 0) |
|---|
| 719 | 879 | goto neg_exit; |
|---|
| 720 | 880 | |
|---|
| 721 | | - if (strcmp(ses->server->vals->version_string, |
|---|
| 881 | + if (strcmp(server->vals->version_string, |
|---|
| 722 | 882 | SMB3ANY_VERSION_STRING) == 0) { |
|---|
| 723 | 883 | if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) { |
|---|
| 724 | | - cifs_dbg(VFS, |
|---|
| 884 | + cifs_server_dbg(VFS, |
|---|
| 725 | 885 | "SMB2 dialect returned but not requested\n"); |
|---|
| 726 | 886 | return -EIO; |
|---|
| 727 | 887 | } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) { |
|---|
| 728 | | - cifs_dbg(VFS, |
|---|
| 888 | + cifs_server_dbg(VFS, |
|---|
| 729 | 889 | "SMB2.1 dialect returned but not requested\n"); |
|---|
| 730 | 890 | return -EIO; |
|---|
| 731 | 891 | } |
|---|
| 732 | | - } else if (strcmp(ses->server->vals->version_string, |
|---|
| 892 | + } else if (strcmp(server->vals->version_string, |
|---|
| 733 | 893 | SMBDEFAULT_VERSION_STRING) == 0) { |
|---|
| 734 | 894 | if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) { |
|---|
| 735 | | - cifs_dbg(VFS, |
|---|
| 895 | + cifs_server_dbg(VFS, |
|---|
| 736 | 896 | "SMB2 dialect returned but not requested\n"); |
|---|
| 737 | 897 | return -EIO; |
|---|
| 738 | 898 | } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) { |
|---|
| 739 | 899 | /* ops set to 3.0 by default for default so update */ |
|---|
| 740 | | - ses->server->ops = &smb21_operations; |
|---|
| 741 | | - ses->server->vals = &smb21_values; |
|---|
| 900 | + server->ops = &smb21_operations; |
|---|
| 901 | + server->vals = &smb21_values; |
|---|
| 902 | + } else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) { |
|---|
| 903 | + server->ops = &smb311_operations; |
|---|
| 904 | + server->vals = &smb311_values; |
|---|
| 742 | 905 | } |
|---|
| 743 | 906 | } else if (le16_to_cpu(rsp->DialectRevision) != |
|---|
| 744 | | - ses->server->vals->protocol_id) { |
|---|
| 907 | + server->vals->protocol_id) { |
|---|
| 745 | 908 | /* if requested single dialect ensure returned dialect matched */ |
|---|
| 746 | | - cifs_dbg(VFS, "Illegal 0x%x dialect returned: not requested\n", |
|---|
| 747 | | - le16_to_cpu(rsp->DialectRevision)); |
|---|
| 909 | + cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n", |
|---|
| 910 | + le16_to_cpu(rsp->DialectRevision)); |
|---|
| 748 | 911 | return -EIO; |
|---|
| 749 | 912 | } |
|---|
| 750 | 913 | |
|---|
| .. | .. |
|---|
| 761 | 924 | else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) |
|---|
| 762 | 925 | cifs_dbg(FYI, "negotiated smb3.1.1 dialect\n"); |
|---|
| 763 | 926 | else { |
|---|
| 764 | | - cifs_dbg(VFS, "Illegal dialect returned by server 0x%x\n", |
|---|
| 765 | | - le16_to_cpu(rsp->DialectRevision)); |
|---|
| 927 | + cifs_server_dbg(VFS, "Invalid dialect returned by server 0x%x\n", |
|---|
| 928 | + le16_to_cpu(rsp->DialectRevision)); |
|---|
| 766 | 929 | rc = -EIO; |
|---|
| 767 | 930 | goto neg_exit; |
|---|
| 768 | 931 | } |
|---|
| .. | .. |
|---|
| 828 | 991 | rc = smb311_decode_neg_context(rsp, server, |
|---|
| 829 | 992 | rsp_iov.iov_len); |
|---|
| 830 | 993 | else |
|---|
| 831 | | - cifs_dbg(VFS, "Missing expected negotiate contexts\n"); |
|---|
| 994 | + cifs_server_dbg(VFS, "Missing expected negotiate contexts\n"); |
|---|
| 832 | 995 | } |
|---|
| 833 | 996 | neg_exit: |
|---|
| 834 | 997 | free_rsp_buf(resp_buftype, rsp); |
|---|
| .. | .. |
|---|
| 842 | 1005 | struct validate_negotiate_info_rsp *pneg_rsp = NULL; |
|---|
| 843 | 1006 | u32 rsplen; |
|---|
| 844 | 1007 | u32 inbuflen; /* max of 4 dialects */ |
|---|
| 1008 | + struct TCP_Server_Info *server = tcon->ses->server; |
|---|
| 845 | 1009 | |
|---|
| 846 | 1010 | cifs_dbg(FYI, "validate negotiate\n"); |
|---|
| 847 | 1011 | |
|---|
| 848 | 1012 | /* In SMB3.11 preauth integrity supersedes validate negotiate */ |
|---|
| 849 | | - if (tcon->ses->server->dialect == SMB311_PROT_ID) |
|---|
| 1013 | + if (server->dialect == SMB311_PROT_ID) |
|---|
| 850 | 1014 | return 0; |
|---|
| 851 | 1015 | |
|---|
| 852 | 1016 | /* |
|---|
| .. | .. |
|---|
| 865 | 1029 | } |
|---|
| 866 | 1030 | |
|---|
| 867 | 1031 | if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_NULL) |
|---|
| 868 | | - cifs_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n"); |
|---|
| 1032 | + cifs_tcon_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n"); |
|---|
| 869 | 1033 | |
|---|
| 870 | 1034 | pneg_inbuf = kmalloc(sizeof(*pneg_inbuf), GFP_NOFS); |
|---|
| 871 | 1035 | if (!pneg_inbuf) |
|---|
| 872 | 1036 | return -ENOMEM; |
|---|
| 873 | 1037 | |
|---|
| 874 | 1038 | pneg_inbuf->Capabilities = |
|---|
| 875 | | - cpu_to_le32(tcon->ses->server->vals->req_capabilities); |
|---|
| 876 | | - memcpy(pneg_inbuf->Guid, tcon->ses->server->client_guid, |
|---|
| 1039 | + cpu_to_le32(server->vals->req_capabilities); |
|---|
| 1040 | + if (tcon->ses->chan_max > 1) |
|---|
| 1041 | + pneg_inbuf->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL); |
|---|
| 1042 | + |
|---|
| 1043 | + memcpy(pneg_inbuf->Guid, server->client_guid, |
|---|
| 877 | 1044 | SMB2_CLIENT_GUID_SIZE); |
|---|
| 878 | 1045 | |
|---|
| 879 | 1046 | if (tcon->ses->sign) |
|---|
| .. | .. |
|---|
| 886 | 1053 | pneg_inbuf->SecurityMode = 0; |
|---|
| 887 | 1054 | |
|---|
| 888 | 1055 | |
|---|
| 889 | | - if (strcmp(tcon->ses->server->vals->version_string, |
|---|
| 1056 | + if (strcmp(server->vals->version_string, |
|---|
| 890 | 1057 | SMB3ANY_VERSION_STRING) == 0) { |
|---|
| 891 | 1058 | pneg_inbuf->Dialects[0] = cpu_to_le16(SMB30_PROT_ID); |
|---|
| 892 | 1059 | pneg_inbuf->Dialects[1] = cpu_to_le16(SMB302_PROT_ID); |
|---|
| 893 | 1060 | pneg_inbuf->DialectCount = cpu_to_le16(2); |
|---|
| 894 | 1061 | /* structure is big enough for 3 dialects, sending only 2 */ |
|---|
| 895 | 1062 | inbuflen = sizeof(*pneg_inbuf) - |
|---|
| 896 | | - sizeof(pneg_inbuf->Dialects[0]); |
|---|
| 897 | | - } else if (strcmp(tcon->ses->server->vals->version_string, |
|---|
| 1063 | + (2 * sizeof(pneg_inbuf->Dialects[0])); |
|---|
| 1064 | + } else if (strcmp(server->vals->version_string, |
|---|
| 898 | 1065 | SMBDEFAULT_VERSION_STRING) == 0) { |
|---|
| 899 | 1066 | pneg_inbuf->Dialects[0] = cpu_to_le16(SMB21_PROT_ID); |
|---|
| 900 | 1067 | pneg_inbuf->Dialects[1] = cpu_to_le16(SMB30_PROT_ID); |
|---|
| 901 | 1068 | pneg_inbuf->Dialects[2] = cpu_to_le16(SMB302_PROT_ID); |
|---|
| 902 | | - pneg_inbuf->DialectCount = cpu_to_le16(3); |
|---|
| 1069 | + pneg_inbuf->Dialects[3] = cpu_to_le16(SMB311_PROT_ID); |
|---|
| 1070 | + pneg_inbuf->DialectCount = cpu_to_le16(4); |
|---|
| 903 | 1071 | /* structure is big enough for 3 dialects */ |
|---|
| 904 | 1072 | inbuflen = sizeof(*pneg_inbuf); |
|---|
| 905 | 1073 | } else { |
|---|
| 906 | 1074 | /* otherwise specific dialect was requested */ |
|---|
| 907 | 1075 | pneg_inbuf->Dialects[0] = |
|---|
| 908 | | - cpu_to_le16(tcon->ses->server->vals->protocol_id); |
|---|
| 1076 | + cpu_to_le16(server->vals->protocol_id); |
|---|
| 909 | 1077 | pneg_inbuf->DialectCount = cpu_to_le16(1); |
|---|
| 910 | | - /* structure is big enough for 3 dialects, sending only 1 */ |
|---|
| 1078 | + /* structure is big enough for 4 dialects, sending only 1 */ |
|---|
| 911 | 1079 | inbuflen = sizeof(*pneg_inbuf) - |
|---|
| 912 | | - sizeof(pneg_inbuf->Dialects[0]) * 2; |
|---|
| 1080 | + sizeof(pneg_inbuf->Dialects[0]) * 3; |
|---|
| 913 | 1081 | } |
|---|
| 914 | 1082 | |
|---|
| 915 | 1083 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, |
|---|
| 916 | | - FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, |
|---|
| 917 | | - (char *)pneg_inbuf, inbuflen, (char **)&pneg_rsp, &rsplen); |
|---|
| 1084 | + FSCTL_VALIDATE_NEGOTIATE_INFO, |
|---|
| 1085 | + (char *)pneg_inbuf, inbuflen, CIFSMaxBufSize, |
|---|
| 1086 | + (char **)&pneg_rsp, &rsplen); |
|---|
| 918 | 1087 | if (rc == -EOPNOTSUPP) { |
|---|
| 919 | 1088 | /* |
|---|
| 920 | 1089 | * Old Windows versions or Netapp SMB server can return |
|---|
| 921 | 1090 | * not supported error. Client should accept it. |
|---|
| 922 | 1091 | */ |
|---|
| 923 | | - cifs_dbg(VFS, "Server does not support validate negotiate\n"); |
|---|
| 1092 | + cifs_tcon_dbg(VFS, "Server does not support validate negotiate\n"); |
|---|
| 924 | 1093 | rc = 0; |
|---|
| 925 | 1094 | goto out_free_inbuf; |
|---|
| 926 | 1095 | } else if (rc != 0) { |
|---|
| 927 | | - cifs_dbg(VFS, "validate protocol negotiate failed: %d\n", rc); |
|---|
| 1096 | + cifs_tcon_dbg(VFS, "validate protocol negotiate failed: %d\n", |
|---|
| 1097 | + rc); |
|---|
| 928 | 1098 | rc = -EIO; |
|---|
| 929 | 1099 | goto out_free_inbuf; |
|---|
| 930 | 1100 | } |
|---|
| 931 | 1101 | |
|---|
| 932 | 1102 | rc = -EIO; |
|---|
| 933 | 1103 | if (rsplen != sizeof(*pneg_rsp)) { |
|---|
| 934 | | - cifs_dbg(VFS, "invalid protocol negotiate response size: %d\n", |
|---|
| 935 | | - rsplen); |
|---|
| 1104 | + cifs_tcon_dbg(VFS, "Invalid protocol negotiate response size: %d\n", |
|---|
| 1105 | + rsplen); |
|---|
| 936 | 1106 | |
|---|
| 937 | 1107 | /* relax check since Mac returns max bufsize allowed on ioctl */ |
|---|
| 938 | 1108 | if (rsplen > CIFSMaxBufSize || rsplen < sizeof(*pneg_rsp)) |
|---|
| .. | .. |
|---|
| 940 | 1110 | } |
|---|
| 941 | 1111 | |
|---|
| 942 | 1112 | /* check validate negotiate info response matches what we got earlier */ |
|---|
| 943 | | - if (pneg_rsp->Dialect != cpu_to_le16(tcon->ses->server->dialect)) |
|---|
| 1113 | + if (pneg_rsp->Dialect != cpu_to_le16(server->dialect)) |
|---|
| 944 | 1114 | goto vneg_out; |
|---|
| 945 | 1115 | |
|---|
| 946 | | - if (pneg_rsp->SecurityMode != cpu_to_le16(tcon->ses->server->sec_mode)) |
|---|
| 1116 | + if (pneg_rsp->SecurityMode != cpu_to_le16(server->sec_mode)) |
|---|
| 947 | 1117 | goto vneg_out; |
|---|
| 948 | 1118 | |
|---|
| 949 | 1119 | /* do not validate server guid because not saved at negprot time yet */ |
|---|
| 950 | 1120 | |
|---|
| 951 | 1121 | if ((le32_to_cpu(pneg_rsp->Capabilities) | SMB2_NT_FIND | |
|---|
| 952 | | - SMB2_LARGE_FILES) != tcon->ses->server->capabilities) |
|---|
| 1122 | + SMB2_LARGE_FILES) != server->capabilities) |
|---|
| 953 | 1123 | goto vneg_out; |
|---|
| 954 | 1124 | |
|---|
| 955 | 1125 | /* validate negotiate successful */ |
|---|
| .. | .. |
|---|
| 958 | 1128 | goto out_free_rsp; |
|---|
| 959 | 1129 | |
|---|
| 960 | 1130 | vneg_out: |
|---|
| 961 | | - cifs_dbg(VFS, "protocol revalidation - security settings mismatch\n"); |
|---|
| 1131 | + cifs_tcon_dbg(VFS, "protocol revalidation - security settings mismatch\n"); |
|---|
| 962 | 1132 | out_free_rsp: |
|---|
| 963 | 1133 | kfree(pneg_rsp); |
|---|
| 964 | 1134 | out_free_inbuf: |
|---|
| .. | .. |
|---|
| 982 | 1152 | if ((server->sec_kerberos || server->sec_mskerberos) && |
|---|
| 983 | 1153 | (global_secflags & CIFSSEC_MAY_KRB5)) |
|---|
| 984 | 1154 | return Kerberos; |
|---|
| 985 | | - /* Fallthrough */ |
|---|
| 1155 | + fallthrough; |
|---|
| 986 | 1156 | default: |
|---|
| 987 | 1157 | return Unspecified; |
|---|
| 988 | 1158 | } |
|---|
| .. | .. |
|---|
| 1013 | 1183 | int rc; |
|---|
| 1014 | 1184 | struct cifs_ses *ses = sess_data->ses; |
|---|
| 1015 | 1185 | struct smb2_sess_setup_req *req; |
|---|
| 1016 | | - struct TCP_Server_Info *server = ses->server; |
|---|
| 1186 | + struct TCP_Server_Info *server = cifs_ses_server(ses); |
|---|
| 1017 | 1187 | unsigned int total_len; |
|---|
| 1018 | 1188 | |
|---|
| 1019 | | - rc = smb2_plain_req_init(SMB2_SESSION_SETUP, NULL, (void **) &req, |
|---|
| 1020 | | - &total_len); |
|---|
| 1189 | + rc = smb2_plain_req_init(SMB2_SESSION_SETUP, NULL, server, |
|---|
| 1190 | + (void **) &req, |
|---|
| 1191 | + &total_len); |
|---|
| 1021 | 1192 | if (rc) |
|---|
| 1022 | 1193 | return rc; |
|---|
| 1023 | 1194 | |
|---|
| 1024 | | - /* First session, not a reauthenticate */ |
|---|
| 1025 | | - req->sync_hdr.SessionId = 0; |
|---|
| 1026 | | - |
|---|
| 1027 | | - /* if reconnect, we need to send previous sess id, otherwise it is 0 */ |
|---|
| 1028 | | - req->PreviousSessionId = sess_data->previous_session; |
|---|
| 1029 | | - |
|---|
| 1030 | | - req->Flags = 0; /* MBZ */ |
|---|
| 1195 | + if (sess_data->ses->binding) { |
|---|
| 1196 | + req->sync_hdr.SessionId = sess_data->ses->Suid; |
|---|
| 1197 | + req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED; |
|---|
| 1198 | + req->PreviousSessionId = 0; |
|---|
| 1199 | + req->Flags = SMB2_SESSION_REQ_FLAG_BINDING; |
|---|
| 1200 | + } else { |
|---|
| 1201 | + /* First session, not a reauthenticate */ |
|---|
| 1202 | + req->sync_hdr.SessionId = 0; |
|---|
| 1203 | + /* |
|---|
| 1204 | + * if reconnect, we need to send previous sess id |
|---|
| 1205 | + * otherwise it is 0 |
|---|
| 1206 | + */ |
|---|
| 1207 | + req->PreviousSessionId = sess_data->previous_session; |
|---|
| 1208 | + req->Flags = 0; /* MBZ */ |
|---|
| 1209 | + } |
|---|
| 1031 | 1210 | |
|---|
| 1032 | 1211 | /* enough to enable echos and oplocks and one max size write */ |
|---|
| 1033 | 1212 | req->sync_hdr.CreditRequest = cpu_to_le16(130); |
|---|
| .. | .. |
|---|
| 1086 | 1265 | |
|---|
| 1087 | 1266 | /* BB add code to build os and lm fields */ |
|---|
| 1088 | 1267 | rc = cifs_send_recv(sess_data->xid, sess_data->ses, |
|---|
| 1268 | + cifs_ses_server(sess_data->ses), |
|---|
| 1089 | 1269 | &rqst, |
|---|
| 1090 | 1270 | &sess_data->buf0_type, |
|---|
| 1091 | 1271 | CIFS_LOG_ERROR | CIFS_NEG_OP, &rsp_iov); |
|---|
| .. | .. |
|---|
| 1100 | 1280 | { |
|---|
| 1101 | 1281 | int rc = 0; |
|---|
| 1102 | 1282 | struct cifs_ses *ses = sess_data->ses; |
|---|
| 1283 | + struct TCP_Server_Info *server = cifs_ses_server(ses); |
|---|
| 1103 | 1284 | |
|---|
| 1104 | | - mutex_lock(&ses->server->srv_mutex); |
|---|
| 1105 | | - if (ses->server->ops->generate_signingkey) { |
|---|
| 1106 | | - rc = ses->server->ops->generate_signingkey(ses); |
|---|
| 1285 | + mutex_lock(&server->srv_mutex); |
|---|
| 1286 | + if (server->ops->generate_signingkey) { |
|---|
| 1287 | + rc = server->ops->generate_signingkey(ses); |
|---|
| 1107 | 1288 | if (rc) { |
|---|
| 1108 | 1289 | cifs_dbg(FYI, |
|---|
| 1109 | 1290 | "SMB3 session key generation failed\n"); |
|---|
| 1110 | | - mutex_unlock(&ses->server->srv_mutex); |
|---|
| 1291 | + mutex_unlock(&server->srv_mutex); |
|---|
| 1111 | 1292 | return rc; |
|---|
| 1112 | 1293 | } |
|---|
| 1113 | 1294 | } |
|---|
| 1114 | | - if (!ses->server->session_estab) { |
|---|
| 1115 | | - ses->server->sequence_number = 0x2; |
|---|
| 1116 | | - ses->server->session_estab = true; |
|---|
| 1295 | + if (!server->session_estab) { |
|---|
| 1296 | + server->sequence_number = 0x2; |
|---|
| 1297 | + server->session_estab = true; |
|---|
| 1117 | 1298 | } |
|---|
| 1118 | | - mutex_unlock(&ses->server->srv_mutex); |
|---|
| 1299 | + mutex_unlock(&server->srv_mutex); |
|---|
| 1119 | 1300 | |
|---|
| 1120 | 1301 | cifs_dbg(FYI, "SMB2/3 session established successfully\n"); |
|---|
| 1121 | | - spin_lock(&GlobalMid_Lock); |
|---|
| 1122 | | - ses->status = CifsGood; |
|---|
| 1123 | | - ses->need_reconnect = false; |
|---|
| 1124 | | - spin_unlock(&GlobalMid_Lock); |
|---|
| 1302 | + /* keep existing ses state if binding */ |
|---|
| 1303 | + if (!ses->binding) { |
|---|
| 1304 | + spin_lock(&GlobalMid_Lock); |
|---|
| 1305 | + ses->status = CifsGood; |
|---|
| 1306 | + ses->need_reconnect = false; |
|---|
| 1307 | + spin_unlock(&GlobalMid_Lock); |
|---|
| 1308 | + } |
|---|
| 1309 | + |
|---|
| 1125 | 1310 | return rc; |
|---|
| 1126 | 1311 | } |
|---|
| 1127 | 1312 | |
|---|
| .. | .. |
|---|
| 1154 | 1339 | * sending us a response in an expected form |
|---|
| 1155 | 1340 | */ |
|---|
| 1156 | 1341 | if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) { |
|---|
| 1157 | | - cifs_dbg(VFS, |
|---|
| 1158 | | - "bad cifs.upcall version. Expected %d got %d", |
|---|
| 1159 | | - CIFS_SPNEGO_UPCALL_VERSION, msg->version); |
|---|
| 1342 | + cifs_dbg(VFS, "bad cifs.upcall version. Expected %d got %d\n", |
|---|
| 1343 | + CIFS_SPNEGO_UPCALL_VERSION, msg->version); |
|---|
| 1160 | 1344 | rc = -EKEYREJECTED; |
|---|
| 1161 | 1345 | goto out_put_spnego_key; |
|---|
| 1162 | 1346 | } |
|---|
| 1163 | 1347 | |
|---|
| 1164 | | - ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len, |
|---|
| 1165 | | - GFP_KERNEL); |
|---|
| 1166 | | - if (!ses->auth_key.response) { |
|---|
| 1167 | | - cifs_dbg(VFS, |
|---|
| 1168 | | - "Kerberos can't allocate (%u bytes) memory", |
|---|
| 1169 | | - msg->sesskey_len); |
|---|
| 1170 | | - rc = -ENOMEM; |
|---|
| 1171 | | - goto out_put_spnego_key; |
|---|
| 1348 | + /* keep session key if binding */ |
|---|
| 1349 | + if (!ses->binding) { |
|---|
| 1350 | + ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len, |
|---|
| 1351 | + GFP_KERNEL); |
|---|
| 1352 | + if (!ses->auth_key.response) { |
|---|
| 1353 | + cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory\n", |
|---|
| 1354 | + msg->sesskey_len); |
|---|
| 1355 | + rc = -ENOMEM; |
|---|
| 1356 | + goto out_put_spnego_key; |
|---|
| 1357 | + } |
|---|
| 1358 | + ses->auth_key.len = msg->sesskey_len; |
|---|
| 1172 | 1359 | } |
|---|
| 1173 | | - ses->auth_key.len = msg->sesskey_len; |
|---|
| 1174 | 1360 | |
|---|
| 1175 | 1361 | sess_data->iov[1].iov_base = msg->data + msg->sesskey_len; |
|---|
| 1176 | 1362 | sess_data->iov[1].iov_len = msg->secblob_len; |
|---|
| .. | .. |
|---|
| 1180 | 1366 | goto out_put_spnego_key; |
|---|
| 1181 | 1367 | |
|---|
| 1182 | 1368 | rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base; |
|---|
| 1183 | | - ses->Suid = rsp->sync_hdr.SessionId; |
|---|
| 1184 | | - |
|---|
| 1185 | | - ses->session_flags = le16_to_cpu(rsp->SessionFlags); |
|---|
| 1369 | + /* keep session id and flags if binding */ |
|---|
| 1370 | + if (!ses->binding) { |
|---|
| 1371 | + ses->Suid = rsp->sync_hdr.SessionId; |
|---|
| 1372 | + ses->session_flags = le16_to_cpu(rsp->SessionFlags); |
|---|
| 1373 | + } |
|---|
| 1186 | 1374 | |
|---|
| 1187 | 1375 | rc = SMB2_sess_establish_session(sess_data); |
|---|
| 1188 | 1376 | out_put_spnego_key: |
|---|
| .. | .. |
|---|
| 1276 | 1464 | |
|---|
| 1277 | 1465 | cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n"); |
|---|
| 1278 | 1466 | |
|---|
| 1279 | | - |
|---|
| 1280 | | - ses->Suid = rsp->sync_hdr.SessionId; |
|---|
| 1281 | | - ses->session_flags = le16_to_cpu(rsp->SessionFlags); |
|---|
| 1467 | + /* keep existing ses id and flags if binding */ |
|---|
| 1468 | + if (!ses->binding) { |
|---|
| 1469 | + ses->Suid = rsp->sync_hdr.SessionId; |
|---|
| 1470 | + ses->session_flags = le16_to_cpu(rsp->SessionFlags); |
|---|
| 1471 | + } |
|---|
| 1282 | 1472 | |
|---|
| 1283 | 1473 | out: |
|---|
| 1284 | 1474 | kfree(ntlmssp_blob); |
|---|
| .. | .. |
|---|
| 1335 | 1525 | |
|---|
| 1336 | 1526 | rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base; |
|---|
| 1337 | 1527 | |
|---|
| 1338 | | - ses->Suid = rsp->sync_hdr.SessionId; |
|---|
| 1339 | | - ses->session_flags = le16_to_cpu(rsp->SessionFlags); |
|---|
| 1528 | + /* keep existing ses id and flags if binding */ |
|---|
| 1529 | + if (!ses->binding) { |
|---|
| 1530 | + ses->Suid = rsp->sync_hdr.SessionId; |
|---|
| 1531 | + ses->session_flags = le16_to_cpu(rsp->SessionFlags); |
|---|
| 1532 | + } |
|---|
| 1340 | 1533 | |
|---|
| 1341 | 1534 | rc = SMB2_sess_establish_session(sess_data); |
|---|
| 1535 | +#ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS |
|---|
| 1536 | + if (ses->server->dialect < SMB30_PROT_ID) { |
|---|
| 1537 | + cifs_dbg(VFS, "%s: dumping generated SMB2 session keys\n", __func__); |
|---|
| 1538 | + /* |
|---|
| 1539 | + * The session id is opaque in terms of endianness, so we can't |
|---|
| 1540 | + * print it as a long long. we dump it as we got it on the wire |
|---|
| 1541 | + */ |
|---|
| 1542 | + cifs_dbg(VFS, "Session Id %*ph\n", (int)sizeof(ses->Suid), |
|---|
| 1543 | + &ses->Suid); |
|---|
| 1544 | + cifs_dbg(VFS, "Session Key %*ph\n", |
|---|
| 1545 | + SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response); |
|---|
| 1546 | + cifs_dbg(VFS, "Signing Key %*ph\n", |
|---|
| 1547 | + SMB3_SIGN_KEY_SIZE, ses->auth_key.response); |
|---|
| 1548 | + } |
|---|
| 1549 | +#endif |
|---|
| 1342 | 1550 | out: |
|---|
| 1343 | 1551 | kfree(ntlmssp_blob); |
|---|
| 1344 | 1552 | SMB2_sess_free_buffer(sess_data); |
|---|
| .. | .. |
|---|
| 1353 | 1561 | { |
|---|
| 1354 | 1562 | int type; |
|---|
| 1355 | 1563 | |
|---|
| 1356 | | - type = smb2_select_sectype(ses->server, ses->sectype); |
|---|
| 1564 | + type = smb2_select_sectype(cifs_ses_server(ses), ses->sectype); |
|---|
| 1357 | 1565 | cifs_dbg(FYI, "sess setup type %d\n", type); |
|---|
| 1358 | 1566 | if (type == Unspecified) { |
|---|
| 1359 | | - cifs_dbg(VFS, |
|---|
| 1360 | | - "Unable to select appropriate authentication method!"); |
|---|
| 1567 | + cifs_dbg(VFS, "Unable to select appropriate authentication method!\n"); |
|---|
| 1361 | 1568 | return -EINVAL; |
|---|
| 1362 | 1569 | } |
|---|
| 1363 | 1570 | |
|---|
| .. | .. |
|---|
| 1381 | 1588 | const struct nls_table *nls_cp) |
|---|
| 1382 | 1589 | { |
|---|
| 1383 | 1590 | int rc = 0; |
|---|
| 1384 | | - struct TCP_Server_Info *server = ses->server; |
|---|
| 1591 | + struct TCP_Server_Info *server = cifs_ses_server(ses); |
|---|
| 1385 | 1592 | struct SMB2_sess_data *sess_data; |
|---|
| 1386 | 1593 | |
|---|
| 1387 | 1594 | cifs_dbg(FYI, "Session Setup\n"); |
|---|
| .. | .. |
|---|
| 1407 | 1614 | /* |
|---|
| 1408 | 1615 | * Initialize the session hash with the server one. |
|---|
| 1409 | 1616 | */ |
|---|
| 1410 | | - memcpy(ses->preauth_sha_hash, ses->server->preauth_sha_hash, |
|---|
| 1617 | + memcpy(ses->preauth_sha_hash, server->preauth_sha_hash, |
|---|
| 1411 | 1618 | SMB2_PREAUTH_HASH_SIZE); |
|---|
| 1412 | 1619 | |
|---|
| 1413 | 1620 | while (sess_data->func) |
|---|
| 1414 | 1621 | sess_data->func(sess_data); |
|---|
| 1415 | 1622 | |
|---|
| 1416 | 1623 | if ((ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) && (ses->sign)) |
|---|
| 1417 | | - cifs_dbg(VFS, "signing requested but authenticated as guest\n"); |
|---|
| 1624 | + cifs_server_dbg(VFS, "signing requested but authenticated as guest\n"); |
|---|
| 1418 | 1625 | rc = sess_data->result; |
|---|
| 1419 | 1626 | out: |
|---|
| 1420 | 1627 | kfree(sess_data); |
|---|
| .. | .. |
|---|
| 1445 | 1652 | if (ses->need_reconnect) |
|---|
| 1446 | 1653 | goto smb2_session_already_dead; |
|---|
| 1447 | 1654 | |
|---|
| 1448 | | - rc = smb2_plain_req_init(SMB2_LOGOFF, NULL, (void **) &req, &total_len); |
|---|
| 1655 | + rc = smb2_plain_req_init(SMB2_LOGOFF, NULL, ses->server, |
|---|
| 1656 | + (void **) &req, &total_len); |
|---|
| 1449 | 1657 | if (rc) |
|---|
| 1450 | 1658 | return rc; |
|---|
| 1451 | 1659 | |
|---|
| .. | .. |
|---|
| 1457 | 1665 | else if (server->sign) |
|---|
| 1458 | 1666 | req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED; |
|---|
| 1459 | 1667 | |
|---|
| 1460 | | - flags |= CIFS_NO_RESP; |
|---|
| 1668 | + flags |= CIFS_NO_RSP_BUF; |
|---|
| 1461 | 1669 | |
|---|
| 1462 | 1670 | iov[0].iov_base = (char *)req; |
|---|
| 1463 | 1671 | iov[0].iov_len = total_len; |
|---|
| .. | .. |
|---|
| 1466 | 1674 | rqst.rq_iov = iov; |
|---|
| 1467 | 1675 | rqst.rq_nvec = 1; |
|---|
| 1468 | 1676 | |
|---|
| 1469 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov); |
|---|
| 1677 | + rc = cifs_send_recv(xid, ses, ses->server, |
|---|
| 1678 | + &rqst, &resp_buf_type, flags, &rsp_iov); |
|---|
| 1470 | 1679 | cifs_small_buf_release(req); |
|---|
| 1471 | 1680 | /* |
|---|
| 1472 | 1681 | * No tcon so can't do |
|---|
| .. | .. |
|---|
| 1507 | 1716 | __le16 *unc_path = NULL; |
|---|
| 1508 | 1717 | int flags = 0; |
|---|
| 1509 | 1718 | unsigned int total_len; |
|---|
| 1719 | + struct TCP_Server_Info *server; |
|---|
| 1720 | + |
|---|
| 1721 | + /* always use master channel */ |
|---|
| 1722 | + server = ses->server; |
|---|
| 1510 | 1723 | |
|---|
| 1511 | 1724 | cifs_dbg(FYI, "TCON\n"); |
|---|
| 1512 | 1725 | |
|---|
| 1513 | | - if (!(ses->server) || !tree) |
|---|
| 1726 | + if (!server || !tree) |
|---|
| 1514 | 1727 | return -EIO; |
|---|
| 1515 | 1728 | |
|---|
| 1516 | 1729 | unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 1526 | 1739 | |
|---|
| 1527 | 1740 | /* SMB2 TREE_CONNECT request must be called with TreeId == 0 */ |
|---|
| 1528 | 1741 | tcon->tid = 0; |
|---|
| 1529 | | - |
|---|
| 1530 | | - rc = smb2_plain_req_init(SMB2_TREE_CONNECT, tcon, (void **) &req, |
|---|
| 1531 | | - &total_len); |
|---|
| 1742 | + atomic_set(&tcon->num_remote_opens, 0); |
|---|
| 1743 | + rc = smb2_plain_req_init(SMB2_TREE_CONNECT, tcon, server, |
|---|
| 1744 | + (void **) &req, &total_len); |
|---|
| 1532 | 1745 | if (rc) { |
|---|
| 1533 | 1746 | kfree(unc_path); |
|---|
| 1534 | 1747 | return rc; |
|---|
| .. | .. |
|---|
| 1553 | 1766 | * unless it is guest or anonymous user. See MS-SMB2 3.2.5.3.1 |
|---|
| 1554 | 1767 | * (Samba servers don't always set the flag so also check if null user) |
|---|
| 1555 | 1768 | */ |
|---|
| 1556 | | - if ((ses->server->dialect == SMB311_PROT_ID) && |
|---|
| 1769 | + if ((server->dialect == SMB311_PROT_ID) && |
|---|
| 1557 | 1770 | !smb3_encryption_required(tcon) && |
|---|
| 1558 | 1771 | !(ses->session_flags & |
|---|
| 1559 | 1772 | (SMB2_SESSION_FLAG_IS_GUEST|SMB2_SESSION_FLAG_IS_NULL)) && |
|---|
| .. | .. |
|---|
| 1564 | 1777 | rqst.rq_iov = iov; |
|---|
| 1565 | 1778 | rqst.rq_nvec = 2; |
|---|
| 1566 | 1779 | |
|---|
| 1567 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 1780 | + /* Need 64 for max size write so ask for more in case not there yet */ |
|---|
| 1781 | + req->sync_hdr.CreditRequest = cpu_to_le16(64); |
|---|
| 1782 | + |
|---|
| 1783 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 1784 | + &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 1568 | 1785 | cifs_small_buf_release(req); |
|---|
| 1569 | 1786 | rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base; |
|---|
| 1570 | | - |
|---|
| 1787 | + trace_smb3_tcon(xid, tcon->tid, ses->Suid, tree, rc); |
|---|
| 1571 | 1788 | if (rc != 0) { |
|---|
| 1572 | 1789 | if (tcon) { |
|---|
| 1573 | 1790 | cifs_stats_fail_inc(tcon, SMB2_TREE_CONNECT_HE); |
|---|
| .. | .. |
|---|
| 1589 | 1806 | cifs_dbg(FYI, "connection to printer\n"); |
|---|
| 1590 | 1807 | break; |
|---|
| 1591 | 1808 | default: |
|---|
| 1592 | | - cifs_dbg(VFS, "unknown share type %d\n", rsp->ShareType); |
|---|
| 1809 | + cifs_server_dbg(VFS, "unknown share type %d\n", rsp->ShareType); |
|---|
| 1593 | 1810 | rc = -EOPNOTSUPP; |
|---|
| 1594 | 1811 | goto tcon_error_exit; |
|---|
| 1595 | 1812 | } |
|---|
| .. | .. |
|---|
| 1604 | 1821 | |
|---|
| 1605 | 1822 | if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) && |
|---|
| 1606 | 1823 | ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) |
|---|
| 1607 | | - cifs_dbg(VFS, "DFS capability contradicts DFS flag\n"); |
|---|
| 1824 | + cifs_tcon_dbg(VFS, "DFS capability contradicts DFS flag\n"); |
|---|
| 1608 | 1825 | |
|---|
| 1609 | 1826 | if (tcon->seal && |
|---|
| 1610 | | - !(tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) |
|---|
| 1611 | | - cifs_dbg(VFS, "Encryption is requested but not supported\n"); |
|---|
| 1827 | + !(server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) |
|---|
| 1828 | + cifs_tcon_dbg(VFS, "Encryption is requested but not supported\n"); |
|---|
| 1612 | 1829 | |
|---|
| 1613 | 1830 | init_copy_chunk_defaults(tcon); |
|---|
| 1614 | | - if (tcon->ses->server->ops->validate_negotiate) |
|---|
| 1615 | | - rc = tcon->ses->server->ops->validate_negotiate(xid, tcon); |
|---|
| 1831 | + if (server->ops->validate_negotiate) |
|---|
| 1832 | + rc = server->ops->validate_negotiate(xid, tcon); |
|---|
| 1616 | 1833 | tcon_exit: |
|---|
| 1834 | + |
|---|
| 1617 | 1835 | free_rsp_buf(resp_buftype, rsp); |
|---|
| 1618 | 1836 | kfree(unc_path); |
|---|
| 1619 | 1837 | return rc; |
|---|
| 1620 | 1838 | |
|---|
| 1621 | 1839 | tcon_error_exit: |
|---|
| 1622 | 1840 | if (rsp && rsp->sync_hdr.Status == STATUS_BAD_NETWORK_NAME) { |
|---|
| 1623 | | - cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree); |
|---|
| 1841 | + cifs_tcon_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree); |
|---|
| 1624 | 1842 | } |
|---|
| 1625 | 1843 | goto tcon_exit; |
|---|
| 1626 | 1844 | } |
|---|
| .. | .. |
|---|
| 1646 | 1864 | if ((tcon->need_reconnect) || (tcon->ses->need_reconnect)) |
|---|
| 1647 | 1865 | return 0; |
|---|
| 1648 | 1866 | |
|---|
| 1649 | | - rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, (void **) &req, |
|---|
| 1650 | | - &total_len); |
|---|
| 1867 | + close_shroot_lease(&tcon->crfid); |
|---|
| 1868 | + |
|---|
| 1869 | + rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, ses->server, |
|---|
| 1870 | + (void **) &req, |
|---|
| 1871 | + &total_len); |
|---|
| 1651 | 1872 | if (rc) |
|---|
| 1652 | 1873 | return rc; |
|---|
| 1653 | 1874 | |
|---|
| 1654 | 1875 | if (smb3_encryption_required(tcon)) |
|---|
| 1655 | 1876 | flags |= CIFS_TRANSFORM_REQ; |
|---|
| 1656 | 1877 | |
|---|
| 1657 | | - flags |= CIFS_NO_RESP; |
|---|
| 1878 | + flags |= CIFS_NO_RSP_BUF; |
|---|
| 1658 | 1879 | |
|---|
| 1659 | 1880 | iov[0].iov_base = (char *)req; |
|---|
| 1660 | 1881 | iov[0].iov_len = total_len; |
|---|
| .. | .. |
|---|
| 1663 | 1884 | rqst.rq_iov = iov; |
|---|
| 1664 | 1885 | rqst.rq_nvec = 1; |
|---|
| 1665 | 1886 | |
|---|
| 1666 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov); |
|---|
| 1887 | + rc = cifs_send_recv(xid, ses, ses->server, |
|---|
| 1888 | + &rqst, &resp_buf_type, flags, &rsp_iov); |
|---|
| 1667 | 1889 | cifs_small_buf_release(req); |
|---|
| 1668 | 1890 | if (rc) |
|---|
| 1669 | 1891 | cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE); |
|---|
| .. | .. |
|---|
| 1720 | 1942 | return buf; |
|---|
| 1721 | 1943 | } |
|---|
| 1722 | 1944 | |
|---|
| 1723 | | -static __u8 |
|---|
| 1724 | | -parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp, |
|---|
| 1725 | | - unsigned int *epoch, char *lease_key) |
|---|
| 1945 | +static void |
|---|
| 1946 | +parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf) |
|---|
| 1947 | +{ |
|---|
| 1948 | + struct create_on_disk_id *pdisk_id = (struct create_on_disk_id *)cc; |
|---|
| 1949 | + |
|---|
| 1950 | + cifs_dbg(FYI, "parse query id context 0x%llx 0x%llx\n", |
|---|
| 1951 | + pdisk_id->DiskFileId, pdisk_id->VolumeId); |
|---|
| 1952 | + buf->IndexNumber = pdisk_id->DiskFileId; |
|---|
| 1953 | +} |
|---|
| 1954 | + |
|---|
| 1955 | +static void |
|---|
| 1956 | +parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *info, |
|---|
| 1957 | + struct create_posix_rsp *posix) |
|---|
| 1958 | +{ |
|---|
| 1959 | + int sid_len; |
|---|
| 1960 | + u8 *beg = (u8 *)cc + le16_to_cpu(cc->DataOffset); |
|---|
| 1961 | + u8 *end = beg + le32_to_cpu(cc->DataLength); |
|---|
| 1962 | + u8 *sid; |
|---|
| 1963 | + |
|---|
| 1964 | + memset(posix, 0, sizeof(*posix)); |
|---|
| 1965 | + |
|---|
| 1966 | + posix->nlink = le32_to_cpu(*(__le32 *)(beg + 0)); |
|---|
| 1967 | + posix->reparse_tag = le32_to_cpu(*(__le32 *)(beg + 4)); |
|---|
| 1968 | + posix->mode = le32_to_cpu(*(__le32 *)(beg + 8)); |
|---|
| 1969 | + |
|---|
| 1970 | + sid = beg + 12; |
|---|
| 1971 | + sid_len = posix_info_sid_size(sid, end); |
|---|
| 1972 | + if (sid_len < 0) { |
|---|
| 1973 | + cifs_dbg(VFS, "bad owner sid in posix create response\n"); |
|---|
| 1974 | + return; |
|---|
| 1975 | + } |
|---|
| 1976 | + memcpy(&posix->owner, sid, sid_len); |
|---|
| 1977 | + |
|---|
| 1978 | + sid = sid + sid_len; |
|---|
| 1979 | + sid_len = posix_info_sid_size(sid, end); |
|---|
| 1980 | + if (sid_len < 0) { |
|---|
| 1981 | + cifs_dbg(VFS, "bad group sid in posix create response\n"); |
|---|
| 1982 | + return; |
|---|
| 1983 | + } |
|---|
| 1984 | + memcpy(&posix->group, sid, sid_len); |
|---|
| 1985 | + |
|---|
| 1986 | + cifs_dbg(FYI, "nlink=%d mode=%o reparse_tag=%x\n", |
|---|
| 1987 | + posix->nlink, posix->mode, posix->reparse_tag); |
|---|
| 1988 | +} |
|---|
| 1989 | + |
|---|
| 1990 | +void |
|---|
| 1991 | +smb2_parse_contexts(struct TCP_Server_Info *server, |
|---|
| 1992 | + struct smb2_create_rsp *rsp, |
|---|
| 1993 | + unsigned int *epoch, char *lease_key, __u8 *oplock, |
|---|
| 1994 | + struct smb2_file_all_info *buf, |
|---|
| 1995 | + struct create_posix_rsp *posix) |
|---|
| 1726 | 1996 | { |
|---|
| 1727 | 1997 | char *data_offset; |
|---|
| 1728 | 1998 | struct create_context *cc; |
|---|
| 1729 | 1999 | unsigned int next; |
|---|
| 1730 | 2000 | unsigned int remaining; |
|---|
| 1731 | 2001 | char *name; |
|---|
| 2002 | + static const char smb3_create_tag_posix[] = { |
|---|
| 2003 | + 0x93, 0xAD, 0x25, 0x50, 0x9C, |
|---|
| 2004 | + 0xB4, 0x11, 0xE7, 0xB4, 0x23, 0x83, |
|---|
| 2005 | + 0xDE, 0x96, 0x8B, 0xCD, 0x7C |
|---|
| 2006 | + }; |
|---|
| 1732 | 2007 | |
|---|
| 2008 | + *oplock = 0; |
|---|
| 1733 | 2009 | data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset); |
|---|
| 1734 | 2010 | remaining = le32_to_cpu(rsp->CreateContextsLength); |
|---|
| 1735 | 2011 | cc = (struct create_context *)data_offset; |
|---|
| 2012 | + |
|---|
| 2013 | + /* Initialize inode number to 0 in case no valid data in qfid context */ |
|---|
| 2014 | + if (buf) |
|---|
| 2015 | + buf->IndexNumber = 0; |
|---|
| 2016 | + |
|---|
| 1736 | 2017 | while (remaining >= sizeof(struct create_context)) { |
|---|
| 1737 | 2018 | name = le16_to_cpu(cc->NameOffset) + (char *)cc; |
|---|
| 1738 | 2019 | if (le16_to_cpu(cc->NameLength) == 4 && |
|---|
| 1739 | | - strncmp(name, "RqLs", 4) == 0) |
|---|
| 1740 | | - return server->ops->parse_lease_buf(cc, epoch, |
|---|
| 1741 | | - lease_key); |
|---|
| 2020 | + strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4) == 0) |
|---|
| 2021 | + *oplock = server->ops->parse_lease_buf(cc, epoch, |
|---|
| 2022 | + lease_key); |
|---|
| 2023 | + else if (buf && (le16_to_cpu(cc->NameLength) == 4) && |
|---|
| 2024 | + strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0) |
|---|
| 2025 | + parse_query_id_ctxt(cc, buf); |
|---|
| 2026 | + else if ((le16_to_cpu(cc->NameLength) == 16)) { |
|---|
| 2027 | + if (posix && |
|---|
| 2028 | + memcmp(name, smb3_create_tag_posix, 16) == 0) |
|---|
| 2029 | + parse_posix_ctxt(cc, buf, posix); |
|---|
| 2030 | + } |
|---|
| 2031 | + /* else { |
|---|
| 2032 | + cifs_dbg(FYI, "Context not matched with len %d\n", |
|---|
| 2033 | + le16_to_cpu(cc->NameLength)); |
|---|
| 2034 | + cifs_dump_mem("Cctxt name: ", name, 4); |
|---|
| 2035 | + } */ |
|---|
| 1742 | 2036 | |
|---|
| 1743 | 2037 | next = le32_to_cpu(cc->Next); |
|---|
| 1744 | 2038 | if (!next) |
|---|
| .. | .. |
|---|
| 1747 | 2041 | cc = (struct create_context *)((char *)cc + next); |
|---|
| 1748 | 2042 | } |
|---|
| 1749 | 2043 | |
|---|
| 1750 | | - return 0; |
|---|
| 2044 | + if (rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE) |
|---|
| 2045 | + *oplock = rsp->OplockLevel; |
|---|
| 2046 | + |
|---|
| 2047 | + return; |
|---|
| 1751 | 2048 | } |
|---|
| 1752 | 2049 | |
|---|
| 1753 | 2050 | static int |
|---|
| .. | .. |
|---|
| 1773 | 2070 | } |
|---|
| 1774 | 2071 | |
|---|
| 1775 | 2072 | static struct create_durable_v2 * |
|---|
| 1776 | | -create_durable_v2_buf(struct cifs_fid *pfid) |
|---|
| 2073 | +create_durable_v2_buf(struct cifs_open_parms *oparms) |
|---|
| 1777 | 2074 | { |
|---|
| 2075 | + struct cifs_fid *pfid = oparms->fid; |
|---|
| 1778 | 2076 | struct create_durable_v2 *buf; |
|---|
| 1779 | 2077 | |
|---|
| 1780 | 2078 | buf = kzalloc(sizeof(struct create_durable_v2), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 1788 | 2086 | (struct create_durable_v2, Name)); |
|---|
| 1789 | 2087 | buf->ccontext.NameLength = cpu_to_le16(4); |
|---|
| 1790 | 2088 | |
|---|
| 1791 | | - buf->dcontext.Timeout = 0; /* Should this be configurable by workload */ |
|---|
| 2089 | + /* |
|---|
| 2090 | + * NB: Handle timeout defaults to 0, which allows server to choose |
|---|
| 2091 | + * (most servers default to 120 seconds) and most clients default to 0. |
|---|
| 2092 | + * This can be overridden at mount ("handletimeout=") if the user wants |
|---|
| 2093 | + * a different persistent (or resilient) handle timeout for all opens |
|---|
| 2094 | + * opens on a particular SMB3 mount. |
|---|
| 2095 | + */ |
|---|
| 2096 | + buf->dcontext.Timeout = cpu_to_le32(oparms->tcon->handle_timeout); |
|---|
| 1792 | 2097 | buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT); |
|---|
| 1793 | 2098 | generate_random_uuid(buf->dcontext.CreateGuid); |
|---|
| 1794 | 2099 | memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16); |
|---|
| .. | .. |
|---|
| 1841 | 2146 | struct smb2_create_req *req = iov[0].iov_base; |
|---|
| 1842 | 2147 | unsigned int num = *num_iovec; |
|---|
| 1843 | 2148 | |
|---|
| 1844 | | - iov[num].iov_base = create_durable_v2_buf(oparms->fid); |
|---|
| 2149 | + iov[num].iov_base = create_durable_v2_buf(oparms); |
|---|
| 1845 | 2150 | if (iov[num].iov_base == NULL) |
|---|
| 1846 | 2151 | return -ENOMEM; |
|---|
| 1847 | 2152 | iov[num].iov_len = sizeof(struct create_durable_v2); |
|---|
| .. | .. |
|---|
| 1956 | 2261 | return 0; |
|---|
| 1957 | 2262 | } |
|---|
| 1958 | 2263 | |
|---|
| 2264 | +/* See See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx */ |
|---|
| 2265 | +static void setup_owner_group_sids(char *buf) |
|---|
| 2266 | +{ |
|---|
| 2267 | + struct owner_group_sids *sids = (struct owner_group_sids *)buf; |
|---|
| 2268 | + |
|---|
| 2269 | + /* Populate the user ownership fields S-1-5-88-1 */ |
|---|
| 2270 | + sids->owner.Revision = 1; |
|---|
| 2271 | + sids->owner.NumAuth = 3; |
|---|
| 2272 | + sids->owner.Authority[5] = 5; |
|---|
| 2273 | + sids->owner.SubAuthorities[0] = cpu_to_le32(88); |
|---|
| 2274 | + sids->owner.SubAuthorities[1] = cpu_to_le32(1); |
|---|
| 2275 | + sids->owner.SubAuthorities[2] = cpu_to_le32(current_fsuid().val); |
|---|
| 2276 | + |
|---|
| 2277 | + /* Populate the group ownership fields S-1-5-88-2 */ |
|---|
| 2278 | + sids->group.Revision = 1; |
|---|
| 2279 | + sids->group.NumAuth = 3; |
|---|
| 2280 | + sids->group.Authority[5] = 5; |
|---|
| 2281 | + sids->group.SubAuthorities[0] = cpu_to_le32(88); |
|---|
| 2282 | + sids->group.SubAuthorities[1] = cpu_to_le32(2); |
|---|
| 2283 | + sids->group.SubAuthorities[2] = cpu_to_le32(current_fsgid().val); |
|---|
| 2284 | + |
|---|
| 2285 | + cifs_dbg(FYI, "owner S-1-5-88-1-%d, group S-1-5-88-2-%d\n", current_fsuid().val, current_fsgid().val); |
|---|
| 2286 | +} |
|---|
| 2287 | + |
|---|
| 2288 | +/* See MS-SMB2 2.2.13.2.2 and MS-DTYP 2.4.6 */ |
|---|
| 2289 | +static struct crt_sd_ctxt * |
|---|
| 2290 | +create_sd_buf(umode_t mode, bool set_owner, unsigned int *len) |
|---|
| 2291 | +{ |
|---|
| 2292 | + struct crt_sd_ctxt *buf; |
|---|
| 2293 | + __u8 *ptr, *aclptr; |
|---|
| 2294 | + unsigned int acelen, acl_size, ace_count; |
|---|
| 2295 | + unsigned int owner_offset = 0; |
|---|
| 2296 | + unsigned int group_offset = 0; |
|---|
| 2297 | + struct smb3_acl acl = {}; |
|---|
| 2298 | + |
|---|
| 2299 | + *len = roundup(sizeof(struct crt_sd_ctxt) + (sizeof(struct cifs_ace) * 4), 8); |
|---|
| 2300 | + |
|---|
| 2301 | + if (set_owner) { |
|---|
| 2302 | + /* sizeof(struct owner_group_sids) is already multiple of 8 so no need to round */ |
|---|
| 2303 | + *len += sizeof(struct owner_group_sids); |
|---|
| 2304 | + } |
|---|
| 2305 | + |
|---|
| 2306 | + buf = kzalloc(*len, GFP_KERNEL); |
|---|
| 2307 | + if (buf == NULL) |
|---|
| 2308 | + return buf; |
|---|
| 2309 | + |
|---|
| 2310 | + ptr = (__u8 *)&buf[1]; |
|---|
| 2311 | + if (set_owner) { |
|---|
| 2312 | + /* offset fields are from beginning of security descriptor not of create context */ |
|---|
| 2313 | + owner_offset = ptr - (__u8 *)&buf->sd; |
|---|
| 2314 | + buf->sd.OffsetOwner = cpu_to_le32(owner_offset); |
|---|
| 2315 | + group_offset = owner_offset + offsetof(struct owner_group_sids, group); |
|---|
| 2316 | + buf->sd.OffsetGroup = cpu_to_le32(group_offset); |
|---|
| 2317 | + |
|---|
| 2318 | + setup_owner_group_sids(ptr); |
|---|
| 2319 | + ptr += sizeof(struct owner_group_sids); |
|---|
| 2320 | + } else { |
|---|
| 2321 | + buf->sd.OffsetOwner = 0; |
|---|
| 2322 | + buf->sd.OffsetGroup = 0; |
|---|
| 2323 | + } |
|---|
| 2324 | + |
|---|
| 2325 | + buf->ccontext.DataOffset = cpu_to_le16(offsetof(struct crt_sd_ctxt, sd)); |
|---|
| 2326 | + buf->ccontext.NameOffset = cpu_to_le16(offsetof(struct crt_sd_ctxt, Name)); |
|---|
| 2327 | + buf->ccontext.NameLength = cpu_to_le16(4); |
|---|
| 2328 | + /* SMB2_CREATE_SD_BUFFER_TOKEN is "SecD" */ |
|---|
| 2329 | + buf->Name[0] = 'S'; |
|---|
| 2330 | + buf->Name[1] = 'e'; |
|---|
| 2331 | + buf->Name[2] = 'c'; |
|---|
| 2332 | + buf->Name[3] = 'D'; |
|---|
| 2333 | + buf->sd.Revision = 1; /* Must be one see MS-DTYP 2.4.6 */ |
|---|
| 2334 | + |
|---|
| 2335 | + /* |
|---|
| 2336 | + * ACL is "self relative" ie ACL is stored in contiguous block of memory |
|---|
| 2337 | + * and "DP" ie the DACL is present |
|---|
| 2338 | + */ |
|---|
| 2339 | + buf->sd.Control = cpu_to_le16(ACL_CONTROL_SR | ACL_CONTROL_DP); |
|---|
| 2340 | + |
|---|
| 2341 | + /* offset owner, group and Sbz1 and SACL are all zero */ |
|---|
| 2342 | + buf->sd.OffsetDacl = cpu_to_le32(ptr - (__u8 *)&buf->sd); |
|---|
| 2343 | + /* Ship the ACL for now. we will copy it into buf later. */ |
|---|
| 2344 | + aclptr = ptr; |
|---|
| 2345 | + ptr += sizeof(struct smb3_acl); |
|---|
| 2346 | + |
|---|
| 2347 | + /* create one ACE to hold the mode embedded in reserved special SID */ |
|---|
| 2348 | + acelen = setup_special_mode_ACE((struct cifs_ace *)ptr, (__u64)mode); |
|---|
| 2349 | + ptr += acelen; |
|---|
| 2350 | + acl_size = acelen + sizeof(struct smb3_acl); |
|---|
| 2351 | + ace_count = 1; |
|---|
| 2352 | + |
|---|
| 2353 | + if (set_owner) { |
|---|
| 2354 | + /* we do not need to reallocate buffer to add the two more ACEs. plenty of space */ |
|---|
| 2355 | + acelen = setup_special_user_owner_ACE((struct cifs_ace *)ptr); |
|---|
| 2356 | + ptr += acelen; |
|---|
| 2357 | + acl_size += acelen; |
|---|
| 2358 | + ace_count += 1; |
|---|
| 2359 | + } |
|---|
| 2360 | + |
|---|
| 2361 | + /* and one more ACE to allow access for authenticated users */ |
|---|
| 2362 | + acelen = setup_authusers_ACE((struct cifs_ace *)ptr); |
|---|
| 2363 | + ptr += acelen; |
|---|
| 2364 | + acl_size += acelen; |
|---|
| 2365 | + ace_count += 1; |
|---|
| 2366 | + |
|---|
| 2367 | + acl.AclRevision = ACL_REVISION; /* See 2.4.4.1 of MS-DTYP */ |
|---|
| 2368 | + acl.AclSize = cpu_to_le16(acl_size); |
|---|
| 2369 | + acl.AceCount = cpu_to_le16(ace_count); |
|---|
| 2370 | + /* acl.Sbz1 and Sbz2 MBZ so are not set here, but initialized above */ |
|---|
| 2371 | + memcpy(aclptr, &acl, sizeof(struct smb3_acl)); |
|---|
| 2372 | + |
|---|
| 2373 | + buf->ccontext.DataLength = cpu_to_le32(ptr - (__u8 *)&buf->sd); |
|---|
| 2374 | + *len = roundup(ptr - (__u8 *)buf, 8); |
|---|
| 2375 | + |
|---|
| 2376 | + return buf; |
|---|
| 2377 | +} |
|---|
| 2378 | + |
|---|
| 2379 | +static int |
|---|
| 2380 | +add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode, bool set_owner) |
|---|
| 2381 | +{ |
|---|
| 2382 | + struct smb2_create_req *req = iov[0].iov_base; |
|---|
| 2383 | + unsigned int num = *num_iovec; |
|---|
| 2384 | + unsigned int len = 0; |
|---|
| 2385 | + |
|---|
| 2386 | + iov[num].iov_base = create_sd_buf(mode, set_owner, &len); |
|---|
| 2387 | + if (iov[num].iov_base == NULL) |
|---|
| 2388 | + return -ENOMEM; |
|---|
| 2389 | + iov[num].iov_len = len; |
|---|
| 2390 | + if (!req->CreateContextsOffset) |
|---|
| 2391 | + req->CreateContextsOffset = cpu_to_le32( |
|---|
| 2392 | + sizeof(struct smb2_create_req) + |
|---|
| 2393 | + iov[num - 1].iov_len); |
|---|
| 2394 | + le32_add_cpu(&req->CreateContextsLength, len); |
|---|
| 2395 | + *num_iovec = num + 1; |
|---|
| 2396 | + return 0; |
|---|
| 2397 | +} |
|---|
| 2398 | + |
|---|
| 2399 | +static struct crt_query_id_ctxt * |
|---|
| 2400 | +create_query_id_buf(void) |
|---|
| 2401 | +{ |
|---|
| 2402 | + struct crt_query_id_ctxt *buf; |
|---|
| 2403 | + |
|---|
| 2404 | + buf = kzalloc(sizeof(struct crt_query_id_ctxt), GFP_KERNEL); |
|---|
| 2405 | + if (!buf) |
|---|
| 2406 | + return NULL; |
|---|
| 2407 | + |
|---|
| 2408 | + buf->ccontext.DataOffset = cpu_to_le16(0); |
|---|
| 2409 | + buf->ccontext.DataLength = cpu_to_le32(0); |
|---|
| 2410 | + buf->ccontext.NameOffset = cpu_to_le16(offsetof |
|---|
| 2411 | + (struct crt_query_id_ctxt, Name)); |
|---|
| 2412 | + buf->ccontext.NameLength = cpu_to_le16(4); |
|---|
| 2413 | + /* SMB2_CREATE_QUERY_ON_DISK_ID is "QFid" */ |
|---|
| 2414 | + buf->Name[0] = 'Q'; |
|---|
| 2415 | + buf->Name[1] = 'F'; |
|---|
| 2416 | + buf->Name[2] = 'i'; |
|---|
| 2417 | + buf->Name[3] = 'd'; |
|---|
| 2418 | + return buf; |
|---|
| 2419 | +} |
|---|
| 2420 | + |
|---|
| 2421 | +/* See MS-SMB2 2.2.13.2.9 */ |
|---|
| 2422 | +static int |
|---|
| 2423 | +add_query_id_context(struct kvec *iov, unsigned int *num_iovec) |
|---|
| 2424 | +{ |
|---|
| 2425 | + struct smb2_create_req *req = iov[0].iov_base; |
|---|
| 2426 | + unsigned int num = *num_iovec; |
|---|
| 2427 | + |
|---|
| 2428 | + iov[num].iov_base = create_query_id_buf(); |
|---|
| 2429 | + if (iov[num].iov_base == NULL) |
|---|
| 2430 | + return -ENOMEM; |
|---|
| 2431 | + iov[num].iov_len = sizeof(struct crt_query_id_ctxt); |
|---|
| 2432 | + if (!req->CreateContextsOffset) |
|---|
| 2433 | + req->CreateContextsOffset = cpu_to_le32( |
|---|
| 2434 | + sizeof(struct smb2_create_req) + |
|---|
| 2435 | + iov[num - 1].iov_len); |
|---|
| 2436 | + le32_add_cpu(&req->CreateContextsLength, sizeof(struct crt_query_id_ctxt)); |
|---|
| 2437 | + *num_iovec = num + 1; |
|---|
| 2438 | + return 0; |
|---|
| 2439 | +} |
|---|
| 2440 | + |
|---|
| 1959 | 2441 | static int |
|---|
| 1960 | 2442 | alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, |
|---|
| 1961 | 2443 | const char *treename, const __le16 *path) |
|---|
| .. | .. |
|---|
| 2009 | 2491 | struct smb_rqst rqst; |
|---|
| 2010 | 2492 | struct smb2_create_req *req; |
|---|
| 2011 | 2493 | struct smb2_create_rsp *rsp = NULL; |
|---|
| 2012 | | - struct TCP_Server_Info *server; |
|---|
| 2013 | 2494 | struct cifs_ses *ses = tcon->ses; |
|---|
| 2014 | 2495 | struct kvec iov[3]; /* make sure at least one for each open context */ |
|---|
| 2015 | 2496 | struct kvec rsp_iov = {NULL, 0}; |
|---|
| .. | .. |
|---|
| 2024 | 2505 | int flags = 0; |
|---|
| 2025 | 2506 | unsigned int total_len; |
|---|
| 2026 | 2507 | __le16 *utf16_path = NULL; |
|---|
| 2508 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
|---|
| 2027 | 2509 | |
|---|
| 2028 | 2510 | cifs_dbg(FYI, "mkdir\n"); |
|---|
| 2029 | 2511 | |
|---|
| .. | .. |
|---|
| 2032 | 2514 | if (!utf16_path) |
|---|
| 2033 | 2515 | return -ENOMEM; |
|---|
| 2034 | 2516 | |
|---|
| 2035 | | - if (ses && (ses->server)) |
|---|
| 2036 | | - server = ses->server; |
|---|
| 2037 | | - else { |
|---|
| 2517 | + if (!ses || !server) { |
|---|
| 2038 | 2518 | rc = -EIO; |
|---|
| 2039 | 2519 | goto err_free_path; |
|---|
| 2040 | 2520 | } |
|---|
| 2041 | 2521 | |
|---|
| 2042 | 2522 | /* resource #2: request */ |
|---|
| 2043 | | - rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len); |
|---|
| 2523 | + rc = smb2_plain_req_init(SMB2_CREATE, tcon, server, |
|---|
| 2524 | + (void **) &req, &total_len); |
|---|
| 2044 | 2525 | if (rc) |
|---|
| 2045 | 2526 | goto err_free_path; |
|---|
| 2046 | 2527 | |
|---|
| .. | .. |
|---|
| 2122 | 2603 | rqst.rq_iov = iov; |
|---|
| 2123 | 2604 | rqst.rq_nvec = n_iov; |
|---|
| 2124 | 2605 | |
|---|
| 2606 | + /* no need to inc num_remote_opens because we close it just below */ |
|---|
| 2607 | + trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, CREATE_NOT_FILE, |
|---|
| 2608 | + FILE_WRITE_ATTRIBUTES); |
|---|
| 2125 | 2609 | /* resource #4: response buffer */ |
|---|
| 2126 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 2610 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 2611 | + &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 2127 | 2612 | if (rc) { |
|---|
| 2128 | 2613 | cifs_stats_fail_inc(tcon, SMB2_CREATE_HE); |
|---|
| 2129 | 2614 | trace_smb3_posix_mkdir_err(xid, tcon->tid, ses->Suid, |
|---|
| .. | .. |
|---|
| 2152 | 2637 | } |
|---|
| 2153 | 2638 | |
|---|
| 2154 | 2639 | int |
|---|
| 2155 | | -SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock, |
|---|
| 2640 | +SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, |
|---|
| 2641 | + struct smb_rqst *rqst, __u8 *oplock, |
|---|
| 2156 | 2642 | struct cifs_open_parms *oparms, __le16 *path) |
|---|
| 2157 | 2643 | { |
|---|
| 2158 | | - struct TCP_Server_Info *server = tcon->ses->server; |
|---|
| 2159 | 2644 | struct smb2_create_req *req; |
|---|
| 2160 | 2645 | unsigned int n_iov = 2; |
|---|
| 2161 | 2646 | __u32 file_attributes = 0; |
|---|
| .. | .. |
|---|
| 2166 | 2651 | __le16 *copy_path; |
|---|
| 2167 | 2652 | int rc; |
|---|
| 2168 | 2653 | |
|---|
| 2169 | | - rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len); |
|---|
| 2654 | + rc = smb2_plain_req_init(SMB2_CREATE, tcon, server, |
|---|
| 2655 | + (void **) &req, &total_len); |
|---|
| 2170 | 2656 | if (rc) |
|---|
| 2171 | 2657 | return rc; |
|---|
| 2172 | 2658 | |
|---|
| .. | .. |
|---|
| 2184 | 2670 | /* File attributes ignored on open (used in create though) */ |
|---|
| 2185 | 2671 | req->FileAttributes = cpu_to_le32(file_attributes); |
|---|
| 2186 | 2672 | req->ShareAccess = FILE_SHARE_ALL_LE; |
|---|
| 2673 | + |
|---|
| 2187 | 2674 | req->CreateDisposition = cpu_to_le32(oparms->disposition); |
|---|
| 2188 | 2675 | req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK); |
|---|
| 2189 | 2676 | req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req)); |
|---|
| .. | .. |
|---|
| 2285 | 2772 | return rc; |
|---|
| 2286 | 2773 | } |
|---|
| 2287 | 2774 | |
|---|
| 2775 | + if ((oparms->disposition != FILE_OPEN) && (oparms->cifs_sb)) { |
|---|
| 2776 | + bool set_mode; |
|---|
| 2777 | + bool set_owner; |
|---|
| 2778 | + |
|---|
| 2779 | + if ((oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) && |
|---|
| 2780 | + (oparms->mode != ACL_NO_MODE)) |
|---|
| 2781 | + set_mode = true; |
|---|
| 2782 | + else { |
|---|
| 2783 | + set_mode = false; |
|---|
| 2784 | + oparms->mode = ACL_NO_MODE; |
|---|
| 2785 | + } |
|---|
| 2786 | + |
|---|
| 2787 | + if (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) |
|---|
| 2788 | + set_owner = true; |
|---|
| 2789 | + else |
|---|
| 2790 | + set_owner = false; |
|---|
| 2791 | + |
|---|
| 2792 | + if (set_owner | set_mode) { |
|---|
| 2793 | + if (n_iov > 2) { |
|---|
| 2794 | + struct create_context *ccontext = |
|---|
| 2795 | + (struct create_context *)iov[n_iov-1].iov_base; |
|---|
| 2796 | + ccontext->Next = cpu_to_le32(iov[n_iov-1].iov_len); |
|---|
| 2797 | + } |
|---|
| 2798 | + |
|---|
| 2799 | + cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode); |
|---|
| 2800 | + rc = add_sd_context(iov, &n_iov, oparms->mode, set_owner); |
|---|
| 2801 | + if (rc) |
|---|
| 2802 | + return rc; |
|---|
| 2803 | + } |
|---|
| 2804 | + } |
|---|
| 2805 | + |
|---|
| 2806 | + if (n_iov > 2) { |
|---|
| 2807 | + struct create_context *ccontext = |
|---|
| 2808 | + (struct create_context *)iov[n_iov-1].iov_base; |
|---|
| 2809 | + ccontext->Next = cpu_to_le32(iov[n_iov-1].iov_len); |
|---|
| 2810 | + } |
|---|
| 2811 | + add_query_id_context(iov, &n_iov); |
|---|
| 2288 | 2812 | |
|---|
| 2289 | 2813 | rqst->rq_nvec = n_iov; |
|---|
| 2290 | 2814 | return 0; |
|---|
| .. | .. |
|---|
| 2309 | 2833 | int |
|---|
| 2310 | 2834 | SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, |
|---|
| 2311 | 2835 | __u8 *oplock, struct smb2_file_all_info *buf, |
|---|
| 2836 | + struct create_posix_rsp *posix, |
|---|
| 2312 | 2837 | struct kvec *err_iov, int *buftype) |
|---|
| 2313 | 2838 | { |
|---|
| 2314 | 2839 | struct smb_rqst rqst; |
|---|
| 2315 | 2840 | struct smb2_create_rsp *rsp = NULL; |
|---|
| 2316 | | - struct TCP_Server_Info *server; |
|---|
| 2317 | 2841 | struct cifs_tcon *tcon = oparms->tcon; |
|---|
| 2318 | 2842 | struct cifs_ses *ses = tcon->ses; |
|---|
| 2843 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
|---|
| 2319 | 2844 | struct kvec iov[SMB2_CREATE_IOV_SIZE]; |
|---|
| 2320 | 2845 | struct kvec rsp_iov = {NULL, 0}; |
|---|
| 2321 | 2846 | int resp_buftype = CIFS_NO_BUFFER; |
|---|
| .. | .. |
|---|
| 2323 | 2848 | int flags = 0; |
|---|
| 2324 | 2849 | |
|---|
| 2325 | 2850 | cifs_dbg(FYI, "create/open\n"); |
|---|
| 2326 | | - if (ses && (ses->server)) |
|---|
| 2327 | | - server = ses->server; |
|---|
| 2328 | | - else |
|---|
| 2851 | + if (!ses || !server) |
|---|
| 2329 | 2852 | return -EIO; |
|---|
| 2330 | 2853 | |
|---|
| 2331 | 2854 | if (smb3_encryption_required(tcon)) |
|---|
| .. | .. |
|---|
| 2336 | 2859 | rqst.rq_iov = iov; |
|---|
| 2337 | 2860 | rqst.rq_nvec = SMB2_CREATE_IOV_SIZE; |
|---|
| 2338 | 2861 | |
|---|
| 2339 | | - rc = SMB2_open_init(tcon, &rqst, oplock, oparms, path); |
|---|
| 2862 | + rc = SMB2_open_init(tcon, server, |
|---|
| 2863 | + &rqst, oplock, oparms, path); |
|---|
| 2340 | 2864 | if (rc) |
|---|
| 2341 | 2865 | goto creat_exit; |
|---|
| 2342 | 2866 | |
|---|
| 2343 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, |
|---|
| 2867 | + trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, |
|---|
| 2868 | + oparms->create_options, oparms->desired_access); |
|---|
| 2869 | + |
|---|
| 2870 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 2871 | + &rqst, &resp_buftype, flags, |
|---|
| 2344 | 2872 | &rsp_iov); |
|---|
| 2345 | 2873 | rsp = (struct smb2_create_rsp *)rsp_iov.iov_base; |
|---|
| 2346 | 2874 | |
|---|
| .. | .. |
|---|
| 2354 | 2882 | } |
|---|
| 2355 | 2883 | trace_smb3_open_err(xid, tcon->tid, ses->Suid, |
|---|
| 2356 | 2884 | oparms->create_options, oparms->desired_access, rc); |
|---|
| 2885 | + if (rc == -EREMCHG) { |
|---|
| 2886 | + pr_warn_once("server share %s deleted\n", |
|---|
| 2887 | + tcon->treeName); |
|---|
| 2888 | + tcon->need_reconnect = true; |
|---|
| 2889 | + } |
|---|
| 2357 | 2890 | goto creat_exit; |
|---|
| 2358 | 2891 | } else |
|---|
| 2359 | 2892 | trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, |
|---|
| 2360 | 2893 | ses->Suid, oparms->create_options, |
|---|
| 2361 | 2894 | oparms->desired_access); |
|---|
| 2362 | 2895 | |
|---|
| 2896 | + atomic_inc(&tcon->num_remote_opens); |
|---|
| 2363 | 2897 | oparms->fid->persistent_fid = rsp->PersistentFileId; |
|---|
| 2364 | 2898 | oparms->fid->volatile_fid = rsp->VolatileFileId; |
|---|
| 2899 | + oparms->fid->access = oparms->desired_access; |
|---|
| 2900 | +#ifdef CONFIG_CIFS_DEBUG2 |
|---|
| 2901 | + oparms->fid->mid = le64_to_cpu(rsp->sync_hdr.MessageId); |
|---|
| 2902 | +#endif /* CIFS_DEBUG2 */ |
|---|
| 2365 | 2903 | |
|---|
| 2366 | 2904 | if (buf) { |
|---|
| 2367 | 2905 | memcpy(buf, &rsp->CreationTime, 32); |
|---|
| .. | .. |
|---|
| 2372 | 2910 | buf->DeletePending = 0; |
|---|
| 2373 | 2911 | } |
|---|
| 2374 | 2912 | |
|---|
| 2375 | | - if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) |
|---|
| 2376 | | - *oplock = parse_lease_state(server, rsp, &oparms->fid->epoch, |
|---|
| 2377 | | - oparms->fid->lease_key); |
|---|
| 2378 | | - else |
|---|
| 2379 | | - *oplock = rsp->OplockLevel; |
|---|
| 2913 | + |
|---|
| 2914 | + smb2_parse_contexts(server, rsp, &oparms->fid->epoch, |
|---|
| 2915 | + oparms->fid->lease_key, oplock, buf, posix); |
|---|
| 2380 | 2916 | creat_exit: |
|---|
| 2381 | 2917 | SMB2_open_free(&rqst); |
|---|
| 2382 | 2918 | free_rsp_buf(resp_buftype, rsp); |
|---|
| 2383 | 2919 | return rc; |
|---|
| 2384 | 2920 | } |
|---|
| 2385 | 2921 | |
|---|
| 2922 | +int |
|---|
| 2923 | +SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, |
|---|
| 2924 | + struct smb_rqst *rqst, |
|---|
| 2925 | + u64 persistent_fid, u64 volatile_fid, u32 opcode, |
|---|
| 2926 | + char *in_data, u32 indatalen, |
|---|
| 2927 | + __u32 max_response_size) |
|---|
| 2928 | +{ |
|---|
| 2929 | + struct smb2_ioctl_req *req; |
|---|
| 2930 | + struct kvec *iov = rqst->rq_iov; |
|---|
| 2931 | + unsigned int total_len; |
|---|
| 2932 | + int rc; |
|---|
| 2933 | + char *in_data_buf; |
|---|
| 2934 | + |
|---|
| 2935 | + rc = smb2_ioctl_req_init(opcode, tcon, server, |
|---|
| 2936 | + (void **) &req, &total_len); |
|---|
| 2937 | + if (rc) |
|---|
| 2938 | + return rc; |
|---|
| 2939 | + |
|---|
| 2940 | + if (indatalen) { |
|---|
| 2941 | + /* |
|---|
| 2942 | + * indatalen is usually small at a couple of bytes max, so |
|---|
| 2943 | + * just allocate through generic pool |
|---|
| 2944 | + */ |
|---|
| 2945 | + in_data_buf = kmemdup(in_data, indatalen, GFP_NOFS); |
|---|
| 2946 | + if (!in_data_buf) { |
|---|
| 2947 | + cifs_small_buf_release(req); |
|---|
| 2948 | + return -ENOMEM; |
|---|
| 2949 | + } |
|---|
| 2950 | + } |
|---|
| 2951 | + |
|---|
| 2952 | + req->CtlCode = cpu_to_le32(opcode); |
|---|
| 2953 | + req->PersistentFileId = persistent_fid; |
|---|
| 2954 | + req->VolatileFileId = volatile_fid; |
|---|
| 2955 | + |
|---|
| 2956 | + iov[0].iov_base = (char *)req; |
|---|
| 2957 | + /* |
|---|
| 2958 | + * If no input data, the size of ioctl struct in |
|---|
| 2959 | + * protocol spec still includes a 1 byte data buffer, |
|---|
| 2960 | + * but if input data passed to ioctl, we do not |
|---|
| 2961 | + * want to double count this, so we do not send |
|---|
| 2962 | + * the dummy one byte of data in iovec[0] if sending |
|---|
| 2963 | + * input data (in iovec[1]). |
|---|
| 2964 | + */ |
|---|
| 2965 | + if (indatalen) { |
|---|
| 2966 | + req->InputCount = cpu_to_le32(indatalen); |
|---|
| 2967 | + /* do not set InputOffset if no input data */ |
|---|
| 2968 | + req->InputOffset = |
|---|
| 2969 | + cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer)); |
|---|
| 2970 | + rqst->rq_nvec = 2; |
|---|
| 2971 | + iov[0].iov_len = total_len - 1; |
|---|
| 2972 | + iov[1].iov_base = in_data_buf; |
|---|
| 2973 | + iov[1].iov_len = indatalen; |
|---|
| 2974 | + } else { |
|---|
| 2975 | + rqst->rq_nvec = 1; |
|---|
| 2976 | + iov[0].iov_len = total_len; |
|---|
| 2977 | + } |
|---|
| 2978 | + |
|---|
| 2979 | + req->OutputOffset = 0; |
|---|
| 2980 | + req->OutputCount = 0; /* MBZ */ |
|---|
| 2981 | + |
|---|
| 2982 | + /* |
|---|
| 2983 | + * In most cases max_response_size is set to 16K (CIFSMaxBufSize) |
|---|
| 2984 | + * We Could increase default MaxOutputResponse, but that could require |
|---|
| 2985 | + * more credits. Windows typically sets this smaller, but for some |
|---|
| 2986 | + * ioctls it may be useful to allow server to send more. No point |
|---|
| 2987 | + * limiting what the server can send as long as fits in one credit |
|---|
| 2988 | + * We can not handle more than CIFS_MAX_BUF_SIZE yet but may want |
|---|
| 2989 | + * to increase this limit up in the future. |
|---|
| 2990 | + * Note that for snapshot queries that servers like Azure expect that |
|---|
| 2991 | + * the first query be minimal size (and just used to get the number/size |
|---|
| 2992 | + * of previous versions) so response size must be specified as EXACTLY |
|---|
| 2993 | + * sizeof(struct snapshot_array) which is 16 when rounded up to multiple |
|---|
| 2994 | + * of eight bytes. Currently that is the only case where we set max |
|---|
| 2995 | + * response size smaller. |
|---|
| 2996 | + */ |
|---|
| 2997 | + req->MaxOutputResponse = cpu_to_le32(max_response_size); |
|---|
| 2998 | + req->sync_hdr.CreditCharge = |
|---|
| 2999 | + cpu_to_le16(DIV_ROUND_UP(max(indatalen, max_response_size), |
|---|
| 3000 | + SMB2_MAX_BUFFER_SIZE)); |
|---|
| 3001 | + /* always an FSCTL (for now) */ |
|---|
| 3002 | + req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL); |
|---|
| 3003 | + |
|---|
| 3004 | + /* validate negotiate request must be signed - see MS-SMB2 3.2.5.5 */ |
|---|
| 3005 | + if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO) |
|---|
| 3006 | + req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED; |
|---|
| 3007 | + |
|---|
| 3008 | + return 0; |
|---|
| 3009 | +} |
|---|
| 3010 | + |
|---|
| 3011 | +void |
|---|
| 3012 | +SMB2_ioctl_free(struct smb_rqst *rqst) |
|---|
| 3013 | +{ |
|---|
| 3014 | + int i; |
|---|
| 3015 | + if (rqst && rqst->rq_iov) { |
|---|
| 3016 | + cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */ |
|---|
| 3017 | + for (i = 1; i < rqst->rq_nvec; i++) |
|---|
| 3018 | + if (rqst->rq_iov[i].iov_base != smb2_padding) |
|---|
| 3019 | + kfree(rqst->rq_iov[i].iov_base); |
|---|
| 3020 | + } |
|---|
| 3021 | +} |
|---|
| 3022 | + |
|---|
| 3023 | + |
|---|
| 2386 | 3024 | /* |
|---|
| 2387 | 3025 | * SMB2 IOCTL is used for both IOCTLs and FSCTLs |
|---|
| 2388 | 3026 | */ |
|---|
| 2389 | 3027 | int |
|---|
| 2390 | 3028 | SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, |
|---|
| 2391 | | - u64 volatile_fid, u32 opcode, bool is_fsctl, |
|---|
| 2392 | | - char *in_data, u32 indatalen, |
|---|
| 2393 | | - char **out_data, u32 *plen /* returned data len */) |
|---|
| 3029 | + u64 volatile_fid, u32 opcode, char *in_data, u32 indatalen, |
|---|
| 3030 | + u32 max_out_data_len, char **out_data, |
|---|
| 3031 | + u32 *plen /* returned data len */) |
|---|
| 2394 | 3032 | { |
|---|
| 2395 | 3033 | struct smb_rqst rqst; |
|---|
| 2396 | | - struct smb2_ioctl_req *req; |
|---|
| 2397 | | - struct smb2_ioctl_rsp *rsp; |
|---|
| 3034 | + struct smb2_ioctl_rsp *rsp = NULL; |
|---|
| 2398 | 3035 | struct cifs_ses *ses; |
|---|
| 2399 | | - struct kvec iov[2]; |
|---|
| 2400 | | - struct kvec rsp_iov; |
|---|
| 2401 | | - int resp_buftype; |
|---|
| 2402 | | - int n_iov; |
|---|
| 3036 | + struct TCP_Server_Info *server; |
|---|
| 3037 | + struct kvec iov[SMB2_IOCTL_IOV_SIZE]; |
|---|
| 3038 | + struct kvec rsp_iov = {NULL, 0}; |
|---|
| 3039 | + int resp_buftype = CIFS_NO_BUFFER; |
|---|
| 2403 | 3040 | int rc = 0; |
|---|
| 2404 | 3041 | int flags = 0; |
|---|
| 2405 | | - unsigned int total_len; |
|---|
| 2406 | 3042 | |
|---|
| 2407 | 3043 | cifs_dbg(FYI, "SMB2 IOCTL\n"); |
|---|
| 2408 | 3044 | |
|---|
| .. | .. |
|---|
| 2413 | 3049 | if (plen) |
|---|
| 2414 | 3050 | *plen = 0; |
|---|
| 2415 | 3051 | |
|---|
| 2416 | | - if (tcon) |
|---|
| 2417 | | - ses = tcon->ses; |
|---|
| 2418 | | - else |
|---|
| 3052 | + if (!tcon) |
|---|
| 2419 | 3053 | return -EIO; |
|---|
| 2420 | 3054 | |
|---|
| 2421 | | - if (!ses || !(ses->server)) |
|---|
| 3055 | + ses = tcon->ses; |
|---|
| 3056 | + if (!ses) |
|---|
| 2422 | 3057 | return -EIO; |
|---|
| 2423 | 3058 | |
|---|
| 2424 | | - rc = smb2_ioctl_req_init(opcode, tcon, (void **) &req, &total_len); |
|---|
| 2425 | | - if (rc) |
|---|
| 2426 | | - return rc; |
|---|
| 3059 | + server = cifs_pick_channel(ses); |
|---|
| 3060 | + if (!server) |
|---|
| 3061 | + return -EIO; |
|---|
| 2427 | 3062 | |
|---|
| 2428 | 3063 | if (smb3_encryption_required(tcon)) |
|---|
| 2429 | 3064 | flags |= CIFS_TRANSFORM_REQ; |
|---|
| 2430 | 3065 | |
|---|
| 2431 | | - req->CtlCode = cpu_to_le32(opcode); |
|---|
| 2432 | | - req->PersistentFileId = persistent_fid; |
|---|
| 2433 | | - req->VolatileFileId = volatile_fid; |
|---|
| 2434 | | - |
|---|
| 2435 | | - if (indatalen) { |
|---|
| 2436 | | - req->InputCount = cpu_to_le32(indatalen); |
|---|
| 2437 | | - /* do not set InputOffset if no input data */ |
|---|
| 2438 | | - req->InputOffset = |
|---|
| 2439 | | - cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer)); |
|---|
| 2440 | | - iov[1].iov_base = in_data; |
|---|
| 2441 | | - iov[1].iov_len = indatalen; |
|---|
| 2442 | | - n_iov = 2; |
|---|
| 2443 | | - } else |
|---|
| 2444 | | - n_iov = 1; |
|---|
| 2445 | | - |
|---|
| 2446 | | - req->OutputOffset = 0; |
|---|
| 2447 | | - req->OutputCount = 0; /* MBZ */ |
|---|
| 2448 | | - |
|---|
| 2449 | | - /* |
|---|
| 2450 | | - * Could increase MaxOutputResponse, but that would require more |
|---|
| 2451 | | - * than one credit. Windows typically sets this smaller, but for some |
|---|
| 2452 | | - * ioctls it may be useful to allow server to send more. No point |
|---|
| 2453 | | - * limiting what the server can send as long as fits in one credit |
|---|
| 2454 | | - * Unfortunately - we can not handle more than CIFS_MAX_MSG_SIZE |
|---|
| 2455 | | - * (by default, note that it can be overridden to make max larger) |
|---|
| 2456 | | - * in responses (except for read responses which can be bigger. |
|---|
| 2457 | | - * We may want to bump this limit up |
|---|
| 2458 | | - */ |
|---|
| 2459 | | - req->MaxOutputResponse = cpu_to_le32(CIFSMaxBufSize); |
|---|
| 2460 | | - |
|---|
| 2461 | | - if (is_fsctl) |
|---|
| 2462 | | - req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL); |
|---|
| 2463 | | - else |
|---|
| 2464 | | - req->Flags = 0; |
|---|
| 2465 | | - |
|---|
| 2466 | | - iov[0].iov_base = (char *)req; |
|---|
| 2467 | | - |
|---|
| 2468 | | - /* |
|---|
| 2469 | | - * If no input data, the size of ioctl struct in |
|---|
| 2470 | | - * protocol spec still includes a 1 byte data buffer, |
|---|
| 2471 | | - * but if input data passed to ioctl, we do not |
|---|
| 2472 | | - * want to double count this, so we do not send |
|---|
| 2473 | | - * the dummy one byte of data in iovec[0] if sending |
|---|
| 2474 | | - * input data (in iovec[1]). |
|---|
| 2475 | | - */ |
|---|
| 2476 | | - |
|---|
| 2477 | | - if (indatalen) { |
|---|
| 2478 | | - iov[0].iov_len = total_len - 1; |
|---|
| 2479 | | - } else |
|---|
| 2480 | | - iov[0].iov_len = total_len; |
|---|
| 2481 | | - |
|---|
| 2482 | | - /* validate negotiate request must be signed - see MS-SMB2 3.2.5.5 */ |
|---|
| 2483 | | - if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO) |
|---|
| 2484 | | - req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED; |
|---|
| 2485 | | - |
|---|
| 2486 | 3066 | memset(&rqst, 0, sizeof(struct smb_rqst)); |
|---|
| 3067 | + memset(&iov, 0, sizeof(iov)); |
|---|
| 2487 | 3068 | rqst.rq_iov = iov; |
|---|
| 2488 | | - rqst.rq_nvec = n_iov; |
|---|
| 3069 | + rqst.rq_nvec = SMB2_IOCTL_IOV_SIZE; |
|---|
| 2489 | 3070 | |
|---|
| 2490 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, |
|---|
| 3071 | + rc = SMB2_ioctl_init(tcon, server, |
|---|
| 3072 | + &rqst, persistent_fid, volatile_fid, opcode, |
|---|
| 3073 | + in_data, indatalen, max_out_data_len); |
|---|
| 3074 | + if (rc) |
|---|
| 3075 | + goto ioctl_exit; |
|---|
| 3076 | + |
|---|
| 3077 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 3078 | + &rqst, &resp_buftype, flags, |
|---|
| 2491 | 3079 | &rsp_iov); |
|---|
| 2492 | | - cifs_small_buf_release(req); |
|---|
| 2493 | 3080 | rsp = (struct smb2_ioctl_rsp *)rsp_iov.iov_base; |
|---|
| 2494 | 3081 | |
|---|
| 2495 | 3082 | if (rc != 0) |
|---|
| 2496 | 3083 | trace_smb3_fsctl_err(xid, persistent_fid, tcon->tid, |
|---|
| 2497 | 3084 | ses->Suid, 0, opcode, rc); |
|---|
| 2498 | 3085 | |
|---|
| 2499 | | - if ((rc != 0) && (rc != -EINVAL)) { |
|---|
| 3086 | + if ((rc != 0) && (rc != -EINVAL) && (rc != -E2BIG)) { |
|---|
| 2500 | 3087 | cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); |
|---|
| 2501 | 3088 | goto ioctl_exit; |
|---|
| 2502 | 3089 | } else if (rc == -EINVAL) { |
|---|
| 2503 | 3090 | if ((opcode != FSCTL_SRV_COPYCHUNK_WRITE) && |
|---|
| 2504 | 3091 | (opcode != FSCTL_SRV_COPYCHUNK)) { |
|---|
| 3092 | + cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); |
|---|
| 3093 | + goto ioctl_exit; |
|---|
| 3094 | + } |
|---|
| 3095 | + } else if (rc == -E2BIG) { |
|---|
| 3096 | + if (opcode != FSCTL_QUERY_ALLOCATED_RANGES) { |
|---|
| 2505 | 3097 | cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); |
|---|
| 2506 | 3098 | goto ioctl_exit; |
|---|
| 2507 | 3099 | } |
|---|
| .. | .. |
|---|
| 2517 | 3109 | if (*plen == 0) |
|---|
| 2518 | 3110 | goto ioctl_exit; /* server returned no data */ |
|---|
| 2519 | 3111 | else if (*plen > rsp_iov.iov_len || *plen > 0xFF00) { |
|---|
| 2520 | | - cifs_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen); |
|---|
| 3112 | + cifs_tcon_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen); |
|---|
| 2521 | 3113 | *plen = 0; |
|---|
| 2522 | 3114 | rc = -EIO; |
|---|
| 2523 | 3115 | goto ioctl_exit; |
|---|
| 2524 | 3116 | } |
|---|
| 2525 | 3117 | |
|---|
| 2526 | 3118 | if (rsp_iov.iov_len - *plen < le32_to_cpu(rsp->OutputOffset)) { |
|---|
| 2527 | | - cifs_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen, |
|---|
| 3119 | + cifs_tcon_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen, |
|---|
| 2528 | 3120 | le32_to_cpu(rsp->OutputOffset)); |
|---|
| 2529 | 3121 | *plen = 0; |
|---|
| 2530 | 3122 | rc = -EIO; |
|---|
| 2531 | 3123 | goto ioctl_exit; |
|---|
| 2532 | 3124 | } |
|---|
| 2533 | 3125 | |
|---|
| 2534 | | - *out_data = kmalloc(*plen, GFP_KERNEL); |
|---|
| 3126 | + *out_data = kmemdup((char *)rsp + le32_to_cpu(rsp->OutputOffset), |
|---|
| 3127 | + *plen, GFP_KERNEL); |
|---|
| 2535 | 3128 | if (*out_data == NULL) { |
|---|
| 2536 | 3129 | rc = -ENOMEM; |
|---|
| 2537 | 3130 | goto ioctl_exit; |
|---|
| 2538 | 3131 | } |
|---|
| 2539 | 3132 | |
|---|
| 2540 | | - memcpy(*out_data, (char *)rsp + le32_to_cpu(rsp->OutputOffset), *plen); |
|---|
| 2541 | 3133 | ioctl_exit: |
|---|
| 3134 | + SMB2_ioctl_free(&rqst); |
|---|
| 2542 | 3135 | free_rsp_buf(resp_buftype, rsp); |
|---|
| 2543 | 3136 | return rc; |
|---|
| 2544 | 3137 | } |
|---|
| .. | .. |
|---|
| 2559 | 3152 | cpu_to_le16(COMPRESSION_FORMAT_DEFAULT); |
|---|
| 2560 | 3153 | |
|---|
| 2561 | 3154 | rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid, |
|---|
| 2562 | | - FSCTL_SET_COMPRESSION, true /* is_fsctl */, |
|---|
| 3155 | + FSCTL_SET_COMPRESSION, |
|---|
| 2563 | 3156 | (char *)&fsctl_input /* data input */, |
|---|
| 2564 | | - 2 /* in data len */, &ret_data /* out data */, NULL); |
|---|
| 3157 | + 2 /* in data len */, CIFSMaxBufSize /* max out data */, |
|---|
| 3158 | + &ret_data /* out data */, NULL); |
|---|
| 2565 | 3159 | |
|---|
| 2566 | 3160 | cifs_dbg(FYI, "set compression rc %d\n", rc); |
|---|
| 2567 | 3161 | |
|---|
| .. | .. |
|---|
| 2569 | 3163 | } |
|---|
| 2570 | 3164 | |
|---|
| 2571 | 3165 | int |
|---|
| 2572 | | -SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, |
|---|
| 2573 | | - u64 persistent_fid, u64 volatile_fid) |
|---|
| 3166 | +SMB2_close_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, |
|---|
| 3167 | + struct smb_rqst *rqst, |
|---|
| 3168 | + u64 persistent_fid, u64 volatile_fid, bool query_attrs) |
|---|
| 2574 | 3169 | { |
|---|
| 2575 | 3170 | struct smb2_close_req *req; |
|---|
| 2576 | 3171 | struct kvec *iov = rqst->rq_iov; |
|---|
| 2577 | 3172 | unsigned int total_len; |
|---|
| 2578 | 3173 | int rc; |
|---|
| 2579 | 3174 | |
|---|
| 2580 | | - rc = smb2_plain_req_init(SMB2_CLOSE, tcon, (void **) &req, &total_len); |
|---|
| 3175 | + rc = smb2_plain_req_init(SMB2_CLOSE, tcon, server, |
|---|
| 3176 | + (void **) &req, &total_len); |
|---|
| 2581 | 3177 | if (rc) |
|---|
| 2582 | 3178 | return rc; |
|---|
| 2583 | 3179 | |
|---|
| 2584 | 3180 | req->PersistentFileId = persistent_fid; |
|---|
| 2585 | 3181 | req->VolatileFileId = volatile_fid; |
|---|
| 3182 | + if (query_attrs) |
|---|
| 3183 | + req->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; |
|---|
| 3184 | + else |
|---|
| 3185 | + req->Flags = 0; |
|---|
| 2586 | 3186 | iov[0].iov_base = (char *)req; |
|---|
| 2587 | 3187 | iov[0].iov_len = total_len; |
|---|
| 2588 | 3188 | |
|---|
| .. | .. |
|---|
| 2597 | 3197 | } |
|---|
| 2598 | 3198 | |
|---|
| 2599 | 3199 | int |
|---|
| 2600 | | -SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 2601 | | - u64 persistent_fid, u64 volatile_fid, int flags) |
|---|
| 3200 | +__SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 3201 | + u64 persistent_fid, u64 volatile_fid, |
|---|
| 3202 | + struct smb2_file_network_open_info *pbuf) |
|---|
| 2602 | 3203 | { |
|---|
| 2603 | 3204 | struct smb_rqst rqst; |
|---|
| 2604 | 3205 | struct smb2_close_rsp *rsp = NULL; |
|---|
| 2605 | 3206 | struct cifs_ses *ses = tcon->ses; |
|---|
| 3207 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
|---|
| 2606 | 3208 | struct kvec iov[1]; |
|---|
| 2607 | 3209 | struct kvec rsp_iov; |
|---|
| 2608 | 3210 | int resp_buftype = CIFS_NO_BUFFER; |
|---|
| 2609 | 3211 | int rc = 0; |
|---|
| 3212 | + int flags = 0; |
|---|
| 3213 | + bool query_attrs = false; |
|---|
| 2610 | 3214 | |
|---|
| 2611 | 3215 | cifs_dbg(FYI, "Close\n"); |
|---|
| 2612 | 3216 | |
|---|
| 2613 | | - if (!ses || !(ses->server)) |
|---|
| 3217 | + if (!ses || !server) |
|---|
| 2614 | 3218 | return -EIO; |
|---|
| 2615 | 3219 | |
|---|
| 2616 | 3220 | if (smb3_encryption_required(tcon)) |
|---|
| .. | .. |
|---|
| 2621 | 3225 | rqst.rq_iov = iov; |
|---|
| 2622 | 3226 | rqst.rq_nvec = 1; |
|---|
| 2623 | 3227 | |
|---|
| 2624 | | - rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid); |
|---|
| 3228 | + /* check if need to ask server to return timestamps in close response */ |
|---|
| 3229 | + if (pbuf) |
|---|
| 3230 | + query_attrs = true; |
|---|
| 3231 | + |
|---|
| 3232 | + trace_smb3_close_enter(xid, persistent_fid, tcon->tid, ses->Suid); |
|---|
| 3233 | + rc = SMB2_close_init(tcon, server, |
|---|
| 3234 | + &rqst, persistent_fid, volatile_fid, |
|---|
| 3235 | + query_attrs); |
|---|
| 2625 | 3236 | if (rc) |
|---|
| 2626 | 3237 | goto close_exit; |
|---|
| 2627 | 3238 | |
|---|
| 2628 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 3239 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 3240 | + &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 2629 | 3241 | rsp = (struct smb2_close_rsp *)rsp_iov.iov_base; |
|---|
| 2630 | 3242 | |
|---|
| 2631 | 3243 | if (rc != 0) { |
|---|
| .. | .. |
|---|
| 2633 | 3245 | trace_smb3_close_err(xid, persistent_fid, tcon->tid, ses->Suid, |
|---|
| 2634 | 3246 | rc); |
|---|
| 2635 | 3247 | goto close_exit; |
|---|
| 3248 | + } else { |
|---|
| 3249 | + trace_smb3_close_done(xid, persistent_fid, tcon->tid, |
|---|
| 3250 | + ses->Suid); |
|---|
| 3251 | + /* |
|---|
| 3252 | + * Note that have to subtract 4 since struct network_open_info |
|---|
| 3253 | + * has a final 4 byte pad that close response does not have |
|---|
| 3254 | + */ |
|---|
| 3255 | + if (pbuf) |
|---|
| 3256 | + memcpy(pbuf, (char *)&rsp->CreationTime, sizeof(*pbuf) - 4); |
|---|
| 2636 | 3257 | } |
|---|
| 2637 | 3258 | |
|---|
| 2638 | | - /* BB FIXME - decode close response, update inode for caching */ |
|---|
| 2639 | | - |
|---|
| 3259 | + atomic_dec(&tcon->num_remote_opens); |
|---|
| 2640 | 3260 | close_exit: |
|---|
| 2641 | 3261 | SMB2_close_free(&rqst); |
|---|
| 2642 | 3262 | free_rsp_buf(resp_buftype, rsp); |
|---|
| 2643 | | - return rc; |
|---|
| 2644 | | -} |
|---|
| 2645 | | - |
|---|
| 2646 | | -int |
|---|
| 2647 | | -SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 2648 | | - u64 persistent_fid, u64 volatile_fid) |
|---|
| 2649 | | -{ |
|---|
| 2650 | | - int rc; |
|---|
| 2651 | | - int tmp_rc; |
|---|
| 2652 | | - |
|---|
| 2653 | | - rc = SMB2_close_flags(xid, tcon, persistent_fid, volatile_fid, 0); |
|---|
| 2654 | 3263 | |
|---|
| 2655 | 3264 | /* retry close in a worker thread if this one is interrupted */ |
|---|
| 2656 | | - if (rc == -EINTR) { |
|---|
| 3265 | + if (is_interrupt_error(rc)) { |
|---|
| 3266 | + int tmp_rc; |
|---|
| 3267 | + |
|---|
| 2657 | 3268 | tmp_rc = smb2_handle_cancelled_close(tcon, persistent_fid, |
|---|
| 2658 | 3269 | volatile_fid); |
|---|
| 2659 | 3270 | if (tmp_rc) |
|---|
| 2660 | 3271 | cifs_dbg(VFS, "handle cancelled close fid 0x%llx returned error %d\n", |
|---|
| 2661 | 3272 | persistent_fid, tmp_rc); |
|---|
| 2662 | 3273 | } |
|---|
| 2663 | | - |
|---|
| 2664 | 3274 | return rc; |
|---|
| 3275 | +} |
|---|
| 3276 | + |
|---|
| 3277 | +int |
|---|
| 3278 | +SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 3279 | + u64 persistent_fid, u64 volatile_fid) |
|---|
| 3280 | +{ |
|---|
| 3281 | + return __SMB2_close(xid, tcon, persistent_fid, volatile_fid, NULL); |
|---|
| 2665 | 3282 | } |
|---|
| 2666 | 3283 | |
|---|
| 2667 | 3284 | int |
|---|
| .. | .. |
|---|
| 2688 | 3305 | } |
|---|
| 2689 | 3306 | |
|---|
| 2690 | 3307 | if ((begin_of_buf > end_of_smb) || (end_of_buf > end_of_smb)) { |
|---|
| 2691 | | - cifs_dbg(VFS, "illegal server response, bad offset to data\n"); |
|---|
| 3308 | + cifs_dbg(VFS, "Invalid server response, bad offset to data\n"); |
|---|
| 2692 | 3309 | return -EINVAL; |
|---|
| 2693 | 3310 | } |
|---|
| 2694 | 3311 | |
|---|
| .. | .. |
|---|
| 2699 | 3316 | * If SMB buffer fields are valid, copy into temporary buffer to hold result. |
|---|
| 2700 | 3317 | * Caller must free buffer. |
|---|
| 2701 | 3318 | */ |
|---|
| 2702 | | -static int |
|---|
| 2703 | | -validate_and_copy_iov(unsigned int offset, unsigned int buffer_length, |
|---|
| 2704 | | - struct kvec *iov, unsigned int minbufsize, |
|---|
| 2705 | | - char *data) |
|---|
| 3319 | +int |
|---|
| 3320 | +smb2_validate_and_copy_iov(unsigned int offset, unsigned int buffer_length, |
|---|
| 3321 | + struct kvec *iov, unsigned int minbufsize, |
|---|
| 3322 | + char *data) |
|---|
| 2706 | 3323 | { |
|---|
| 2707 | 3324 | char *begin_of_buf = offset + (char *)iov->iov_base; |
|---|
| 2708 | 3325 | int rc; |
|---|
| .. | .. |
|---|
| 2720 | 3337 | } |
|---|
| 2721 | 3338 | |
|---|
| 2722 | 3339 | int |
|---|
| 2723 | | -SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, |
|---|
| 3340 | +SMB2_query_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, |
|---|
| 3341 | + struct smb_rqst *rqst, |
|---|
| 2724 | 3342 | u64 persistent_fid, u64 volatile_fid, |
|---|
| 2725 | 3343 | u8 info_class, u8 info_type, u32 additional_info, |
|---|
| 2726 | | - size_t output_len) |
|---|
| 3344 | + size_t output_len, size_t input_len, void *input) |
|---|
| 2727 | 3345 | { |
|---|
| 2728 | 3346 | struct smb2_query_info_req *req; |
|---|
| 2729 | 3347 | struct kvec *iov = rqst->rq_iov; |
|---|
| 2730 | 3348 | unsigned int total_len; |
|---|
| 2731 | 3349 | int rc; |
|---|
| 2732 | 3350 | |
|---|
| 2733 | | - rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req, |
|---|
| 2734 | | - &total_len); |
|---|
| 3351 | + rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, server, |
|---|
| 3352 | + (void **) &req, &total_len); |
|---|
| 2735 | 3353 | if (rc) |
|---|
| 2736 | 3354 | return rc; |
|---|
| 2737 | 3355 | |
|---|
| .. | .. |
|---|
| 2741 | 3359 | req->VolatileFileId = volatile_fid; |
|---|
| 2742 | 3360 | req->AdditionalInformation = cpu_to_le32(additional_info); |
|---|
| 2743 | 3361 | |
|---|
| 2744 | | - /* |
|---|
| 2745 | | - * We do not use the input buffer (do not send extra byte) |
|---|
| 2746 | | - */ |
|---|
| 2747 | | - req->InputBufferOffset = 0; |
|---|
| 2748 | | - |
|---|
| 2749 | 3362 | req->OutputBufferLength = cpu_to_le32(output_len); |
|---|
| 3363 | + if (input_len) { |
|---|
| 3364 | + req->InputBufferLength = cpu_to_le32(input_len); |
|---|
| 3365 | + /* total_len for smb query request never close to le16 max */ |
|---|
| 3366 | + req->InputBufferOffset = cpu_to_le16(total_len - 1); |
|---|
| 3367 | + memcpy(req->Buffer, input, input_len); |
|---|
| 3368 | + } |
|---|
| 2750 | 3369 | |
|---|
| 2751 | 3370 | iov[0].iov_base = (char *)req; |
|---|
| 2752 | 3371 | /* 1 for Buffer */ |
|---|
| 2753 | | - iov[0].iov_len = total_len - 1; |
|---|
| 3372 | + iov[0].iov_len = total_len - 1 + input_len; |
|---|
| 2754 | 3373 | return 0; |
|---|
| 2755 | 3374 | } |
|---|
| 2756 | 3375 | |
|---|
| .. | .. |
|---|
| 2774 | 3393 | int rc = 0; |
|---|
| 2775 | 3394 | int resp_buftype = CIFS_NO_BUFFER; |
|---|
| 2776 | 3395 | struct cifs_ses *ses = tcon->ses; |
|---|
| 3396 | + struct TCP_Server_Info *server; |
|---|
| 2777 | 3397 | int flags = 0; |
|---|
| 3398 | + bool allocated = false; |
|---|
| 2778 | 3399 | |
|---|
| 2779 | 3400 | cifs_dbg(FYI, "Query Info\n"); |
|---|
| 2780 | 3401 | |
|---|
| 2781 | | - if (!ses || !(ses->server)) |
|---|
| 3402 | + if (!ses) |
|---|
| 3403 | + return -EIO; |
|---|
| 3404 | + server = cifs_pick_channel(ses); |
|---|
| 3405 | + if (!server) |
|---|
| 2782 | 3406 | return -EIO; |
|---|
| 2783 | 3407 | |
|---|
| 2784 | 3408 | if (smb3_encryption_required(tcon)) |
|---|
| .. | .. |
|---|
| 2789 | 3413 | rqst.rq_iov = iov; |
|---|
| 2790 | 3414 | rqst.rq_nvec = 1; |
|---|
| 2791 | 3415 | |
|---|
| 2792 | | - rc = SMB2_query_info_init(tcon, &rqst, persistent_fid, volatile_fid, |
|---|
| 3416 | + rc = SMB2_query_info_init(tcon, server, |
|---|
| 3417 | + &rqst, persistent_fid, volatile_fid, |
|---|
| 2793 | 3418 | info_class, info_type, additional_info, |
|---|
| 2794 | | - output_len); |
|---|
| 3419 | + output_len, 0, NULL); |
|---|
| 2795 | 3420 | if (rc) |
|---|
| 2796 | 3421 | goto qinf_exit; |
|---|
| 2797 | 3422 | |
|---|
| 2798 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 3423 | + trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid, |
|---|
| 3424 | + ses->Suid, info_class, (__u32)info_type); |
|---|
| 3425 | + |
|---|
| 3426 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 3427 | + &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 2799 | 3428 | rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; |
|---|
| 2800 | 3429 | |
|---|
| 2801 | 3430 | if (rc) { |
|---|
| .. | .. |
|---|
| 2805 | 3434 | goto qinf_exit; |
|---|
| 2806 | 3435 | } |
|---|
| 2807 | 3436 | |
|---|
| 3437 | + trace_smb3_query_info_done(xid, persistent_fid, tcon->tid, |
|---|
| 3438 | + ses->Suid, info_class, (__u32)info_type); |
|---|
| 3439 | + |
|---|
| 2808 | 3440 | if (dlen) { |
|---|
| 2809 | 3441 | *dlen = le32_to_cpu(rsp->OutputBufferLength); |
|---|
| 2810 | 3442 | if (!*data) { |
|---|
| 2811 | 3443 | *data = kmalloc(*dlen, GFP_KERNEL); |
|---|
| 2812 | 3444 | if (!*data) { |
|---|
| 2813 | | - cifs_dbg(VFS, |
|---|
| 3445 | + cifs_tcon_dbg(VFS, |
|---|
| 2814 | 3446 | "Error %d allocating memory for acl\n", |
|---|
| 2815 | 3447 | rc); |
|---|
| 2816 | 3448 | *dlen = 0; |
|---|
| 3449 | + rc = -ENOMEM; |
|---|
| 2817 | 3450 | goto qinf_exit; |
|---|
| 2818 | 3451 | } |
|---|
| 3452 | + allocated = true; |
|---|
| 2819 | 3453 | } |
|---|
| 2820 | 3454 | } |
|---|
| 2821 | 3455 | |
|---|
| 2822 | | - rc = validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset), |
|---|
| 2823 | | - le32_to_cpu(rsp->OutputBufferLength), |
|---|
| 2824 | | - &rsp_iov, min_len, *data); |
|---|
| 3456 | + rc = smb2_validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset), |
|---|
| 3457 | + le32_to_cpu(rsp->OutputBufferLength), |
|---|
| 3458 | + &rsp_iov, min_len, *data); |
|---|
| 3459 | + if (rc && allocated) { |
|---|
| 3460 | + kfree(*data); |
|---|
| 3461 | + *data = NULL; |
|---|
| 3462 | + *dlen = 0; |
|---|
| 3463 | + } |
|---|
| 2825 | 3464 | |
|---|
| 2826 | 3465 | qinf_exit: |
|---|
| 2827 | 3466 | SMB2_query_info_free(&rqst); |
|---|
| 2828 | 3467 | free_rsp_buf(resp_buftype, rsp); |
|---|
| 2829 | 3468 | return rc; |
|---|
| 2830 | | -} |
|---|
| 2831 | | - |
|---|
| 2832 | | -int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 2833 | | - u64 persistent_fid, u64 volatile_fid, |
|---|
| 2834 | | - int ea_buf_size, struct smb2_file_full_ea_info *data) |
|---|
| 2835 | | -{ |
|---|
| 2836 | | - return query_info(xid, tcon, persistent_fid, volatile_fid, |
|---|
| 2837 | | - FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE, 0, |
|---|
| 2838 | | - ea_buf_size, |
|---|
| 2839 | | - sizeof(struct smb2_file_full_ea_info), |
|---|
| 2840 | | - (void **)&data, |
|---|
| 2841 | | - NULL); |
|---|
| 2842 | 3469 | } |
|---|
| 2843 | 3470 | |
|---|
| 2844 | 3471 | int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| .. | .. |
|---|
| 2849 | 3476 | sizeof(struct smb2_file_all_info) + PATH_MAX * 2, |
|---|
| 2850 | 3477 | sizeof(struct smb2_file_all_info), (void **)&data, |
|---|
| 2851 | 3478 | NULL); |
|---|
| 3479 | +} |
|---|
| 3480 | + |
|---|
| 3481 | +int |
|---|
| 3482 | +SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 3483 | + u64 persistent_fid, u64 volatile_fid, struct smb311_posix_qinfo *data, u32 *plen) |
|---|
| 3484 | +{ |
|---|
| 3485 | + size_t output_len = sizeof(struct smb311_posix_qinfo *) + |
|---|
| 3486 | + (sizeof(struct cifs_sid) * 2) + (PATH_MAX * 2); |
|---|
| 3487 | + *plen = 0; |
|---|
| 3488 | + |
|---|
| 3489 | + return query_info(xid, tcon, persistent_fid, volatile_fid, |
|---|
| 3490 | + SMB_FIND_FILE_POSIX_INFO, SMB2_O_INFO_FILE, 0, |
|---|
| 3491 | + output_len, sizeof(struct smb311_posix_qinfo), (void **)&data, plen); |
|---|
| 2852 | 3492 | } |
|---|
| 2853 | 3493 | |
|---|
| 2854 | 3494 | int |
|---|
| .. | .. |
|---|
| 2876 | 3516 | } |
|---|
| 2877 | 3517 | |
|---|
| 2878 | 3518 | /* |
|---|
| 3519 | + * CHANGE_NOTIFY Request is sent to get notifications on changes to a directory |
|---|
| 3520 | + * See MS-SMB2 2.2.35 and 2.2.36 |
|---|
| 3521 | + */ |
|---|
| 3522 | + |
|---|
| 3523 | +static int |
|---|
| 3524 | +SMB2_notify_init(const unsigned int xid, struct smb_rqst *rqst, |
|---|
| 3525 | + struct cifs_tcon *tcon, struct TCP_Server_Info *server, |
|---|
| 3526 | + u64 persistent_fid, u64 volatile_fid, |
|---|
| 3527 | + u32 completion_filter, bool watch_tree) |
|---|
| 3528 | +{ |
|---|
| 3529 | + struct smb2_change_notify_req *req; |
|---|
| 3530 | + struct kvec *iov = rqst->rq_iov; |
|---|
| 3531 | + unsigned int total_len; |
|---|
| 3532 | + int rc; |
|---|
| 3533 | + |
|---|
| 3534 | + rc = smb2_plain_req_init(SMB2_CHANGE_NOTIFY, tcon, server, |
|---|
| 3535 | + (void **) &req, &total_len); |
|---|
| 3536 | + if (rc) |
|---|
| 3537 | + return rc; |
|---|
| 3538 | + |
|---|
| 3539 | + req->PersistentFileId = persistent_fid; |
|---|
| 3540 | + req->VolatileFileId = volatile_fid; |
|---|
| 3541 | + /* See note 354 of MS-SMB2, 64K max */ |
|---|
| 3542 | + req->OutputBufferLength = |
|---|
| 3543 | + cpu_to_le32(SMB2_MAX_BUFFER_SIZE - MAX_SMB2_HDR_SIZE); |
|---|
| 3544 | + req->CompletionFilter = cpu_to_le32(completion_filter); |
|---|
| 3545 | + if (watch_tree) |
|---|
| 3546 | + req->Flags = cpu_to_le16(SMB2_WATCH_TREE); |
|---|
| 3547 | + else |
|---|
| 3548 | + req->Flags = 0; |
|---|
| 3549 | + |
|---|
| 3550 | + iov[0].iov_base = (char *)req; |
|---|
| 3551 | + iov[0].iov_len = total_len; |
|---|
| 3552 | + |
|---|
| 3553 | + return 0; |
|---|
| 3554 | +} |
|---|
| 3555 | + |
|---|
| 3556 | +int |
|---|
| 3557 | +SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 3558 | + u64 persistent_fid, u64 volatile_fid, bool watch_tree, |
|---|
| 3559 | + u32 completion_filter) |
|---|
| 3560 | +{ |
|---|
| 3561 | + struct cifs_ses *ses = tcon->ses; |
|---|
| 3562 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
|---|
| 3563 | + struct smb_rqst rqst; |
|---|
| 3564 | + struct kvec iov[1]; |
|---|
| 3565 | + struct kvec rsp_iov = {NULL, 0}; |
|---|
| 3566 | + int resp_buftype = CIFS_NO_BUFFER; |
|---|
| 3567 | + int flags = 0; |
|---|
| 3568 | + int rc = 0; |
|---|
| 3569 | + |
|---|
| 3570 | + cifs_dbg(FYI, "change notify\n"); |
|---|
| 3571 | + if (!ses || !server) |
|---|
| 3572 | + return -EIO; |
|---|
| 3573 | + |
|---|
| 3574 | + if (smb3_encryption_required(tcon)) |
|---|
| 3575 | + flags |= CIFS_TRANSFORM_REQ; |
|---|
| 3576 | + |
|---|
| 3577 | + memset(&rqst, 0, sizeof(struct smb_rqst)); |
|---|
| 3578 | + memset(&iov, 0, sizeof(iov)); |
|---|
| 3579 | + rqst.rq_iov = iov; |
|---|
| 3580 | + rqst.rq_nvec = 1; |
|---|
| 3581 | + |
|---|
| 3582 | + rc = SMB2_notify_init(xid, &rqst, tcon, server, |
|---|
| 3583 | + persistent_fid, volatile_fid, |
|---|
| 3584 | + completion_filter, watch_tree); |
|---|
| 3585 | + if (rc) |
|---|
| 3586 | + goto cnotify_exit; |
|---|
| 3587 | + |
|---|
| 3588 | + trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid, |
|---|
| 3589 | + (u8)watch_tree, completion_filter); |
|---|
| 3590 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 3591 | + &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 3592 | + |
|---|
| 3593 | + if (rc != 0) { |
|---|
| 3594 | + cifs_stats_fail_inc(tcon, SMB2_CHANGE_NOTIFY_HE); |
|---|
| 3595 | + trace_smb3_notify_err(xid, persistent_fid, tcon->tid, ses->Suid, |
|---|
| 3596 | + (u8)watch_tree, completion_filter, rc); |
|---|
| 3597 | + } else |
|---|
| 3598 | + trace_smb3_notify_done(xid, persistent_fid, tcon->tid, |
|---|
| 3599 | + ses->Suid, (u8)watch_tree, completion_filter); |
|---|
| 3600 | + |
|---|
| 3601 | + cnotify_exit: |
|---|
| 3602 | + if (rqst.rq_iov) |
|---|
| 3603 | + cifs_small_buf_release(rqst.rq_iov[0].iov_base); /* request */ |
|---|
| 3604 | + free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
|---|
| 3605 | + return rc; |
|---|
| 3606 | +} |
|---|
| 3607 | + |
|---|
| 3608 | + |
|---|
| 3609 | + |
|---|
| 3610 | +/* |
|---|
| 2879 | 3611 | * This is a no-op for now. We're not really interested in the reply, but |
|---|
| 2880 | 3612 | * rather in the fact that the server sent one and that server->lstrp |
|---|
| 2881 | 3613 | * gets updated. |
|---|
| .. | .. |
|---|
| 2887 | 3619 | { |
|---|
| 2888 | 3620 | struct TCP_Server_Info *server = mid->callback_data; |
|---|
| 2889 | 3621 | struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf; |
|---|
| 2890 | | - unsigned int credits_received = 0; |
|---|
| 3622 | + struct cifs_credits credits = { .value = 0, .instance = 0 }; |
|---|
| 2891 | 3623 | |
|---|
| 2892 | 3624 | if (mid->mid_state == MID_RESPONSE_RECEIVED |
|---|
| 2893 | | - || mid->mid_state == MID_RESPONSE_MALFORMED) |
|---|
| 2894 | | - credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); |
|---|
| 3625 | + || mid->mid_state == MID_RESPONSE_MALFORMED) { |
|---|
| 3626 | + credits.value = le16_to_cpu(rsp->sync_hdr.CreditRequest); |
|---|
| 3627 | + credits.instance = server->reconnect_instance; |
|---|
| 3628 | + } |
|---|
| 2895 | 3629 | |
|---|
| 2896 | 3630 | DeleteMidQEntry(mid); |
|---|
| 2897 | | - add_credits(server, credits_received, CIFS_ECHO_OP); |
|---|
| 3631 | + add_credits(server, &credits, CIFS_ECHO_OP); |
|---|
| 2898 | 3632 | } |
|---|
| 2899 | 3633 | |
|---|
| 2900 | 3634 | void smb2_reconnect_server(struct work_struct *work) |
|---|
| .. | .. |
|---|
| 2924 | 3658 | tcon_exist = true; |
|---|
| 2925 | 3659 | } |
|---|
| 2926 | 3660 | } |
|---|
| 3661 | + /* |
|---|
| 3662 | + * IPC has the same lifetime as its session and uses its |
|---|
| 3663 | + * refcount. |
|---|
| 3664 | + */ |
|---|
| 2927 | 3665 | if (ses->tcon_ipc && ses->tcon_ipc->need_reconnect) { |
|---|
| 2928 | 3666 | list_add_tail(&ses->tcon_ipc->rlist, &tmp_list); |
|---|
| 2929 | 3667 | tcon_exist = true; |
|---|
| 3668 | + ses->ses_count++; |
|---|
| 2930 | 3669 | } |
|---|
| 2931 | 3670 | } |
|---|
| 2932 | 3671 | /* |
|---|
| .. | .. |
|---|
| 2939 | 3678 | spin_unlock(&cifs_tcp_ses_lock); |
|---|
| 2940 | 3679 | |
|---|
| 2941 | 3680 | list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) { |
|---|
| 2942 | | - rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon); |
|---|
| 3681 | + rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server); |
|---|
| 2943 | 3682 | if (!rc) |
|---|
| 2944 | 3683 | cifs_reopen_persistent_handles(tcon); |
|---|
| 2945 | 3684 | else |
|---|
| 2946 | 3685 | resched = true; |
|---|
| 2947 | 3686 | list_del_init(&tcon->rlist); |
|---|
| 2948 | | - cifs_put_tcon(tcon); |
|---|
| 3687 | + if (tcon->ipc) |
|---|
| 3688 | + cifs_put_smb_ses(tcon->ses); |
|---|
| 3689 | + else |
|---|
| 3690 | + cifs_put_tcon(tcon); |
|---|
| 2949 | 3691 | } |
|---|
| 2950 | 3692 | |
|---|
| 2951 | 3693 | cifs_dbg(FYI, "Reconnecting tcons finished\n"); |
|---|
| .. | .. |
|---|
| 2972 | 3714 | |
|---|
| 2973 | 3715 | if (server->tcpStatus == CifsNeedNegotiate) { |
|---|
| 2974 | 3716 | /* No need to send echo on newly established connections */ |
|---|
| 2975 | | - queue_delayed_work(cifsiod_wq, &server->reconnect, 0); |
|---|
| 3717 | + mod_delayed_work(cifsiod_wq, &server->reconnect, 0); |
|---|
| 2976 | 3718 | return rc; |
|---|
| 2977 | 3719 | } |
|---|
| 2978 | 3720 | |
|---|
| 2979 | | - rc = smb2_plain_req_init(SMB2_ECHO, NULL, (void **)&req, &total_len); |
|---|
| 3721 | + rc = smb2_plain_req_init(SMB2_ECHO, NULL, server, |
|---|
| 3722 | + (void **)&req, &total_len); |
|---|
| 2980 | 3723 | if (rc) |
|---|
| 2981 | 3724 | return rc; |
|---|
| 2982 | 3725 | |
|---|
| .. | .. |
|---|
| 2986 | 3729 | iov[0].iov_base = (char *)req; |
|---|
| 2987 | 3730 | |
|---|
| 2988 | 3731 | rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL, |
|---|
| 2989 | | - server, CIFS_ECHO_OP); |
|---|
| 3732 | + server, CIFS_ECHO_OP, NULL); |
|---|
| 2990 | 3733 | if (rc) |
|---|
| 2991 | 3734 | cifs_dbg(FYI, "Echo request failed: %d\n", rc); |
|---|
| 2992 | 3735 | |
|---|
| .. | .. |
|---|
| 2994 | 3737 | return rc; |
|---|
| 2995 | 3738 | } |
|---|
| 2996 | 3739 | |
|---|
| 2997 | | -int |
|---|
| 2998 | | -SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, |
|---|
| 2999 | | - u64 volatile_fid) |
|---|
| 3740 | +void |
|---|
| 3741 | +SMB2_flush_free(struct smb_rqst *rqst) |
|---|
| 3000 | 3742 | { |
|---|
| 3001 | | - struct smb_rqst rqst; |
|---|
| 3743 | + if (rqst && rqst->rq_iov) |
|---|
| 3744 | + cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */ |
|---|
| 3745 | +} |
|---|
| 3746 | + |
|---|
| 3747 | +int |
|---|
| 3748 | +SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst, |
|---|
| 3749 | + struct cifs_tcon *tcon, struct TCP_Server_Info *server, |
|---|
| 3750 | + u64 persistent_fid, u64 volatile_fid) |
|---|
| 3751 | +{ |
|---|
| 3002 | 3752 | struct smb2_flush_req *req; |
|---|
| 3003 | | - struct cifs_ses *ses = tcon->ses; |
|---|
| 3004 | | - struct kvec iov[1]; |
|---|
| 3005 | | - struct kvec rsp_iov; |
|---|
| 3006 | | - int resp_buftype; |
|---|
| 3007 | | - int rc = 0; |
|---|
| 3008 | | - int flags = 0; |
|---|
| 3753 | + struct kvec *iov = rqst->rq_iov; |
|---|
| 3009 | 3754 | unsigned int total_len; |
|---|
| 3755 | + int rc; |
|---|
| 3010 | 3756 | |
|---|
| 3011 | | - cifs_dbg(FYI, "Flush\n"); |
|---|
| 3012 | | - |
|---|
| 3013 | | - if (!ses || !(ses->server)) |
|---|
| 3014 | | - return -EIO; |
|---|
| 3015 | | - |
|---|
| 3016 | | - rc = smb2_plain_req_init(SMB2_FLUSH, tcon, (void **) &req, &total_len); |
|---|
| 3757 | + rc = smb2_plain_req_init(SMB2_FLUSH, tcon, server, |
|---|
| 3758 | + (void **) &req, &total_len); |
|---|
| 3017 | 3759 | if (rc) |
|---|
| 3018 | 3760 | return rc; |
|---|
| 3019 | | - |
|---|
| 3020 | | - if (smb3_encryption_required(tcon)) |
|---|
| 3021 | | - flags |= CIFS_TRANSFORM_REQ; |
|---|
| 3022 | 3761 | |
|---|
| 3023 | 3762 | req->PersistentFileId = persistent_fid; |
|---|
| 3024 | 3763 | req->VolatileFileId = volatile_fid; |
|---|
| .. | .. |
|---|
| 3026 | 3765 | iov[0].iov_base = (char *)req; |
|---|
| 3027 | 3766 | iov[0].iov_len = total_len; |
|---|
| 3028 | 3767 | |
|---|
| 3768 | + return 0; |
|---|
| 3769 | +} |
|---|
| 3770 | + |
|---|
| 3771 | +int |
|---|
| 3772 | +SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, |
|---|
| 3773 | + u64 volatile_fid) |
|---|
| 3774 | +{ |
|---|
| 3775 | + struct cifs_ses *ses = tcon->ses; |
|---|
| 3776 | + struct smb_rqst rqst; |
|---|
| 3777 | + struct kvec iov[1]; |
|---|
| 3778 | + struct kvec rsp_iov = {NULL, 0}; |
|---|
| 3779 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
|---|
| 3780 | + int resp_buftype = CIFS_NO_BUFFER; |
|---|
| 3781 | + int flags = 0; |
|---|
| 3782 | + int rc = 0; |
|---|
| 3783 | + |
|---|
| 3784 | + cifs_dbg(FYI, "flush\n"); |
|---|
| 3785 | + if (!ses || !(ses->server)) |
|---|
| 3786 | + return -EIO; |
|---|
| 3787 | + |
|---|
| 3788 | + if (smb3_encryption_required(tcon)) |
|---|
| 3789 | + flags |= CIFS_TRANSFORM_REQ; |
|---|
| 3790 | + |
|---|
| 3029 | 3791 | memset(&rqst, 0, sizeof(struct smb_rqst)); |
|---|
| 3792 | + memset(&iov, 0, sizeof(iov)); |
|---|
| 3030 | 3793 | rqst.rq_iov = iov; |
|---|
| 3031 | 3794 | rqst.rq_nvec = 1; |
|---|
| 3032 | 3795 | |
|---|
| 3033 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 3034 | | - cifs_small_buf_release(req); |
|---|
| 3796 | + rc = SMB2_flush_init(xid, &rqst, tcon, server, |
|---|
| 3797 | + persistent_fid, volatile_fid); |
|---|
| 3798 | + if (rc) |
|---|
| 3799 | + goto flush_exit; |
|---|
| 3800 | + |
|---|
| 3801 | + trace_smb3_flush_enter(xid, persistent_fid, tcon->tid, ses->Suid); |
|---|
| 3802 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 3803 | + &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 3035 | 3804 | |
|---|
| 3036 | 3805 | if (rc != 0) { |
|---|
| 3037 | 3806 | cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE); |
|---|
| 3038 | 3807 | trace_smb3_flush_err(xid, persistent_fid, tcon->tid, ses->Suid, |
|---|
| 3039 | 3808 | rc); |
|---|
| 3040 | | - } |
|---|
| 3809 | + } else |
|---|
| 3810 | + trace_smb3_flush_done(xid, persistent_fid, tcon->tid, |
|---|
| 3811 | + ses->Suid); |
|---|
| 3041 | 3812 | |
|---|
| 3813 | + flush_exit: |
|---|
| 3814 | + SMB2_flush_free(&rqst); |
|---|
| 3042 | 3815 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
|---|
| 3043 | 3816 | return rc; |
|---|
| 3044 | 3817 | } |
|---|
| .. | .. |
|---|
| 3055 | 3828 | int rc = -EACCES; |
|---|
| 3056 | 3829 | struct smb2_read_plain_req *req = NULL; |
|---|
| 3057 | 3830 | struct smb2_sync_hdr *shdr; |
|---|
| 3058 | | - struct TCP_Server_Info *server; |
|---|
| 3831 | + struct TCP_Server_Info *server = io_parms->server; |
|---|
| 3059 | 3832 | |
|---|
| 3060 | | - rc = smb2_plain_req_init(SMB2_READ, io_parms->tcon, (void **) &req, |
|---|
| 3061 | | - total_len); |
|---|
| 3833 | + rc = smb2_plain_req_init(SMB2_READ, io_parms->tcon, server, |
|---|
| 3834 | + (void **) &req, total_len); |
|---|
| 3062 | 3835 | if (rc) |
|---|
| 3063 | 3836 | return rc; |
|---|
| 3064 | 3837 | |
|---|
| 3065 | | - server = io_parms->tcon->ses->server; |
|---|
| 3066 | 3838 | if (server == NULL) |
|---|
| 3067 | 3839 | return -ECONNABORTED; |
|---|
| 3068 | 3840 | |
|---|
| .. | .. |
|---|
| 3077 | 3849 | req->MinimumCount = 0; |
|---|
| 3078 | 3850 | req->Length = cpu_to_le32(io_parms->length); |
|---|
| 3079 | 3851 | req->Offset = cpu_to_le64(io_parms->offset); |
|---|
| 3852 | + |
|---|
| 3853 | + trace_smb3_read_enter(0 /* xid */, |
|---|
| 3854 | + io_parms->persistent_fid, |
|---|
| 3855 | + io_parms->tcon->tid, io_parms->tcon->ses->Suid, |
|---|
| 3856 | + io_parms->offset, io_parms->length); |
|---|
| 3080 | 3857 | #ifdef CONFIG_CIFS_SMB_DIRECT |
|---|
| 3081 | 3858 | /* |
|---|
| 3082 | 3859 | * If we want to do a RDMA write, fill in and append |
|---|
| .. | .. |
|---|
| 3086 | 3863 | rdata->bytes >= server->smbd_conn->rdma_readwrite_threshold) { |
|---|
| 3087 | 3864 | |
|---|
| 3088 | 3865 | struct smbd_buffer_descriptor_v1 *v1; |
|---|
| 3089 | | - bool need_invalidate = |
|---|
| 3090 | | - io_parms->tcon->ses->server->dialect == SMB30_PROT_ID; |
|---|
| 3866 | + bool need_invalidate = server->dialect == SMB30_PROT_ID; |
|---|
| 3091 | 3867 | |
|---|
| 3092 | 3868 | rdata->mr = smbd_register_mr( |
|---|
| 3093 | 3869 | server->smbd_conn, rdata->pages, |
|---|
| 3094 | 3870 | rdata->nr_pages, rdata->page_offset, |
|---|
| 3095 | 3871 | rdata->tailsz, true, need_invalidate); |
|---|
| 3096 | 3872 | if (!rdata->mr) |
|---|
| 3097 | | - return -ENOBUFS; |
|---|
| 3873 | + return -EAGAIN; |
|---|
| 3098 | 3874 | |
|---|
| 3099 | 3875 | req->Channel = SMB2_CHANNEL_RDMA_V1_INVALIDATE; |
|---|
| 3100 | 3876 | if (need_invalidate) |
|---|
| .. | .. |
|---|
| 3144 | 3920 | { |
|---|
| 3145 | 3921 | struct cifs_readdata *rdata = mid->callback_data; |
|---|
| 3146 | 3922 | struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); |
|---|
| 3147 | | - struct TCP_Server_Info *server = tcon->ses->server; |
|---|
| 3923 | + struct TCP_Server_Info *server = rdata->server; |
|---|
| 3148 | 3924 | struct smb2_sync_hdr *shdr = |
|---|
| 3149 | 3925 | (struct smb2_sync_hdr *)rdata->iov[0].iov_base; |
|---|
| 3150 | | - unsigned int credits_received = 0; |
|---|
| 3926 | + struct cifs_credits credits = { .value = 0, .instance = 0 }; |
|---|
| 3151 | 3927 | struct smb_rqst rqst = { .rq_iov = &rdata->iov[1], |
|---|
| 3152 | 3928 | .rq_nvec = 1, |
|---|
| 3153 | 3929 | .rq_pages = rdata->pages, |
|---|
| .. | .. |
|---|
| 3156 | 3932 | .rq_pagesz = rdata->pagesz, |
|---|
| 3157 | 3933 | .rq_tailsz = rdata->tailsz }; |
|---|
| 3158 | 3934 | |
|---|
| 3935 | + WARN_ONCE(rdata->server != mid->server, |
|---|
| 3936 | + "rdata server %p != mid server %p", |
|---|
| 3937 | + rdata->server, mid->server); |
|---|
| 3938 | + |
|---|
| 3159 | 3939 | cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n", |
|---|
| 3160 | 3940 | __func__, mid->mid, mid->mid_state, rdata->result, |
|---|
| 3161 | 3941 | rdata->bytes); |
|---|
| 3162 | 3942 | |
|---|
| 3163 | 3943 | switch (mid->mid_state) { |
|---|
| 3164 | 3944 | case MID_RESPONSE_RECEIVED: |
|---|
| 3165 | | - credits_received = le16_to_cpu(shdr->CreditRequest); |
|---|
| 3945 | + credits.value = le16_to_cpu(shdr->CreditRequest); |
|---|
| 3946 | + credits.instance = server->reconnect_instance; |
|---|
| 3166 | 3947 | /* result already set, check signature */ |
|---|
| 3167 | 3948 | if (server->sign && !mid->decrypted) { |
|---|
| 3168 | 3949 | int rc; |
|---|
| 3169 | 3950 | |
|---|
| 3170 | 3951 | rc = smb2_verify_signature(&rqst, server); |
|---|
| 3171 | 3952 | if (rc) |
|---|
| 3172 | | - cifs_dbg(VFS, "SMB signature verification returned error = %d\n", |
|---|
| 3953 | + cifs_tcon_dbg(VFS, "SMB signature verification returned error = %d\n", |
|---|
| 3173 | 3954 | rc); |
|---|
| 3174 | 3955 | } |
|---|
| 3175 | 3956 | /* FIXME: should this be counted toward the initiating task? */ |
|---|
| .. | .. |
|---|
| 3187 | 3968 | cifs_stats_bytes_read(tcon, rdata->got_bytes); |
|---|
| 3188 | 3969 | break; |
|---|
| 3189 | 3970 | case MID_RESPONSE_MALFORMED: |
|---|
| 3190 | | - credits_received = le16_to_cpu(shdr->CreditRequest); |
|---|
| 3191 | | - /* fall through */ |
|---|
| 3971 | + credits.value = le16_to_cpu(shdr->CreditRequest); |
|---|
| 3972 | + credits.instance = server->reconnect_instance; |
|---|
| 3973 | + fallthrough; |
|---|
| 3192 | 3974 | default: |
|---|
| 3193 | | - if (rdata->result != -ENODATA) |
|---|
| 3194 | | - rdata->result = -EIO; |
|---|
| 3975 | + rdata->result = -EIO; |
|---|
| 3195 | 3976 | } |
|---|
| 3196 | 3977 | #ifdef CONFIG_CIFS_SMB_DIRECT |
|---|
| 3197 | 3978 | /* |
|---|
| .. | .. |
|---|
| 3218 | 3999 | |
|---|
| 3219 | 4000 | queue_work(cifsiod_wq, &rdata->work); |
|---|
| 3220 | 4001 | DeleteMidQEntry(mid); |
|---|
| 3221 | | - add_credits(server, credits_received, 0); |
|---|
| 4002 | + add_credits(server, &credits, 0); |
|---|
| 3222 | 4003 | } |
|---|
| 3223 | 4004 | |
|---|
| 3224 | 4005 | /* smb2_async_readv - send an async read, and set up mid to handle result */ |
|---|
| .. | .. |
|---|
| 3232 | 4013 | struct smb_rqst rqst = { .rq_iov = rdata->iov, |
|---|
| 3233 | 4014 | .rq_nvec = 1 }; |
|---|
| 3234 | 4015 | struct TCP_Server_Info *server; |
|---|
| 4016 | + struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); |
|---|
| 3235 | 4017 | unsigned int total_len; |
|---|
| 3236 | 4018 | |
|---|
| 3237 | 4019 | cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", |
|---|
| 3238 | 4020 | __func__, rdata->offset, rdata->bytes); |
|---|
| 3239 | 4021 | |
|---|
| 4022 | + if (!rdata->server) |
|---|
| 4023 | + rdata->server = cifs_pick_channel(tcon->ses); |
|---|
| 4024 | + |
|---|
| 3240 | 4025 | io_parms.tcon = tlink_tcon(rdata->cfile->tlink); |
|---|
| 4026 | + io_parms.server = server = rdata->server; |
|---|
| 3241 | 4027 | io_parms.offset = rdata->offset; |
|---|
| 3242 | 4028 | io_parms.length = rdata->bytes; |
|---|
| 3243 | 4029 | io_parms.persistent_fid = rdata->cfile->fid.persistent_fid; |
|---|
| 3244 | 4030 | io_parms.volatile_fid = rdata->cfile->fid.volatile_fid; |
|---|
| 3245 | 4031 | io_parms.pid = rdata->pid; |
|---|
| 3246 | 4032 | |
|---|
| 3247 | | - server = io_parms.tcon->ses->server; |
|---|
| 3248 | | - |
|---|
| 3249 | 4033 | rc = smb2_new_read_req( |
|---|
| 3250 | 4034 | (void **) &buf, &total_len, &io_parms, rdata, 0, 0); |
|---|
| 3251 | | - if (rc) { |
|---|
| 3252 | | - if (rc == -EAGAIN && rdata->credits) { |
|---|
| 3253 | | - /* credits was reset by reconnect */ |
|---|
| 3254 | | - rdata->credits = 0; |
|---|
| 3255 | | - /* reduce in_flight value since we won't send the req */ |
|---|
| 3256 | | - spin_lock(&server->req_lock); |
|---|
| 3257 | | - server->in_flight--; |
|---|
| 3258 | | - spin_unlock(&server->req_lock); |
|---|
| 3259 | | - } |
|---|
| 4035 | + if (rc) |
|---|
| 3260 | 4036 | return rc; |
|---|
| 3261 | | - } |
|---|
| 3262 | 4037 | |
|---|
| 3263 | 4038 | if (smb3_encryption_required(io_parms.tcon)) |
|---|
| 3264 | 4039 | flags |= CIFS_TRANSFORM_REQ; |
|---|
| .. | .. |
|---|
| 3268 | 4043 | |
|---|
| 3269 | 4044 | shdr = (struct smb2_sync_hdr *)buf; |
|---|
| 3270 | 4045 | |
|---|
| 3271 | | - if (rdata->credits) { |
|---|
| 4046 | + if (rdata->credits.value > 0) { |
|---|
| 3272 | 4047 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, |
|---|
| 3273 | 4048 | SMB2_MAX_BUFFER_SIZE)); |
|---|
| 3274 | | - shdr->CreditRequest = |
|---|
| 3275 | | - cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); |
|---|
| 3276 | | - spin_lock(&server->req_lock); |
|---|
| 3277 | | - server->credits += rdata->credits - |
|---|
| 3278 | | - le16_to_cpu(shdr->CreditCharge); |
|---|
| 3279 | | - spin_unlock(&server->req_lock); |
|---|
| 3280 | | - wake_up(&server->request_q); |
|---|
| 3281 | | - rdata->credits = le16_to_cpu(shdr->CreditCharge); |
|---|
| 4049 | + shdr->CreditRequest = cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 8); |
|---|
| 4050 | + |
|---|
| 4051 | + rc = adjust_credits(server, &rdata->credits, rdata->bytes); |
|---|
| 4052 | + if (rc) |
|---|
| 4053 | + goto async_readv_out; |
|---|
| 4054 | + |
|---|
| 3282 | 4055 | flags |= CIFS_HAS_CREDITS; |
|---|
| 3283 | 4056 | } |
|---|
| 3284 | 4057 | |
|---|
| 3285 | 4058 | kref_get(&rdata->refcount); |
|---|
| 3286 | | - rc = cifs_call_async(io_parms.tcon->ses->server, &rqst, |
|---|
| 4059 | + rc = cifs_call_async(server, &rqst, |
|---|
| 3287 | 4060 | cifs_readv_receive, smb2_readv_callback, |
|---|
| 3288 | | - smb3_handle_read_data, rdata, flags); |
|---|
| 4061 | + smb3_handle_read_data, rdata, flags, |
|---|
| 4062 | + &rdata->credits); |
|---|
| 3289 | 4063 | if (rc) { |
|---|
| 3290 | 4064 | kref_put(&rdata->refcount, cifs_readdata_release); |
|---|
| 3291 | 4065 | cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); |
|---|
| .. | .. |
|---|
| 3295 | 4069 | io_parms.offset, io_parms.length, rc); |
|---|
| 3296 | 4070 | } |
|---|
| 3297 | 4071 | |
|---|
| 4072 | +async_readv_out: |
|---|
| 3298 | 4073 | cifs_small_buf_release(buf); |
|---|
| 3299 | 4074 | return rc; |
|---|
| 3300 | 4075 | } |
|---|
| .. | .. |
|---|
| 3304 | 4079 | unsigned int *nbytes, char **buf, int *buf_type) |
|---|
| 3305 | 4080 | { |
|---|
| 3306 | 4081 | struct smb_rqst rqst; |
|---|
| 3307 | | - int resp_buftype, rc = -EACCES; |
|---|
| 4082 | + int resp_buftype, rc; |
|---|
| 3308 | 4083 | struct smb2_read_plain_req *req = NULL; |
|---|
| 3309 | 4084 | struct smb2_read_rsp *rsp = NULL; |
|---|
| 3310 | 4085 | struct kvec iov[1]; |
|---|
| .. | .. |
|---|
| 3312 | 4087 | unsigned int total_len; |
|---|
| 3313 | 4088 | int flags = CIFS_LOG_ERROR; |
|---|
| 3314 | 4089 | struct cifs_ses *ses = io_parms->tcon->ses; |
|---|
| 4090 | + |
|---|
| 4091 | + if (!io_parms->server) |
|---|
| 4092 | + io_parms->server = cifs_pick_channel(io_parms->tcon->ses); |
|---|
| 3315 | 4093 | |
|---|
| 3316 | 4094 | *nbytes = 0; |
|---|
| 3317 | 4095 | rc = smb2_new_read_req((void **)&req, &total_len, io_parms, NULL, 0, 0); |
|---|
| .. | .. |
|---|
| 3328 | 4106 | rqst.rq_iov = iov; |
|---|
| 3329 | 4107 | rqst.rq_nvec = 1; |
|---|
| 3330 | 4108 | |
|---|
| 3331 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 4109 | + rc = cifs_send_recv(xid, ses, io_parms->server, |
|---|
| 4110 | + &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 3332 | 4111 | rsp = (struct smb2_read_rsp *)rsp_iov.iov_base; |
|---|
| 3333 | 4112 | |
|---|
| 3334 | 4113 | if (rc) { |
|---|
| .. | .. |
|---|
| 3339 | 4118 | io_parms->tcon->tid, ses->Suid, |
|---|
| 3340 | 4119 | io_parms->offset, io_parms->length, |
|---|
| 3341 | 4120 | rc); |
|---|
| 3342 | | - } |
|---|
| 4121 | + } else |
|---|
| 4122 | + trace_smb3_read_done(xid, req->PersistentFileId, |
|---|
| 4123 | + io_parms->tcon->tid, ses->Suid, |
|---|
| 4124 | + io_parms->offset, 0); |
|---|
| 3343 | 4125 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
|---|
| 3344 | 4126 | cifs_small_buf_release(req); |
|---|
| 3345 | 4127 | return rc == -ENODATA ? 0 : rc; |
|---|
| .. | .. |
|---|
| 3381 | 4163 | { |
|---|
| 3382 | 4164 | struct cifs_writedata *wdata = mid->callback_data; |
|---|
| 3383 | 4165 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); |
|---|
| 4166 | + struct TCP_Server_Info *server = wdata->server; |
|---|
| 3384 | 4167 | unsigned int written; |
|---|
| 3385 | 4168 | struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf; |
|---|
| 3386 | | - unsigned int credits_received = 0; |
|---|
| 4169 | + struct cifs_credits credits = { .value = 0, .instance = 0 }; |
|---|
| 4170 | + |
|---|
| 4171 | + WARN_ONCE(wdata->server != mid->server, |
|---|
| 4172 | + "wdata server %p != mid server %p", |
|---|
| 4173 | + wdata->server, mid->server); |
|---|
| 3387 | 4174 | |
|---|
| 3388 | 4175 | switch (mid->mid_state) { |
|---|
| 3389 | 4176 | case MID_RESPONSE_RECEIVED: |
|---|
| 3390 | | - credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); |
|---|
| 3391 | | - wdata->result = smb2_check_receive(mid, tcon->ses->server, 0); |
|---|
| 4177 | + credits.value = le16_to_cpu(rsp->sync_hdr.CreditRequest); |
|---|
| 4178 | + credits.instance = server->reconnect_instance; |
|---|
| 4179 | + wdata->result = smb2_check_receive(mid, server, 0); |
|---|
| 3392 | 4180 | if (wdata->result != 0) |
|---|
| 3393 | 4181 | break; |
|---|
| 3394 | 4182 | |
|---|
| .. | .. |
|---|
| 3412 | 4200 | wdata->result = -EAGAIN; |
|---|
| 3413 | 4201 | break; |
|---|
| 3414 | 4202 | case MID_RESPONSE_MALFORMED: |
|---|
| 3415 | | - credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); |
|---|
| 3416 | | - /* fall through */ |
|---|
| 4203 | + credits.value = le16_to_cpu(rsp->sync_hdr.CreditRequest); |
|---|
| 4204 | + credits.instance = server->reconnect_instance; |
|---|
| 4205 | + fallthrough; |
|---|
| 3417 | 4206 | default: |
|---|
| 3418 | 4207 | wdata->result = -EIO; |
|---|
| 3419 | 4208 | break; |
|---|
| .. | .. |
|---|
| 3438 | 4227 | tcon->tid, tcon->ses->Suid, wdata->offset, |
|---|
| 3439 | 4228 | wdata->bytes, wdata->result); |
|---|
| 3440 | 4229 | if (wdata->result == -ENOSPC) |
|---|
| 3441 | | - printk_once(KERN_WARNING "Out of space writing to %s\n", |
|---|
| 3442 | | - tcon->treeName); |
|---|
| 4230 | + pr_warn_once("Out of space writing to %s\n", |
|---|
| 4231 | + tcon->treeName); |
|---|
| 3443 | 4232 | } else |
|---|
| 3444 | 4233 | trace_smb3_write_done(0 /* no xid */, |
|---|
| 3445 | 4234 | wdata->cfile->fid.persistent_fid, |
|---|
| .. | .. |
|---|
| 3448 | 4237 | |
|---|
| 3449 | 4238 | queue_work(cifsiod_wq, &wdata->work); |
|---|
| 3450 | 4239 | DeleteMidQEntry(mid); |
|---|
| 3451 | | - add_credits(tcon->ses->server, credits_received, 0); |
|---|
| 4240 | + add_credits(server, &credits, 0); |
|---|
| 3452 | 4241 | } |
|---|
| 3453 | 4242 | |
|---|
| 3454 | 4243 | /* smb2_async_writev - send an async write, and set up mid to handle result */ |
|---|
| .. | .. |
|---|
| 3460 | 4249 | struct smb2_write_req *req = NULL; |
|---|
| 3461 | 4250 | struct smb2_sync_hdr *shdr; |
|---|
| 3462 | 4251 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); |
|---|
| 3463 | | - struct TCP_Server_Info *server = tcon->ses->server; |
|---|
| 4252 | + struct TCP_Server_Info *server = wdata->server; |
|---|
| 3464 | 4253 | struct kvec iov[1]; |
|---|
| 3465 | 4254 | struct smb_rqst rqst = { }; |
|---|
| 3466 | 4255 | unsigned int total_len; |
|---|
| 3467 | 4256 | |
|---|
| 3468 | | - rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len); |
|---|
| 3469 | | - if (rc) { |
|---|
| 3470 | | - if (rc == -EAGAIN && wdata->credits) { |
|---|
| 3471 | | - /* credits was reset by reconnect */ |
|---|
| 3472 | | - wdata->credits = 0; |
|---|
| 3473 | | - /* reduce in_flight value since we won't send the req */ |
|---|
| 3474 | | - spin_lock(&server->req_lock); |
|---|
| 3475 | | - server->in_flight--; |
|---|
| 3476 | | - spin_unlock(&server->req_lock); |
|---|
| 3477 | | - } |
|---|
| 3478 | | - goto async_writev_out; |
|---|
| 3479 | | - } |
|---|
| 4257 | + if (!wdata->server) |
|---|
| 4258 | + server = wdata->server = cifs_pick_channel(tcon->ses); |
|---|
| 4259 | + |
|---|
| 4260 | + rc = smb2_plain_req_init(SMB2_WRITE, tcon, server, |
|---|
| 4261 | + (void **) &req, &total_len); |
|---|
| 4262 | + if (rc) |
|---|
| 4263 | + return rc; |
|---|
| 3480 | 4264 | |
|---|
| 3481 | 4265 | if (smb3_encryption_required(tcon)) |
|---|
| 3482 | 4266 | flags |= CIFS_TRANSFORM_REQ; |
|---|
| .. | .. |
|---|
| 3493 | 4277 | req->DataOffset = cpu_to_le16( |
|---|
| 3494 | 4278 | offsetof(struct smb2_write_req, Buffer)); |
|---|
| 3495 | 4279 | req->RemainingBytes = 0; |
|---|
| 4280 | + |
|---|
| 4281 | + trace_smb3_write_enter(0 /* xid */, wdata->cfile->fid.persistent_fid, |
|---|
| 4282 | + tcon->tid, tcon->ses->Suid, wdata->offset, wdata->bytes); |
|---|
| 3496 | 4283 | #ifdef CONFIG_CIFS_SMB_DIRECT |
|---|
| 3497 | 4284 | /* |
|---|
| 3498 | 4285 | * If we want to do a server RDMA read, fill in and append |
|---|
| .. | .. |
|---|
| 3509 | 4296 | wdata->nr_pages, wdata->page_offset, |
|---|
| 3510 | 4297 | wdata->tailsz, false, need_invalidate); |
|---|
| 3511 | 4298 | if (!wdata->mr) { |
|---|
| 3512 | | - rc = -ENOBUFS; |
|---|
| 4299 | + rc = -EAGAIN; |
|---|
| 3513 | 4300 | goto async_writev_out; |
|---|
| 3514 | 4301 | } |
|---|
| 3515 | 4302 | req->Length = 0; |
|---|
| .. | .. |
|---|
| 3562 | 4349 | req->Length = cpu_to_le32(wdata->bytes); |
|---|
| 3563 | 4350 | #endif |
|---|
| 3564 | 4351 | |
|---|
| 3565 | | - if (wdata->credits) { |
|---|
| 4352 | + if (wdata->credits.value > 0) { |
|---|
| 3566 | 4353 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, |
|---|
| 3567 | 4354 | SMB2_MAX_BUFFER_SIZE)); |
|---|
| 3568 | | - shdr->CreditRequest = |
|---|
| 3569 | | - cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); |
|---|
| 3570 | | - spin_lock(&server->req_lock); |
|---|
| 3571 | | - server->credits += wdata->credits - |
|---|
| 3572 | | - le16_to_cpu(shdr->CreditCharge); |
|---|
| 3573 | | - spin_unlock(&server->req_lock); |
|---|
| 3574 | | - wake_up(&server->request_q); |
|---|
| 3575 | | - wdata->credits = le16_to_cpu(shdr->CreditCharge); |
|---|
| 4355 | + shdr->CreditRequest = cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 8); |
|---|
| 4356 | + |
|---|
| 4357 | + rc = adjust_credits(server, &wdata->credits, wdata->bytes); |
|---|
| 4358 | + if (rc) |
|---|
| 4359 | + goto async_writev_out; |
|---|
| 4360 | + |
|---|
| 3576 | 4361 | flags |= CIFS_HAS_CREDITS; |
|---|
| 3577 | 4362 | } |
|---|
| 3578 | 4363 | |
|---|
| 3579 | 4364 | kref_get(&wdata->refcount); |
|---|
| 3580 | 4365 | rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, NULL, |
|---|
| 3581 | | - wdata, flags); |
|---|
| 4366 | + wdata, flags, &wdata->credits); |
|---|
| 3582 | 4367 | |
|---|
| 3583 | 4368 | if (rc) { |
|---|
| 3584 | 4369 | trace_smb3_write_err(0 /* no xid */, req->PersistentFileId, |
|---|
| .. | .. |
|---|
| 3611 | 4396 | struct kvec rsp_iov; |
|---|
| 3612 | 4397 | int flags = 0; |
|---|
| 3613 | 4398 | unsigned int total_len; |
|---|
| 4399 | + struct TCP_Server_Info *server; |
|---|
| 3614 | 4400 | |
|---|
| 3615 | 4401 | *nbytes = 0; |
|---|
| 3616 | 4402 | |
|---|
| 3617 | 4403 | if (n_vec < 1) |
|---|
| 3618 | 4404 | return rc; |
|---|
| 3619 | 4405 | |
|---|
| 3620 | | - rc = smb2_plain_req_init(SMB2_WRITE, io_parms->tcon, (void **) &req, |
|---|
| 3621 | | - &total_len); |
|---|
| 4406 | + if (!io_parms->server) |
|---|
| 4407 | + io_parms->server = cifs_pick_channel(io_parms->tcon->ses); |
|---|
| 4408 | + server = io_parms->server; |
|---|
| 4409 | + if (server == NULL) |
|---|
| 4410 | + return -ECONNABORTED; |
|---|
| 4411 | + |
|---|
| 4412 | + rc = smb2_plain_req_init(SMB2_WRITE, io_parms->tcon, server, |
|---|
| 4413 | + (void **) &req, &total_len); |
|---|
| 3622 | 4414 | if (rc) |
|---|
| 3623 | 4415 | return rc; |
|---|
| 3624 | | - |
|---|
| 3625 | | - if (io_parms->tcon->ses->server == NULL) |
|---|
| 3626 | | - return -ECONNABORTED; |
|---|
| 3627 | 4416 | |
|---|
| 3628 | 4417 | if (smb3_encryption_required(io_parms->tcon)) |
|---|
| 3629 | 4418 | flags |= CIFS_TRANSFORM_REQ; |
|---|
| .. | .. |
|---|
| 3641 | 4430 | offsetof(struct smb2_write_req, Buffer)); |
|---|
| 3642 | 4431 | req->RemainingBytes = 0; |
|---|
| 3643 | 4432 | |
|---|
| 4433 | + trace_smb3_write_enter(xid, io_parms->persistent_fid, |
|---|
| 4434 | + io_parms->tcon->tid, io_parms->tcon->ses->Suid, |
|---|
| 4435 | + io_parms->offset, io_parms->length); |
|---|
| 4436 | + |
|---|
| 3644 | 4437 | iov[0].iov_base = (char *)req; |
|---|
| 3645 | 4438 | /* 1 for Buffer */ |
|---|
| 3646 | 4439 | iov[0].iov_len = total_len - 1; |
|---|
| .. | .. |
|---|
| 3649 | 4442 | rqst.rq_iov = iov; |
|---|
| 3650 | 4443 | rqst.rq_nvec = n_vec + 1; |
|---|
| 3651 | 4444 | |
|---|
| 3652 | | - rc = cifs_send_recv(xid, io_parms->tcon->ses, &rqst, |
|---|
| 4445 | + rc = cifs_send_recv(xid, io_parms->tcon->ses, server, |
|---|
| 4446 | + &rqst, |
|---|
| 3653 | 4447 | &resp_buftype, flags, &rsp_iov); |
|---|
| 3654 | 4448 | rsp = (struct smb2_write_rsp *)rsp_iov.iov_base; |
|---|
| 3655 | 4449 | |
|---|
| .. | .. |
|---|
| 3673 | 4467 | return rc; |
|---|
| 3674 | 4468 | } |
|---|
| 3675 | 4469 | |
|---|
| 4470 | +int posix_info_sid_size(const void *beg, const void *end) |
|---|
| 4471 | +{ |
|---|
| 4472 | + size_t subauth; |
|---|
| 4473 | + int total; |
|---|
| 4474 | + |
|---|
| 4475 | + if (beg + 1 > end) |
|---|
| 4476 | + return -1; |
|---|
| 4477 | + |
|---|
| 4478 | + subauth = *(u8 *)(beg+1); |
|---|
| 4479 | + if (subauth < 1 || subauth > 15) |
|---|
| 4480 | + return -1; |
|---|
| 4481 | + |
|---|
| 4482 | + total = 1 + 1 + 6 + 4*subauth; |
|---|
| 4483 | + if (beg + total > end) |
|---|
| 4484 | + return -1; |
|---|
| 4485 | + |
|---|
| 4486 | + return total; |
|---|
| 4487 | +} |
|---|
| 4488 | + |
|---|
| 4489 | +int posix_info_parse(const void *beg, const void *end, |
|---|
| 4490 | + struct smb2_posix_info_parsed *out) |
|---|
| 4491 | + |
|---|
| 4492 | +{ |
|---|
| 4493 | + int total_len = 0; |
|---|
| 4494 | + int sid_len; |
|---|
| 4495 | + int name_len; |
|---|
| 4496 | + const void *owner_sid; |
|---|
| 4497 | + const void *group_sid; |
|---|
| 4498 | + const void *name; |
|---|
| 4499 | + |
|---|
| 4500 | + /* if no end bound given, assume payload to be correct */ |
|---|
| 4501 | + if (!end) { |
|---|
| 4502 | + const struct smb2_posix_info *p = beg; |
|---|
| 4503 | + |
|---|
| 4504 | + end = beg + le32_to_cpu(p->NextEntryOffset); |
|---|
| 4505 | + /* last element will have a 0 offset, pick a sensible bound */ |
|---|
| 4506 | + if (end == beg) |
|---|
| 4507 | + end += 0xFFFF; |
|---|
| 4508 | + } |
|---|
| 4509 | + |
|---|
| 4510 | + /* check base buf */ |
|---|
| 4511 | + if (beg + sizeof(struct smb2_posix_info) > end) |
|---|
| 4512 | + return -1; |
|---|
| 4513 | + total_len = sizeof(struct smb2_posix_info); |
|---|
| 4514 | + |
|---|
| 4515 | + /* check owner sid */ |
|---|
| 4516 | + owner_sid = beg + total_len; |
|---|
| 4517 | + sid_len = posix_info_sid_size(owner_sid, end); |
|---|
| 4518 | + if (sid_len < 0) |
|---|
| 4519 | + return -1; |
|---|
| 4520 | + total_len += sid_len; |
|---|
| 4521 | + |
|---|
| 4522 | + /* check group sid */ |
|---|
| 4523 | + group_sid = beg + total_len; |
|---|
| 4524 | + sid_len = posix_info_sid_size(group_sid, end); |
|---|
| 4525 | + if (sid_len < 0) |
|---|
| 4526 | + return -1; |
|---|
| 4527 | + total_len += sid_len; |
|---|
| 4528 | + |
|---|
| 4529 | + /* check name len */ |
|---|
| 4530 | + if (beg + total_len + 4 > end) |
|---|
| 4531 | + return -1; |
|---|
| 4532 | + name_len = le32_to_cpu(*(__le32 *)(beg + total_len)); |
|---|
| 4533 | + if (name_len < 1 || name_len > 0xFFFF) |
|---|
| 4534 | + return -1; |
|---|
| 4535 | + total_len += 4; |
|---|
| 4536 | + |
|---|
| 4537 | + /* check name */ |
|---|
| 4538 | + name = beg + total_len; |
|---|
| 4539 | + if (name + name_len > end) |
|---|
| 4540 | + return -1; |
|---|
| 4541 | + total_len += name_len; |
|---|
| 4542 | + |
|---|
| 4543 | + if (out) { |
|---|
| 4544 | + out->base = beg; |
|---|
| 4545 | + out->size = total_len; |
|---|
| 4546 | + out->name_len = name_len; |
|---|
| 4547 | + out->name = name; |
|---|
| 4548 | + memcpy(&out->owner, owner_sid, |
|---|
| 4549 | + posix_info_sid_size(owner_sid, end)); |
|---|
| 4550 | + memcpy(&out->group, group_sid, |
|---|
| 4551 | + posix_info_sid_size(group_sid, end)); |
|---|
| 4552 | + } |
|---|
| 4553 | + return total_len; |
|---|
| 4554 | +} |
|---|
| 4555 | + |
|---|
| 4556 | +static int posix_info_extra_size(const void *beg, const void *end) |
|---|
| 4557 | +{ |
|---|
| 4558 | + int len = posix_info_parse(beg, end, NULL); |
|---|
| 4559 | + |
|---|
| 4560 | + if (len < 0) |
|---|
| 4561 | + return -1; |
|---|
| 4562 | + return len - sizeof(struct smb2_posix_info); |
|---|
| 4563 | +} |
|---|
| 4564 | + |
|---|
| 3676 | 4565 | static unsigned int |
|---|
| 3677 | | -num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size) |
|---|
| 4566 | +num_entries(int infotype, char *bufstart, char *end_of_buf, char **lastentry, |
|---|
| 4567 | + size_t size) |
|---|
| 3678 | 4568 | { |
|---|
| 3679 | 4569 | int len; |
|---|
| 3680 | 4570 | unsigned int entrycount = 0; |
|---|
| .. | .. |
|---|
| 3698 | 4588 | entryptr = entryptr + next_offset; |
|---|
| 3699 | 4589 | dir_info = (FILE_DIRECTORY_INFO *)entryptr; |
|---|
| 3700 | 4590 | |
|---|
| 3701 | | - len = le32_to_cpu(dir_info->FileNameLength); |
|---|
| 3702 | | - if (entryptr + len < entryptr || |
|---|
| 4591 | + if (infotype == SMB_FIND_FILE_POSIX_INFO) |
|---|
| 4592 | + len = posix_info_extra_size(entryptr, end_of_buf); |
|---|
| 4593 | + else |
|---|
| 4594 | + len = le32_to_cpu(dir_info->FileNameLength); |
|---|
| 4595 | + |
|---|
| 4596 | + if (len < 0 || |
|---|
| 4597 | + entryptr + len < entryptr || |
|---|
| 3703 | 4598 | entryptr + len > end_of_buf || |
|---|
| 3704 | 4599 | entryptr + len + size > end_of_buf) { |
|---|
| 3705 | 4600 | cifs_dbg(VFS, "directory entry name would overflow frame end of buf %p\n", |
|---|
| .. | .. |
|---|
| 3721 | 4616 | /* |
|---|
| 3722 | 4617 | * Readdir/FindFirst |
|---|
| 3723 | 4618 | */ |
|---|
| 3724 | | -int |
|---|
| 3725 | | -SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 3726 | | - u64 persistent_fid, u64 volatile_fid, int index, |
|---|
| 3727 | | - struct cifs_search_info *srch_inf) |
|---|
| 4619 | +int SMB2_query_directory_init(const unsigned int xid, |
|---|
| 4620 | + struct cifs_tcon *tcon, |
|---|
| 4621 | + struct TCP_Server_Info *server, |
|---|
| 4622 | + struct smb_rqst *rqst, |
|---|
| 4623 | + u64 persistent_fid, u64 volatile_fid, |
|---|
| 4624 | + int index, int info_level) |
|---|
| 3728 | 4625 | { |
|---|
| 3729 | | - struct smb_rqst rqst; |
|---|
| 3730 | 4626 | struct smb2_query_directory_req *req; |
|---|
| 3731 | | - struct smb2_query_directory_rsp *rsp = NULL; |
|---|
| 3732 | | - struct kvec iov[2]; |
|---|
| 3733 | | - struct kvec rsp_iov; |
|---|
| 3734 | | - int rc = 0; |
|---|
| 3735 | | - int len; |
|---|
| 3736 | | - int resp_buftype = CIFS_NO_BUFFER; |
|---|
| 3737 | 4627 | unsigned char *bufptr; |
|---|
| 3738 | | - struct TCP_Server_Info *server; |
|---|
| 3739 | | - struct cifs_ses *ses = tcon->ses; |
|---|
| 3740 | 4628 | __le16 asteriks = cpu_to_le16('*'); |
|---|
| 3741 | | - char *end_of_smb; |
|---|
| 3742 | | - unsigned int output_size = CIFSMaxBufSize; |
|---|
| 3743 | | - size_t info_buf_size; |
|---|
| 3744 | | - int flags = 0; |
|---|
| 4629 | + unsigned int output_size = CIFSMaxBufSize - |
|---|
| 4630 | + MAX_SMB2_CREATE_RESPONSE_SIZE - |
|---|
| 4631 | + MAX_SMB2_CLOSE_RESPONSE_SIZE; |
|---|
| 3745 | 4632 | unsigned int total_len; |
|---|
| 4633 | + struct kvec *iov = rqst->rq_iov; |
|---|
| 4634 | + int len, rc; |
|---|
| 3746 | 4635 | |
|---|
| 3747 | | - if (ses && (ses->server)) |
|---|
| 3748 | | - server = ses->server; |
|---|
| 3749 | | - else |
|---|
| 3750 | | - return -EIO; |
|---|
| 3751 | | - |
|---|
| 3752 | | - rc = smb2_plain_req_init(SMB2_QUERY_DIRECTORY, tcon, (void **) &req, |
|---|
| 3753 | | - &total_len); |
|---|
| 4636 | + rc = smb2_plain_req_init(SMB2_QUERY_DIRECTORY, tcon, server, |
|---|
| 4637 | + (void **) &req, &total_len); |
|---|
| 3754 | 4638 | if (rc) |
|---|
| 3755 | 4639 | return rc; |
|---|
| 3756 | 4640 | |
|---|
| 3757 | | - if (smb3_encryption_required(tcon)) |
|---|
| 3758 | | - flags |= CIFS_TRANSFORM_REQ; |
|---|
| 3759 | | - |
|---|
| 3760 | | - switch (srch_inf->info_level) { |
|---|
| 4641 | + switch (info_level) { |
|---|
| 3761 | 4642 | case SMB_FIND_FILE_DIRECTORY_INFO: |
|---|
| 3762 | 4643 | req->FileInformationClass = FILE_DIRECTORY_INFORMATION; |
|---|
| 3763 | | - info_buf_size = sizeof(FILE_DIRECTORY_INFO) - 1; |
|---|
| 3764 | 4644 | break; |
|---|
| 3765 | 4645 | case SMB_FIND_FILE_ID_FULL_DIR_INFO: |
|---|
| 3766 | 4646 | req->FileInformationClass = FILEID_FULL_DIRECTORY_INFORMATION; |
|---|
| 3767 | | - info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO) - 1; |
|---|
| 4647 | + break; |
|---|
| 4648 | + case SMB_FIND_FILE_POSIX_INFO: |
|---|
| 4649 | + req->FileInformationClass = SMB_FIND_FILE_POSIX_INFO; |
|---|
| 3768 | 4650 | break; |
|---|
| 3769 | 4651 | default: |
|---|
| 3770 | | - cifs_dbg(VFS, "info level %u isn't supported\n", |
|---|
| 3771 | | - srch_inf->info_level); |
|---|
| 3772 | | - rc = -EINVAL; |
|---|
| 3773 | | - goto qdir_exit; |
|---|
| 4652 | + cifs_tcon_dbg(VFS, "info level %u isn't supported\n", |
|---|
| 4653 | + info_level); |
|---|
| 4654 | + return -EINVAL; |
|---|
| 3774 | 4655 | } |
|---|
| 3775 | 4656 | |
|---|
| 3776 | 4657 | req->FileIndex = cpu_to_le32(index); |
|---|
| .. | .. |
|---|
| 3799 | 4680 | iov[1].iov_base = (char *)(req->Buffer); |
|---|
| 3800 | 4681 | iov[1].iov_len = len; |
|---|
| 3801 | 4682 | |
|---|
| 3802 | | - memset(&rqst, 0, sizeof(struct smb_rqst)); |
|---|
| 3803 | | - rqst.rq_iov = iov; |
|---|
| 3804 | | - rqst.rq_nvec = 2; |
|---|
| 4683 | + trace_smb3_query_dir_enter(xid, persistent_fid, tcon->tid, |
|---|
| 4684 | + tcon->ses->Suid, index, output_size); |
|---|
| 3805 | 4685 | |
|---|
| 3806 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 3807 | | - cifs_small_buf_release(req); |
|---|
| 3808 | | - rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base; |
|---|
| 4686 | + return 0; |
|---|
| 4687 | +} |
|---|
| 3809 | 4688 | |
|---|
| 3810 | | - if (rc) { |
|---|
| 3811 | | - if (rc == -ENODATA && |
|---|
| 3812 | | - rsp->sync_hdr.Status == STATUS_NO_MORE_FILES) { |
|---|
| 3813 | | - srch_inf->endOfSearch = true; |
|---|
| 3814 | | - rc = 0; |
|---|
| 3815 | | - } else |
|---|
| 3816 | | - cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); |
|---|
| 3817 | | - goto qdir_exit; |
|---|
| 4689 | +void SMB2_query_directory_free(struct smb_rqst *rqst) |
|---|
| 4690 | +{ |
|---|
| 4691 | + if (rqst && rqst->rq_iov) { |
|---|
| 4692 | + cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */ |
|---|
| 4693 | + } |
|---|
| 4694 | +} |
|---|
| 4695 | + |
|---|
| 4696 | +int |
|---|
| 4697 | +smb2_parse_query_directory(struct cifs_tcon *tcon, |
|---|
| 4698 | + struct kvec *rsp_iov, |
|---|
| 4699 | + int resp_buftype, |
|---|
| 4700 | + struct cifs_search_info *srch_inf) |
|---|
| 4701 | +{ |
|---|
| 4702 | + struct smb2_query_directory_rsp *rsp; |
|---|
| 4703 | + size_t info_buf_size; |
|---|
| 4704 | + char *end_of_smb; |
|---|
| 4705 | + int rc; |
|---|
| 4706 | + |
|---|
| 4707 | + rsp = (struct smb2_query_directory_rsp *)rsp_iov->iov_base; |
|---|
| 4708 | + |
|---|
| 4709 | + switch (srch_inf->info_level) { |
|---|
| 4710 | + case SMB_FIND_FILE_DIRECTORY_INFO: |
|---|
| 4711 | + info_buf_size = sizeof(FILE_DIRECTORY_INFO) - 1; |
|---|
| 4712 | + break; |
|---|
| 4713 | + case SMB_FIND_FILE_ID_FULL_DIR_INFO: |
|---|
| 4714 | + info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO) - 1; |
|---|
| 4715 | + break; |
|---|
| 4716 | + case SMB_FIND_FILE_POSIX_INFO: |
|---|
| 4717 | + /* note that posix payload are variable size */ |
|---|
| 4718 | + info_buf_size = sizeof(struct smb2_posix_info); |
|---|
| 4719 | + break; |
|---|
| 4720 | + default: |
|---|
| 4721 | + cifs_tcon_dbg(VFS, "info level %u isn't supported\n", |
|---|
| 4722 | + srch_inf->info_level); |
|---|
| 4723 | + return -EINVAL; |
|---|
| 3818 | 4724 | } |
|---|
| 3819 | 4725 | |
|---|
| 3820 | 4726 | rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), |
|---|
| 3821 | | - le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, |
|---|
| 4727 | + le32_to_cpu(rsp->OutputBufferLength), rsp_iov, |
|---|
| 3822 | 4728 | info_buf_size); |
|---|
| 3823 | | - if (rc) |
|---|
| 3824 | | - goto qdir_exit; |
|---|
| 4729 | + if (rc) { |
|---|
| 4730 | + cifs_tcon_dbg(VFS, "bad info payload"); |
|---|
| 4731 | + return rc; |
|---|
| 4732 | + } |
|---|
| 3825 | 4733 | |
|---|
| 3826 | 4734 | srch_inf->unicode = true; |
|---|
| 3827 | 4735 | |
|---|
| .. | .. |
|---|
| 3834 | 4742 | srch_inf->ntwrk_buf_start = (char *)rsp; |
|---|
| 3835 | 4743 | srch_inf->srch_entries_start = srch_inf->last_entry = |
|---|
| 3836 | 4744 | (char *)rsp + le16_to_cpu(rsp->OutputBufferOffset); |
|---|
| 3837 | | - end_of_smb = rsp_iov.iov_len + (char *)rsp; |
|---|
| 3838 | | - srch_inf->entries_in_buffer = |
|---|
| 3839 | | - num_entries(srch_inf->srch_entries_start, end_of_smb, |
|---|
| 3840 | | - &srch_inf->last_entry, info_buf_size); |
|---|
| 4745 | + end_of_smb = rsp_iov->iov_len + (char *)rsp; |
|---|
| 4746 | + |
|---|
| 4747 | + srch_inf->entries_in_buffer = num_entries( |
|---|
| 4748 | + srch_inf->info_level, |
|---|
| 4749 | + srch_inf->srch_entries_start, |
|---|
| 4750 | + end_of_smb, |
|---|
| 4751 | + &srch_inf->last_entry, |
|---|
| 4752 | + info_buf_size); |
|---|
| 4753 | + |
|---|
| 3841 | 4754 | srch_inf->index_of_last_entry += srch_inf->entries_in_buffer; |
|---|
| 3842 | 4755 | cifs_dbg(FYI, "num entries %d last_index %lld srch start %p srch end %p\n", |
|---|
| 3843 | 4756 | srch_inf->entries_in_buffer, srch_inf->index_of_last_entry, |
|---|
| .. | .. |
|---|
| 3847 | 4760 | else if (resp_buftype == CIFS_SMALL_BUFFER) |
|---|
| 3848 | 4761 | srch_inf->smallBuf = true; |
|---|
| 3849 | 4762 | else |
|---|
| 3850 | | - cifs_dbg(VFS, "illegal search buffer type\n"); |
|---|
| 4763 | + cifs_tcon_dbg(VFS, "Invalid search buffer type\n"); |
|---|
| 3851 | 4764 | |
|---|
| 3852 | | - return rc; |
|---|
| 3853 | | - |
|---|
| 3854 | | -qdir_exit: |
|---|
| 3855 | | - free_rsp_buf(resp_buftype, rsp); |
|---|
| 3856 | | - return rc; |
|---|
| 4765 | + return 0; |
|---|
| 3857 | 4766 | } |
|---|
| 3858 | 4767 | |
|---|
| 3859 | | -static int |
|---|
| 3860 | | -send_set_info(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 3861 | | - u64 persistent_fid, u64 volatile_fid, u32 pid, u8 info_class, |
|---|
| 3862 | | - u8 info_type, u32 additional_info, unsigned int num, |
|---|
| 3863 | | - void **data, unsigned int *size) |
|---|
| 4768 | +int |
|---|
| 4769 | +SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 4770 | + u64 persistent_fid, u64 volatile_fid, int index, |
|---|
| 4771 | + struct cifs_search_info *srch_inf) |
|---|
| 3864 | 4772 | { |
|---|
| 3865 | 4773 | struct smb_rqst rqst; |
|---|
| 3866 | | - struct smb2_set_info_req *req; |
|---|
| 3867 | | - struct smb2_set_info_rsp *rsp = NULL; |
|---|
| 3868 | | - struct kvec *iov; |
|---|
| 4774 | + struct kvec iov[SMB2_QUERY_DIRECTORY_IOV_SIZE]; |
|---|
| 4775 | + struct smb2_query_directory_rsp *rsp = NULL; |
|---|
| 4776 | + int resp_buftype = CIFS_NO_BUFFER; |
|---|
| 3869 | 4777 | struct kvec rsp_iov; |
|---|
| 3870 | 4778 | int rc = 0; |
|---|
| 3871 | | - int resp_buftype; |
|---|
| 3872 | | - unsigned int i; |
|---|
| 3873 | 4779 | struct cifs_ses *ses = tcon->ses; |
|---|
| 4780 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
|---|
| 3874 | 4781 | int flags = 0; |
|---|
| 3875 | | - unsigned int total_len; |
|---|
| 3876 | 4782 | |
|---|
| 3877 | 4783 | if (!ses || !(ses->server)) |
|---|
| 3878 | 4784 | return -EIO; |
|---|
| 3879 | 4785 | |
|---|
| 3880 | | - if (!num) |
|---|
| 3881 | | - return -EINVAL; |
|---|
| 3882 | | - |
|---|
| 3883 | | - iov = kmalloc_array(num, sizeof(struct kvec), GFP_KERNEL); |
|---|
| 3884 | | - if (!iov) |
|---|
| 3885 | | - return -ENOMEM; |
|---|
| 3886 | | - |
|---|
| 3887 | | - rc = smb2_plain_req_init(SMB2_SET_INFO, tcon, (void **) &req, &total_len); |
|---|
| 3888 | | - if (rc) { |
|---|
| 3889 | | - kfree(iov); |
|---|
| 3890 | | - return rc; |
|---|
| 3891 | | - } |
|---|
| 3892 | | - |
|---|
| 3893 | 4786 | if (smb3_encryption_required(tcon)) |
|---|
| 3894 | 4787 | flags |= CIFS_TRANSFORM_REQ; |
|---|
| 3895 | 4788 | |
|---|
| 3896 | | - req->sync_hdr.ProcessId = cpu_to_le32(pid); |
|---|
| 4789 | + memset(&rqst, 0, sizeof(struct smb_rqst)); |
|---|
| 4790 | + memset(&iov, 0, sizeof(iov)); |
|---|
| 4791 | + rqst.rq_iov = iov; |
|---|
| 4792 | + rqst.rq_nvec = SMB2_QUERY_DIRECTORY_IOV_SIZE; |
|---|
| 3897 | 4793 | |
|---|
| 4794 | + rc = SMB2_query_directory_init(xid, tcon, server, |
|---|
| 4795 | + &rqst, persistent_fid, |
|---|
| 4796 | + volatile_fid, index, |
|---|
| 4797 | + srch_inf->info_level); |
|---|
| 4798 | + if (rc) |
|---|
| 4799 | + goto qdir_exit; |
|---|
| 4800 | + |
|---|
| 4801 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 4802 | + &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 4803 | + rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base; |
|---|
| 4804 | + |
|---|
| 4805 | + if (rc) { |
|---|
| 4806 | + if (rc == -ENODATA && |
|---|
| 4807 | + rsp->sync_hdr.Status == STATUS_NO_MORE_FILES) { |
|---|
| 4808 | + trace_smb3_query_dir_done(xid, persistent_fid, |
|---|
| 4809 | + tcon->tid, tcon->ses->Suid, index, 0); |
|---|
| 4810 | + srch_inf->endOfSearch = true; |
|---|
| 4811 | + rc = 0; |
|---|
| 4812 | + } else { |
|---|
| 4813 | + trace_smb3_query_dir_err(xid, persistent_fid, tcon->tid, |
|---|
| 4814 | + tcon->ses->Suid, index, 0, rc); |
|---|
| 4815 | + cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); |
|---|
| 4816 | + } |
|---|
| 4817 | + goto qdir_exit; |
|---|
| 4818 | + } |
|---|
| 4819 | + |
|---|
| 4820 | + rc = smb2_parse_query_directory(tcon, &rsp_iov, resp_buftype, |
|---|
| 4821 | + srch_inf); |
|---|
| 4822 | + if (rc) { |
|---|
| 4823 | + trace_smb3_query_dir_err(xid, persistent_fid, tcon->tid, |
|---|
| 4824 | + tcon->ses->Suid, index, 0, rc); |
|---|
| 4825 | + goto qdir_exit; |
|---|
| 4826 | + } |
|---|
| 4827 | + resp_buftype = CIFS_NO_BUFFER; |
|---|
| 4828 | + |
|---|
| 4829 | + trace_smb3_query_dir_done(xid, persistent_fid, tcon->tid, |
|---|
| 4830 | + tcon->ses->Suid, index, srch_inf->entries_in_buffer); |
|---|
| 4831 | + |
|---|
| 4832 | +qdir_exit: |
|---|
| 4833 | + SMB2_query_directory_free(&rqst); |
|---|
| 4834 | + free_rsp_buf(resp_buftype, rsp); |
|---|
| 4835 | + return rc; |
|---|
| 4836 | +} |
|---|
| 4837 | + |
|---|
| 4838 | +int |
|---|
| 4839 | +SMB2_set_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, |
|---|
| 4840 | + struct smb_rqst *rqst, |
|---|
| 4841 | + u64 persistent_fid, u64 volatile_fid, u32 pid, |
|---|
| 4842 | + u8 info_class, u8 info_type, u32 additional_info, |
|---|
| 4843 | + void **data, unsigned int *size) |
|---|
| 4844 | +{ |
|---|
| 4845 | + struct smb2_set_info_req *req; |
|---|
| 4846 | + struct kvec *iov = rqst->rq_iov; |
|---|
| 4847 | + unsigned int i, total_len; |
|---|
| 4848 | + int rc; |
|---|
| 4849 | + |
|---|
| 4850 | + rc = smb2_plain_req_init(SMB2_SET_INFO, tcon, server, |
|---|
| 4851 | + (void **) &req, &total_len); |
|---|
| 4852 | + if (rc) |
|---|
| 4853 | + return rc; |
|---|
| 4854 | + |
|---|
| 4855 | + req->sync_hdr.ProcessId = cpu_to_le32(pid); |
|---|
| 3898 | 4856 | req->InfoType = info_type; |
|---|
| 3899 | 4857 | req->FileInfoClass = info_class; |
|---|
| 3900 | 4858 | req->PersistentFileId = persistent_fid; |
|---|
| .. | .. |
|---|
| 3912 | 4870 | /* 1 for Buffer */ |
|---|
| 3913 | 4871 | iov[0].iov_len = total_len - 1; |
|---|
| 3914 | 4872 | |
|---|
| 3915 | | - for (i = 1; i < num; i++) { |
|---|
| 4873 | + for (i = 1; i < rqst->rq_nvec; i++) { |
|---|
| 3916 | 4874 | le32_add_cpu(&req->BufferLength, size[i]); |
|---|
| 3917 | 4875 | iov[i].iov_base = (char *)data[i]; |
|---|
| 3918 | 4876 | iov[i].iov_len = size[i]; |
|---|
| 3919 | 4877 | } |
|---|
| 3920 | 4878 | |
|---|
| 4879 | + return 0; |
|---|
| 4880 | +} |
|---|
| 4881 | + |
|---|
| 4882 | +void |
|---|
| 4883 | +SMB2_set_info_free(struct smb_rqst *rqst) |
|---|
| 4884 | +{ |
|---|
| 4885 | + if (rqst && rqst->rq_iov) |
|---|
| 4886 | + cifs_buf_release(rqst->rq_iov[0].iov_base); /* request */ |
|---|
| 4887 | +} |
|---|
| 4888 | + |
|---|
| 4889 | +static int |
|---|
| 4890 | +send_set_info(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 4891 | + u64 persistent_fid, u64 volatile_fid, u32 pid, u8 info_class, |
|---|
| 4892 | + u8 info_type, u32 additional_info, unsigned int num, |
|---|
| 4893 | + void **data, unsigned int *size) |
|---|
| 4894 | +{ |
|---|
| 4895 | + struct smb_rqst rqst; |
|---|
| 4896 | + struct smb2_set_info_rsp *rsp = NULL; |
|---|
| 4897 | + struct kvec *iov; |
|---|
| 4898 | + struct kvec rsp_iov; |
|---|
| 4899 | + int rc = 0; |
|---|
| 4900 | + int resp_buftype; |
|---|
| 4901 | + struct cifs_ses *ses = tcon->ses; |
|---|
| 4902 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
|---|
| 4903 | + int flags = 0; |
|---|
| 4904 | + |
|---|
| 4905 | + if (!ses || !server) |
|---|
| 4906 | + return -EIO; |
|---|
| 4907 | + |
|---|
| 4908 | + if (!num) |
|---|
| 4909 | + return -EINVAL; |
|---|
| 4910 | + |
|---|
| 4911 | + if (smb3_encryption_required(tcon)) |
|---|
| 4912 | + flags |= CIFS_TRANSFORM_REQ; |
|---|
| 4913 | + |
|---|
| 4914 | + iov = kmalloc_array(num, sizeof(struct kvec), GFP_KERNEL); |
|---|
| 4915 | + if (!iov) |
|---|
| 4916 | + return -ENOMEM; |
|---|
| 4917 | + |
|---|
| 3921 | 4918 | memset(&rqst, 0, sizeof(struct smb_rqst)); |
|---|
| 3922 | 4919 | rqst.rq_iov = iov; |
|---|
| 3923 | 4920 | rqst.rq_nvec = num; |
|---|
| 3924 | 4921 | |
|---|
| 3925 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, |
|---|
| 4922 | + rc = SMB2_set_info_init(tcon, server, |
|---|
| 4923 | + &rqst, persistent_fid, volatile_fid, pid, |
|---|
| 4924 | + info_class, info_type, additional_info, |
|---|
| 4925 | + data, size); |
|---|
| 4926 | + if (rc) { |
|---|
| 4927 | + kfree(iov); |
|---|
| 4928 | + return rc; |
|---|
| 4929 | + } |
|---|
| 4930 | + |
|---|
| 4931 | + |
|---|
| 4932 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 4933 | + &rqst, &resp_buftype, flags, |
|---|
| 3926 | 4934 | &rsp_iov); |
|---|
| 3927 | | - cifs_buf_release(req); |
|---|
| 4935 | + SMB2_set_info_free(&rqst); |
|---|
| 3928 | 4936 | rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base; |
|---|
| 3929 | 4937 | |
|---|
| 3930 | 4938 | if (rc != 0) { |
|---|
| .. | .. |
|---|
| 3939 | 4947 | } |
|---|
| 3940 | 4948 | |
|---|
| 3941 | 4949 | int |
|---|
| 3942 | | -SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 3943 | | - u64 persistent_fid, u64 volatile_fid, __le16 *target_file) |
|---|
| 3944 | | -{ |
|---|
| 3945 | | - struct smb2_file_rename_info info; |
|---|
| 3946 | | - void **data; |
|---|
| 3947 | | - unsigned int size[2]; |
|---|
| 3948 | | - int rc; |
|---|
| 3949 | | - int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX)); |
|---|
| 3950 | | - |
|---|
| 3951 | | - data = kmalloc_array(2, sizeof(void *), GFP_KERNEL); |
|---|
| 3952 | | - if (!data) |
|---|
| 3953 | | - return -ENOMEM; |
|---|
| 3954 | | - |
|---|
| 3955 | | - info.ReplaceIfExists = 1; /* 1 = replace existing target with new */ |
|---|
| 3956 | | - /* 0 = fail if target already exists */ |
|---|
| 3957 | | - info.RootDirectory = 0; /* MBZ for network ops (why does spec say?) */ |
|---|
| 3958 | | - info.FileNameLength = cpu_to_le32(len); |
|---|
| 3959 | | - |
|---|
| 3960 | | - data[0] = &info; |
|---|
| 3961 | | - size[0] = sizeof(struct smb2_file_rename_info); |
|---|
| 3962 | | - |
|---|
| 3963 | | - data[1] = target_file; |
|---|
| 3964 | | - size[1] = len + 2 /* null */; |
|---|
| 3965 | | - |
|---|
| 3966 | | - rc = send_set_info(xid, tcon, persistent_fid, volatile_fid, |
|---|
| 3967 | | - current->tgid, FILE_RENAME_INFORMATION, SMB2_O_INFO_FILE, |
|---|
| 3968 | | - 0, 2, data, size); |
|---|
| 3969 | | - kfree(data); |
|---|
| 3970 | | - return rc; |
|---|
| 3971 | | -} |
|---|
| 3972 | | - |
|---|
| 3973 | | -int |
|---|
| 3974 | | -SMB2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 3975 | | - u64 persistent_fid, u64 volatile_fid) |
|---|
| 3976 | | -{ |
|---|
| 3977 | | - __u8 delete_pending = 1; |
|---|
| 3978 | | - void *data; |
|---|
| 3979 | | - unsigned int size; |
|---|
| 3980 | | - |
|---|
| 3981 | | - data = &delete_pending; |
|---|
| 3982 | | - size = 1; /* sizeof __u8 */ |
|---|
| 3983 | | - |
|---|
| 3984 | | - return send_set_info(xid, tcon, persistent_fid, volatile_fid, |
|---|
| 3985 | | - current->tgid, FILE_DISPOSITION_INFORMATION, SMB2_O_INFO_FILE, |
|---|
| 3986 | | - 0, 1, &data, &size); |
|---|
| 3987 | | -} |
|---|
| 3988 | | - |
|---|
| 3989 | | -int |
|---|
| 3990 | | -SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 3991 | | - u64 persistent_fid, u64 volatile_fid, __le16 *target_file) |
|---|
| 3992 | | -{ |
|---|
| 3993 | | - struct smb2_file_link_info info; |
|---|
| 3994 | | - void **data; |
|---|
| 3995 | | - unsigned int size[2]; |
|---|
| 3996 | | - int rc; |
|---|
| 3997 | | - int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX)); |
|---|
| 3998 | | - |
|---|
| 3999 | | - data = kmalloc_array(2, sizeof(void *), GFP_KERNEL); |
|---|
| 4000 | | - if (!data) |
|---|
| 4001 | | - return -ENOMEM; |
|---|
| 4002 | | - |
|---|
| 4003 | | - info.ReplaceIfExists = 0; /* 1 = replace existing link with new */ |
|---|
| 4004 | | - /* 0 = fail if link already exists */ |
|---|
| 4005 | | - info.RootDirectory = 0; /* MBZ for network ops (why does spec say?) */ |
|---|
| 4006 | | - info.FileNameLength = cpu_to_le32(len); |
|---|
| 4007 | | - |
|---|
| 4008 | | - data[0] = &info; |
|---|
| 4009 | | - size[0] = sizeof(struct smb2_file_link_info); |
|---|
| 4010 | | - |
|---|
| 4011 | | - data[1] = target_file; |
|---|
| 4012 | | - size[1] = len + 2 /* null */; |
|---|
| 4013 | | - |
|---|
| 4014 | | - rc = send_set_info(xid, tcon, persistent_fid, volatile_fid, |
|---|
| 4015 | | - current->tgid, FILE_LINK_INFORMATION, SMB2_O_INFO_FILE, |
|---|
| 4016 | | - 0, 2, data, size); |
|---|
| 4017 | | - kfree(data); |
|---|
| 4018 | | - return rc; |
|---|
| 4019 | | -} |
|---|
| 4020 | | - |
|---|
| 4021 | | -int |
|---|
| 4022 | 4950 | SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, |
|---|
| 4023 | | - u64 volatile_fid, u32 pid, __le64 *eof, bool is_falloc) |
|---|
| 4951 | + u64 volatile_fid, u32 pid, __le64 *eof) |
|---|
| 4024 | 4952 | { |
|---|
| 4025 | 4953 | struct smb2_file_eof_info info; |
|---|
| 4026 | 4954 | void *data; |
|---|
| .. | .. |
|---|
| 4031 | 4959 | data = &info; |
|---|
| 4032 | 4960 | size = sizeof(struct smb2_file_eof_info); |
|---|
| 4033 | 4961 | |
|---|
| 4034 | | - if (is_falloc) |
|---|
| 4035 | | - return send_set_info(xid, tcon, persistent_fid, volatile_fid, |
|---|
| 4036 | | - pid, FILE_ALLOCATION_INFORMATION, SMB2_O_INFO_FILE, |
|---|
| 4037 | | - 0, 1, &data, &size); |
|---|
| 4038 | | - else |
|---|
| 4039 | | - return send_set_info(xid, tcon, persistent_fid, volatile_fid, |
|---|
| 4962 | + return send_set_info(xid, tcon, persistent_fid, volatile_fid, |
|---|
| 4040 | 4963 | pid, FILE_END_OF_FILE_INFORMATION, SMB2_O_INFO_FILE, |
|---|
| 4041 | 4964 | 0, 1, &data, &size); |
|---|
| 4042 | | -} |
|---|
| 4043 | | - |
|---|
| 4044 | | -int |
|---|
| 4045 | | -SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 4046 | | - u64 persistent_fid, u64 volatile_fid, FILE_BASIC_INFO *buf) |
|---|
| 4047 | | -{ |
|---|
| 4048 | | - unsigned int size; |
|---|
| 4049 | | - size = sizeof(FILE_BASIC_INFO); |
|---|
| 4050 | | - return send_set_info(xid, tcon, persistent_fid, volatile_fid, |
|---|
| 4051 | | - current->tgid, FILE_BASIC_INFORMATION, SMB2_O_INFO_FILE, |
|---|
| 4052 | | - 0, 1, (void **)&buf, &size); |
|---|
| 4053 | 4965 | } |
|---|
| 4054 | 4966 | |
|---|
| 4055 | 4967 | int |
|---|
| .. | .. |
|---|
| 4081 | 4993 | int rc; |
|---|
| 4082 | 4994 | struct smb2_oplock_break *req = NULL; |
|---|
| 4083 | 4995 | struct cifs_ses *ses = tcon->ses; |
|---|
| 4996 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
|---|
| 4084 | 4997 | int flags = CIFS_OBREAK_OP; |
|---|
| 4085 | 4998 | unsigned int total_len; |
|---|
| 4086 | 4999 | struct kvec iov[1]; |
|---|
| .. | .. |
|---|
| 4088 | 5001 | int resp_buf_type; |
|---|
| 4089 | 5002 | |
|---|
| 4090 | 5003 | cifs_dbg(FYI, "SMB2_oplock_break\n"); |
|---|
| 4091 | | - rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req, |
|---|
| 4092 | | - &total_len); |
|---|
| 5004 | + rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, server, |
|---|
| 5005 | + (void **) &req, &total_len); |
|---|
| 4093 | 5006 | if (rc) |
|---|
| 4094 | 5007 | return rc; |
|---|
| 4095 | 5008 | |
|---|
| .. | .. |
|---|
| 4101 | 5014 | req->OplockLevel = oplock_level; |
|---|
| 4102 | 5015 | req->sync_hdr.CreditRequest = cpu_to_le16(1); |
|---|
| 4103 | 5016 | |
|---|
| 4104 | | - flags |= CIFS_NO_RESP; |
|---|
| 5017 | + flags |= CIFS_NO_RSP_BUF; |
|---|
| 4105 | 5018 | |
|---|
| 4106 | 5019 | iov[0].iov_base = (char *)req; |
|---|
| 4107 | 5020 | iov[0].iov_len = total_len; |
|---|
| .. | .. |
|---|
| 4110 | 5023 | rqst.rq_iov = iov; |
|---|
| 4111 | 5024 | rqst.rq_nvec = 1; |
|---|
| 4112 | 5025 | |
|---|
| 4113 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov); |
|---|
| 5026 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 5027 | + &rqst, &resp_buf_type, flags, &rsp_iov); |
|---|
| 4114 | 5028 | cifs_small_buf_release(req); |
|---|
| 4115 | 5029 | |
|---|
| 4116 | 5030 | if (rc) { |
|---|
| .. | .. |
|---|
| 4153 | 5067 | } |
|---|
| 4154 | 5068 | |
|---|
| 4155 | 5069 | static int |
|---|
| 4156 | | -build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level, |
|---|
| 4157 | | - int outbuf_len, u64 persistent_fid, u64 volatile_fid) |
|---|
| 5070 | +build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, |
|---|
| 5071 | + struct TCP_Server_Info *server, |
|---|
| 5072 | + int level, int outbuf_len, u64 persistent_fid, |
|---|
| 5073 | + u64 volatile_fid) |
|---|
| 4158 | 5074 | { |
|---|
| 4159 | | - struct TCP_Server_Info *server; |
|---|
| 4160 | 5075 | int rc; |
|---|
| 4161 | 5076 | struct smb2_query_info_req *req; |
|---|
| 4162 | 5077 | unsigned int total_len; |
|---|
| 4163 | 5078 | |
|---|
| 4164 | 5079 | cifs_dbg(FYI, "Query FSInfo level %d\n", level); |
|---|
| 4165 | 5080 | |
|---|
| 4166 | | - if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) |
|---|
| 5081 | + if ((tcon->ses == NULL) || server == NULL) |
|---|
| 4167 | 5082 | return -EIO; |
|---|
| 4168 | 5083 | |
|---|
| 4169 | | - server = tcon->ses->server; |
|---|
| 4170 | | - |
|---|
| 4171 | | - rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req, |
|---|
| 4172 | | - &total_len); |
|---|
| 5084 | + rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, server, |
|---|
| 5085 | + (void **) &req, &total_len); |
|---|
| 4173 | 5086 | if (rc) |
|---|
| 4174 | 5087 | return rc; |
|---|
| 4175 | 5088 | |
|---|
| .. | .. |
|---|
| 4199 | 5112 | int rc = 0; |
|---|
| 4200 | 5113 | int resp_buftype; |
|---|
| 4201 | 5114 | struct cifs_ses *ses = tcon->ses; |
|---|
| 5115 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
|---|
| 4202 | 5116 | FILE_SYSTEM_POSIX_INFO *info = NULL; |
|---|
| 4203 | 5117 | int flags = 0; |
|---|
| 4204 | 5118 | |
|---|
| 4205 | | - rc = build_qfs_info_req(&iov, tcon, FS_POSIX_INFORMATION, |
|---|
| 5119 | + rc = build_qfs_info_req(&iov, tcon, server, |
|---|
| 5120 | + FS_POSIX_INFORMATION, |
|---|
| 4206 | 5121 | sizeof(FILE_SYSTEM_POSIX_INFO), |
|---|
| 4207 | 5122 | persistent_fid, volatile_fid); |
|---|
| 4208 | 5123 | if (rc) |
|---|
| .. | .. |
|---|
| 4215 | 5130 | rqst.rq_iov = &iov; |
|---|
| 4216 | 5131 | rqst.rq_nvec = 1; |
|---|
| 4217 | 5132 | |
|---|
| 4218 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 5133 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 5134 | + &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 4219 | 5135 | cifs_small_buf_release(iov.iov_base); |
|---|
| 4220 | 5136 | if (rc) { |
|---|
| 4221 | 5137 | cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE); |
|---|
| .. | .. |
|---|
| 4247 | 5163 | int rc = 0; |
|---|
| 4248 | 5164 | int resp_buftype; |
|---|
| 4249 | 5165 | struct cifs_ses *ses = tcon->ses; |
|---|
| 5166 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
|---|
| 4250 | 5167 | struct smb2_fs_full_size_info *info = NULL; |
|---|
| 4251 | 5168 | int flags = 0; |
|---|
| 4252 | 5169 | |
|---|
| 4253 | | - rc = build_qfs_info_req(&iov, tcon, FS_FULL_SIZE_INFORMATION, |
|---|
| 5170 | + rc = build_qfs_info_req(&iov, tcon, server, |
|---|
| 5171 | + FS_FULL_SIZE_INFORMATION, |
|---|
| 4254 | 5172 | sizeof(struct smb2_fs_full_size_info), |
|---|
| 4255 | 5173 | persistent_fid, volatile_fid); |
|---|
| 4256 | 5174 | if (rc) |
|---|
| .. | .. |
|---|
| 4263 | 5181 | rqst.rq_iov = &iov; |
|---|
| 4264 | 5182 | rqst.rq_nvec = 1; |
|---|
| 4265 | 5183 | |
|---|
| 4266 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 5184 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 5185 | + &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 4267 | 5186 | cifs_small_buf_release(iov.iov_base); |
|---|
| 4268 | 5187 | if (rc) { |
|---|
| 4269 | 5188 | cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE); |
|---|
| .. | .. |
|---|
| 4295 | 5214 | int rc = 0; |
|---|
| 4296 | 5215 | int resp_buftype, max_len, min_len; |
|---|
| 4297 | 5216 | struct cifs_ses *ses = tcon->ses; |
|---|
| 5217 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
|---|
| 4298 | 5218 | unsigned int rsp_len, offset; |
|---|
| 4299 | 5219 | int flags = 0; |
|---|
| 4300 | 5220 | |
|---|
| .. | .. |
|---|
| 4315 | 5235 | return -EINVAL; |
|---|
| 4316 | 5236 | } |
|---|
| 4317 | 5237 | |
|---|
| 4318 | | - rc = build_qfs_info_req(&iov, tcon, level, max_len, |
|---|
| 5238 | + rc = build_qfs_info_req(&iov, tcon, server, |
|---|
| 5239 | + level, max_len, |
|---|
| 4319 | 5240 | persistent_fid, volatile_fid); |
|---|
| 4320 | 5241 | if (rc) |
|---|
| 4321 | 5242 | return rc; |
|---|
| .. | .. |
|---|
| 4327 | 5248 | rqst.rq_iov = &iov; |
|---|
| 4328 | 5249 | rqst.rq_nvec = 1; |
|---|
| 4329 | 5250 | |
|---|
| 4330 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 5251 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 5252 | + &rqst, &resp_buftype, flags, &rsp_iov); |
|---|
| 4331 | 5253 | cifs_small_buf_release(iov.iov_base); |
|---|
| 4332 | 5254 | if (rc) { |
|---|
| 4333 | 5255 | cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE); |
|---|
| .. | .. |
|---|
| 4378 | 5300 | struct kvec rsp_iov; |
|---|
| 4379 | 5301 | int resp_buf_type; |
|---|
| 4380 | 5302 | unsigned int count; |
|---|
| 4381 | | - int flags = CIFS_NO_RESP; |
|---|
| 5303 | + int flags = CIFS_NO_RSP_BUF; |
|---|
| 4382 | 5304 | unsigned int total_len; |
|---|
| 5305 | + struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses); |
|---|
| 4383 | 5306 | |
|---|
| 4384 | 5307 | cifs_dbg(FYI, "smb2_lockv num lock %d\n", num_lock); |
|---|
| 4385 | 5308 | |
|---|
| 4386 | | - rc = smb2_plain_req_init(SMB2_LOCK, tcon, (void **) &req, &total_len); |
|---|
| 5309 | + rc = smb2_plain_req_init(SMB2_LOCK, tcon, server, |
|---|
| 5310 | + (void **) &req, &total_len); |
|---|
| 4387 | 5311 | if (rc) |
|---|
| 4388 | 5312 | return rc; |
|---|
| 4389 | 5313 | |
|---|
| .. | .. |
|---|
| 4409 | 5333 | rqst.rq_iov = iov; |
|---|
| 4410 | 5334 | rqst.rq_nvec = 2; |
|---|
| 4411 | 5335 | |
|---|
| 4412 | | - rc = cifs_send_recv(xid, tcon->ses, &rqst, &resp_buf_type, flags, |
|---|
| 5336 | + rc = cifs_send_recv(xid, tcon->ses, server, |
|---|
| 5337 | + &rqst, &resp_buf_type, flags, |
|---|
| 4413 | 5338 | &rsp_iov); |
|---|
| 4414 | 5339 | cifs_small_buf_release(req); |
|---|
| 4415 | 5340 | if (rc) { |
|---|
| .. | .. |
|---|
| 4452 | 5377 | struct kvec iov[1]; |
|---|
| 4453 | 5378 | struct kvec rsp_iov; |
|---|
| 4454 | 5379 | int resp_buf_type; |
|---|
| 5380 | + __u64 *please_key_high; |
|---|
| 5381 | + __u64 *please_key_low; |
|---|
| 5382 | + struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses); |
|---|
| 4455 | 5383 | |
|---|
| 4456 | 5384 | cifs_dbg(FYI, "SMB2_lease_break\n"); |
|---|
| 4457 | | - rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req, |
|---|
| 4458 | | - &total_len); |
|---|
| 5385 | + rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, server, |
|---|
| 5386 | + (void **) &req, &total_len); |
|---|
| 4459 | 5387 | if (rc) |
|---|
| 4460 | 5388 | return rc; |
|---|
| 4461 | 5389 | |
|---|
| .. | .. |
|---|
| 4469 | 5397 | memcpy(req->LeaseKey, lease_key, 16); |
|---|
| 4470 | 5398 | req->LeaseState = lease_state; |
|---|
| 4471 | 5399 | |
|---|
| 4472 | | - flags |= CIFS_NO_RESP; |
|---|
| 5400 | + flags |= CIFS_NO_RSP_BUF; |
|---|
| 4473 | 5401 | |
|---|
| 4474 | 5402 | iov[0].iov_base = (char *)req; |
|---|
| 4475 | 5403 | iov[0].iov_len = total_len; |
|---|
| .. | .. |
|---|
| 4478 | 5406 | rqst.rq_iov = iov; |
|---|
| 4479 | 5407 | rqst.rq_nvec = 1; |
|---|
| 4480 | 5408 | |
|---|
| 4481 | | - rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov); |
|---|
| 5409 | + rc = cifs_send_recv(xid, ses, server, |
|---|
| 5410 | + &rqst, &resp_buf_type, flags, &rsp_iov); |
|---|
| 4482 | 5411 | cifs_small_buf_release(req); |
|---|
| 4483 | 5412 | |
|---|
| 5413 | + please_key_low = (__u64 *)lease_key; |
|---|
| 5414 | + please_key_high = (__u64 *)(lease_key+8); |
|---|
| 4484 | 5415 | if (rc) { |
|---|
| 4485 | 5416 | cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE); |
|---|
| 5417 | + trace_smb3_lease_err(le32_to_cpu(lease_state), tcon->tid, |
|---|
| 5418 | + ses->Suid, *please_key_low, *please_key_high, rc); |
|---|
| 4486 | 5419 | cifs_dbg(FYI, "Send error in Lease Break = %d\n", rc); |
|---|
| 4487 | | - } |
|---|
| 5420 | + } else |
|---|
| 5421 | + trace_smb3_lease_done(le32_to_cpu(lease_state), tcon->tid, |
|---|
| 5422 | + ses->Suid, *please_key_low, *please_key_high); |
|---|
| 4488 | 5423 | |
|---|
| 4489 | 5424 | return rc; |
|---|
| 4490 | 5425 | } |
|---|