1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Dispatch function for SMB2_OPLOCK_BREAK
  18  */
  19 
  20 #include <smbsrv/smb2_kproto.h>
  21 
  22 /*
  23  * SMB2 Oplock Break Acknowledgement
  24  * [MS-SMB2 2.2.24]
  25  */
  26 smb_sdrc_t
  27 smb2_oplock_break_ack(smb_request_t *sr)
  28 {
  29         smb_node_t *node;
  30         smb2fid_t smb2fid;
  31         uint32_t status;
  32         uint16_t StructSize;
  33         uint8_t OplockLevel;
  34         uint8_t brk;
  35         int rc = 0;
  36 
  37         /*
  38          * Decode the SMB2 Oplock Break Ack.
  39          */
  40         rc = smb_mbc_decodef(
  41             &sr->smb_data, "wb5.qq",
  42             &StructSize,            /* w */
  43             &OplockLevel,           /* b */
  44             /* reserved                   5. */
  45             &smb2fid.persistent,    /* q */
  46             &smb2fid.temporal);             /* q */
  47         if (rc || StructSize != 24)
  48                 return (SDRC_ERROR);
  49 
  50         status = smb2sr_lookup_fid(sr, &smb2fid);
  51         if (status)
  52                 goto errout;
  53         if ((node = sr->fid_ofile->f_node) == NULL) {
  54                 /* Not a regular file */
  55                 status = NT_STATUS_INVALID_PARAMETER;
  56                 goto errout;
  57         }
  58 
  59         /*
  60          * Process the oplock break ack.  We only expect levels
  61          * at or below the hightest break levels we send, which is
  62          * currently SMB2_OPLOCK_LEVEL_II.
  63          */
  64         switch (OplockLevel) {
  65         case SMB2_OPLOCK_LEVEL_NONE:    /* 0x00 */
  66                 brk = SMB_OPLOCK_BREAK_TO_NONE;
  67                 break;
  68 
  69         case SMB2_OPLOCK_LEVEL_II:      /* 0x01 */
  70                 brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
  71                 break;
  72 
  73         /* We don't break to these levels (yet). */
  74         case SMB2_OPLOCK_LEVEL_EXCLUSIVE: /* 0x08 */
  75         case SMB2_OPLOCK_LEVEL_BATCH:   /* 0x09 */
  76         case SMB2_OPLOCK_LEVEL_LEASE:   /* 0xFF */
  77         default: /* gcc -Wuninitialized */
  78                 status = NT_STATUS_INVALID_PARAMETER;
  79                 goto errout;
  80         }
  81 
  82         smb_oplock_ack(node, sr->fid_ofile, brk);
  83 
  84         /*
  85          * Generate SMB2 Oplock Break response
  86          * [MS-SMB2] 2.2.25
  87          */
  88         StructSize = 24;
  89         (void) smb_mbc_encodef(
  90             &sr->reply, "wb5.qq",
  91             StructSize,                 /* w */
  92             OplockLevel,                /* b */
  93             /* reserved                   5. */
  94             smb2fid.persistent,         /* q */
  95             smb2fid.temporal);          /* q */
  96         return (SDRC_SUCCESS);
  97 
  98 errout:
  99         smb2sr_put_error(sr, status);
 100         return (SDRC_SUCCESS);
 101 }
 102 
 103 /*
 104  * Compose an SMB2 Oplock Break Notification packet, including
 105  * the SMB2 header and everything, in sr->reply.
 106  * The caller will send it and free the request.
 107  */
 108 void
 109 smb2_oplock_break_notification(smb_request_t *sr, uint8_t brk)
 110 {
 111         smb_ofile_t *ofile = sr->fid_ofile;
 112         smb2fid_t smb2fid;
 113         uint16_t StructSize;
 114         uint8_t OplockLevel;
 115 
 116         switch (brk) {
 117         default:
 118                 ASSERT(0);
 119                 /* FALLTHROUGH */
 120         case SMB_OPLOCK_BREAK_TO_NONE:
 121                 OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
 122                 break;
 123         case SMB_OPLOCK_BREAK_TO_LEVEL_II:
 124                 OplockLevel = SMB2_OPLOCK_LEVEL_II;
 125                 break;
 126         }
 127 
 128         /*
 129          * SMB2 Header
 130          */
 131         sr->smb2_cmd_code = SMB2_OPLOCK_BREAK;
 132         sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
 133         sr->smb_tid = ofile->f_tree->t_tid;
 134         sr->smb_pid = 0;
 135         sr->smb_uid = 0;
 136         sr->smb2_messageid = UINT64_MAX;
 137         (void) smb2_encode_header(sr, B_FALSE);
 138 
 139         /*
 140          * SMB2 Oplock Break, variable part
 141          */
 142         StructSize = 24;
 143         smb2fid.persistent = 0;
 144         smb2fid.temporal = ofile->f_fid;
 145         (void) smb_mbc_encodef(
 146             &sr->reply, "wb5.qq",
 147             StructSize,         /* w */
 148             OplockLevel,        /* b */
 149             /* reserved           5. */
 150             smb2fid.persistent, /* q */
 151             smb2fid.temporal);  /* q */
 152 }