void config_int_set(enum card_info_subcommand subcommand, int set_to) { struct var_byte_response args; fill_with_int(&args, set_to); card_config_set(subcommand, &args); wait_for_response(); }
static void try_redirect(newtComponent c) { struct ast_chan *chan; char dest[256]; struct message *m; char channame[256]; char tmp[80]; char *context; chan = newtListboxGetCurrent(c); if (chan) { strncpy(channame, chan->name, sizeof(channame) - 1); snprintf(tmp, sizeof(tmp), "Enter new extension for %s", channame); if (get_user_input(tmp, dest, sizeof(dest))) return; if ((context = strchr(dest, '@'))) { *context = '\0'; context++; manager_action("Redirect", "Channel: %s\r\nContext: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name,context,dest); } else { manager_action("Redirect", "Channel: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name, dest); } m = wait_for_response(10000); if (!m) { show_message("Hangup Failed", "Timeout waiting for response"); } else if (strcasecmp(get_header(m, "Response"), "Success")) { show_message("Hangup Failed", get_header(m, "Message")); } } }
/* ask for updates. if new prefix is set, update and notify user */ int state_verify( int fd, int itf, Msgs *msgs ){ Message *m; diag( COMPONENT, DIAG_INFO, "State S9: verify" ); ilmi_state = up; action_A6( fd, msgs ); /* stop timer */ action_A7( fd, msgs ); /* retries = 0 */ action_A5( fd, msgs ); /* start timer */ m = wait_for_response( fd, itf, msgs, POLL_PERIOD ); if(( m == NULL ) && ( ilmi_errno == ECOLDSTART )){ return S1; } else if( ilmi_errno == EALARM ){ /* interface information must be no older than 30 seconds */ alarm_flag = 0; action_A12( fd, msgs ); /* request attachment point */ while((( m = wait_for_attachment_point( fd, itf, msgs )) == NULL ) && ( retries < 4 )){ action_A12( fd, msgs ); action_A8( fd, msgs ); } if( retries >= 4 ) return S2; /* check for attachment point change */ } return S9; }
int issue_noarg_command(u8 cmd) { struct noarg_request req; debug_printf(4, "%s() cmd: %d\n", __func__, cmd); req.req = cmd; write_struct(REQM, &req); return wait_for_response(); }
int card_info_cmd(enum card_info_subcommand cmd) { struct card_info_req cir; cir.o = 'o'; cir.subcommand = cmd; write_struct(REQM, &cir); return wait_for_response(); }
int get_log_at_offset(u32 offset) { struct fetch_log_cmd cmd; cmd.m = 'm'; cmd.offset = u32_to_be32(offset); debug_printf(2, "getting log at offset: %08x\n", offset); write_struct(REQM, &cmd); return wait_for_response(); }
bool gsm_on() { gsm_on_raw(); if ( !wait_for_response( "+PSSUP", 0 ) || !wait_for_ready() ) { gsm_off(); return false; } return true; }
void wlan_disable(int do_disable) { struct card_config_cmd req; req.O = 'O'; req.subcommand = WLAN_DISABLE; req.u8_args[0] = do_disable; req.u8_args[1] = do_disable; write_to(REQM, &req, offsetof(struct card_config_cmd, u8_args) + 1); wait_for_response(); }
static void try_status(void) { struct message *m; manager_action("Status", ""); m = wait_for_response(10000); if (!m) { show_message("Status Failed", "Timeout waiting for response"); } else if (strcasecmp(get_header(m, "Response"), "Success")) { show_message("Status Failed Failed", get_header(m, "Message")); } }
static int wait_for_ack(int timeout, int cmd_id) { int result = wait_for_response(timeout, receive_cmd, CMD_SIZE); if(result && receive_cmd[1] == CMD_ACK && receive_cmd[2] == cmd_id) { return 1; } return 0; }
/* Wait for the codec to be ready, write the verb, then wait for the * codec to be have a valid response. */ static int exec_one_verb(uint32_t base, uint32_t val, uint32_t *response) { if (wait_for_ready(base) == -1) return -1; writel(val, base + HDA_ICII_COMMAND_REG); if (wait_for_response(base, response) == -1) return -1; return 0; }
bool gsm_send_sms( const char* destination, const char* message ) { int i, len; gsm_send_at_cmd( "AT+E=0" ); gsm_send_at_cmd( "AT+CMGF=1" ); sends(U1, "AT+CMGS=\""); sends(U1, destination ); sends(U1, "\"\r"); wait_for_response( ">", 0 ); len = strlen(message); if ( len > 160 ) len = 160; for ( i=0; i<len; ++i ) { put( U1, message[i] ); } put( U1, 0x1A ); // ASCII ctrl-z = 0x1A return wait_for_response( "OK", "ERROR" ); }
int card_config_set(enum card_info_subcommand cmd, struct var_byte_response *args) { int len; struct card_config_cmd req; req.O = 'O'; req.subcommand = cmd; req.arg.len = args->len; memcpy(&req.arg.bytes[0], &args->bytes[0], args->len); // try to write a sane number of bytes len = offsetof(struct card_config_cmd, arg) + var_byte_len(args); debug_printf(2, "%s() writing %d bytes (%ld + %d)\n", __func__, len, offsetof(struct card_config_cmd, arg), var_byte_len(args)); write_to(REQM, &req, len); return wait_for_response(); }
static void try_hangup(newtComponent c) { struct ast_chan *chan; struct message *m; chan = newtListboxGetCurrent(c); if (chan) { manager_action("Hangup", "Channel: %s\r\n", chan->name); m = wait_for_response(10000); if (!m) { show_message("Hangup Failed", "Timeout waiting for response"); } else if (strcasecmp(get_header(m, "Response"), "Success")) { show_message("Hangup Failed", get_header(m, "Message")); } } }
int network_action(char cmd, char *essid, char *ascii_password) { struct net_request nr; memset(&nr, 0, sizeof(nr)); nr.req = cmd; strcpy(&nr.essid[0], essid); nr.essid_len = strlen(essid); if (ascii_password) { int ret = make_network_key(&nr.key, essid, ascii_password); if (ret) return ret; } write_struct(REQM, &nr); return wait_for_response(); }
int SendReceive2(const unsigned int xid, struct cifs_ses *ses, struct kvec *iov, int n_vec, int *resp_buf_type /* ret */, const int flags) { int rc = 0; int timeout, optype; struct mid_q_entry *midQ; char *buf = iov[0].iov_base; unsigned int credits = 1; struct smb_rqst rqst = { .rq_iov = iov, .rq_nvec = n_vec }; timeout = flags & CIFS_TIMEOUT_MASK; optype = flags & CIFS_OP_MASK; *resp_buf_type = CIFS_NO_BUFFER; /* no response buf yet */ if ((ses == NULL) || (ses->server == NULL)) { cifs_small_buf_release(buf); cifs_dbg(VFS, "Null session\n"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) { cifs_small_buf_release(buf); return -ENOENT; } /* * Ensure that we do not send more than 50 overlapping requests * to the same server. We may make this configurable later or * use ses->maxReq. */ rc = wait_for_free_request(ses->server, timeout, optype); if (rc) { cifs_small_buf_release(buf); return rc; } /* * Make sure that we sign in the same order that we send on this socket * and avoid races inside tcp sendmsg code that could cause corruption * of smb data. */ mutex_lock(&ses->server->srv_mutex); midQ = ses->server->ops->setup_request(ses, &rqst); if (IS_ERR(midQ)) { mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(buf); /* Update # of requests on wire to server */ add_credits(ses->server, 1, optype); return PTR_ERR(midQ); } midQ->mid_state = MID_REQUEST_SUBMITTED; cifs_in_send_inc(ses->server); rc = smb_sendv(ses->server, iov, n_vec); cifs_in_send_dec(ses->server); cifs_save_when_sent(midQ); if (rc < 0) ses->server->sequence_number -= 2; mutex_unlock(&ses->server->srv_mutex); if (rc < 0) { cifs_small_buf_release(buf); goto out; } if (timeout == CIFS_ASYNC_OP) { cifs_small_buf_release(buf); goto out; } rc = wait_for_response(ses->server, midQ); if (rc != 0) { send_cancel(ses->server, buf, midQ); spin_lock(&GlobalMid_Lock); if (midQ->mid_state == MID_REQUEST_SUBMITTED) { midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); cifs_small_buf_release(buf); add_credits(ses->server, 1, optype); return rc; } spin_unlock(&GlobalMid_Lock); } cifs_small_buf_release(buf); rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { add_credits(ses->server, 1, optype); return rc; } if (!midQ->resp_buf || midQ->mid_state != MID_RESPONSE_RECEIVED) { rc = -EIO; cifs_dbg(FYI, "Bad MID state?\n"); goto out; } buf = (char *)midQ->resp_buf; iov[0].iov_base = buf; iov[0].iov_len = get_rfc1002_length(buf) + 4; if (midQ->large_buf) *resp_buf_type = CIFS_LARGE_BUFFER; else *resp_buf_type = CIFS_SMALL_BUFFER; credits = ses->server->ops->get_credits(midQ); rc = ses->server->ops->check_receive(midQ, ses->server, flags & CIFS_LOG_ERROR); /* mark it so buf will not be freed by cifs_delete_mid */ if ((flags & CIFS_NO_RESP) == 0) midQ->resp_buf = NULL; out: cifs_delete_mid(midQ); add_credits(ses->server, credits, optype); return rc; }
int SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, struct smb_hdr *in_buf, struct smb_hdr *out_buf, int *pbytes_returned) { int rc = 0; int rstart = 0; unsigned int receive_len; struct mid_q_entry *midQ; struct cifsSesInfo *ses; if (tcon == NULL || tcon->ses == NULL) { cERROR(1, "Null smb session"); return -EIO; } ses = tcon->ses; if (ses->server == NULL) { cERROR(1, "Null tcp session"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) return -ENOENT; /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { cERROR(1, "Illegal length, greater than maximum frame, %d", in_buf->smb_buf_length); return -EIO; } rc = wait_for_free_request(ses, CIFS_BLOCKING_OP); if (rc) return rc; /* make sure that we sign in the same order that we send on this socket and avoid races inside tcp sendmsg code that could cause corruption of smb data */ mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { mutex_unlock(&ses->server->srv_mutex); return rc; } rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); if (rc) { DeleteMidQEntry(midQ); mutex_unlock(&ses->server->srv_mutex); return rc; } midQ->midState = MID_REQUEST_SUBMITTED; #ifdef CONFIG_CIFS_STATS2 atomic_inc(&ses->server->inSend); #endif rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; #endif mutex_unlock(&ses->server->srv_mutex); if (rc < 0) { DeleteMidQEntry(midQ); return rc; } /* Wait for a reply - allow signals to interrupt. */ rc = wait_event_interruptible(ses->server->response_q, (!(midQ->midState == MID_REQUEST_SUBMITTED)) || ((ses->server->tcpStatus != CifsGood) && (ses->server->tcpStatus != CifsNew))); /* Were we interrupted by a signal ? */ if ((rc == -ERESTARTSYS) && (midQ->midState == MID_REQUEST_SUBMITTED) && ((ses->server->tcpStatus == CifsGood) || (ses->server->tcpStatus == CifsNew))) { if (in_buf->Command == SMB_COM_TRANSACTION2) { /* POSIX lock. We send a NT_CANCEL SMB to cause the blocking lock to return. */ rc = send_nt_cancel(tcon, in_buf, midQ); if (rc) { DeleteMidQEntry(midQ); return rc; } } else { /* Windows lock. We send a LOCKINGX_CANCEL_LOCK to cause the blocking lock to return. */ rc = send_lock_cancel(xid, tcon, in_buf, out_buf); /* If we get -ENOLCK back the lock may have already been removed. Don't exit in this case. */ if (rc && rc != -ENOLCK) { DeleteMidQEntry(midQ); return rc; } } /* Wait 5 seconds for the response. */ if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) { /* We got the response - restart system call. */ rstart = 1; } } spin_lock(&GlobalMid_Lock); if (midQ->resp_buf) { spin_unlock(&GlobalMid_Lock); receive_len = midQ->resp_buf->smb_buf_length; } else { cERROR(1, "No response for cmd %d mid %d", midQ->command, midQ->mid); if (midQ->midState == MID_REQUEST_SUBMITTED) { if (ses->server->tcpStatus == CifsExiting) rc = -EHOSTDOWN; else { ses->server->tcpStatus = CifsNeedReconnect; midQ->midState = MID_RETRY_NEEDED; } } if (rc != -EHOSTDOWN) { if (midQ->midState == MID_RETRY_NEEDED) { rc = -EAGAIN; cFYI(1, "marking request for retry"); } else { rc = -EIO; } } spin_unlock(&GlobalMid_Lock); DeleteMidQEntry(midQ); return rc; } if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, "Frame too large received. Length: %d Xid: %d", receive_len, xid); rc = -EIO; goto out; } /* rcvd frame is ok */ if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) { rc = -EIO; cERROR(1, "Bad MID state?"); goto out; } out_buf->smb_buf_length = receive_len; memcpy((char *)out_buf + 4, (char *)midQ->resp_buf + 4, receive_len); dump_smb(out_buf, 92); /* convert the length into a more usable form */ if ((receive_len > 24) && (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(out_buf, ses->server, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); /* BB FIXME add code to kill session */ } } *pbytes_returned = out_buf->smb_buf_length; /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); /* convert ByteCount if necessary */ if (receive_len >= sizeof(struct smb_hdr) - 4 /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); out: DeleteMidQEntry(midQ); if (rstart && rc == -EACCES) return -ERESTARTSYS; return rc; }
int SendReceive(const unsigned int xid, struct cifsSesInfo *ses, struct smb_hdr *in_buf, struct smb_hdr *out_buf, int *pbytes_returned, const int long_op) { int rc = 0; unsigned int receive_len; unsigned long timeout; struct mid_q_entry *midQ; if (ses == NULL) { cERROR(1, "Null smb session"); return -EIO; } if (ses->server == NULL) { cERROR(1, "Null tcp session"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) return -ENOENT; /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { cERROR(1, "Illegal length, greater than maximum frame, %d", in_buf->smb_buf_length); return -EIO; } rc = wait_for_free_request(ses, long_op); if (rc) return rc; /* make sure that we sign in the same order that we send on this socket and avoid races inside tcp sendmsg code that could cause corruption of smb data */ mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); if (rc) { mutex_unlock(&ses->server->srv_mutex); goto out; } midQ->midState = MID_REQUEST_SUBMITTED; #ifdef CONFIG_CIFS_STATS2 atomic_inc(&ses->server->inSend); #endif rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; #endif mutex_unlock(&ses->server->srv_mutex); if (rc < 0) goto out; if (long_op == CIFS_STD_OP) timeout = 15 * HZ; /* wait for 15 seconds or until woken up due to response arriving or due to last connection to this server being unmounted */ else if (long_op == CIFS_ASYNC_OP) goto out; else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */ timeout = 180 * HZ; else if (long_op == CIFS_LONG_OP) timeout = 45 * HZ; /* should be greater than servers oplock break timeout (about 43 seconds) */ else if (long_op == CIFS_BLOCKING_OP) timeout = 0x7FFFFFFF; /* large but no so large as to wrap */ else { cERROR(1, "unknown timeout flag %d", long_op); rc = -EIO; goto out; } if (signal_pending(current)) { /* if signal pending do not hold up user for full smb timeout but we still give response a chance to complete */ timeout = 2 * HZ; } /* No user interrupts in wait - wreaks havoc with performance */ wait_for_response(ses, midQ, timeout, 10 * HZ); spin_lock(&GlobalMid_Lock); if (midQ->resp_buf == NULL) { cERROR(1, "No response for cmd %d mid %d", midQ->command, midQ->mid); if (midQ->midState == MID_REQUEST_SUBMITTED) { if (ses->server->tcpStatus == CifsExiting) rc = -EHOSTDOWN; else { ses->server->tcpStatus = CifsNeedReconnect; midQ->midState = MID_RETRY_NEEDED; } } if (rc != -EHOSTDOWN) { if (midQ->midState == MID_RETRY_NEEDED) { rc = -EAGAIN; cFYI(1, "marking request for retry"); } else { rc = -EIO; } } spin_unlock(&GlobalMid_Lock); DeleteMidQEntry(midQ); /* Update # of requests on wire to server */ atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } spin_unlock(&GlobalMid_Lock); receive_len = midQ->resp_buf->smb_buf_length; if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, "Frame too large received. Length: %d Xid: %d", receive_len, xid); rc = -EIO; goto out; } /* rcvd frame is ok */ if (midQ->resp_buf && out_buf && (midQ->midState == MID_RESPONSE_RECEIVED)) { out_buf->smb_buf_length = receive_len; memcpy((char *)out_buf + 4, (char *)midQ->resp_buf + 4, receive_len); dump_smb(out_buf, 92); /* convert the length into a more usable form */ if ((receive_len > 24) && (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(out_buf, ses->server, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); /* BB FIXME add code to kill session */ } } *pbytes_returned = out_buf->smb_buf_length; /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); /* convert ByteCount if necessary */ if (receive_len >= sizeof(struct smb_hdr) - 4 /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); } else { rc = -EIO; cERROR(1, "Bad MID state?"); } out: DeleteMidQEntry(midQ); atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; }
bool gsm_send_at_cmd( const char* cmd ) { sends( U1, cmd ); sends( U1, "\r\n" ); return wait_for_response( "OK", "ERROR" ); }
void testit0(void) { char c; struct testbuf tb; int i; int fdin; int fdout; //start_direct(); print_direct_status(); //enable_direct_mode(60, 120); enable_direct_mode(DIRECT_WAIT_FOREVER, DIRECT_WAIT_FOREVER); print_direct_status(); start_direct(); exit(0); //char new_cmd[] = {'O', 0x06, 0x0d, 0x0a, 0x31, 0x30, 0x2e, 0x36, 0x2e, 0x30, 0x2e, 0x31, 0x33, 0x37}; //printf("waiting...\n"); //print_transfer_status(); //exit(0); //int doagain = 1; //wlan_disable(0); //int to_test[] = {5, 8, 9, 11, 15, 16, 255, -1}; int to_test[] = {0xFF, -1}; zero_card_files(); for (i = 0; i < 100; i++) { print_transfer_status(); } exit(0); while (1) { //fprintf(stderr, "testing...\n"); for (i = 0; i < 255; i++) { int cmd = to_test[i]; if (cmd == -1) break; //zero_card_files(); card_info_cmd(cmd); printf("UNKNOWN %3d result: ", cmd); int printed = dumpbuf(eyefi_buf, 256); if (!printed) printf("\n"); print_transfer_status(); print_connected_to(); } } exit(0); scan_print_nets(); printf("WLAN enabled: %d\n", wlan_enabled()); //wlan_disable(); printf("WLAN enabled: %d\n", wlan_enabled()); for (i = 10; i <= 13; i++) { int printed; zero_card_files(); card_info_cmd(i); printf("UNKNOWN %d result:\n", i); printed = dumpbuf(eyefi_buf, 64); printf("WLAN enabled: %d\n", wlan_enabled()); } i = 0xff; card_info_cmd(i); printf("UNKNOWN %d result:", i); dumpbuf(eyefi_buf, 64); exit(3); card_info_cmd(3); printf("o3 result:\n"); dumpbuf(eyefi_buf, 64); memset(&zbuf[0], 0, EYEFI_BUF_SIZE); zbuf[0] = 'o'; zbuf[1] = 2; write_to(REQM, &zbuf[0], 16384); printf("o2 written\n"); printf("seq: %x\n", (int)eyefi_seq.seq); inc_seq(); for (i=0; i < 4; i++) { read_from(RSPC); printf("RSPC %d:\n", i); dumpbuf(eyefi_buf, 64); usleep(20000); } printf("RSPM1:\n"); read_from(RSPM); dumpbuf(eyefi_buf, 64); memset(&zbuf[0], 0, EYEFI_BUF_SIZE); write_to(RSPM, zbuf, EYEFI_BUF_SIZE); write_to(REQM, zbuf, EYEFI_BUF_SIZE); fdin = open("/home/dave/projects/eyefi/EYEFIFWU.BIN.2.0001", O_RDONLY); perror("fdin"); fdout = open("/media/EYE-FI/EYEFIFWU.BIN", O_WRONLY|O_CREAT); perror("fdout"); if (fdin <= 0 || fdout <= 0) exit(1); fd_flush(fdin); i = read(fdin, &fwbuf[0], 524288); perror("read"); if (i != 524288) exit(2); i = write(fdout, &fwbuf[0], 524288); fd_flush(fdout); perror("write"); if (i != 524288) exit(3); printf("RSPM2:\n"); read_from(RSPM); dumpbuf(eyefi_buf, 64); reboot_card(); printf("after reboot:\n"); dumpbuf(eyefi_buf, 64); printf("cic3:\n"); card_info_cmd(3); dumpbuf(eyefi_buf, 64); printf("cic2:\n"); card_info_cmd(2); dumpbuf(eyefi_buf, 64); memset(&zbuf[0], 0, EYEFI_BUF_SIZE); write_to(RSPM, zbuf, EYEFI_BUF_SIZE); write_to(REQM, zbuf, EYEFI_BUF_SIZE); printf("cic2v2:\n"); card_info_cmd(2); dumpbuf(eyefi_buf, 64); exit(0); strcpy(tb.name, "www.sr71.net/"); tb.l1 = strlen(tb.name); for (i = 0; i < 10; i++) { tb.cmd = 'O'; tb.l1 = i; write_struct(RSPM, &z); write_struct(REQM, &tb); wait_for_response(); printf("buffer after O %d:\n", i); dumpbuf(eyefi_buf, 64); printf("----------------\n"); write_struct(REQM, &tb); card_info_cmd(i); printf("card info(%d):\n", i); dumpbuf(eyefi_buf, 64); printf("-----------\n"); } return; strcpy(tb.name, "/public/eyefi/servname"); strcpy(tb.name, "/config/networks.xml"); //tb.len = strlen(tb.name); tb.l1 = 0; for (c = 'O'; c <= 'O'; c++) { tb.cmd = c; write_struct(REQM, &tb); wait_for_response(); printf("dumping buffer:\n"); dumpbuf(eyefi_buf, 64); printf("buffer dump done\n"); } }
int SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, struct kvec *iov, int n_vec, int *pRespBufType /* ret */, const int flags) { int rc = 0; int long_op; unsigned int receive_len; struct mid_q_entry *midQ; struct smb_hdr *in_buf = iov[0].iov_base; long_op = flags & CIFS_TIMEOUT_MASK; *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ if ((ses == NULL) || (ses->server == NULL)) { cifs_small_buf_release(in_buf); cERROR(1, "Null session"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) { cifs_small_buf_release(in_buf); return -ENOENT; } /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ rc = wait_for_free_request(ses->server, long_op); if (rc) { cifs_small_buf_release(in_buf); return rc; } /* make sure that we sign in the same order that we send on this socket and avoid races inside tcp sendmsg code that could cause corruption of smb data */ mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(in_buf); /* Update # of requests on wire to server */ atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); if (rc) { mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(in_buf); goto out; } midQ->midState = MID_REQUEST_SUBMITTED; #ifdef CONFIG_CIFS_STATS2 atomic_inc(&ses->server->inSend); #endif rc = smb_sendv(ses->server, iov, n_vec); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; #endif mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(in_buf); if (rc < 0) goto out; if (long_op == CIFS_ASYNC_OP) goto out; rc = wait_for_response(ses->server, midQ); if (rc != 0) goto out; rc = sync_mid_result(midQ, ses->server); if (rc != 0) { atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } receive_len = midQ->resp_buf->smb_buf_length; if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, "Frame too large received. Length: %d Xid: %d", receive_len, xid); rc = -EIO; goto out; } /* rcvd frame is ok */ if (midQ->resp_buf && (midQ->midState == MID_RESPONSE_RECEIVED)) { iov[0].iov_base = (char *)midQ->resp_buf; if (midQ->largeBuf) *pRespBufType = CIFS_LARGE_BUFFER; else *pRespBufType = CIFS_SMALL_BUFFER; iov[0].iov_len = receive_len + 4; dump_smb(midQ->resp_buf, 80); /* convert the length into a more usable form */ if ((receive_len > 24) && (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(midQ->resp_buf, ses->server, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); /* BB FIXME add code to kill session */ } } /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(midQ->resp_buf, flags & CIFS_LOG_ERROR); /* convert ByteCount if necessary */ if (receive_len >= sizeof(struct smb_hdr) - 4 /* do not count RFC1001 header */ + (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf); if ((flags & CIFS_NO_RESP) == 0) midQ->resp_buf = NULL; /* mark it so buf will not be freed by delete_mid */ } else { rc = -EIO; cFYI(1, "Bad MID state?"); } out: delete_mid(midQ); atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; }
int SendReceive(const unsigned int xid, struct cifsSesInfo *ses, struct smb_hdr *in_buf, struct smb_hdr *out_buf, int *pbytes_returned, const int long_op) { int rc = 0; unsigned int receive_len; struct mid_q_entry *midQ; if (ses == NULL) { cERROR(1, "Null smb session"); return -EIO; } if (ses->server == NULL) { cERROR(1, "Null tcp session"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) return -ENOENT; /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { cERROR(1, "Illegal length, greater than maximum frame, %d", in_buf->smb_buf_length); return -EIO; } rc = wait_for_free_request(ses->server, long_op); if (rc) return rc; /* make sure that we sign in the same order that we send on this socket and avoid races inside tcp sendmsg code that could cause corruption of smb data */ mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); if (rc) { mutex_unlock(&ses->server->srv_mutex); goto out; } midQ->midState = MID_REQUEST_SUBMITTED; #ifdef CONFIG_CIFS_STATS2 atomic_inc(&ses->server->inSend); #endif rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; #endif mutex_unlock(&ses->server->srv_mutex); if (rc < 0) goto out; if (long_op == CIFS_ASYNC_OP) goto out; rc = wait_for_response(ses->server, midQ); if (rc != 0) goto out; rc = sync_mid_result(midQ, ses->server); if (rc != 0) { atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } receive_len = midQ->resp_buf->smb_buf_length; if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, "Frame too large received. Length: %d Xid: %d", receive_len, xid); rc = -EIO; goto out; } /* rcvd frame is ok */ if (midQ->resp_buf && out_buf && (midQ->midState == MID_RESPONSE_RECEIVED)) { out_buf->smb_buf_length = receive_len; memcpy((char *)out_buf + 4, (char *)midQ->resp_buf + 4, receive_len); dump_smb(out_buf, 92); /* convert the length into a more usable form */ if ((receive_len > 24) && (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(out_buf, ses->server, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); /* BB FIXME add code to kill session */ } } *pbytes_returned = out_buf->smb_buf_length; /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); /* convert ByteCount if necessary */ if (receive_len >= sizeof(struct smb_hdr) - 4 /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf); } else { rc = -EIO; cERROR(1, "Bad MID state?"); } out: delete_mid(midQ); atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; }
int SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, struct kvec *iov, int n_vec, int * pRespBufType /* ret */, const int long_op) { int rc = 0; unsigned int receive_len; unsigned long timeout; struct mid_q_entry *midQ; struct smb_hdr *in_buf = iov[0].iov_base; *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ if ((ses == NULL) || (ses->server == NULL)) { cifs_small_buf_release(in_buf); cERROR(1,("Null session")); return -EIO; } if(ses->server->tcpStatus == CifsExiting) { cifs_small_buf_release(in_buf); return -ENOENT; } /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ rc = wait_for_free_request(ses, long_op); if (rc) { cifs_small_buf_release(in_buf); return rc; } /* make sure that we sign in the same order that we send on this socket and avoid races inside tcp sendmsg code that could cause corruption of smb data */ down(&ses->server->tcpSem); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { up(&ses->server->tcpSem); cifs_small_buf_release(in_buf); /* Update # of requests on wire to server */ atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; #ifdef CONFIG_CIFS_STATS2 atomic_inc(&ses->server->inSend); #endif rc = smb_send2(ses->server->ssocket, iov, n_vec, (struct sockaddr *) &(ses->server->addr.sockAddr)); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; #endif up(&ses->server->tcpSem); cifs_small_buf_release(in_buf); if(rc < 0) goto out; if (long_op == -1) goto out; else if (long_op == 2) /* writes past end of file can take loong time */ timeout = 180 * HZ; else if (long_op == 1) timeout = 45 * HZ; /* should be greater than servers oplock break timeout (about 43 seconds) */ else timeout = 15 * HZ; /* wait for 15 seconds or until woken up due to response arriving or due to last connection to this server being unmounted */ if (signal_pending(current)) { /* if signal pending do not hold up user for full smb timeout but we still give response a change to complete */ timeout = 2 * HZ; } /* No user interrupts in wait - wreaks havoc with performance */ wait_for_response(ses, midQ, timeout, 10 * HZ); spin_lock(&GlobalMid_Lock); if (midQ->resp_buf) { spin_unlock(&GlobalMid_Lock); receive_len = midQ->resp_buf->smb_buf_length; } else { cERROR(1,("No response to cmd %d mid %d", midQ->command, midQ->mid)); if(midQ->midState == MID_REQUEST_SUBMITTED) { if(ses->server->tcpStatus == CifsExiting) rc = -EHOSTDOWN; else { ses->server->tcpStatus = CifsNeedReconnect; midQ->midState = MID_RETRY_NEEDED; } } if (rc != -EHOSTDOWN) { if(midQ->midState == MID_RETRY_NEEDED) { rc = -EAGAIN; cFYI(1,("marking request for retry")); } else { rc = -EIO; } } spin_unlock(&GlobalMid_Lock); DeleteMidQEntry(midQ); /* Update # of requests on wire to server */ atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, ("Frame too large received. Length: %d Xid: %d", receive_len, xid)); rc = -EIO; } else { /* rcvd frame is ok */ if (midQ->resp_buf && (midQ->midState == MID_RESPONSE_RECEIVED)) { iov[0].iov_base = (char *)midQ->resp_buf; if(midQ->largeBuf) *pRespBufType = CIFS_LARGE_BUFFER; else *pRespBufType = CIFS_SMALL_BUFFER; iov[0].iov_len = receive_len + 4; dump_smb(midQ->resp_buf, 80); /* convert the length into a more usable form */ if((receive_len > 24) && (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(midQ->resp_buf, ses->server->mac_signing_key, midQ->sequence_number+1); if(rc) { cERROR(1,("Unexpected SMB signature")); /* BB FIXME add code to kill session */ } } /* BB special case reconnect tid and uid here? */ /* BB special case Errbadpassword and pwdexpired here */ rc = map_smb_to_linux_error(midQ->resp_buf); /* convert ByteCount if necessary */ if (receive_len >= sizeof (struct smb_hdr) - 4 /* do not count RFC1001 header */ + (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) BCC(midQ->resp_buf) = le16_to_cpu(BCC_LE(midQ->resp_buf)); midQ->resp_buf = NULL; /* mark it so will not be freed by DeleteMidQEntry */ } else { rc = -EIO; cFYI(1,("Bad MID state?")); } } out: DeleteMidQEntry(midQ); atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; }
static int login(char *hostname) { newtComponent form; newtComponent cancel; newtComponent login; newtComponent username; newtComponent password; newtComponent label; newtComponent ulabel; newtComponent plabel; const char *user; const char *pass; struct message *m; struct newtExitStruct es; char tmp[55]; struct hostent *hp; int res = -1; session.fd = socket(AF_INET, SOCK_STREAM, 0); if (session.fd < 0) { snprintf(tmp, sizeof(tmp), "socket() failed: %s\n", strerror(errno)); show_message("Socket failed", tmp); return -1; } snprintf(tmp, sizeof(tmp), "Looking up %s\n", hostname); show_doing("Connecting....", tmp); hp = gethostbyname(hostname); if (!hp) { snprintf(tmp, sizeof(tmp), "No such address: %s\n", hostname); show_message("Host lookup failed", tmp); return -1; } hide_doing(); snprintf(tmp, sizeof(tmp), "Connecting to %s", hostname); show_doing("Connecting...", tmp); session.sin.sin_family = AF_INET; session.sin.sin_port = htons(DEFAULT_MANAGER_PORT); memcpy(&session.sin.sin_addr, hp->h_addr, sizeof(session.sin.sin_addr)); if (connect(session.fd,(struct sockaddr*)&session.sin, sizeof(session.sin))) { snprintf(tmp, sizeof(tmp), "%s failed: %s\n", hostname, strerror(errno)); show_message("Connect Failed", tmp); return -1; } hide_doing(); login = newtButton(5, 6, "Login"); cancel = newtButton(25, 6, "Cancel"); newtCenteredWindow(40, 10, "Asterisk Manager Login"); snprintf(tmp, sizeof(tmp), "Host: %s", hostname); label = newtLabel(4,1, tmp); ulabel = newtLabel(4,2,"Username:"******"Password:"******"", 20, _NEWT_CAST &user, 0); password = newtEntry(14, 3, "", 20, _NEWT_CAST &pass, NEWT_FLAG_HIDDEN); form = newtForm(NULL, NULL, 0); newtFormAddComponents(form, username, password, login, cancel, label, ulabel, plabel,NULL); newtFormRun(form, &es); if (es.reason == NEWT_EXIT_COMPONENT) { if (es.u.co == login) { snprintf(tmp, sizeof(tmp), "Logging in '%s'...", user); show_doing("Logging in", tmp); /* Check to see if the remote host supports MD5 Authentication */ manager_action("Challenge", "AuthType: MD5\r\n"); m = wait_for_response(10000); if (m && !strcasecmp(get_header(m, "Response"), "Success")) { char *challenge = get_header(m, "Challenge"); int x; int len = 0; char md5key[256] = ""; struct MD5Context md5; unsigned char digest[16]; MD5Init(&md5); MD5Update(&md5, (unsigned char *)challenge, strlen(challenge)); MD5Update(&md5, (unsigned char *)pass, strlen(pass)); MD5Final(digest, &md5); for (x=0; x<16; x++) len += sprintf(md5key + len, "%2.2x", digest[x]); manager_action("Login", "AuthType: MD5\r\n" "Username: %s\r\n" "Key: %s\r\n", user, md5key); m = wait_for_response(10000); hide_doing(); if (!strcasecmp(get_header(m, "Response"), "Success")) { res = 0; } else { show_message("Login Failed", get_header(m, "Message")); } } else { memset(m, 0, sizeof(m)); manager_action("Login", "Username: %s\r\n" "Secret: %s\r\n", user, pass); m = wait_for_response(10000); hide_doing(); if (m) { if (!strcasecmp(get_header(m, "Response"), "Success")) { res = 0; } else { show_message("Login Failed", get_header(m, "Message")); } } } } } newtFormDestroy(form); return res; }
int SendReceive(const unsigned int xid, struct cifsSesInfo *ses, struct smb_hdr *in_buf, struct smb_hdr *out_buf, int *pbytes_returned, const int long_op) { int rc = 0; struct mid_q_entry *midQ; if (ses == NULL) { cERROR(1, "Null smb session"); return -EIO; } if (ses->server == NULL) { cERROR(1, "Null tcp session"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) return -ENOENT; /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { cERROR(1, "Illegal length, greater than maximum frame, %d", be32_to_cpu(in_buf->smb_buf_length)); return -EIO; } rc = wait_for_free_request(ses->server, long_op); if (rc) return rc; /* make sure that we sign in the same order that we send on this socket and avoid races inside tcp sendmsg code that could cause corruption of smb data */ mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); if (rc) { mutex_unlock(&ses->server->srv_mutex); goto out; } midQ->midState = MID_REQUEST_SUBMITTED; #ifdef CONFIG_CIFS_STATS2 atomic_inc(&ses->server->inSend); #endif rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; #endif mutex_unlock(&ses->server->srv_mutex); if (rc < 0) goto out; if (long_op == CIFS_ASYNC_OP) goto out; rc = wait_for_response(ses->server, midQ); if (rc != 0) { send_nt_cancel(ses->server, in_buf, midQ); spin_lock(&GlobalMid_Lock); if (midQ->midState == MID_REQUEST_SUBMITTED) { /* no longer considered to be "in-flight" */ midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } spin_unlock(&GlobalMid_Lock); } rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } if (!midQ->resp_buf || !out_buf || midQ->midState != MID_RESPONSE_RECEIVED) { rc = -EIO; cERROR(1, "Bad MID state?"); goto out; } *pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length); memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); rc = cifs_check_receive(midQ, ses->server, 0); out: delete_mid(midQ); atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; }
int SendReceive2(const unsigned int xid, struct cifs_ses *ses, struct kvec *iov, int n_vec, int *pRespBufType /* ret */, const int flags) { int rc = 0; int long_op; struct mid_q_entry *midQ; struct smb_hdr *in_buf = iov[0].iov_base; long_op = flags & CIFS_TIMEOUT_MASK; *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ if ((ses == NULL) || (ses->server == NULL)) { cifs_small_buf_release(in_buf); cERROR(1, "Null session"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) { cifs_small_buf_release(in_buf); return -ENOENT; } /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ rc = wait_for_free_request(ses->server, long_op); if (rc) { cifs_small_buf_release(in_buf); return rc; } /* make sure that we sign in the same order that we send on this socket and avoid races inside tcp sendmsg code that could cause corruption of smb data */ mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(in_buf); /* Update # of requests on wire to server */ atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); if (rc) { mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(in_buf); goto out; } midQ->midState = MID_REQUEST_SUBMITTED; #ifdef CONFIG_CIFS_STATS2 atomic_inc(&ses->server->inSend); #endif rc = smb_sendv(ses->server, iov, n_vec); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; #endif mutex_unlock(&ses->server->srv_mutex); if (rc < 0) { cifs_small_buf_release(in_buf); goto out; } if (long_op == CIFS_ASYNC_OP) { cifs_small_buf_release(in_buf); goto out; } rc = wait_for_response(ses->server, midQ); if (rc != 0) { send_nt_cancel(ses->server, in_buf, midQ); spin_lock(&GlobalMid_Lock); if (midQ->midState == MID_REQUEST_SUBMITTED) { midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); cifs_small_buf_release(in_buf); atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } spin_unlock(&GlobalMid_Lock); } cifs_small_buf_release(in_buf); rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; } if (!midQ->resp_buf || midQ->midState != MID_RESPONSE_RECEIVED) { rc = -EIO; cFYI(1, "Bad MID state?"); goto out; } iov[0].iov_base = (char *)midQ->resp_buf; iov[0].iov_len = be32_to_cpu(midQ->resp_buf->smb_buf_length) + 4; if (midQ->largeBuf) *pRespBufType = CIFS_LARGE_BUFFER; else *pRespBufType = CIFS_SMALL_BUFFER; rc = cifs_check_receive(midQ, ses->server, flags & CIFS_LOG_ERROR); /* mark it so buf will not be freed by delete_mid */ if ((flags & CIFS_NO_RESP) == 0) midQ->resp_buf = NULL; out: delete_mid(midQ); atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); return rc; }
int SendReceive(const unsigned int xid, struct cifs_ses *ses, struct smb_hdr *in_buf, struct smb_hdr *out_buf, int *pbytes_returned, const int timeout) { int rc = 0; struct mid_q_entry *midQ; if (ses == NULL) { cifs_dbg(VFS, "Null smb session\n"); return -EIO; } if (ses->server == NULL) { cifs_dbg(VFS, "Null tcp session\n"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) return -ENOENT; /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n", be32_to_cpu(in_buf->smb_buf_length)); return -EIO; } rc = wait_for_free_request(ses->server, timeout, 0); if (rc) return rc; /* make sure that we sign in the same order that we send on this socket and avoid races inside tcp sendmsg code that could cause corruption of smb data */ mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ add_credits(ses->server, 1, 0); return rc; } rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); if (rc) { mutex_unlock(&ses->server->srv_mutex); goto out; } midQ->mid_state = MID_REQUEST_SUBMITTED; cifs_in_send_inc(ses->server); rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); cifs_in_send_dec(ses->server); cifs_save_when_sent(midQ); if (rc < 0) ses->server->sequence_number -= 2; mutex_unlock(&ses->server->srv_mutex); if (rc < 0) goto out; if (timeout == CIFS_ASYNC_OP) goto out; rc = wait_for_response(ses->server, midQ); if (rc != 0) { send_cancel(ses->server, in_buf, midQ); spin_lock(&GlobalMid_Lock); if (midQ->mid_state == MID_REQUEST_SUBMITTED) { /* no longer considered to be "in-flight" */ midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); add_credits(ses->server, 1, 0); return rc; } spin_unlock(&GlobalMid_Lock); } rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { add_credits(ses->server, 1, 0); return rc; } if (!midQ->resp_buf || !out_buf || midQ->mid_state != MID_RESPONSE_RECEIVED) { rc = -EIO; cifs_dbg(VFS, "Bad MID state?\n"); goto out; } *pbytes_returned = get_rfc1002_length(midQ->resp_buf); memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); rc = cifs_check_receive(midQ, ses->server, 0); out: cifs_delete_mid(midQ); add_credits(ses->server, 1, 0); return rc; }
int compound_send_recv(const unsigned int xid, struct cifs_ses *ses, const int flags, const int num_rqst, struct smb_rqst *rqst, int *resp_buf_type, struct kvec *resp_iov) { int i, j, rc = 0; int timeout, optype; struct mid_q_entry *midQ[MAX_COMPOUND]; unsigned int credits = 1; char *buf; timeout = flags & CIFS_TIMEOUT_MASK; optype = flags & CIFS_OP_MASK; for (i = 0; i < num_rqst; i++) resp_buf_type[i] = CIFS_NO_BUFFER; /* no response buf yet */ if ((ses == NULL) || (ses->server == NULL)) { cifs_dbg(VFS, "Null session\n"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) return -ENOENT; /* * Ensure that we do not send more than 50 overlapping requests * to the same server. We may make this configurable later or * use ses->maxReq. */ rc = wait_for_free_request(ses->server, timeout, optype); if (rc) return rc; /* * Make sure that we sign in the same order that we send on this socket * and avoid races inside tcp sendmsg code that could cause corruption * of smb data. */ mutex_lock(&ses->server->srv_mutex); for (i = 0; i < num_rqst; i++) { midQ[i] = ses->server->ops->setup_request(ses, &rqst[i]); if (IS_ERR(midQ[i])) { for (j = 0; j < i; j++) cifs_delete_mid(midQ[j]); mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ add_credits(ses->server, 1, optype); return PTR_ERR(midQ[i]); } midQ[i]->mid_state = MID_REQUEST_SUBMITTED; /* * We don't invoke the callback compounds unless it is the last * request. */ if (i < num_rqst - 1) midQ[i]->callback = cifs_noop_callback; } cifs_in_send_inc(ses->server); rc = smb_send_rqst(ses->server, num_rqst, rqst, flags); cifs_in_send_dec(ses->server); for (i = 0; i < num_rqst; i++) cifs_save_when_sent(midQ[i]); if (rc < 0) ses->server->sequence_number -= 2; mutex_unlock(&ses->server->srv_mutex); for (i = 0; i < num_rqst; i++) { if (rc < 0) goto out; if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) smb311_update_preauth_hash(ses, rqst[i].rq_iov, rqst[i].rq_nvec); if (timeout == CIFS_ASYNC_OP) goto out; rc = wait_for_response(ses->server, midQ[i]); if (rc != 0) { cifs_dbg(FYI, "Cancelling wait for mid %llu\n", midQ[i]->mid); send_cancel(ses->server, &rqst[i], midQ[i]); spin_lock(&GlobalMid_Lock); if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) { midQ[i]->mid_flags |= MID_WAIT_CANCELLED; midQ[i]->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); add_credits(ses->server, 1, optype); return rc; } spin_unlock(&GlobalMid_Lock); } rc = cifs_sync_mid_result(midQ[i], ses->server); if (rc != 0) { add_credits(ses->server, 1, optype); return rc; } if (!midQ[i]->resp_buf || midQ[i]->mid_state != MID_RESPONSE_RECEIVED) { rc = -EIO; cifs_dbg(FYI, "Bad MID state?\n"); goto out; } buf = (char *)midQ[i]->resp_buf; resp_iov[i].iov_base = buf; resp_iov[i].iov_len = midQ[i]->resp_buf_size + ses->server->vals->header_preamble_size; if (midQ[i]->large_buf) resp_buf_type[i] = CIFS_LARGE_BUFFER; else resp_buf_type[i] = CIFS_SMALL_BUFFER; if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) { struct kvec iov = { .iov_base = resp_iov[i].iov_base, .iov_len = resp_iov[i].iov_len }; smb311_update_preauth_hash(ses, &iov, 1); } credits = ses->server->ops->get_credits(midQ[i]); rc = ses->server->ops->check_receive(midQ[i], ses->server, flags & CIFS_LOG_ERROR); /* mark it so buf will not be freed by cifs_delete_mid */ if ((flags & CIFS_NO_RESP) == 0) midQ[i]->resp_buf = NULL; } out: /* * This will dequeue all mids. After this it is important that the * demultiplex_thread will not process any of these mids any futher. * This is prevented above by using a noop callback that will not * wake this thread except for the very last PDU. */ for (i = 0; i < num_rqst; i++) cifs_delete_mid(midQ[i]); add_credits(ses->server, credits, optype); return rc; } int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, struct smb_rqst *rqst, int *resp_buf_type, const int flags, struct kvec *resp_iov) { return compound_send_recv(xid, ses, flags, 1, rqst, resp_buf_type, resp_iov); } int SendReceive2(const unsigned int xid, struct cifs_ses *ses, struct kvec *iov, int n_vec, int *resp_buf_type /* ret */, const int flags, struct kvec *resp_iov) { struct smb_rqst rqst; struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov; int rc; if (n_vec + 1 > CIFS_MAX_IOV_SIZE) { new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec), GFP_KERNEL); if (!new_iov) { /* otherwise cifs_send_recv below sets resp_buf_type */ *resp_buf_type = CIFS_NO_BUFFER; return -ENOMEM; } } else new_iov = s_iov; /* 1st iov is a RFC1001 length followed by the rest of the packet */ memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec)); new_iov[0].iov_base = new_iov[1].iov_base; new_iov[0].iov_len = 4; new_iov[1].iov_base += 4; new_iov[1].iov_len -= 4; memset(&rqst, 0, sizeof(struct smb_rqst)); rqst.rq_iov = new_iov; rqst.rq_nvec = n_vec + 1; rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov); if (n_vec + 1 > CIFS_MAX_IOV_SIZE) kfree(new_iov); return rc; } int SendReceive(const unsigned int xid, struct cifs_ses *ses, struct smb_hdr *in_buf, struct smb_hdr *out_buf, int *pbytes_returned, const int timeout) { int rc = 0; struct mid_q_entry *midQ; unsigned int len = be32_to_cpu(in_buf->smb_buf_length); struct kvec iov = { .iov_base = in_buf, .iov_len = len }; struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 }; if (ses == NULL) { cifs_dbg(VFS, "Null smb session\n"); return -EIO; } if (ses->server == NULL) { cifs_dbg(VFS, "Null tcp session\n"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) return -ENOENT; /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n", len); return -EIO; } rc = wait_for_free_request(ses->server, timeout, 0); if (rc) return rc; /* make sure that we sign in the same order that we send on this socket and avoid races inside tcp sendmsg code that could cause corruption of smb data */ mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ add_credits(ses->server, 1, 0); return rc; } rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); if (rc) { mutex_unlock(&ses->server->srv_mutex); goto out; } midQ->mid_state = MID_REQUEST_SUBMITTED; cifs_in_send_inc(ses->server); rc = smb_send(ses->server, in_buf, len); cifs_in_send_dec(ses->server); cifs_save_when_sent(midQ); if (rc < 0) ses->server->sequence_number -= 2; mutex_unlock(&ses->server->srv_mutex); if (rc < 0) goto out; if (timeout == CIFS_ASYNC_OP) goto out; rc = wait_for_response(ses->server, midQ); if (rc != 0) { send_cancel(ses->server, &rqst, midQ); spin_lock(&GlobalMid_Lock); if (midQ->mid_state == MID_REQUEST_SUBMITTED) { /* no longer considered to be "in-flight" */ midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); add_credits(ses->server, 1, 0); return rc; } spin_unlock(&GlobalMid_Lock); } rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { add_credits(ses->server, 1, 0); return rc; } if (!midQ->resp_buf || !out_buf || midQ->mid_state != MID_RESPONSE_RECEIVED) { rc = -EIO; cifs_dbg(VFS, "Bad MID state?\n"); goto out; } *pbytes_returned = get_rfc1002_length(midQ->resp_buf); memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); rc = cifs_check_receive(midQ, ses->server, 0); out: cifs_delete_mid(midQ); add_credits(ses->server, 1, 0); return rc; } /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows blocking lock to return. */ static int send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon, struct smb_hdr *in_buf, struct smb_hdr *out_buf) { int bytes_returned; struct cifs_ses *ses = tcon->ses; LOCK_REQ *pSMB = (LOCK_REQ *)in_buf; /* We just modify the current in_buf to change the type of lock from LOCKING_ANDX_SHARED_LOCK or LOCKING_ANDX_EXCLUSIVE_LOCK to LOCKING_ANDX_CANCEL_LOCK. */ pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES; pSMB->Timeout = 0; pSMB->hdr.Mid = get_next_mid(ses->server); return SendReceive(xid, ses, in_buf, out_buf, &bytes_returned, 0); }
int SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, struct smb_hdr *in_buf, struct smb_hdr *out_buf, int *pbytes_returned) { int rc = 0; int rstart = 0; struct mid_q_entry *midQ; struct cifs_ses *ses; if (tcon == NULL || tcon->ses == NULL) { cifs_dbg(VFS, "Null smb session\n"); return -EIO; } ses = tcon->ses; if (ses->server == NULL) { cifs_dbg(VFS, "Null tcp session\n"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) return -ENOENT; /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n", be32_to_cpu(in_buf->smb_buf_length)); return -EIO; } rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP, 0); if (rc) return rc; /* make sure that we sign in the same order that we send on this socket and avoid races inside tcp sendmsg code that could cause corruption of smb data */ mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { mutex_unlock(&ses->server->srv_mutex); return rc; } rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); if (rc) { cifs_delete_mid(midQ); mutex_unlock(&ses->server->srv_mutex); return rc; } midQ->mid_state = MID_REQUEST_SUBMITTED; cifs_in_send_inc(ses->server); rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); cifs_in_send_dec(ses->server); cifs_save_when_sent(midQ); if (rc < 0) ses->server->sequence_number -= 2; mutex_unlock(&ses->server->srv_mutex); if (rc < 0) { cifs_delete_mid(midQ); return rc; } /* Wait for a reply - allow signals to interrupt. */ rc = wait_event_interruptible(ses->server->response_q, (!(midQ->mid_state == MID_REQUEST_SUBMITTED)) || ((ses->server->tcpStatus != CifsGood) && (ses->server->tcpStatus != CifsNew))); /* Were we interrupted by a signal ? */ if ((rc == -ERESTARTSYS) && (midQ->mid_state == MID_REQUEST_SUBMITTED) && ((ses->server->tcpStatus == CifsGood) || (ses->server->tcpStatus == CifsNew))) { if (in_buf->Command == SMB_COM_TRANSACTION2) { /* POSIX lock. We send a NT_CANCEL SMB to cause the blocking lock to return. */ rc = send_cancel(ses->server, in_buf, midQ); if (rc) { cifs_delete_mid(midQ); return rc; } } else { /* Windows lock. We send a LOCKINGX_CANCEL_LOCK to cause the blocking lock to return. */ rc = send_lock_cancel(xid, tcon, in_buf, out_buf); /* If we get -ENOLCK back the lock may have already been removed. Don't exit in this case. */ if (rc && rc != -ENOLCK) { cifs_delete_mid(midQ); return rc; } } rc = wait_for_response(ses->server, midQ); if (rc) { send_cancel(ses->server, in_buf, midQ); spin_lock(&GlobalMid_Lock); if (midQ->mid_state == MID_REQUEST_SUBMITTED) { /* no longer considered to be "in-flight" */ midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); return rc; } spin_unlock(&GlobalMid_Lock); } /* We got the response - restart system call. */ rstart = 1; } rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) return rc; /* rcvd frame is ok */ if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_RECEIVED) { rc = -EIO; cifs_dbg(VFS, "Bad MID state?\n"); goto out; } *pbytes_returned = get_rfc1002_length(midQ->resp_buf); memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); rc = cifs_check_receive(midQ, ses->server, 0); out: cifs_delete_mid(midQ); if (rstart && rc == -EACCES) return -ERESTARTSYS; return rc; }
int compound_send_recv(const unsigned int xid, struct cifs_ses *ses, const int flags, const int num_rqst, struct smb_rqst *rqst, int *resp_buf_type, struct kvec *resp_iov) { int i, j, rc = 0; int timeout, optype; struct mid_q_entry *midQ[MAX_COMPOUND]; bool cancelled_mid[MAX_COMPOUND] = {false}; unsigned int credits[MAX_COMPOUND] = {0}; char *buf; timeout = flags & CIFS_TIMEOUT_MASK; optype = flags & CIFS_OP_MASK; for (i = 0; i < num_rqst; i++) resp_buf_type[i] = CIFS_NO_BUFFER; /* no response buf yet */ if ((ses == NULL) || (ses->server == NULL)) { cifs_dbg(VFS, "Null session\n"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) return -ENOENT; /* * Ensure we obtain 1 credit per request in the compound chain. * It can be optimized further by waiting for all the credits * at once but this can wait long enough if we don't have enough * credits due to some heavy operations in progress or the server * not granting us much, so a fallback to the current approach is * needed anyway. */ for (i = 0; i < num_rqst; i++) { rc = wait_for_free_request(ses->server, timeout, optype); if (rc) { /* * We haven't sent an SMB packet to the server yet but * we already obtained credits for i requests in the * compound chain - need to return those credits back * for future use. Note that we need to call add_credits * multiple times to match the way we obtained credits * in the first place and to account for in flight * requests correctly. */ for (j = 0; j < i; j++) add_credits(ses->server, 1, optype); return rc; } credits[i] = 1; } /* * Make sure that we sign in the same order that we send on this socket * and avoid races inside tcp sendmsg code that could cause corruption * of smb data. */ mutex_lock(&ses->server->srv_mutex); for (i = 0; i < num_rqst; i++) { midQ[i] = ses->server->ops->setup_request(ses, &rqst[i]); if (IS_ERR(midQ[i])) { for (j = 0; j < i; j++) cifs_delete_mid(midQ[j]); mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ for (j = 0; j < num_rqst; j++) add_credits(ses->server, credits[j], optype); return PTR_ERR(midQ[i]); } midQ[i]->mid_state = MID_REQUEST_SUBMITTED; midQ[i]->optype = optype; /* * Invoke callback for every part of the compound chain * to calculate credits properly. Wake up this thread only when * the last element is received. */ if (i < num_rqst - 1) midQ[i]->callback = cifs_compound_callback; else midQ[i]->callback = cifs_compound_last_callback; } cifs_in_send_inc(ses->server); rc = smb_send_rqst(ses->server, num_rqst, rqst, flags); cifs_in_send_dec(ses->server); for (i = 0; i < num_rqst; i++) cifs_save_when_sent(midQ[i]); if (rc < 0) ses->server->sequence_number -= 2; mutex_unlock(&ses->server->srv_mutex); if (rc < 0) { /* Sending failed for some reason - return credits back */ for (i = 0; i < num_rqst; i++) add_credits(ses->server, credits[i], optype); goto out; } /* * At this point the request is passed to the network stack - we assume * that any credits taken from the server structure on the client have * been spent and we can't return them back. Once we receive responses * we will collect credits granted by the server in the mid callbacks * and add those credits to the server structure. */ /* * Compounding is never used during session establish. */ if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) smb311_update_preauth_hash(ses, rqst[0].rq_iov, rqst[0].rq_nvec); if (timeout == CIFS_ASYNC_OP) goto out; for (i = 0; i < num_rqst; i++) { rc = wait_for_response(ses->server, midQ[i]); if (rc != 0) break; } if (rc != 0) { for (; i < num_rqst; i++) { cifs_dbg(VFS, "Cancelling wait for mid %llu cmd: %d\n", midQ[i]->mid, le16_to_cpu(midQ[i]->command)); send_cancel(ses->server, &rqst[i], midQ[i]); spin_lock(&GlobalMid_Lock); if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) { midQ[i]->mid_flags |= MID_WAIT_CANCELLED; midQ[i]->callback = cifs_cancelled_callback; cancelled_mid[i] = true; credits[i] = 0; } spin_unlock(&GlobalMid_Lock); } } for (i = 0; i < num_rqst; i++) { if (rc < 0) goto out; rc = cifs_sync_mid_result(midQ[i], ses->server); if (rc != 0) { /* mark this mid as cancelled to not free it below */ cancelled_mid[i] = true; goto out; } if (!midQ[i]->resp_buf || midQ[i]->mid_state != MID_RESPONSE_RECEIVED) { rc = -EIO; cifs_dbg(FYI, "Bad MID state?\n"); goto out; } buf = (char *)midQ[i]->resp_buf; resp_iov[i].iov_base = buf; resp_iov[i].iov_len = midQ[i]->resp_buf_size + ses->server->vals->header_preamble_size; if (midQ[i]->large_buf) resp_buf_type[i] = CIFS_LARGE_BUFFER; else resp_buf_type[i] = CIFS_SMALL_BUFFER; rc = ses->server->ops->check_receive(midQ[i], ses->server, flags & CIFS_LOG_ERROR); /* mark it so buf will not be freed by cifs_delete_mid */ if ((flags & CIFS_NO_RESP) == 0) midQ[i]->resp_buf = NULL; } /* * Compounding is never used during session establish. */ if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) { struct kvec iov = { .iov_base = resp_iov[0].iov_base, .iov_len = resp_iov[0].iov_len }; smb311_update_preauth_hash(ses, &iov, 1); } out: /* * This will dequeue all mids. After this it is important that the * demultiplex_thread will not process any of these mids any futher. * This is prevented above by using a noop callback that will not * wake this thread except for the very last PDU. */ for (i = 0; i < num_rqst; i++) { if (!cancelled_mid[i]) cifs_delete_mid(midQ[i]); } return rc; } int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, struct smb_rqst *rqst, int *resp_buf_type, const int flags, struct kvec *resp_iov) { return compound_send_recv(xid, ses, flags, 1, rqst, resp_buf_type, resp_iov); } int SendReceive2(const unsigned int xid, struct cifs_ses *ses, struct kvec *iov, int n_vec, int *resp_buf_type /* ret */, const int flags, struct kvec *resp_iov) { struct smb_rqst rqst; struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov; int rc; if (n_vec + 1 > CIFS_MAX_IOV_SIZE) { new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec), GFP_KERNEL); if (!new_iov) { /* otherwise cifs_send_recv below sets resp_buf_type */ *resp_buf_type = CIFS_NO_BUFFER; return -ENOMEM; } } else new_iov = s_iov; /* 1st iov is a RFC1001 length followed by the rest of the packet */ memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec)); new_iov[0].iov_base = new_iov[1].iov_base; new_iov[0].iov_len = 4; new_iov[1].iov_base += 4; new_iov[1].iov_len -= 4; memset(&rqst, 0, sizeof(struct smb_rqst)); rqst.rq_iov = new_iov; rqst.rq_nvec = n_vec + 1; rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov); if (n_vec + 1 > CIFS_MAX_IOV_SIZE) kfree(new_iov); return rc; } int SendReceive(const unsigned int xid, struct cifs_ses *ses, struct smb_hdr *in_buf, struct smb_hdr *out_buf, int *pbytes_returned, const int timeout) { int rc = 0; struct mid_q_entry *midQ; unsigned int len = be32_to_cpu(in_buf->smb_buf_length); struct kvec iov = { .iov_base = in_buf, .iov_len = len }; struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 }; if (ses == NULL) { cifs_dbg(VFS, "Null smb session\n"); return -EIO; } if (ses->server == NULL) { cifs_dbg(VFS, "Null tcp session\n"); return -EIO; } if (ses->server->tcpStatus == CifsExiting) return -ENOENT; /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n", len); return -EIO; } rc = wait_for_free_request(ses->server, timeout, 0); if (rc) return rc; /* make sure that we sign in the same order that we send on this socket and avoid races inside tcp sendmsg code that could cause corruption of smb data */ mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ add_credits(ses->server, 1, 0); return rc; } rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); if (rc) { mutex_unlock(&ses->server->srv_mutex); goto out; } midQ->mid_state = MID_REQUEST_SUBMITTED; cifs_in_send_inc(ses->server); rc = smb_send(ses->server, in_buf, len); cifs_in_send_dec(ses->server); cifs_save_when_sent(midQ); if (rc < 0) ses->server->sequence_number -= 2; mutex_unlock(&ses->server->srv_mutex); if (rc < 0) goto out; if (timeout == CIFS_ASYNC_OP) goto out; rc = wait_for_response(ses->server, midQ); if (rc != 0) { send_cancel(ses->server, &rqst, midQ); spin_lock(&GlobalMid_Lock); if (midQ->mid_state == MID_REQUEST_SUBMITTED) { /* no longer considered to be "in-flight" */ midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); add_credits(ses->server, 1, 0); return rc; } spin_unlock(&GlobalMid_Lock); } rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { add_credits(ses->server, 1, 0); return rc; } if (!midQ->resp_buf || !out_buf || midQ->mid_state != MID_RESPONSE_RECEIVED) { rc = -EIO; cifs_dbg(VFS, "Bad MID state?\n"); goto out; } *pbytes_returned = get_rfc1002_length(midQ->resp_buf); memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); rc = cifs_check_receive(midQ, ses->server, 0); out: cifs_delete_mid(midQ); add_credits(ses->server, 1, 0); return rc; } /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows blocking lock to return. */ static int send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon, struct smb_hdr *in_buf, struct smb_hdr *out_buf) { int bytes_returned; struct cifs_ses *ses = tcon->ses; LOCK_REQ *pSMB = (LOCK_REQ *)in_buf; /* We just modify the current in_buf to change the type of lock from LOCKING_ANDX_SHARED_LOCK or LOCKING_ANDX_EXCLUSIVE_LOCK to LOCKING_ANDX_CANCEL_LOCK. */ pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES; pSMB->Timeout = 0; pSMB->hdr.Mid = get_next_mid(ses->server); return SendReceive(xid, ses, in_buf, out_buf, &bytes_returned, 0); }