138c8a9a5SSteve French // SPDX-License-Identifier: GPL-2.0-only 238c8a9a5SSteve French /* 338c8a9a5SSteve French * SMB1 (CIFS) version specific operations 438c8a9a5SSteve French * 538c8a9a5SSteve French * Copyright (c) 2012, Jeff Layton <jlayton@redhat.com> 638c8a9a5SSteve French */ 738c8a9a5SSteve French 838c8a9a5SSteve French #include <linux/pagemap.h> 938c8a9a5SSteve French #include <linux/vfs.h> 1038c8a9a5SSteve French #include <uapi/linux/magic.h> 1138c8a9a5SSteve French #include "cifsglob.h" 1238c8a9a5SSteve French #include "cifsproto.h" 1338c8a9a5SSteve French #include "cifs_debug.h" 1438c8a9a5SSteve French #include "cifspdu.h" 1538c8a9a5SSteve French #include "cifs_unicode.h" 1638c8a9a5SSteve French #include "fs_context.h" 1738c8a9a5SSteve French 1838c8a9a5SSteve French /* 1938c8a9a5SSteve French * An NT cancel request header looks just like the original request except: 2038c8a9a5SSteve French * 2138c8a9a5SSteve French * The Command is SMB_COM_NT_CANCEL 2238c8a9a5SSteve French * The WordCount is zeroed out 2338c8a9a5SSteve French * The ByteCount is zeroed out 2438c8a9a5SSteve French * 2538c8a9a5SSteve French * This function mangles an existing request buffer into a 2638c8a9a5SSteve French * SMB_COM_NT_CANCEL request and then sends it. 2738c8a9a5SSteve French */ 2838c8a9a5SSteve French static int 2938c8a9a5SSteve French send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst, 3038c8a9a5SSteve French struct mid_q_entry *mid) 3138c8a9a5SSteve French { 3238c8a9a5SSteve French int rc = 0; 3338c8a9a5SSteve French struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base; 3438c8a9a5SSteve French 3538c8a9a5SSteve French /* -4 for RFC1001 length and +2 for BCC field */ 3638c8a9a5SSteve French in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2); 3738c8a9a5SSteve French in_buf->Command = SMB_COM_NT_CANCEL; 3838c8a9a5SSteve French in_buf->WordCount = 0; 3938c8a9a5SSteve French put_bcc(0, in_buf); 4038c8a9a5SSteve French 4138c8a9a5SSteve French cifs_server_lock(server); 4238c8a9a5SSteve French rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); 4338c8a9a5SSteve French if (rc) { 4438c8a9a5SSteve French cifs_server_unlock(server); 4538c8a9a5SSteve French return rc; 4638c8a9a5SSteve French } 4738c8a9a5SSteve French 4838c8a9a5SSteve French /* 4938c8a9a5SSteve French * The response to this call was already factored into the sequence 5038c8a9a5SSteve French * number when the call went out, so we must adjust it back downward 5138c8a9a5SSteve French * after signing here. 5238c8a9a5SSteve French */ 5338c8a9a5SSteve French --server->sequence_number; 5438c8a9a5SSteve French rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); 5538c8a9a5SSteve French if (rc < 0) 5638c8a9a5SSteve French server->sequence_number--; 5738c8a9a5SSteve French 5838c8a9a5SSteve French cifs_server_unlock(server); 5938c8a9a5SSteve French 6038c8a9a5SSteve French cifs_dbg(FYI, "issued NT_CANCEL for mid %u, rc = %d\n", 6138c8a9a5SSteve French get_mid(in_buf), rc); 6238c8a9a5SSteve French 6338c8a9a5SSteve French return rc; 6438c8a9a5SSteve French } 6538c8a9a5SSteve French 6638c8a9a5SSteve French static bool 6738c8a9a5SSteve French cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2) 6838c8a9a5SSteve French { 6938c8a9a5SSteve French return ob1->fid.netfid == ob2->fid.netfid; 7038c8a9a5SSteve French } 7138c8a9a5SSteve French 7238c8a9a5SSteve French static unsigned int 7338c8a9a5SSteve French cifs_read_data_offset(char *buf) 7438c8a9a5SSteve French { 7538c8a9a5SSteve French READ_RSP *rsp = (READ_RSP *)buf; 7638c8a9a5SSteve French return le16_to_cpu(rsp->DataOffset); 7738c8a9a5SSteve French } 7838c8a9a5SSteve French 7938c8a9a5SSteve French static unsigned int 8038c8a9a5SSteve French cifs_read_data_length(char *buf, bool in_remaining) 8138c8a9a5SSteve French { 8238c8a9a5SSteve French READ_RSP *rsp = (READ_RSP *)buf; 8338c8a9a5SSteve French /* It's a bug reading remaining data for SMB1 packets */ 8438c8a9a5SSteve French WARN_ON(in_remaining); 8538c8a9a5SSteve French return (le16_to_cpu(rsp->DataLengthHigh) << 16) + 8638c8a9a5SSteve French le16_to_cpu(rsp->DataLength); 8738c8a9a5SSteve French } 8838c8a9a5SSteve French 8938c8a9a5SSteve French static struct mid_q_entry * 9038c8a9a5SSteve French cifs_find_mid(struct TCP_Server_Info *server, char *buffer) 9138c8a9a5SSteve French { 9238c8a9a5SSteve French struct smb_hdr *buf = (struct smb_hdr *)buffer; 9338c8a9a5SSteve French struct mid_q_entry *mid; 9438c8a9a5SSteve French 9538c8a9a5SSteve French spin_lock(&server->mid_lock); 9638c8a9a5SSteve French list_for_each_entry(mid, &server->pending_mid_q, qhead) { 9738c8a9a5SSteve French if (compare_mid(mid->mid, buf) && 9838c8a9a5SSteve French mid->mid_state == MID_REQUEST_SUBMITTED && 9938c8a9a5SSteve French le16_to_cpu(mid->command) == buf->Command) { 10038c8a9a5SSteve French kref_get(&mid->refcount); 10138c8a9a5SSteve French spin_unlock(&server->mid_lock); 10238c8a9a5SSteve French return mid; 10338c8a9a5SSteve French } 10438c8a9a5SSteve French } 10538c8a9a5SSteve French spin_unlock(&server->mid_lock); 10638c8a9a5SSteve French return NULL; 10738c8a9a5SSteve French } 10838c8a9a5SSteve French 10938c8a9a5SSteve French static void 11038c8a9a5SSteve French cifs_add_credits(struct TCP_Server_Info *server, 11138c8a9a5SSteve French const struct cifs_credits *credits, const int optype) 11238c8a9a5SSteve French { 11338c8a9a5SSteve French spin_lock(&server->req_lock); 11438c8a9a5SSteve French server->credits += credits->value; 11538c8a9a5SSteve French server->in_flight--; 11638c8a9a5SSteve French spin_unlock(&server->req_lock); 11738c8a9a5SSteve French wake_up(&server->request_q); 11838c8a9a5SSteve French } 11938c8a9a5SSteve French 12038c8a9a5SSteve French static void 12138c8a9a5SSteve French cifs_set_credits(struct TCP_Server_Info *server, const int val) 12238c8a9a5SSteve French { 12338c8a9a5SSteve French spin_lock(&server->req_lock); 12438c8a9a5SSteve French server->credits = val; 12538c8a9a5SSteve French server->oplocks = val > 1 ? enable_oplocks : false; 12638c8a9a5SSteve French spin_unlock(&server->req_lock); 12738c8a9a5SSteve French } 12838c8a9a5SSteve French 12938c8a9a5SSteve French static int * 13038c8a9a5SSteve French cifs_get_credits_field(struct TCP_Server_Info *server, const int optype) 13138c8a9a5SSteve French { 13238c8a9a5SSteve French return &server->credits; 13338c8a9a5SSteve French } 13438c8a9a5SSteve French 13538c8a9a5SSteve French static unsigned int 13638c8a9a5SSteve French cifs_get_credits(struct mid_q_entry *mid) 13738c8a9a5SSteve French { 13838c8a9a5SSteve French return 1; 13938c8a9a5SSteve French } 14038c8a9a5SSteve French 14138c8a9a5SSteve French /* 14238c8a9a5SSteve French * Find a free multiplex id (SMB mid). Otherwise there could be 14338c8a9a5SSteve French * mid collisions which might cause problems, demultiplexing the 14438c8a9a5SSteve French * wrong response to this request. Multiplex ids could collide if 14538c8a9a5SSteve French * one of a series requests takes much longer than the others, or 14638c8a9a5SSteve French * if a very large number of long lived requests (byte range 14738c8a9a5SSteve French * locks or FindNotify requests) are pending. No more than 14838c8a9a5SSteve French * 64K-1 requests can be outstanding at one time. If no 14938c8a9a5SSteve French * mids are available, return zero. A future optimization 15038c8a9a5SSteve French * could make the combination of mids and uid the key we use 15138c8a9a5SSteve French * to demultiplex on (rather than mid alone). 15238c8a9a5SSteve French * In addition to the above check, the cifs demultiplex 15338c8a9a5SSteve French * code already used the command code as a secondary 15438c8a9a5SSteve French * check of the frame and if signing is negotiated the 15538c8a9a5SSteve French * response would be discarded if the mid were the same 15638c8a9a5SSteve French * but the signature was wrong. Since the mid is not put in the 15738c8a9a5SSteve French * pending queue until later (when it is about to be dispatched) 15838c8a9a5SSteve French * we do have to limit the number of outstanding requests 15938c8a9a5SSteve French * to somewhat less than 64K-1 although it is hard to imagine 16038c8a9a5SSteve French * so many threads being in the vfs at one time. 16138c8a9a5SSteve French */ 16238c8a9a5SSteve French static __u64 16338c8a9a5SSteve French cifs_get_next_mid(struct TCP_Server_Info *server) 16438c8a9a5SSteve French { 16538c8a9a5SSteve French __u64 mid = 0; 16638c8a9a5SSteve French __u16 last_mid, cur_mid; 16738c8a9a5SSteve French bool collision, reconnect = false; 16838c8a9a5SSteve French 16938c8a9a5SSteve French spin_lock(&server->mid_lock); 17038c8a9a5SSteve French 17138c8a9a5SSteve French /* mid is 16 bit only for CIFS/SMB */ 17238c8a9a5SSteve French cur_mid = (__u16)((server->CurrentMid) & 0xffff); 17338c8a9a5SSteve French /* we do not want to loop forever */ 17438c8a9a5SSteve French last_mid = cur_mid; 17538c8a9a5SSteve French cur_mid++; 17638c8a9a5SSteve French /* avoid 0xFFFF MID */ 17738c8a9a5SSteve French if (cur_mid == 0xffff) 17838c8a9a5SSteve French cur_mid++; 17938c8a9a5SSteve French 18038c8a9a5SSteve French /* 18138c8a9a5SSteve French * This nested loop looks more expensive than it is. 18238c8a9a5SSteve French * In practice the list of pending requests is short, 18338c8a9a5SSteve French * fewer than 50, and the mids are likely to be unique 18438c8a9a5SSteve French * on the first pass through the loop unless some request 18538c8a9a5SSteve French * takes longer than the 64 thousand requests before it 18638c8a9a5SSteve French * (and it would also have to have been a request that 18738c8a9a5SSteve French * did not time out). 18838c8a9a5SSteve French */ 18938c8a9a5SSteve French while (cur_mid != last_mid) { 19038c8a9a5SSteve French struct mid_q_entry *mid_entry; 19138c8a9a5SSteve French unsigned int num_mids; 19238c8a9a5SSteve French 19338c8a9a5SSteve French collision = false; 19438c8a9a5SSteve French if (cur_mid == 0) 19538c8a9a5SSteve French cur_mid++; 19638c8a9a5SSteve French 19738c8a9a5SSteve French num_mids = 0; 19838c8a9a5SSteve French list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { 19938c8a9a5SSteve French ++num_mids; 20038c8a9a5SSteve French if (mid_entry->mid == cur_mid && 20138c8a9a5SSteve French mid_entry->mid_state == MID_REQUEST_SUBMITTED) { 20238c8a9a5SSteve French /* This mid is in use, try a different one */ 20338c8a9a5SSteve French collision = true; 20438c8a9a5SSteve French break; 20538c8a9a5SSteve French } 20638c8a9a5SSteve French } 20738c8a9a5SSteve French 20838c8a9a5SSteve French /* 20938c8a9a5SSteve French * if we have more than 32k mids in the list, then something 21038c8a9a5SSteve French * is very wrong. Possibly a local user is trying to DoS the 21138c8a9a5SSteve French * box by issuing long-running calls and SIGKILL'ing them. If 21238c8a9a5SSteve French * we get to 2^16 mids then we're in big trouble as this 21338c8a9a5SSteve French * function could loop forever. 21438c8a9a5SSteve French * 21538c8a9a5SSteve French * Go ahead and assign out the mid in this situation, but force 21638c8a9a5SSteve French * an eventual reconnect to clean out the pending_mid_q. 21738c8a9a5SSteve French */ 21838c8a9a5SSteve French if (num_mids > 32768) 21938c8a9a5SSteve French reconnect = true; 22038c8a9a5SSteve French 22138c8a9a5SSteve French if (!collision) { 22238c8a9a5SSteve French mid = (__u64)cur_mid; 22338c8a9a5SSteve French server->CurrentMid = mid; 22438c8a9a5SSteve French break; 22538c8a9a5SSteve French } 22638c8a9a5SSteve French cur_mid++; 22738c8a9a5SSteve French } 22838c8a9a5SSteve French spin_unlock(&server->mid_lock); 22938c8a9a5SSteve French 23038c8a9a5SSteve French if (reconnect) { 23138c8a9a5SSteve French cifs_signal_cifsd_for_reconnect(server, false); 23238c8a9a5SSteve French } 23338c8a9a5SSteve French 23438c8a9a5SSteve French return mid; 23538c8a9a5SSteve French } 23638c8a9a5SSteve French 23738c8a9a5SSteve French /* 23838c8a9a5SSteve French return codes: 23938c8a9a5SSteve French 0 not a transact2, or all data present 24038c8a9a5SSteve French >0 transact2 with that much data missing 24138c8a9a5SSteve French -EINVAL invalid transact2 24238c8a9a5SSteve French */ 24338c8a9a5SSteve French static int 24438c8a9a5SSteve French check2ndT2(char *buf) 24538c8a9a5SSteve French { 24638c8a9a5SSteve French struct smb_hdr *pSMB = (struct smb_hdr *)buf; 24738c8a9a5SSteve French struct smb_t2_rsp *pSMBt; 24838c8a9a5SSteve French int remaining; 24938c8a9a5SSteve French __u16 total_data_size, data_in_this_rsp; 25038c8a9a5SSteve French 25138c8a9a5SSteve French if (pSMB->Command != SMB_COM_TRANSACTION2) 25238c8a9a5SSteve French return 0; 25338c8a9a5SSteve French 25438c8a9a5SSteve French /* check for plausible wct, bcc and t2 data and parm sizes */ 25538c8a9a5SSteve French /* check for parm and data offset going beyond end of smb */ 25638c8a9a5SSteve French if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */ 25738c8a9a5SSteve French cifs_dbg(FYI, "Invalid transact2 word count\n"); 25838c8a9a5SSteve French return -EINVAL; 25938c8a9a5SSteve French } 26038c8a9a5SSteve French 26138c8a9a5SSteve French pSMBt = (struct smb_t2_rsp *)pSMB; 26238c8a9a5SSteve French 26338c8a9a5SSteve French total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); 26438c8a9a5SSteve French data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount); 26538c8a9a5SSteve French 26638c8a9a5SSteve French if (total_data_size == data_in_this_rsp) 26738c8a9a5SSteve French return 0; 26838c8a9a5SSteve French else if (total_data_size < data_in_this_rsp) { 26938c8a9a5SSteve French cifs_dbg(FYI, "total data %d smaller than data in frame %d\n", 27038c8a9a5SSteve French total_data_size, data_in_this_rsp); 27138c8a9a5SSteve French return -EINVAL; 27238c8a9a5SSteve French } 27338c8a9a5SSteve French 27438c8a9a5SSteve French remaining = total_data_size - data_in_this_rsp; 27538c8a9a5SSteve French 27638c8a9a5SSteve French cifs_dbg(FYI, "missing %d bytes from transact2, check next response\n", 27738c8a9a5SSteve French remaining); 27838c8a9a5SSteve French if (total_data_size > CIFSMaxBufSize) { 27938c8a9a5SSteve French cifs_dbg(VFS, "TotalDataSize %d is over maximum buffer %d\n", 28038c8a9a5SSteve French total_data_size, CIFSMaxBufSize); 28138c8a9a5SSteve French return -EINVAL; 28238c8a9a5SSteve French } 28338c8a9a5SSteve French return remaining; 28438c8a9a5SSteve French } 28538c8a9a5SSteve French 28638c8a9a5SSteve French static int 28738c8a9a5SSteve French coalesce_t2(char *second_buf, struct smb_hdr *target_hdr) 28838c8a9a5SSteve French { 28938c8a9a5SSteve French struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf; 29038c8a9a5SSteve French struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)target_hdr; 29138c8a9a5SSteve French char *data_area_of_tgt; 29238c8a9a5SSteve French char *data_area_of_src; 29338c8a9a5SSteve French int remaining; 29438c8a9a5SSteve French unsigned int byte_count, total_in_tgt; 29538c8a9a5SSteve French __u16 tgt_total_cnt, src_total_cnt, total_in_src; 29638c8a9a5SSteve French 29738c8a9a5SSteve French src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount); 29838c8a9a5SSteve French tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); 29938c8a9a5SSteve French 30038c8a9a5SSteve French if (tgt_total_cnt != src_total_cnt) 30138c8a9a5SSteve French cifs_dbg(FYI, "total data count of primary and secondary t2 differ source=%hu target=%hu\n", 30238c8a9a5SSteve French src_total_cnt, tgt_total_cnt); 30338c8a9a5SSteve French 30438c8a9a5SSteve French total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount); 30538c8a9a5SSteve French 30638c8a9a5SSteve French remaining = tgt_total_cnt - total_in_tgt; 30738c8a9a5SSteve French 30838c8a9a5SSteve French if (remaining < 0) { 30938c8a9a5SSteve French cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%u\n", 31038c8a9a5SSteve French tgt_total_cnt, total_in_tgt); 31138c8a9a5SSteve French return -EPROTO; 31238c8a9a5SSteve French } 31338c8a9a5SSteve French 31438c8a9a5SSteve French if (remaining == 0) { 31538c8a9a5SSteve French /* nothing to do, ignore */ 31638c8a9a5SSteve French cifs_dbg(FYI, "no more data remains\n"); 31738c8a9a5SSteve French return 0; 31838c8a9a5SSteve French } 31938c8a9a5SSteve French 32038c8a9a5SSteve French total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount); 32138c8a9a5SSteve French if (remaining < total_in_src) 32238c8a9a5SSteve French cifs_dbg(FYI, "transact2 2nd response contains too much data\n"); 32338c8a9a5SSteve French 32438c8a9a5SSteve French /* find end of first SMB data area */ 32538c8a9a5SSteve French data_area_of_tgt = (char *)&pSMBt->hdr.Protocol + 32638c8a9a5SSteve French get_unaligned_le16(&pSMBt->t2_rsp.DataOffset); 32738c8a9a5SSteve French 32838c8a9a5SSteve French /* validate target area */ 32938c8a9a5SSteve French data_area_of_src = (char *)&pSMBs->hdr.Protocol + 33038c8a9a5SSteve French get_unaligned_le16(&pSMBs->t2_rsp.DataOffset); 33138c8a9a5SSteve French 33238c8a9a5SSteve French data_area_of_tgt += total_in_tgt; 33338c8a9a5SSteve French 33438c8a9a5SSteve French total_in_tgt += total_in_src; 33538c8a9a5SSteve French /* is the result too big for the field? */ 33638c8a9a5SSteve French if (total_in_tgt > USHRT_MAX) { 33738c8a9a5SSteve French cifs_dbg(FYI, "coalesced DataCount too large (%u)\n", 33838c8a9a5SSteve French total_in_tgt); 33938c8a9a5SSteve French return -EPROTO; 34038c8a9a5SSteve French } 34138c8a9a5SSteve French put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount); 34238c8a9a5SSteve French 34338c8a9a5SSteve French /* fix up the BCC */ 34438c8a9a5SSteve French byte_count = get_bcc(target_hdr); 34538c8a9a5SSteve French byte_count += total_in_src; 34638c8a9a5SSteve French /* is the result too big for the field? */ 34738c8a9a5SSteve French if (byte_count > USHRT_MAX) { 34838c8a9a5SSteve French cifs_dbg(FYI, "coalesced BCC too large (%u)\n", byte_count); 34938c8a9a5SSteve French return -EPROTO; 35038c8a9a5SSteve French } 35138c8a9a5SSteve French put_bcc(byte_count, target_hdr); 35238c8a9a5SSteve French 35338c8a9a5SSteve French byte_count = be32_to_cpu(target_hdr->smb_buf_length); 35438c8a9a5SSteve French byte_count += total_in_src; 35538c8a9a5SSteve French /* don't allow buffer to overflow */ 35638c8a9a5SSteve French if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { 35738c8a9a5SSteve French cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n", 35838c8a9a5SSteve French byte_count); 35938c8a9a5SSteve French return -ENOBUFS; 36038c8a9a5SSteve French } 36138c8a9a5SSteve French target_hdr->smb_buf_length = cpu_to_be32(byte_count); 36238c8a9a5SSteve French 36338c8a9a5SSteve French /* copy second buffer into end of first buffer */ 36438c8a9a5SSteve French memcpy(data_area_of_tgt, data_area_of_src, total_in_src); 36538c8a9a5SSteve French 36638c8a9a5SSteve French if (remaining != total_in_src) { 36738c8a9a5SSteve French /* more responses to go */ 36838c8a9a5SSteve French cifs_dbg(FYI, "waiting for more secondary responses\n"); 36938c8a9a5SSteve French return 1; 37038c8a9a5SSteve French } 37138c8a9a5SSteve French 37238c8a9a5SSteve French /* we are done */ 37338c8a9a5SSteve French cifs_dbg(FYI, "found the last secondary response\n"); 37438c8a9a5SSteve French return 0; 37538c8a9a5SSteve French } 37638c8a9a5SSteve French 37738c8a9a5SSteve French static void 37838c8a9a5SSteve French cifs_downgrade_oplock(struct TCP_Server_Info *server, 37938c8a9a5SSteve French struct cifsInodeInfo *cinode, __u32 oplock, 38038c8a9a5SSteve French unsigned int epoch, bool *purge_cache) 38138c8a9a5SSteve French { 38238c8a9a5SSteve French cifs_set_oplock_level(cinode, oplock); 38338c8a9a5SSteve French } 38438c8a9a5SSteve French 38538c8a9a5SSteve French static bool 38638c8a9a5SSteve French cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server, 38738c8a9a5SSteve French char *buf, int malformed) 38838c8a9a5SSteve French { 38938c8a9a5SSteve French if (malformed) 39038c8a9a5SSteve French return false; 39138c8a9a5SSteve French if (check2ndT2(buf) <= 0) 39238c8a9a5SSteve French return false; 39338c8a9a5SSteve French mid->multiRsp = true; 39438c8a9a5SSteve French if (mid->resp_buf) { 39538c8a9a5SSteve French /* merge response - fix up 1st*/ 39638c8a9a5SSteve French malformed = coalesce_t2(buf, mid->resp_buf); 39738c8a9a5SSteve French if (malformed > 0) 39838c8a9a5SSteve French return true; 39938c8a9a5SSteve French /* All parts received or packet is malformed. */ 40038c8a9a5SSteve French mid->multiEnd = true; 40138c8a9a5SSteve French dequeue_mid(mid, malformed); 40238c8a9a5SSteve French return true; 40338c8a9a5SSteve French } 40438c8a9a5SSteve French if (!server->large_buf) { 40538c8a9a5SSteve French /*FIXME: switch to already allocated largebuf?*/ 40638c8a9a5SSteve French cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n"); 40738c8a9a5SSteve French } else { 40838c8a9a5SSteve French /* Have first buffer */ 40938c8a9a5SSteve French mid->resp_buf = buf; 41038c8a9a5SSteve French mid->large_buf = true; 41138c8a9a5SSteve French server->bigbuf = NULL; 41238c8a9a5SSteve French } 41338c8a9a5SSteve French return true; 41438c8a9a5SSteve French } 41538c8a9a5SSteve French 41638c8a9a5SSteve French static bool 41738c8a9a5SSteve French cifs_need_neg(struct TCP_Server_Info *server) 41838c8a9a5SSteve French { 41938c8a9a5SSteve French return server->maxBuf == 0; 42038c8a9a5SSteve French } 42138c8a9a5SSteve French 42238c8a9a5SSteve French static int 42338c8a9a5SSteve French cifs_negotiate(const unsigned int xid, 42438c8a9a5SSteve French struct cifs_ses *ses, 42538c8a9a5SSteve French struct TCP_Server_Info *server) 42638c8a9a5SSteve French { 42738c8a9a5SSteve French int rc; 42838c8a9a5SSteve French rc = CIFSSMBNegotiate(xid, ses, server); 42938c8a9a5SSteve French if (rc == -EAGAIN) { 43038c8a9a5SSteve French /* retry only once on 1st time connection */ 43138c8a9a5SSteve French set_credits(server, 1); 43238c8a9a5SSteve French rc = CIFSSMBNegotiate(xid, ses, server); 43338c8a9a5SSteve French if (rc == -EAGAIN) 43438c8a9a5SSteve French rc = -EHOSTDOWN; 43538c8a9a5SSteve French } 43638c8a9a5SSteve French return rc; 43738c8a9a5SSteve French } 43838c8a9a5SSteve French 43938c8a9a5SSteve French static unsigned int 44038c8a9a5SSteve French cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) 44138c8a9a5SSteve French { 44238c8a9a5SSteve French __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); 44338c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 44438c8a9a5SSteve French unsigned int wsize; 44538c8a9a5SSteve French 44638c8a9a5SSteve French /* start with specified wsize, or default */ 44738c8a9a5SSteve French if (ctx->wsize) 44838c8a9a5SSteve French wsize = ctx->wsize; 44938c8a9a5SSteve French else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP)) 45038c8a9a5SSteve French wsize = CIFS_DEFAULT_IOSIZE; 45138c8a9a5SSteve French else 45238c8a9a5SSteve French wsize = CIFS_DEFAULT_NON_POSIX_WSIZE; 45338c8a9a5SSteve French 45438c8a9a5SSteve French /* can server support 24-bit write sizes? (via UNIX extensions) */ 45538c8a9a5SSteve French if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP)) 45638c8a9a5SSteve French wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE); 45738c8a9a5SSteve French 45838c8a9a5SSteve French /* 45938c8a9a5SSteve French * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set? 46038c8a9a5SSteve French * Limit it to max buffer offered by the server, minus the size of the 46138c8a9a5SSteve French * WRITEX header, not including the 4 byte RFC1001 length. 46238c8a9a5SSteve French */ 46338c8a9a5SSteve French if (!(server->capabilities & CAP_LARGE_WRITE_X) || 46438c8a9a5SSteve French (!(server->capabilities & CAP_UNIX) && server->sign)) 46538c8a9a5SSteve French wsize = min_t(unsigned int, wsize, 46638c8a9a5SSteve French server->maxBuf - sizeof(WRITE_REQ) + 4); 46738c8a9a5SSteve French 46838c8a9a5SSteve French /* hard limit of CIFS_MAX_WSIZE */ 46938c8a9a5SSteve French wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE); 47038c8a9a5SSteve French 47138c8a9a5SSteve French return wsize; 47238c8a9a5SSteve French } 47338c8a9a5SSteve French 47438c8a9a5SSteve French static unsigned int 47538c8a9a5SSteve French cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) 47638c8a9a5SSteve French { 47738c8a9a5SSteve French __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); 47838c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 47938c8a9a5SSteve French unsigned int rsize, defsize; 48038c8a9a5SSteve French 48138c8a9a5SSteve French /* 48238c8a9a5SSteve French * Set default value... 48338c8a9a5SSteve French * 48438c8a9a5SSteve French * HACK alert! Ancient servers have very small buffers. Even though 48538c8a9a5SSteve French * MS-CIFS indicates that servers are only limited by the client's 48638c8a9a5SSteve French * bufsize for reads, testing against win98se shows that it throws 48738c8a9a5SSteve French * INVALID_PARAMETER errors if you try to request too large a read. 48838c8a9a5SSteve French * OS/2 just sends back short reads. 48938c8a9a5SSteve French * 49038c8a9a5SSteve French * If the server doesn't advertise CAP_LARGE_READ_X, then assume that 49138c8a9a5SSteve French * it can't handle a read request larger than its MaxBufferSize either. 49238c8a9a5SSteve French */ 49338c8a9a5SSteve French if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP)) 49438c8a9a5SSteve French defsize = CIFS_DEFAULT_IOSIZE; 49538c8a9a5SSteve French else if (server->capabilities & CAP_LARGE_READ_X) 49638c8a9a5SSteve French defsize = CIFS_DEFAULT_NON_POSIX_RSIZE; 49738c8a9a5SSteve French else 49838c8a9a5SSteve French defsize = server->maxBuf - sizeof(READ_RSP); 49938c8a9a5SSteve French 50038c8a9a5SSteve French rsize = ctx->rsize ? ctx->rsize : defsize; 50138c8a9a5SSteve French 50238c8a9a5SSteve French /* 50338c8a9a5SSteve French * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to 50438c8a9a5SSteve French * the client's MaxBufferSize. 50538c8a9a5SSteve French */ 50638c8a9a5SSteve French if (!(server->capabilities & CAP_LARGE_READ_X)) 50738c8a9a5SSteve French rsize = min_t(unsigned int, CIFSMaxBufSize, rsize); 50838c8a9a5SSteve French 50938c8a9a5SSteve French /* hard limit of CIFS_MAX_RSIZE */ 51038c8a9a5SSteve French rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE); 51138c8a9a5SSteve French 51238c8a9a5SSteve French return rsize; 51338c8a9a5SSteve French } 51438c8a9a5SSteve French 51538c8a9a5SSteve French static void 51638c8a9a5SSteve French cifs_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, 51738c8a9a5SSteve French struct cifs_sb_info *cifs_sb) 51838c8a9a5SSteve French { 51938c8a9a5SSteve French CIFSSMBQFSDeviceInfo(xid, tcon); 52038c8a9a5SSteve French CIFSSMBQFSAttributeInfo(xid, tcon); 52138c8a9a5SSteve French } 52238c8a9a5SSteve French 52338c8a9a5SSteve French static int 52438c8a9a5SSteve French cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, 52538c8a9a5SSteve French struct cifs_sb_info *cifs_sb, const char *full_path) 52638c8a9a5SSteve French { 52738c8a9a5SSteve French int rc; 52838c8a9a5SSteve French FILE_ALL_INFO *file_info; 52938c8a9a5SSteve French 53038c8a9a5SSteve French file_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); 53138c8a9a5SSteve French if (file_info == NULL) 53238c8a9a5SSteve French return -ENOMEM; 53338c8a9a5SSteve French 53438c8a9a5SSteve French rc = CIFSSMBQPathInfo(xid, tcon, full_path, file_info, 53538c8a9a5SSteve French 0 /* not legacy */, cifs_sb->local_nls, 53638c8a9a5SSteve French cifs_remap(cifs_sb)); 53738c8a9a5SSteve French 53838c8a9a5SSteve French if (rc == -EOPNOTSUPP || rc == -EINVAL) 53938c8a9a5SSteve French rc = SMBQueryInformation(xid, tcon, full_path, file_info, 54038c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 54138c8a9a5SSteve French kfree(file_info); 54238c8a9a5SSteve French return rc; 54338c8a9a5SSteve French } 54438c8a9a5SSteve French 5458b4e285dSPaulo Alcantara static int cifs_query_path_info(const unsigned int xid, 5468b4e285dSPaulo Alcantara struct cifs_tcon *tcon, 5478b4e285dSPaulo Alcantara struct cifs_sb_info *cifs_sb, 5488b4e285dSPaulo Alcantara const char *full_path, 5498b4e285dSPaulo Alcantara struct cifs_open_info_data *data) 55038c8a9a5SSteve French { 55138c8a9a5SSteve French int rc; 55238c8a9a5SSteve French FILE_ALL_INFO fi = {}; 55338c8a9a5SSteve French 5548b4e285dSPaulo Alcantara data->symlink = false; 5558b4e285dSPaulo Alcantara data->adjust_tz = false; 55638c8a9a5SSteve French 55738c8a9a5SSteve French /* could do find first instead but this returns more info */ 55838c8a9a5SSteve French rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, cifs_sb->local_nls, 55938c8a9a5SSteve French cifs_remap(cifs_sb)); 56038c8a9a5SSteve French /* 56138c8a9a5SSteve French * BB optimize code so we do not make the above call when server claims 56238c8a9a5SSteve French * no NT SMB support and the above call failed at least once - set flag 56338c8a9a5SSteve French * in tcon or mount. 56438c8a9a5SSteve French */ 56538c8a9a5SSteve French if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { 56638c8a9a5SSteve French rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls, 56738c8a9a5SSteve French cifs_remap(cifs_sb)); 5688b4e285dSPaulo Alcantara data->adjust_tz = true; 56938c8a9a5SSteve French } 57038c8a9a5SSteve French 57138c8a9a5SSteve French if (!rc) { 57238c8a9a5SSteve French int tmprc; 57338c8a9a5SSteve French int oplock = 0; 57438c8a9a5SSteve French struct cifs_fid fid; 57538c8a9a5SSteve French struct cifs_open_parms oparms; 57638c8a9a5SSteve French 57738c8a9a5SSteve French move_cifs_info_to_smb2(&data->fi, &fi); 57838c8a9a5SSteve French 57938c8a9a5SSteve French if (!(le32_to_cpu(fi.Attributes) & ATTR_REPARSE)) 58038c8a9a5SSteve French return 0; 58138c8a9a5SSteve French 58238c8a9a5SSteve French oparms = (struct cifs_open_parms) { 58338c8a9a5SSteve French .tcon = tcon, 58438c8a9a5SSteve French .cifs_sb = cifs_sb, 58538c8a9a5SSteve French .desired_access = FILE_READ_ATTRIBUTES, 58638c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, 0), 58738c8a9a5SSteve French .disposition = FILE_OPEN, 58838c8a9a5SSteve French .path = full_path, 58938c8a9a5SSteve French .fid = &fid, 59038c8a9a5SSteve French }; 59138c8a9a5SSteve French 59238c8a9a5SSteve French /* Need to check if this is a symbolic link or not */ 59338c8a9a5SSteve French tmprc = CIFS_open(xid, &oparms, &oplock, NULL); 59438c8a9a5SSteve French if (tmprc == -EOPNOTSUPP) 5958b4e285dSPaulo Alcantara data->symlink = true; 59638c8a9a5SSteve French else if (tmprc == 0) 59738c8a9a5SSteve French CIFSSMBClose(xid, tcon, fid.netfid); 59838c8a9a5SSteve French } 59938c8a9a5SSteve French 60038c8a9a5SSteve French return rc; 60138c8a9a5SSteve French } 60238c8a9a5SSteve French 60338c8a9a5SSteve French static int cifs_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon, 60438c8a9a5SSteve French struct cifs_sb_info *cifs_sb, const char *full_path, 60538c8a9a5SSteve French u64 *uniqueid, struct cifs_open_info_data *unused) 60638c8a9a5SSteve French { 60738c8a9a5SSteve French /* 60838c8a9a5SSteve French * We can not use the IndexNumber field by default from Windows or 60938c8a9a5SSteve French * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA 61038c8a9a5SSteve French * CIFS spec claims that this value is unique within the scope of a 61138c8a9a5SSteve French * share, and the windows docs hint that it's actually unique 61238c8a9a5SSteve French * per-machine. 61338c8a9a5SSteve French * 61438c8a9a5SSteve French * There may be higher info levels that work but are there Windows 61538c8a9a5SSteve French * server or network appliances for which IndexNumber field is not 61638c8a9a5SSteve French * guaranteed unique? 61738c8a9a5SSteve French */ 61838c8a9a5SSteve French return CIFSGetSrvInodeNumber(xid, tcon, full_path, uniqueid, 61938c8a9a5SSteve French cifs_sb->local_nls, 62038c8a9a5SSteve French cifs_remap(cifs_sb)); 62138c8a9a5SSteve French } 62238c8a9a5SSteve French 62338c8a9a5SSteve French static int cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon, 62438c8a9a5SSteve French struct cifsFileInfo *cfile, struct cifs_open_info_data *data) 62538c8a9a5SSteve French { 62638c8a9a5SSteve French int rc; 62738c8a9a5SSteve French FILE_ALL_INFO fi = {}; 62838c8a9a5SSteve French 62938c8a9a5SSteve French if (cfile->symlink_target) { 63038c8a9a5SSteve French data->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); 63138c8a9a5SSteve French if (!data->symlink_target) 63238c8a9a5SSteve French return -ENOMEM; 63338c8a9a5SSteve French } 63438c8a9a5SSteve French 63538c8a9a5SSteve French rc = CIFSSMBQFileInfo(xid, tcon, cfile->fid.netfid, &fi); 63638c8a9a5SSteve French if (!rc) 63738c8a9a5SSteve French move_cifs_info_to_smb2(&data->fi, &fi); 63838c8a9a5SSteve French return rc; 63938c8a9a5SSteve French } 64038c8a9a5SSteve French 64138c8a9a5SSteve French static void 64238c8a9a5SSteve French cifs_clear_stats(struct cifs_tcon *tcon) 64338c8a9a5SSteve French { 64438c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_writes, 0); 64538c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_reads, 0); 64638c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_flushes, 0); 64738c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_oplock_brks, 0); 64838c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_opens, 0); 64938c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_posixopens, 0); 65038c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_posixmkdirs, 0); 65138c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_closes, 0); 65238c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_deletes, 0); 65338c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_mkdirs, 0); 65438c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_rmdirs, 0); 65538c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_renames, 0); 65638c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_t2renames, 0); 65738c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_ffirst, 0); 65838c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_fnext, 0); 65938c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_fclose, 0); 66038c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_hardlinks, 0); 66138c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_symlinks, 0); 66238c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_locks, 0); 66338c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_acl_get, 0); 66438c8a9a5SSteve French atomic_set(&tcon->stats.cifs_stats.num_acl_set, 0); 66538c8a9a5SSteve French } 66638c8a9a5SSteve French 66738c8a9a5SSteve French static void 66838c8a9a5SSteve French cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon) 66938c8a9a5SSteve French { 67038c8a9a5SSteve French seq_printf(m, " Oplocks breaks: %d", 67138c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_oplock_brks)); 67238c8a9a5SSteve French seq_printf(m, "\nReads: %d Bytes: %llu", 67338c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_reads), 67438c8a9a5SSteve French (long long)(tcon->bytes_read)); 67538c8a9a5SSteve French seq_printf(m, "\nWrites: %d Bytes: %llu", 67638c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_writes), 67738c8a9a5SSteve French (long long)(tcon->bytes_written)); 67838c8a9a5SSteve French seq_printf(m, "\nFlushes: %d", 67938c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_flushes)); 68038c8a9a5SSteve French seq_printf(m, "\nLocks: %d HardLinks: %d Symlinks: %d", 68138c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_locks), 68238c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_hardlinks), 68338c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_symlinks)); 68438c8a9a5SSteve French seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d", 68538c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_opens), 68638c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_closes), 68738c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_deletes)); 68838c8a9a5SSteve French seq_printf(m, "\nPosix Opens: %d Posix Mkdirs: %d", 68938c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_posixopens), 69038c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_posixmkdirs)); 69138c8a9a5SSteve French seq_printf(m, "\nMkdirs: %d Rmdirs: %d", 69238c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_mkdirs), 69338c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_rmdirs)); 69438c8a9a5SSteve French seq_printf(m, "\nRenames: %d T2 Renames %d", 69538c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_renames), 69638c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_t2renames)); 69738c8a9a5SSteve French seq_printf(m, "\nFindFirst: %d FNext %d FClose %d", 69838c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_ffirst), 69938c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_fnext), 70038c8a9a5SSteve French atomic_read(&tcon->stats.cifs_stats.num_fclose)); 70138c8a9a5SSteve French } 70238c8a9a5SSteve French 70338c8a9a5SSteve French static void 70438c8a9a5SSteve French cifs_mkdir_setinfo(struct inode *inode, const char *full_path, 70538c8a9a5SSteve French struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, 70638c8a9a5SSteve French const unsigned int xid) 70738c8a9a5SSteve French { 70838c8a9a5SSteve French FILE_BASIC_INFO info; 70938c8a9a5SSteve French struct cifsInodeInfo *cifsInode; 71038c8a9a5SSteve French u32 dosattrs; 71138c8a9a5SSteve French int rc; 71238c8a9a5SSteve French 71338c8a9a5SSteve French memset(&info, 0, sizeof(info)); 71438c8a9a5SSteve French cifsInode = CIFS_I(inode); 71538c8a9a5SSteve French dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; 71638c8a9a5SSteve French info.Attributes = cpu_to_le32(dosattrs); 71738c8a9a5SSteve French rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls, 71838c8a9a5SSteve French cifs_sb); 71938c8a9a5SSteve French if (rc == 0) 72038c8a9a5SSteve French cifsInode->cifsAttrs = dosattrs; 72138c8a9a5SSteve French } 72238c8a9a5SSteve French 72338c8a9a5SSteve French static int cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock, 72438c8a9a5SSteve French void *buf) 72538c8a9a5SSteve French { 72638c8a9a5SSteve French struct cifs_open_info_data *data = buf; 72738c8a9a5SSteve French FILE_ALL_INFO fi = {}; 72838c8a9a5SSteve French int rc; 72938c8a9a5SSteve French 73038c8a9a5SSteve French if (!(oparms->tcon->ses->capabilities & CAP_NT_SMBS)) 73138c8a9a5SSteve French rc = SMBLegacyOpen(xid, oparms->tcon, oparms->path, 73238c8a9a5SSteve French oparms->disposition, 73338c8a9a5SSteve French oparms->desired_access, 73438c8a9a5SSteve French oparms->create_options, 73538c8a9a5SSteve French &oparms->fid->netfid, oplock, &fi, 73638c8a9a5SSteve French oparms->cifs_sb->local_nls, 73738c8a9a5SSteve French cifs_remap(oparms->cifs_sb)); 73838c8a9a5SSteve French else 73938c8a9a5SSteve French rc = CIFS_open(xid, oparms, oplock, &fi); 74038c8a9a5SSteve French 74138c8a9a5SSteve French if (!rc && data) 74238c8a9a5SSteve French move_cifs_info_to_smb2(&data->fi, &fi); 74338c8a9a5SSteve French 74438c8a9a5SSteve French return rc; 74538c8a9a5SSteve French } 74638c8a9a5SSteve French 74738c8a9a5SSteve French static void 74838c8a9a5SSteve French cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) 74938c8a9a5SSteve French { 75038c8a9a5SSteve French struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); 75138c8a9a5SSteve French cfile->fid.netfid = fid->netfid; 75238c8a9a5SSteve French cifs_set_oplock_level(cinode, oplock); 75338c8a9a5SSteve French cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode); 75438c8a9a5SSteve French } 75538c8a9a5SSteve French 756*6f17163bSRitvik Budhiraja static int 75738c8a9a5SSteve French cifs_close_file(const unsigned int xid, struct cifs_tcon *tcon, 75838c8a9a5SSteve French struct cifs_fid *fid) 75938c8a9a5SSteve French { 760*6f17163bSRitvik Budhiraja return CIFSSMBClose(xid, tcon, fid->netfid); 76138c8a9a5SSteve French } 76238c8a9a5SSteve French 76338c8a9a5SSteve French static int 76438c8a9a5SSteve French cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon, 76538c8a9a5SSteve French struct cifs_fid *fid) 76638c8a9a5SSteve French { 76738c8a9a5SSteve French return CIFSSMBFlush(xid, tcon, fid->netfid); 76838c8a9a5SSteve French } 76938c8a9a5SSteve French 77038c8a9a5SSteve French static int 77138c8a9a5SSteve French cifs_sync_read(const unsigned int xid, struct cifs_fid *pfid, 77238c8a9a5SSteve French struct cifs_io_parms *parms, unsigned int *bytes_read, 77338c8a9a5SSteve French char **buf, int *buf_type) 77438c8a9a5SSteve French { 77538c8a9a5SSteve French parms->netfid = pfid->netfid; 77638c8a9a5SSteve French return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type); 77738c8a9a5SSteve French } 77838c8a9a5SSteve French 77938c8a9a5SSteve French static int 78038c8a9a5SSteve French cifs_sync_write(const unsigned int xid, struct cifs_fid *pfid, 78138c8a9a5SSteve French struct cifs_io_parms *parms, unsigned int *written, 78238c8a9a5SSteve French struct kvec *iov, unsigned long nr_segs) 78338c8a9a5SSteve French { 78438c8a9a5SSteve French 78538c8a9a5SSteve French parms->netfid = pfid->netfid; 78638c8a9a5SSteve French return CIFSSMBWrite2(xid, parms, written, iov, nr_segs); 78738c8a9a5SSteve French } 78838c8a9a5SSteve French 78938c8a9a5SSteve French static int 79038c8a9a5SSteve French smb_set_file_info(struct inode *inode, const char *full_path, 79138c8a9a5SSteve French FILE_BASIC_INFO *buf, const unsigned int xid) 79238c8a9a5SSteve French { 79338c8a9a5SSteve French int oplock = 0; 79438c8a9a5SSteve French int rc; 79538c8a9a5SSteve French __u32 netpid; 79638c8a9a5SSteve French struct cifs_fid fid; 79738c8a9a5SSteve French struct cifs_open_parms oparms; 79838c8a9a5SSteve French struct cifsFileInfo *open_file; 79938c8a9a5SSteve French struct cifsInodeInfo *cinode = CIFS_I(inode); 80038c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 80138c8a9a5SSteve French struct tcon_link *tlink = NULL; 80238c8a9a5SSteve French struct cifs_tcon *tcon; 80338c8a9a5SSteve French 80438c8a9a5SSteve French /* if the file is already open for write, just use that fileid */ 80538c8a9a5SSteve French open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY); 80638c8a9a5SSteve French if (open_file) { 80738c8a9a5SSteve French fid.netfid = open_file->fid.netfid; 80838c8a9a5SSteve French netpid = open_file->pid; 80938c8a9a5SSteve French tcon = tlink_tcon(open_file->tlink); 81038c8a9a5SSteve French goto set_via_filehandle; 81138c8a9a5SSteve French } 81238c8a9a5SSteve French 81338c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 81438c8a9a5SSteve French if (IS_ERR(tlink)) { 81538c8a9a5SSteve French rc = PTR_ERR(tlink); 81638c8a9a5SSteve French tlink = NULL; 81738c8a9a5SSteve French goto out; 81838c8a9a5SSteve French } 81938c8a9a5SSteve French tcon = tlink_tcon(tlink); 82038c8a9a5SSteve French 82138c8a9a5SSteve French rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls, 82238c8a9a5SSteve French cifs_sb); 82338c8a9a5SSteve French if (rc == 0) { 82438c8a9a5SSteve French cinode->cifsAttrs = le32_to_cpu(buf->Attributes); 82538c8a9a5SSteve French goto out; 82638c8a9a5SSteve French } else if (rc != -EOPNOTSUPP && rc != -EINVAL) { 82738c8a9a5SSteve French goto out; 82838c8a9a5SSteve French } 82938c8a9a5SSteve French 83038c8a9a5SSteve French oparms = (struct cifs_open_parms) { 83138c8a9a5SSteve French .tcon = tcon, 83238c8a9a5SSteve French .cifs_sb = cifs_sb, 83338c8a9a5SSteve French .desired_access = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, 83438c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 83538c8a9a5SSteve French .disposition = FILE_OPEN, 83638c8a9a5SSteve French .path = full_path, 83738c8a9a5SSteve French .fid = &fid, 83838c8a9a5SSteve French }; 83938c8a9a5SSteve French 84038c8a9a5SSteve French cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n"); 84138c8a9a5SSteve French rc = CIFS_open(xid, &oparms, &oplock, NULL); 84238c8a9a5SSteve French if (rc != 0) { 84338c8a9a5SSteve French if (rc == -EIO) 84438c8a9a5SSteve French rc = -EINVAL; 84538c8a9a5SSteve French goto out; 84638c8a9a5SSteve French } 84738c8a9a5SSteve French 84838c8a9a5SSteve French netpid = current->tgid; 84938c8a9a5SSteve French 85038c8a9a5SSteve French set_via_filehandle: 85138c8a9a5SSteve French rc = CIFSSMBSetFileInfo(xid, tcon, buf, fid.netfid, netpid); 85238c8a9a5SSteve French if (!rc) 85338c8a9a5SSteve French cinode->cifsAttrs = le32_to_cpu(buf->Attributes); 85438c8a9a5SSteve French 85538c8a9a5SSteve French if (open_file == NULL) 85638c8a9a5SSteve French CIFSSMBClose(xid, tcon, fid.netfid); 85738c8a9a5SSteve French else 85838c8a9a5SSteve French cifsFileInfo_put(open_file); 85938c8a9a5SSteve French out: 86038c8a9a5SSteve French if (tlink != NULL) 86138c8a9a5SSteve French cifs_put_tlink(tlink); 86238c8a9a5SSteve French return rc; 86338c8a9a5SSteve French } 86438c8a9a5SSteve French 86538c8a9a5SSteve French static int 86638c8a9a5SSteve French cifs_set_compression(const unsigned int xid, struct cifs_tcon *tcon, 86738c8a9a5SSteve French struct cifsFileInfo *cfile) 86838c8a9a5SSteve French { 86938c8a9a5SSteve French return CIFSSMB_set_compression(xid, tcon, cfile->fid.netfid); 87038c8a9a5SSteve French } 87138c8a9a5SSteve French 87238c8a9a5SSteve French static int 87338c8a9a5SSteve French cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, 87438c8a9a5SSteve French const char *path, struct cifs_sb_info *cifs_sb, 87538c8a9a5SSteve French struct cifs_fid *fid, __u16 search_flags, 87638c8a9a5SSteve French struct cifs_search_info *srch_inf) 87738c8a9a5SSteve French { 87838c8a9a5SSteve French int rc; 87938c8a9a5SSteve French 88038c8a9a5SSteve French rc = CIFSFindFirst(xid, tcon, path, cifs_sb, 88138c8a9a5SSteve French &fid->netfid, search_flags, srch_inf, true); 88238c8a9a5SSteve French if (rc) 88338c8a9a5SSteve French cifs_dbg(FYI, "find first failed=%d\n", rc); 88438c8a9a5SSteve French return rc; 88538c8a9a5SSteve French } 88638c8a9a5SSteve French 88738c8a9a5SSteve French static int 88838c8a9a5SSteve French cifs_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon, 88938c8a9a5SSteve French struct cifs_fid *fid, __u16 search_flags, 89038c8a9a5SSteve French struct cifs_search_info *srch_inf) 89138c8a9a5SSteve French { 89238c8a9a5SSteve French return CIFSFindNext(xid, tcon, fid->netfid, search_flags, srch_inf); 89338c8a9a5SSteve French } 89438c8a9a5SSteve French 89538c8a9a5SSteve French static int 89638c8a9a5SSteve French cifs_close_dir(const unsigned int xid, struct cifs_tcon *tcon, 89738c8a9a5SSteve French struct cifs_fid *fid) 89838c8a9a5SSteve French { 89938c8a9a5SSteve French return CIFSFindClose(xid, tcon, fid->netfid); 90038c8a9a5SSteve French } 90138c8a9a5SSteve French 90238c8a9a5SSteve French static int 90338c8a9a5SSteve French cifs_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid, 90438c8a9a5SSteve French __u64 volatile_fid, __u16 net_fid, struct cifsInodeInfo *cinode) 90538c8a9a5SSteve French { 90638c8a9a5SSteve French return CIFSSMBLock(0, tcon, net_fid, current->tgid, 0, 0, 0, 0, 90738c8a9a5SSteve French LOCKING_ANDX_OPLOCK_RELEASE, false, CIFS_CACHE_READ(cinode) ? 1 : 0); 90838c8a9a5SSteve French } 90938c8a9a5SSteve French 91038c8a9a5SSteve French static int 91138c8a9a5SSteve French cifs_queryfs(const unsigned int xid, struct cifs_tcon *tcon, 91238c8a9a5SSteve French struct cifs_sb_info *cifs_sb, struct kstatfs *buf) 91338c8a9a5SSteve French { 91438c8a9a5SSteve French int rc = -EOPNOTSUPP; 91538c8a9a5SSteve French 91638c8a9a5SSteve French buf->f_type = CIFS_SUPER_MAGIC; 91738c8a9a5SSteve French 91838c8a9a5SSteve French /* 91938c8a9a5SSteve French * We could add a second check for a QFS Unix capability bit 92038c8a9a5SSteve French */ 92138c8a9a5SSteve French if ((tcon->ses->capabilities & CAP_UNIX) && 92238c8a9a5SSteve French (CIFS_POSIX_EXTENSIONS & le64_to_cpu(tcon->fsUnixInfo.Capability))) 92338c8a9a5SSteve French rc = CIFSSMBQFSPosixInfo(xid, tcon, buf); 92438c8a9a5SSteve French 92538c8a9a5SSteve French /* 92638c8a9a5SSteve French * Only need to call the old QFSInfo if failed on newer one, 92738c8a9a5SSteve French * e.g. by OS/2. 92838c8a9a5SSteve French **/ 92938c8a9a5SSteve French if (rc && (tcon->ses->capabilities & CAP_NT_SMBS)) 93038c8a9a5SSteve French rc = CIFSSMBQFSInfo(xid, tcon, buf); 93138c8a9a5SSteve French 93238c8a9a5SSteve French /* 93338c8a9a5SSteve French * Some old Windows servers also do not support level 103, retry with 93438c8a9a5SSteve French * older level one if old server failed the previous call or we 93538c8a9a5SSteve French * bypassed it because we detected that this was an older LANMAN sess 93638c8a9a5SSteve French */ 93738c8a9a5SSteve French if (rc) 93838c8a9a5SSteve French rc = SMBOldQFSInfo(xid, tcon, buf); 93938c8a9a5SSteve French return rc; 94038c8a9a5SSteve French } 94138c8a9a5SSteve French 94238c8a9a5SSteve French static int 94338c8a9a5SSteve French cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset, 94438c8a9a5SSteve French __u64 length, __u32 type, int lock, int unlock, bool wait) 94538c8a9a5SSteve French { 94638c8a9a5SSteve French return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->fid.netfid, 94738c8a9a5SSteve French current->tgid, length, offset, unlock, lock, 94838c8a9a5SSteve French (__u8)type, wait, 0); 94938c8a9a5SSteve French } 95038c8a9a5SSteve French 95138c8a9a5SSteve French static int 95238c8a9a5SSteve French cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon, 95338c8a9a5SSteve French const unsigned char *searchName, char **symlinkinfo, 95438c8a9a5SSteve French const struct nls_table *nls_codepage) 95538c8a9a5SSteve French { 95638c8a9a5SSteve French #ifdef CONFIG_CIFS_DFS_UPCALL 95738c8a9a5SSteve French int rc; 95838c8a9a5SSteve French struct dfs_info3_param referral = {0}; 95938c8a9a5SSteve French 96038c8a9a5SSteve French rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage, &referral, 96138c8a9a5SSteve French 0); 96238c8a9a5SSteve French 96338c8a9a5SSteve French if (!rc) { 96438c8a9a5SSteve French *symlinkinfo = kstrdup(referral.node_name, GFP_KERNEL); 96538c8a9a5SSteve French free_dfs_info_param(&referral); 96638c8a9a5SSteve French if (!*symlinkinfo) 96738c8a9a5SSteve French rc = -ENOMEM; 96838c8a9a5SSteve French } 96938c8a9a5SSteve French return rc; 97038c8a9a5SSteve French #else /* No DFS support */ 97138c8a9a5SSteve French return -EREMOTE; 97238c8a9a5SSteve French #endif 97338c8a9a5SSteve French } 97438c8a9a5SSteve French 9759a49e221SPaulo Alcantara static int cifs_query_symlink(const unsigned int xid, 9769a49e221SPaulo Alcantara struct cifs_tcon *tcon, 9779a49e221SPaulo Alcantara struct cifs_sb_info *cifs_sb, 9789a49e221SPaulo Alcantara const char *full_path, 9794d07e5dfSPaulo Alcantara char **target_path) 9804d07e5dfSPaulo Alcantara { 9814d07e5dfSPaulo Alcantara int rc; 9824d07e5dfSPaulo Alcantara 9834d07e5dfSPaulo Alcantara cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path); 9844d07e5dfSPaulo Alcantara 9854d07e5dfSPaulo Alcantara if (!cap_unix(tcon->ses)) 9864d07e5dfSPaulo Alcantara return -EOPNOTSUPP; 9874d07e5dfSPaulo Alcantara 9884d07e5dfSPaulo Alcantara rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path, 9894d07e5dfSPaulo Alcantara cifs_sb->local_nls, cifs_remap(cifs_sb)); 9904d07e5dfSPaulo Alcantara if (rc == -EREMOTE) 9914d07e5dfSPaulo Alcantara rc = cifs_unix_dfs_readlink(xid, tcon, full_path, 9924d07e5dfSPaulo Alcantara target_path, cifs_sb->local_nls); 9934d07e5dfSPaulo Alcantara return rc; 9944d07e5dfSPaulo Alcantara } 9954d07e5dfSPaulo Alcantara 9964d07e5dfSPaulo Alcantara static int cifs_parse_reparse_point(struct cifs_sb_info *cifs_sb, 9974d07e5dfSPaulo Alcantara struct kvec *rsp_iov, 9984d07e5dfSPaulo Alcantara struct cifs_open_info_data *data) 99938c8a9a5SSteve French { 1000d5c959a1SPaulo Alcantara struct reparse_data_buffer *buf; 1001d5c959a1SPaulo Alcantara TRANSACT_IOCTL_RSP *io = rsp_iov->iov_base; 1002d5c959a1SPaulo Alcantara bool unicode = !!(io->hdr.Flags2 & SMBFLG2_UNICODE); 1003d5c959a1SPaulo Alcantara u32 plen = le16_to_cpu(io->ByteCount); 100438c8a9a5SSteve French 1005d5c959a1SPaulo Alcantara buf = (struct reparse_data_buffer *)((__u8 *)&io->hdr.Protocol + 1006d5c959a1SPaulo Alcantara le32_to_cpu(io->DataOffset)); 1007df32e887SPaulo Alcantara return parse_reparse_point(buf, plen, cifs_sb, unicode, data); 100838c8a9a5SSteve French } 100938c8a9a5SSteve French 101038c8a9a5SSteve French static bool 101138c8a9a5SSteve French cifs_is_read_op(__u32 oplock) 101238c8a9a5SSteve French { 101338c8a9a5SSteve French return oplock == OPLOCK_READ; 101438c8a9a5SSteve French } 101538c8a9a5SSteve French 101638c8a9a5SSteve French static unsigned int 101738c8a9a5SSteve French cifs_wp_retry_size(struct inode *inode) 101838c8a9a5SSteve French { 101938c8a9a5SSteve French return CIFS_SB(inode->i_sb)->ctx->wsize; 102038c8a9a5SSteve French } 102138c8a9a5SSteve French 102238c8a9a5SSteve French static bool 102338c8a9a5SSteve French cifs_dir_needs_close(struct cifsFileInfo *cfile) 102438c8a9a5SSteve French { 102538c8a9a5SSteve French return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle; 102638c8a9a5SSteve French } 102738c8a9a5SSteve French 102838c8a9a5SSteve French static bool 102938c8a9a5SSteve French cifs_can_echo(struct TCP_Server_Info *server) 103038c8a9a5SSteve French { 103138c8a9a5SSteve French if (server->tcpStatus == CifsGood) 103238c8a9a5SSteve French return true; 103338c8a9a5SSteve French 103438c8a9a5SSteve French return false; 103538c8a9a5SSteve French } 103638c8a9a5SSteve French 103738c8a9a5SSteve French static int 103838c8a9a5SSteve French cifs_make_node(unsigned int xid, struct inode *inode, 103938c8a9a5SSteve French struct dentry *dentry, struct cifs_tcon *tcon, 104038c8a9a5SSteve French const char *full_path, umode_t mode, dev_t dev) 104138c8a9a5SSteve French { 104238c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 104338c8a9a5SSteve French struct inode *newinode = NULL; 104438c8a9a5SSteve French int rc = -EPERM; 104538c8a9a5SSteve French struct cifs_open_info_data buf = {}; 104638c8a9a5SSteve French struct cifs_io_parms io_parms; 104738c8a9a5SSteve French __u32 oplock = 0; 104838c8a9a5SSteve French struct cifs_fid fid; 104938c8a9a5SSteve French struct cifs_open_parms oparms; 105038c8a9a5SSteve French unsigned int bytes_written; 105138c8a9a5SSteve French struct win_dev *pdev; 105238c8a9a5SSteve French struct kvec iov[2]; 105338c8a9a5SSteve French 105438c8a9a5SSteve French if (tcon->unix_ext) { 105538c8a9a5SSteve French /* 105638c8a9a5SSteve French * SMB1 Unix Extensions: requires server support but 105738c8a9a5SSteve French * works with all special files 105838c8a9a5SSteve French */ 105938c8a9a5SSteve French struct cifs_unix_set_info_args args = { 106038c8a9a5SSteve French .mode = mode & ~current_umask(), 106138c8a9a5SSteve French .ctime = NO_CHANGE_64, 106238c8a9a5SSteve French .atime = NO_CHANGE_64, 106338c8a9a5SSteve French .mtime = NO_CHANGE_64, 106438c8a9a5SSteve French .device = dev, 106538c8a9a5SSteve French }; 106638c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 106738c8a9a5SSteve French args.uid = current_fsuid(); 106838c8a9a5SSteve French args.gid = current_fsgid(); 106938c8a9a5SSteve French } else { 107038c8a9a5SSteve French args.uid = INVALID_UID; /* no change */ 107138c8a9a5SSteve French args.gid = INVALID_GID; /* no change */ 107238c8a9a5SSteve French } 107338c8a9a5SSteve French rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, 107438c8a9a5SSteve French cifs_sb->local_nls, 107538c8a9a5SSteve French cifs_remap(cifs_sb)); 107638c8a9a5SSteve French if (rc) 107738c8a9a5SSteve French return rc; 107838c8a9a5SSteve French 107938c8a9a5SSteve French rc = cifs_get_inode_info_unix(&newinode, full_path, 108038c8a9a5SSteve French inode->i_sb, xid); 108138c8a9a5SSteve French 108238c8a9a5SSteve French if (rc == 0) 108338c8a9a5SSteve French d_instantiate(dentry, newinode); 108438c8a9a5SSteve French return rc; 108538c8a9a5SSteve French } 108638c8a9a5SSteve French 108738c8a9a5SSteve French /* 108838c8a9a5SSteve French * SMB1 SFU emulation: should work with all servers, but only 108938c8a9a5SSteve French * support block and char device (no socket & fifo) 109038c8a9a5SSteve French */ 109138c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) 109238c8a9a5SSteve French return rc; 109338c8a9a5SSteve French 109438c8a9a5SSteve French if (!S_ISCHR(mode) && !S_ISBLK(mode)) 109538c8a9a5SSteve French return rc; 109638c8a9a5SSteve French 109738c8a9a5SSteve French cifs_dbg(FYI, "sfu compat create special file\n"); 109838c8a9a5SSteve French 109938c8a9a5SSteve French oparms = (struct cifs_open_parms) { 110038c8a9a5SSteve French .tcon = tcon, 110138c8a9a5SSteve French .cifs_sb = cifs_sb, 110238c8a9a5SSteve French .desired_access = GENERIC_WRITE, 110338c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR | 110438c8a9a5SSteve French CREATE_OPTION_SPECIAL), 110538c8a9a5SSteve French .disposition = FILE_CREATE, 110638c8a9a5SSteve French .path = full_path, 110738c8a9a5SSteve French .fid = &fid, 110838c8a9a5SSteve French }; 110938c8a9a5SSteve French 111038c8a9a5SSteve French if (tcon->ses->server->oplocks) 111138c8a9a5SSteve French oplock = REQ_OPLOCK; 111238c8a9a5SSteve French else 111338c8a9a5SSteve French oplock = 0; 111438c8a9a5SSteve French rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &buf); 111538c8a9a5SSteve French if (rc) 111638c8a9a5SSteve French return rc; 111738c8a9a5SSteve French 111838c8a9a5SSteve French /* 111938c8a9a5SSteve French * BB Do not bother to decode buf since no local inode yet to put 112038c8a9a5SSteve French * timestamps in, but we can reuse it safely. 112138c8a9a5SSteve French */ 112238c8a9a5SSteve French 112338c8a9a5SSteve French pdev = (struct win_dev *)&buf.fi; 112438c8a9a5SSteve French io_parms.pid = current->tgid; 112538c8a9a5SSteve French io_parms.tcon = tcon; 112638c8a9a5SSteve French io_parms.offset = 0; 112738c8a9a5SSteve French io_parms.length = sizeof(struct win_dev); 112838c8a9a5SSteve French iov[1].iov_base = &buf.fi; 112938c8a9a5SSteve French iov[1].iov_len = sizeof(struct win_dev); 113038c8a9a5SSteve French if (S_ISCHR(mode)) { 113138c8a9a5SSteve French memcpy(pdev->type, "IntxCHR", 8); 113238c8a9a5SSteve French pdev->major = cpu_to_le64(MAJOR(dev)); 113338c8a9a5SSteve French pdev->minor = cpu_to_le64(MINOR(dev)); 113438c8a9a5SSteve French rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, 113538c8a9a5SSteve French &bytes_written, iov, 1); 113638c8a9a5SSteve French } else if (S_ISBLK(mode)) { 113738c8a9a5SSteve French memcpy(pdev->type, "IntxBLK", 8); 113838c8a9a5SSteve French pdev->major = cpu_to_le64(MAJOR(dev)); 113938c8a9a5SSteve French pdev->minor = cpu_to_le64(MINOR(dev)); 114038c8a9a5SSteve French rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, 114138c8a9a5SSteve French &bytes_written, iov, 1); 114238c8a9a5SSteve French } 114338c8a9a5SSteve French tcon->ses->server->ops->close(xid, tcon, &fid); 114438c8a9a5SSteve French d_drop(dentry); 114538c8a9a5SSteve French 114638c8a9a5SSteve French /* FIXME: add code here to set EAs */ 114738c8a9a5SSteve French 114838c8a9a5SSteve French cifs_free_open_info(&buf); 114938c8a9a5SSteve French return rc; 115038c8a9a5SSteve French } 115138c8a9a5SSteve French 115238c8a9a5SSteve French 115338c8a9a5SSteve French 115438c8a9a5SSteve French struct smb_version_operations smb1_operations = { 115538c8a9a5SSteve French .send_cancel = send_nt_cancel, 115638c8a9a5SSteve French .compare_fids = cifs_compare_fids, 115738c8a9a5SSteve French .setup_request = cifs_setup_request, 115838c8a9a5SSteve French .setup_async_request = cifs_setup_async_request, 115938c8a9a5SSteve French .check_receive = cifs_check_receive, 116038c8a9a5SSteve French .add_credits = cifs_add_credits, 116138c8a9a5SSteve French .set_credits = cifs_set_credits, 116238c8a9a5SSteve French .get_credits_field = cifs_get_credits_field, 116338c8a9a5SSteve French .get_credits = cifs_get_credits, 116438c8a9a5SSteve French .wait_mtu_credits = cifs_wait_mtu_credits, 116538c8a9a5SSteve French .get_next_mid = cifs_get_next_mid, 116638c8a9a5SSteve French .read_data_offset = cifs_read_data_offset, 116738c8a9a5SSteve French .read_data_length = cifs_read_data_length, 116838c8a9a5SSteve French .map_error = map_smb_to_linux_error, 116938c8a9a5SSteve French .find_mid = cifs_find_mid, 117038c8a9a5SSteve French .check_message = checkSMB, 117138c8a9a5SSteve French .dump_detail = cifs_dump_detail, 117238c8a9a5SSteve French .clear_stats = cifs_clear_stats, 117338c8a9a5SSteve French .print_stats = cifs_print_stats, 117438c8a9a5SSteve French .is_oplock_break = is_valid_oplock_break, 117538c8a9a5SSteve French .downgrade_oplock = cifs_downgrade_oplock, 117638c8a9a5SSteve French .check_trans2 = cifs_check_trans2, 117738c8a9a5SSteve French .need_neg = cifs_need_neg, 117838c8a9a5SSteve French .negotiate = cifs_negotiate, 117938c8a9a5SSteve French .negotiate_wsize = cifs_negotiate_wsize, 118038c8a9a5SSteve French .negotiate_rsize = cifs_negotiate_rsize, 118138c8a9a5SSteve French .sess_setup = CIFS_SessSetup, 118238c8a9a5SSteve French .logoff = CIFSSMBLogoff, 118338c8a9a5SSteve French .tree_connect = CIFSTCon, 118438c8a9a5SSteve French .tree_disconnect = CIFSSMBTDis, 118538c8a9a5SSteve French .get_dfs_refer = CIFSGetDFSRefer, 118638c8a9a5SSteve French .qfs_tcon = cifs_qfs_tcon, 118738c8a9a5SSteve French .is_path_accessible = cifs_is_path_accessible, 118838c8a9a5SSteve French .can_echo = cifs_can_echo, 118938c8a9a5SSteve French .query_path_info = cifs_query_path_info, 1190d5c959a1SPaulo Alcantara .query_reparse_point = cifs_query_reparse_point, 119138c8a9a5SSteve French .query_file_info = cifs_query_file_info, 119238c8a9a5SSteve French .get_srv_inum = cifs_get_srv_inum, 119338c8a9a5SSteve French .set_path_size = CIFSSMBSetEOF, 119438c8a9a5SSteve French .set_file_size = CIFSSMBSetFileSize, 119538c8a9a5SSteve French .set_file_info = smb_set_file_info, 119638c8a9a5SSteve French .set_compression = cifs_set_compression, 119738c8a9a5SSteve French .echo = CIFSSMBEcho, 119838c8a9a5SSteve French .mkdir = CIFSSMBMkDir, 119938c8a9a5SSteve French .mkdir_setinfo = cifs_mkdir_setinfo, 120038c8a9a5SSteve French .rmdir = CIFSSMBRmDir, 120138c8a9a5SSteve French .unlink = CIFSSMBDelFile, 120238c8a9a5SSteve French .rename_pending_delete = cifs_rename_pending_delete, 120338c8a9a5SSteve French .rename = CIFSSMBRename, 120438c8a9a5SSteve French .create_hardlink = CIFSCreateHardLink, 120538c8a9a5SSteve French .query_symlink = cifs_query_symlink, 12064d07e5dfSPaulo Alcantara .parse_reparse_point = cifs_parse_reparse_point, 120738c8a9a5SSteve French .open = cifs_open_file, 120838c8a9a5SSteve French .set_fid = cifs_set_fid, 120938c8a9a5SSteve French .close = cifs_close_file, 121038c8a9a5SSteve French .flush = cifs_flush_file, 121138c8a9a5SSteve French .async_readv = cifs_async_readv, 121238c8a9a5SSteve French .async_writev = cifs_async_writev, 121338c8a9a5SSteve French .sync_read = cifs_sync_read, 121438c8a9a5SSteve French .sync_write = cifs_sync_write, 121538c8a9a5SSteve French .query_dir_first = cifs_query_dir_first, 121638c8a9a5SSteve French .query_dir_next = cifs_query_dir_next, 121738c8a9a5SSteve French .close_dir = cifs_close_dir, 121838c8a9a5SSteve French .calc_smb_size = smbCalcSize, 121938c8a9a5SSteve French .oplock_response = cifs_oplock_response, 122038c8a9a5SSteve French .queryfs = cifs_queryfs, 122138c8a9a5SSteve French .mand_lock = cifs_mand_lock, 122238c8a9a5SSteve French .mand_unlock_range = cifs_unlock_range, 122338c8a9a5SSteve French .push_mand_locks = cifs_push_mandatory_locks, 122438c8a9a5SSteve French .query_mf_symlink = cifs_query_mf_symlink, 122538c8a9a5SSteve French .create_mf_symlink = cifs_create_mf_symlink, 122638c8a9a5SSteve French .is_read_op = cifs_is_read_op, 122738c8a9a5SSteve French .wp_retry_size = cifs_wp_retry_size, 122838c8a9a5SSteve French .dir_needs_close = cifs_dir_needs_close, 122938c8a9a5SSteve French .select_sectype = cifs_select_sectype, 123038c8a9a5SSteve French #ifdef CONFIG_CIFS_XATTR 123138c8a9a5SSteve French .query_all_EAs = CIFSSMBQAllEAs, 123238c8a9a5SSteve French .set_EA = CIFSSMBSetEA, 123338c8a9a5SSteve French #endif /* CIFS_XATTR */ 123438c8a9a5SSteve French .get_acl = get_cifs_acl, 123538c8a9a5SSteve French .get_acl_by_fid = get_cifs_acl_by_fid, 123638c8a9a5SSteve French .set_acl = set_cifs_acl, 123738c8a9a5SSteve French .make_node = cifs_make_node, 123838c8a9a5SSteve French }; 123938c8a9a5SSteve French 124038c8a9a5SSteve French struct smb_version_values smb1_values = { 124138c8a9a5SSteve French .version_string = SMB1_VERSION_STRING, 124238c8a9a5SSteve French .protocol_id = SMB10_PROT_ID, 124338c8a9a5SSteve French .large_lock_type = LOCKING_ANDX_LARGE_FILES, 124438c8a9a5SSteve French .exclusive_lock_type = 0, 124538c8a9a5SSteve French .shared_lock_type = LOCKING_ANDX_SHARED_LOCK, 124638c8a9a5SSteve French .unlock_lock_type = 0, 124738c8a9a5SSteve French .header_preamble_size = 4, 124838c8a9a5SSteve French .header_size = sizeof(struct smb_hdr), 124938c8a9a5SSteve French .max_header_size = MAX_CIFS_HDR_SIZE, 125038c8a9a5SSteve French .read_rsp_size = sizeof(READ_RSP), 125138c8a9a5SSteve French .lock_cmd = cpu_to_le16(SMB_COM_LOCKING_ANDX), 125238c8a9a5SSteve French .cap_unix = CAP_UNIX, 125338c8a9a5SSteve French .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND, 125438c8a9a5SSteve French .cap_large_files = CAP_LARGE_FILES, 125538c8a9a5SSteve French .signing_enabled = SECMODE_SIGN_ENABLED, 125638c8a9a5SSteve French .signing_required = SECMODE_SIGN_REQUIRED, 125738c8a9a5SSteve French }; 1258