smb2ops.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * SMB2 version specific operations
  3. *
  4. * Copyright (c) 2012, Jeff Layton <jlayton@redhat.com>
  5. *
  6. * This library is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License v2 as published
  8. * by the Free Software Foundation.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  13. * the GNU Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public License
  16. * along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #include "cifsglob.h"
  20. #include "smb2pdu.h"
  21. #include "smb2proto.h"
  22. #include "cifsproto.h"
  23. #include "cifs_debug.h"
  24. static int
  25. change_conf(struct TCP_Server_Info *server)
  26. {
  27. server->credits += server->echo_credits + server->oplock_credits;
  28. server->oplock_credits = server->echo_credits = 0;
  29. switch (server->credits) {
  30. case 0:
  31. return -1;
  32. case 1:
  33. server->echoes = false;
  34. server->oplocks = false;
  35. cERROR(1, "disabling echoes and oplocks");
  36. break;
  37. case 2:
  38. server->echoes = true;
  39. server->oplocks = false;
  40. server->echo_credits = 1;
  41. cFYI(1, "disabling oplocks");
  42. break;
  43. default:
  44. server->echoes = true;
  45. server->oplocks = true;
  46. server->echo_credits = 1;
  47. server->oplock_credits = 1;
  48. }
  49. server->credits -= server->echo_credits + server->oplock_credits;
  50. return 0;
  51. }
  52. static void
  53. smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
  54. const int optype)
  55. {
  56. int *val, rc = 0;
  57. spin_lock(&server->req_lock);
  58. val = server->ops->get_credits_field(server, optype);
  59. *val += add;
  60. server->in_flight--;
  61. if (server->in_flight == 0 && (optype & CIFS_OP_MASK) != CIFS_NEG_OP)
  62. rc = change_conf(server);
  63. spin_unlock(&server->req_lock);
  64. wake_up(&server->request_q);
  65. if (rc)
  66. cifs_reconnect(server);
  67. }
  68. static void
  69. smb2_set_credits(struct TCP_Server_Info *server, const int val)
  70. {
  71. spin_lock(&server->req_lock);
  72. server->credits = val;
  73. spin_unlock(&server->req_lock);
  74. }
  75. static int *
  76. smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
  77. {
  78. switch (optype) {
  79. case CIFS_ECHO_OP:
  80. return &server->echo_credits;
  81. case CIFS_OBREAK_OP:
  82. return &server->oplock_credits;
  83. default:
  84. return &server->credits;
  85. }
  86. }
  87. static unsigned int
  88. smb2_get_credits(struct mid_q_entry *mid)
  89. {
  90. return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest);
  91. }
  92. static __u64
  93. smb2_get_next_mid(struct TCP_Server_Info *server)
  94. {
  95. __u64 mid;
  96. /* for SMB2 we need the current value */
  97. spin_lock(&GlobalMid_Lock);
  98. mid = server->CurrentMid++;
  99. spin_unlock(&GlobalMid_Lock);
  100. return mid;
  101. }
  102. static struct mid_q_entry *
  103. smb2_find_mid(struct TCP_Server_Info *server, char *buf)
  104. {
  105. struct mid_q_entry *mid;
  106. struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
  107. spin_lock(&GlobalMid_Lock);
  108. list_for_each_entry(mid, &server->pending_mid_q, qhead) {
  109. if ((mid->mid == hdr->MessageId) &&
  110. (mid->mid_state == MID_REQUEST_SUBMITTED) &&
  111. (mid->command == hdr->Command)) {
  112. spin_unlock(&GlobalMid_Lock);
  113. return mid;
  114. }
  115. }
  116. spin_unlock(&GlobalMid_Lock);
  117. return NULL;
  118. }
  119. static void
  120. smb2_dump_detail(void *buf)
  121. {
  122. #ifdef CONFIG_CIFS_DEBUG2
  123. struct smb2_hdr *smb = (struct smb2_hdr *)buf;
  124. cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d",
  125. smb->Command, smb->Status, smb->Flags, smb->MessageId,
  126. smb->ProcessId);
  127. cERROR(1, "smb buf %p len %u", smb, smb2_calc_size(smb));
  128. #endif
  129. }
  130. static bool
  131. smb2_need_neg(struct TCP_Server_Info *server)
  132. {
  133. return server->max_read == 0;
  134. }
  135. static int
  136. smb2_negotiate(const unsigned int xid, struct cifs_ses *ses)
  137. {
  138. int rc;
  139. ses->server->CurrentMid = 0;
  140. rc = SMB2_negotiate(xid, ses);
  141. /* BB we probably don't need to retry with modern servers */
  142. if (rc == -EAGAIN)
  143. rc = -EHOSTDOWN;
  144. return rc;
  145. }
  146. static int
  147. smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
  148. struct cifs_sb_info *cifs_sb, const char *full_path)
  149. {
  150. int rc;
  151. __u64 persistent_fid, volatile_fid;
  152. __le16 *utf16_path;
  153. utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
  154. if (!utf16_path)
  155. return -ENOMEM;
  156. rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
  157. FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0);
  158. if (rc) {
  159. kfree(utf16_path);
  160. return rc;
  161. }
  162. rc = SMB2_close(xid, tcon, persistent_fid, volatile_fid);
  163. kfree(utf16_path);
  164. return rc;
  165. }
  166. static int
  167. smb2_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
  168. struct cifs_sb_info *cifs_sb, const char *full_path,
  169. u64 *uniqueid, FILE_ALL_INFO *data)
  170. {
  171. *uniqueid = le64_to_cpu(data->IndexNumber);
  172. return 0;
  173. }
  174. static char *
  175. smb2_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
  176. struct cifs_tcon *tcon)
  177. {
  178. int pplen = vol->prepath ? strlen(vol->prepath) : 0;
  179. char *full_path = NULL;
  180. /* if no prefix path, simply set path to the root of share to "" */
  181. if (pplen == 0) {
  182. full_path = kzalloc(2, GFP_KERNEL);
  183. return full_path;
  184. }
  185. cERROR(1, "prefixpath is not supported for SMB2 now");
  186. return NULL;
  187. }
  188. static bool
  189. smb2_can_echo(struct TCP_Server_Info *server)
  190. {
  191. return server->echoes;
  192. }
  193. struct smb_version_operations smb21_operations = {
  194. .setup_request = smb2_setup_request,
  195. .setup_async_request = smb2_setup_async_request,
  196. .check_receive = smb2_check_receive,
  197. .add_credits = smb2_add_credits,
  198. .set_credits = smb2_set_credits,
  199. .get_credits_field = smb2_get_credits_field,
  200. .get_credits = smb2_get_credits,
  201. .get_next_mid = smb2_get_next_mid,
  202. .find_mid = smb2_find_mid,
  203. .check_message = smb2_check_message,
  204. .dump_detail = smb2_dump_detail,
  205. .need_neg = smb2_need_neg,
  206. .negotiate = smb2_negotiate,
  207. .sess_setup = SMB2_sess_setup,
  208. .logoff = SMB2_logoff,
  209. .tree_connect = SMB2_tcon,
  210. .tree_disconnect = SMB2_tdis,
  211. .is_path_accessible = smb2_is_path_accessible,
  212. .can_echo = smb2_can_echo,
  213. .echo = SMB2_echo,
  214. .query_path_info = smb2_query_path_info,
  215. .get_srv_inum = smb2_get_srv_inum,
  216. .build_path_to_root = smb2_build_path_to_root,
  217. };
  218. struct smb_version_values smb21_values = {
  219. .version_string = SMB21_VERSION_STRING,
  220. .header_size = sizeof(struct smb2_hdr),
  221. .max_header_size = MAX_SMB2_HDR_SIZE,
  222. .lock_cmd = SMB2_LOCK,
  223. };