Пример #1
0
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"));
		}
	}
	
}
Пример #3
0
/* 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;
}
Пример #4
0
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();
}
Пример #5
0
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();
}
Пример #6
0
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();
}
Пример #7
0
bool gsm_on()
{
    gsm_on_raw();
    if ( !wait_for_response( "+PSSUP", 0 ) || !wait_for_ready() )
    {
        gsm_off();
        return false;
    }
    return true;
}
Пример #8
0
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"));
	}
}
Пример #10
0
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;
}
Пример #11
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;
}
Пример #12
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" );
}
Пример #13
0
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"));
		}
	}
	
}
Пример #15
0
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();
}
Пример #16
0
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;
}
Пример #17
0
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;
}
Пример #18
0
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;
}
Пример #19
0
bool gsm_send_at_cmd( const char* cmd )
{
    sends( U1, cmd );
    sends( U1, "\r\n" );
    return wait_for_response( "OK", "ERROR" );
}
Пример #20
0
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");
	}
}
Пример #21
0
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;
}
Пример #22
0
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;
}
Пример #23
0
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;
}
Пример #25
0
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;
}
Пример #26
0
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;
}
Пример #27
0
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;
}
Пример #28
0
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);
}
Пример #29
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;
}
Пример #30
0
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);
}