aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/smb2misc.c4
-rw-r--r--fs/cifs/smb2pdu.c116
-rw-r--r--fs/cifs/smb2pdu.h23
-rw-r--r--fs/cifs/smb2proto.h4
4 files changed, 147 insertions, 0 deletions
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 10383d8c015b..b0c43345cd98 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -266,6 +266,10 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
266 ((struct smb2_query_directory_rsp *)hdr)->OutputBufferLength); 266 ((struct smb2_query_directory_rsp *)hdr)->OutputBufferLength);
267 break; 267 break;
268 case SMB2_IOCTL: 268 case SMB2_IOCTL:
269 *off = le32_to_cpu(
270 ((struct smb2_ioctl_rsp *)hdr)->OutputOffset);
271 *len = le32_to_cpu(((struct smb2_ioctl_rsp *)hdr)->OutputCount);
272 break;
269 case SMB2_CHANGE_NOTIFY: 273 case SMB2_CHANGE_NOTIFY:
270 default: 274 default:
271 /* BB FIXME for unimplemented cases above */ 275 /* BB FIXME for unimplemented cases above */
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 0de6a82e2465..c0d102615d0a 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -997,6 +997,122 @@ creat_exit:
997 return rc; 997 return rc;
998} 998}
999 999
1000/*
1001 * SMB2 IOCTL is used for both IOCTLs and FSCTLs
1002 */
1003int
1004SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
1005 u64 volatile_fid, u32 opcode, bool is_fsctl, char *in_data,
1006 u32 indatalen, char **out_data, u32 *plen /* returned data len */)
1007{
1008 struct smb2_ioctl_req *req;
1009 struct smb2_ioctl_rsp *rsp;
1010 struct TCP_Server_Info *server;
1011 struct cifs_ses *ses = tcon->ses;
1012 struct kvec iov[2];
1013 int resp_buftype;
1014 int num_iovecs;
1015 int rc = 0;
1016
1017 cifs_dbg(FYI, "SMB2 IOCTL\n");
1018
1019 /* zero out returned data len, in case of error */
1020 if (plen)
1021 *plen = 0;
1022
1023 if (ses && (ses->server))
1024 server = ses->server;
1025 else
1026 return -EIO;
1027
1028 rc = small_smb2_init(SMB2_IOCTL, tcon, (void **) &req);
1029 if (rc)
1030 return rc;
1031
1032 req->CtlCode = cpu_to_le32(opcode);
1033 req->PersistentFileId = persistent_fid;
1034 req->VolatileFileId = volatile_fid;
1035
1036 if (indatalen) {
1037 req->InputCount = cpu_to_le32(indatalen);
1038 /* do not set InputOffset if no input data */
1039 req->InputOffset =
1040 cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer) - 4);
1041 iov[1].iov_base = in_data;
1042 iov[1].iov_len = indatalen;
1043 num_iovecs = 2;
1044 } else
1045 num_iovecs = 1;
1046
1047 req->OutputOffset = 0;
1048 req->OutputCount = 0; /* MBZ */
1049
1050 /*
1051 * Could increase MaxOutputResponse, but that would require more
1052 * than one credit. Windows typically sets this smaller, but for some
1053 * ioctls it may be useful to allow server to send more. No point
1054 * limiting what the server can send as long as fits in one credit
1055 */
1056 req->MaxOutputResponse = cpu_to_le32(0xFF00); /* < 64K uses 1 credit */
1057
1058 if (is_fsctl)
1059 req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
1060 else
1061 req->Flags = 0;
1062
1063 iov[0].iov_base = (char *)req;
1064 /* 4 for rfc1002 length field */
1065 iov[0].iov_len = get_rfc1002_length(req) + 4;
1066
1067 if (indatalen)
1068 inc_rfc1001_len(req, indatalen);
1069
1070 rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
1071 rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base;
1072
1073 if (rc != 0) {
1074 if (tcon)
1075 cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
1076 goto ioctl_exit;
1077 }
1078
1079 /* check if caller wants to look at return data or just return rc */
1080 if ((plen == NULL) || (out_data == NULL))
1081 goto ioctl_exit;
1082
1083 *plen = le32_to_cpu(rsp->OutputCount);
1084
1085 /* We check for obvious errors in the output buffer length and offset */
1086 if (*plen == 0)
1087 goto ioctl_exit; /* server returned no data */
1088 else if (*plen > 0xFF00) {
1089 cifs_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen);
1090 *plen = 0;
1091 rc = -EIO;
1092 goto ioctl_exit;
1093 }
1094
1095 if (get_rfc1002_length(rsp) < le32_to_cpu(rsp->OutputOffset) + *plen) {
1096 cifs_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen,
1097 le32_to_cpu(rsp->OutputOffset));
1098 *plen = 0;
1099 rc = -EIO;
1100 goto ioctl_exit;
1101 }
1102
1103 *out_data = kmalloc(*plen, GFP_KERNEL);
1104 if (*out_data == NULL) {
1105 rc = -ENOMEM;
1106 goto ioctl_exit;
1107 }
1108
1109 memcpy(*out_data, rsp->hdr.ProtocolId + le32_to_cpu(rsp->OutputOffset),
1110 *plen);
1111ioctl_exit:
1112 free_rsp_buf(resp_buftype, rsp);
1113 return rc;
1114}
1115
1000int 1116int
1001SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, 1117SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
1002 u64 persistent_fid, u64 volatile_fid) 1118 u64 persistent_fid, u64 volatile_fid)
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 0ef06ec24a06..f31043b26bd3 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -497,6 +497,29 @@ struct copychunk_ioctl {
497 __u32 Reserved2; 497 __u32 Reserved2;
498} __packed; 498} __packed;
499 499
500/* Response and Request are the same format */
501struct validate_negotiate_info {
502 __le32 Capabilities;
503 __u8 Guid[SMB2_CLIENT_GUID_SIZE];
504 __le16 SecurityMode;
505 __le16 DialectCount;
506 __le16 Dialect[1];
507} __packed;
508
509#define RSS_CAPABLE 0x00000001
510#define RDMA_CAPABLE 0x00000002
511
512struct network_interface_info_ioctl_rsp {
513 __le32 Next; /* next interface. zero if this is last one */
514 __le32 IfIndex;
515 __le32 Capability; /* RSS or RDMA Capable */
516 __le32 Reserved;
517 __le64 LinkSpeed;
518 char SockAddr_Storage[128];
519} __packed;
520
521#define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */
522
500struct smb2_ioctl_req { 523struct smb2_ioctl_req {
501 struct smb2_hdr hdr; 524 struct smb2_hdr hdr;
502 __le16 StructureSize; /* Must be 57 */ 525 __le16 StructureSize; /* Must be 57 */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 2aa3535e38ce..d4e1eb807457 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -111,6 +111,10 @@ extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
111 __u32 desired_access, __u32 create_disposition, 111 __u32 desired_access, __u32 create_disposition,
112 __u32 file_attributes, __u32 create_options, 112 __u32 file_attributes, __u32 create_options,
113 __u8 *oplock, struct smb2_file_all_info *buf); 113 __u8 *oplock, struct smb2_file_all_info *buf);
114extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
115 u64 persistent_fid, u64 volatile_fid, u32 opcode,
116 bool is_fsctl, char *in_data, u32 indatalen,
117 char **out_data, u32 *plen /* returned data len */);
114extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, 118extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
115 u64 persistent_file_id, u64 volatile_file_id); 119 u64 persistent_file_id, u64 volatile_file_id);
116extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, 120extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,