Пример #1
0
int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len)
{
	int ret;
	u8 *buf;

	LOG_TRACE(priv, FW_MSG, "Sending hcmd:\n");

	/* add padding to 256 for IWMC */
	((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256;

	LOG_HEXDUMP(FW_MSG, cmd, len);

	if (len > FW_HCMD_BLOCK_SIZE) {
		LOG_ERROR(priv, FW_MSG, "size %d exceeded hcmd max size %d\n",
			  len, FW_HCMD_BLOCK_SIZE);
		return -1;
	}

	buf = kzalloc(FW_HCMD_BLOCK_SIZE, GFP_KERNEL);
	if (!buf) {
		LOG_ERROR(priv, FW_MSG, "kzalloc error, buf size %d\n",
			  FW_HCMD_BLOCK_SIZE);
		return -1;
	}

	memcpy(buf, cmd, len);
	ret = iwmct_tx(priv, buf, FW_HCMD_BLOCK_SIZE);

	kfree(buf);
	return ret;
}
static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump)
{
	struct iwmct_parser *parser = &priv->parser;
	struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf;
	int ret;
	u32 cmd;

	LOG_TRACE(priv, FW_DOWNLOAD, "-->\n");

	memset(parser->buf, 0, parser->buf_size);
	cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
	if (jump) {
		cmd |= IWMC_OPCODE_JUMP << CMD_HDR_OPCODE_POS;
		hdr->target_addr = cpu_to_le32(parser->entry_point);
		LOG_INFO(priv, FW_DOWNLOAD, "jump address 0x%x\n",
				parser->entry_point);
	} else {
		cmd |= IWMC_OPCODE_LAST_COMMAND << CMD_HDR_OPCODE_POS;
		LOG_INFO(priv, FW_DOWNLOAD, "last command\n");
	}

	hdr->cmd = cpu_to_le32(cmd);

	LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr));
	/* send it down */
	/* TODO: add more proper sending and error checking */
	ret = iwmct_tx(priv, parser->buf, IWMC_SDIO_BLK_SIZE);
	if (ret)
		LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret);

	LOG_TRACE(priv, FW_DOWNLOAD, "<--\n");
	return 0;
}
Пример #3
0
static void iwmct_irq_read_worker(struct work_struct *ws)
{
	struct iwmct_priv *priv;
	struct iwmct_work_struct *read_req;
	__le32 *buf = NULL;
	int ret;
	int iosize;
	u32 barker;
	bool is_barker;

	priv = container_of(ws, struct iwmct_priv, isr_worker);

	LOG_TRACE(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws);

	/* --------------------- Handshake with device -------------------- */
	sdio_claim_host(priv->func);

	/* all list manipulations have to be protected by
	 * sdio_claim_host/sdio_release_host */
	if (list_empty(&priv->read_req_list)) {
		LOG_ERROR(priv, IRQ, "read_req_list empty in read worker\n");
		goto exit_release;
	}

	read_req = list_entry(priv->read_req_list.next,
			      struct iwmct_work_struct, list);

	list_del(&read_req->list);
	iosize = read_req->iosize;
	kfree(read_req);

	buf = kzalloc(iosize, GFP_KERNEL);
	if (!buf) {
		LOG_ERROR(priv, IRQ, "kzalloc error, buf size %d\n", iosize);
		goto exit_release;
	}

	LOG_INFO(priv, IRQ, "iosize=%d, buf=%p, func=%d\n",
				iosize, buf, priv->func->num);

	/* read from device */
	ret = sdio_memcpy_fromio(priv->func, buf, IWMC_SDIO_DATA_ADDR, iosize);
	if (ret) {
		LOG_ERROR(priv, IRQ, "error %d reading buffer\n", ret);
		goto exit_release;
	}

	LOG_HEXDUMP(IRQ, (u8 *)buf, iosize);

	barker = le32_to_cpu(buf[0]);

	/* Verify whether it's a barker and if not - treat as regular Rx */
	if (barker == IWMC_BARKER_ACK ||
	    (barker & BARKER_DNLOAD_BARKER_MSK) == IWMC_BARKER_REBOOT) {

		/* Valid Barker is equal on first 4 dwords */
		is_barker = (buf[1] == buf[0]) &&
			    (buf[2] == buf[0]) &&
			    (buf[3] == buf[0]);

		if (!is_barker) {
			LOG_WARNING(priv, IRQ,
				"Potentially inconsistent barker "
				"%08X_%08X_%08X_%08X\n",
				le32_to_cpu(buf[0]), le32_to_cpu(buf[1]),
				le32_to_cpu(buf[2]), le32_to_cpu(buf[3]));
		}
	} else {
		is_barker = false;
	}

	/* Handle Top CommHub message */
	if (!is_barker) {
		sdio_release_host(priv->func);
		handle_top_message(priv, (u8 *)buf, iosize);
		goto exit;
	} else if (barker == IWMC_BARKER_ACK) { /* Handle barkers */
		if (atomic_read(&priv->dev_sync) == 0) {
			LOG_ERROR(priv, IRQ,
				  "ACK barker arrived out-of-sync\n");
			goto exit_release;
		}

		/* Continuing to FW download (after Sync is completed)*/
		atomic_set(&priv->dev_sync, 0);
		LOG_INFO(priv, IRQ, "ACK barker arrived "
				"- starting FW download\n");
	} else { /* REBOOT barker */
		LOG_INFO(priv, IRQ, "Recieved reboot barker: %x\n", barker);
		priv->barker = barker;

		if (barker & BARKER_DNLOAD_SYNC_MSK) {
			/* Send the same barker back */
			ret = __iwmct_tx(priv, buf, iosize);
			if (ret) {
				LOG_ERROR(priv, IRQ,
					 "error %d echoing barker\n", ret);
				goto exit_release;
			}
			LOG_INFO(priv, IRQ, "Echoing barker to device\n");
			atomic_set(&priv->dev_sync, 1);
			goto exit_release;
		}

		/* Continuing to FW download (without Sync) */
		LOG_INFO(priv, IRQ, "No sync requested "
				    "- starting FW download\n");
	}

	sdio_release_host(priv->func);

	if (priv->dbg.fw_download)
		iwmct_fw_load(priv);
	else
		LOG_ERROR(priv, IRQ, "FW download not allowed\n");

	goto exit;

exit_release:
	sdio_release_host(priv->func);
exit:
	kfree(buf);
	LOG_TRACE(priv, IRQ, "exit iwmct_irq_read_worker\n");
}
static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec,
				size_t sec_size, __le32 addr)
{
	struct iwmct_parser *parser = &priv->parser;
	struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf;
	const u8 *cur_block = p_sec;
	size_t sent = 0;
	int cnt = 0;
	int ret = 0;
	u32 cmd = 0;

	LOG_TRACE(priv, FW_DOWNLOAD, "-->\n");
	LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n",
				addr, sec_size);

	while (sent < sec_size) {
		int i;
		u32 chksm = 0;
		u32 reset = atomic_read(&priv->reset);
		/* actual FW data */
		u32 data_size = min(parser->buf_size - sizeof(*hdr),
				    sec_size - sent);
		/* Pad to block size */
		u32 trans_size = (data_size + sizeof(*hdr) +
				  IWMC_SDIO_BLK_SIZE - 1) &
				  ~(IWMC_SDIO_BLK_SIZE - 1);
		++cnt;

		/* in case of reset, interrupt FW DOWNLAOD */
		if (reset) {
			LOG_INFO(priv, FW_DOWNLOAD,
				 "Reset detected. Abort FW download!!!");
			ret = -ECANCELED;
			goto exit;
		}

		memset(parser->buf, 0, parser->buf_size);
		cmd |= IWMC_OPCODE_WRITE << CMD_HDR_OPCODE_POS;
		cmd |= IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
		cmd |= (priv->dbg.direct ? 1 : 0) << CMD_HDR_DIRECT_ACCESS_POS;
		cmd |= (priv->dbg.checksum ? 1 : 0) << CMD_HDR_USE_CHECKSUM_POS;
		hdr->data_size = cpu_to_le32(data_size);
		hdr->target_addr = addr;

		/* checksum is allowed for sizes divisible by 4 */
		if (data_size & 0x3)
			cmd &= ~CMD_HDR_USE_CHECKSUM_MSK;

		memcpy(hdr->data, cur_block, data_size);


		if (cmd & CMD_HDR_USE_CHECKSUM_MSK) {

			chksm = data_size + le32_to_cpu(addr) + cmd;
			for (i = 0; i < data_size >> 2; i++)
				chksm += ((u32 *)cur_block)[i];

			hdr->block_chksm = cpu_to_le32(chksm);
			LOG_INFO(priv, FW_DOWNLOAD, "Checksum = 0x%X\n",
				 hdr->block_chksm);
		}

		LOG_INFO(priv, FW_DOWNLOAD, "trans#%d, len=%d, sent=%zd, "
				"sec_size=%zd, startAddress 0x%X\n",
				cnt, trans_size, sent, sec_size, addr);

		if (priv->dbg.dump)
			LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, trans_size);


		hdr->cmd = cpu_to_le32(cmd);
		/* send it down */
		/* TODO: add more proper sending and error checking */
		ret = iwmct_tx(priv, parser->buf, trans_size);
		if (ret != 0) {
			LOG_INFO(priv, FW_DOWNLOAD,
				"iwmct_tx returned %d\n", ret);
			goto exit;
		}

		addr = cpu_to_le32(le32_to_cpu(addr) + data_size);
		sent += data_size;
		cur_block = p_sec + sent;

		if (priv->dbg.blocks && (cnt + 1) >= priv->dbg.blocks) {
			LOG_INFO(priv, FW_DOWNLOAD,
				"Block number limit is reached [%d]\n",
				priv->dbg.blocks);
			break;
		}
	}

	if (sent < sec_size)
		ret = -EINVAL;
exit:
	LOG_TRACE(priv, FW_DOWNLOAD, "<--\n");
	return ret;
}
Пример #5
0
int proxy_thread( struct thread_data *td )
{
    int remote_fd = -1;
    int state;
    int n, client_fd;
	int result = -1;
    uint32 client_ip;
    ssize_t writed;
    int already_authorized = 0;
    // if some http data coming together with request
    char *data = NULL;
    int data_len = 0;

#define BUF_SIZE 1504
#define REQ_SIZE 15004
#define clear_buffer() memset(buffer, 0, BUF_SIZE)
#define clear_request() memset(request, 0, REQ_SIZE);
#define clear_req() memset(&req, 0, sizeof(req));
        
    char buffer[BUF_SIZE];
    char last_host[BUF_SIZE];
    request = malloc(REQ_SIZE);


    struct sockaddr_in remote_addr;
    struct hostent *remote_host;
    struct timeval timeout;

    fd_set rfds;

	FENTER;
	ASSERT(request);

    client_fd = td->client_fd;
    client_ip = td->client_ip;

    /* fetch the http request headers */
    FD_ZERO( &rfds );
    FD_SET( (unsigned int) client_fd, &rfds );

    timeout.tv_sec  = 15;
    timeout.tv_usec =  0;

    if ( select(client_fd + 1, &rfds, NULL, NULL, &timeout ) <= 0) {
		ERR("select() timeout", 0);
		result = 11;
        goto exit;
    }

    char *end_of_req = NULL;
    char *preq = request;
    clear_req();
    clear_request();
    clear_buffer();
    if ( ( n = read(client_fd, buffer, sizeof(buffer)-4) ) <= 0 ) {
        ERR("read() fail", 0);
        result = 12;
        goto exit;
    }
    DBG("-  recv %d bytes", n);
    // append
    memcpy(preq, buffer, n);
    preq += n;

process_request:
    while ( !(end_of_req = strstr(request, "\r\n\r\n")) ) {
        DBG("-  request without %s", ANSI_WHITE"CRLFCRLF"ANSI_RESET);
        clear_buffer();
        if ( ( n = read(client_fd, buffer, sizeof(buffer)-4) ) <= 0 ) {
            ERR("read() fail", 0);
            result = 12;
            goto exit;
        }
        DBG("-  recv %d bytes", n);
        // append
        memcpy(preq, buffer, n);
        preq += n;
    }
    end_of_req += 4; // first byte after CRLFCRLF

    if ( (unsigned int)(end_of_req - request) == strlen(request) ) {
        DBG("no data found in this request", 0);
    } else {
        data_len = preq - end_of_req;
        DBG("%d data bytes found in this request", data_len);
        data = malloc(data_len);
        if (!data) {
            ERR("malloc() %d", data_len);
            goto exit;
        }
        memcpy(data, end_of_req, data_len);
    }

//#define DUMP
#ifdef DUMP
    LOG_HEXDUMP("RECEIVED FROM CLIENT", (unsigned char*)request, preq-request);
#else
    DBG("RECEIVED FROM CLIENT %d bytes", preq-request);
#endif
    if (!parse_request()) {
        WARN("bad request:", request);
        return -1;
    };

    if (!already_authorized) { 
        if (is_proxy_authorized()) {
            already_authorized = 1;
        } else {
            proxy_unauthorized(td);
            goto exit;
        }
    }

    if ( is_syscmd() ) {
        if ( is_sys_authorized() ) {
            process_sys_cmd();
            goto exit;
        } else {
            sys_unauthorized(td);
            goto exit;
        }
    }


    //LOG_HEXDUMP("BEFORE", (unsigned char*)req.headers, BUF_SIZE);
    remove_header("Proxy-Authorization");
    remove_header("Proxy-Connection");
    //LOG_HEXDUMP("AFTER", (unsigned char*)req.headers, BUF_SIZE);

    /* resolve the http server hostname */
    if ( !(req.hostname) || !( remote_host = gethostbyname( req.hostname ) ) ) {
		WARN("-  fail to resolve '%s'", req.hostname);
        result = 19;
		goto exit;
    }

    if ( req.connect ) {
        if( td->connect == 1 && req.port != 443 ) {
            result = 20;
			goto exit;
        }
    }

    /* connect to the remote server, if not already connected */
    if ( 1 || strcmp(req.hostname, last_host) ) {
        shutdown( remote_fd, 2 );
        close( remote_fd );

        remote_fd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP );

        if (remote_fd < 0) {
			WARN("-  socket() fail", 0);
            result = 21;
			goto exit;
        }

        remote_addr.sin_family = AF_INET;
        remote_addr.sin_port = htons( (unsigned short) req.port );

        memcpy( (void *) &remote_addr.sin_addr,
                (void *) remote_host->h_addr,
                remote_host->h_length );

        if ( connect( remote_fd, (struct sockaddr *) &remote_addr, sizeof( remote_addr ) ) < 0 ) {
			WARN("-  connect() to '%s:%d' fail", req.hostname, req.port);
            result = 22;
            goto exit;
        }
        DBG("-  connected to %s:%d", req.url_host, req.port);

        memset( last_host, 0, sizeof( last_host ) );
        strncpy( last_host, req.hostname, sizeof( last_host ) - 1 );
    } else {
        INFO("reuse current connection", 0);
    }

    if ( req.connect ) {
        /* send HTTP/1.0 200 OK */
        snprintf(buffer, sizeof(buffer), "HTTP/1.0 200 OK\r\n\r\n");

        if ( (writed = write(client_fd, buffer, 19)) != 19 ) {
            WARN("write() fail: %d", writed);
            result = 23;
			goto exit;
        }
        req.sent_to_client += writed;
    }
    else
    {
        /* Construct and send modified request */
        size_t server_req_size = strlen(req.method) + strlen(req.url) + strlen(req.http_ver) + strlen(req.headers) + 16;
        char *server_req = malloc(server_req_size);
        if (!server_req) {
            ERR("malloc() fail: %d", server_req_size); 
            result = 235;
            goto exit;
        }
        memset(server_req, 0, server_req_size);
		n = snprintf(server_req, server_req_size - 4, "%s %s %s%s", req.method, req.url, req.http_ver, req.headers);
        if ((writed = write(remote_fd, server_req, n)) != n) {
            WARN("write() fail: %d", writed);
            result = 24;
			goto exit;
        }
        req.sent_to_server += writed;
#ifdef DUMP
		LOG_HEXDUMP("SENDED TO SERVER", (unsigned char*)server_req, n);
#else
        DBG("SENDED TO SERVER %d bytes", n);
#endif
        free(server_req);

        if ( data ) {
            // Some additional data was found in initial request
            if ((writed = write(remote_fd, data, data_len)) != data_len) {
                WARN("write() fail: %d", writed);
                result = 35;
                goto exit;
            }
            req.sent_to_server += writed;
#ifdef DUMP
            LOG_HEXDUMP("SENDED TO SERVER (data)", (unsigned char*)data, data_len);
#else
            DBG("SENDED TO SERVER %d bytes (data)", n);
#endif
            // clear data
            free(data);
            data = NULL;
            data_len = 0;
        }
    }

    /* tunnel the data between the client and the server */

    state = 0;

    while( 1 )
    {
        FD_ZERO( &rfds );
        FD_SET( (unsigned int) client_fd, &rfds );
        FD_SET( (unsigned int) remote_fd, &rfds );
    
        n = ( client_fd > remote_fd ) ? client_fd : remote_fd;

        if ( select( n + 1, &rfds, NULL, NULL, NULL ) < 0 ) {
            ERR("select() fail", 0);
            result = 25;
			goto exit;
        }

        if ( FD_ISSET( remote_fd, &rfds ) ) {
            clear_buffer();
            if ( ( n = read( remote_fd, buffer, BUF_SIZE-1) ) <= 0 ) {
                WARN("read() fail: %d", n);
                result = 26;
				goto exit;
            }
#ifdef DUMP
			LOG_HEXDUMP("RECEIVED FROM SERVER (tunneled)", (unsigned char*)buffer, n);
#else
            DBG("RECEIVED FROM SERVER (tunneled) %d bytes", n);
#endif

            state = 1; /* client finished sending data */

            if ( (writed = write( client_fd, buffer, n )) != n ) {
                WARN("write() fail: %d", writed);
                result = 27;
				goto exit;
            }
            req.sent_to_client += n;
#ifdef DUMP
			LOG_HEXDUMP("SENDED TO CLIENT (tunneled)", (unsigned char*)buffer, n);
#else
            DBG("SENDED TO CLIENT (tunneled) %d bytes", n);
#endif
        }

        if ( FD_ISSET( client_fd, &rfds ) ) {
            clear_buffer();
            if ( (n = read( client_fd, buffer, BUF_SIZE-1)) <= 0 ) {
                WARN("read() fail: %d", n);
                result = 28;
				goto exit;
            }
#ifdef DUMP
			LOG_HEXDUMP("RECEIVED FROM CLIENT (tunneled)", (unsigned char*)buffer, n);
#else
            DBG("RECEIVED FROM CLIENT (tunneled) %d bytes", n);
#endif

            if ( state && !req.connect ) {
                /* new http request */
                INFO("-  process new http request", 0);
                syslog_request();

                LOG_HEXDUMP("request", (unsigned char*)buffer, n);

                memset(&req, 0, sizeof(req));
                int req_len = MIN((size_t)n, REQ_SIZE-1);
                strncpy(request, buffer, req_len);
                preq = request + req_len;
                goto process_request;
            }

            if ((writed = write( remote_fd, buffer, n)) != n ) {
                WARN("write() fail: %d", writed);
                result = 29;
				goto exit;
            }
            req.sent_to_server += n;
#ifdef DUMP
			LOG_HEXDUMP("SENDED TO SERVER (tunneled)", (unsigned char*)buffer, n);
#else
            DBG("SENDED TO SERVER (tunneled) %d bytes", n);
#endif
        }
    }


    /* not reached */
exit:

    shutdown( client_fd, 2 );
    shutdown( remote_fd, 2 );
    close( client_fd );
    close( remote_fd );
    syslog_request();
    closelog();
	if (request) free(request);
	FLEAVEA("exit with %d code sent to client: %d, to server: %d", result, req.sent_to_client, req.sent_to_server);
    return( result );
}
Пример #6
0
int parse_request()
{
    int result = 0;
    if ( sscanf(request, "%31s %1023s %15s", req.method, req.url, req.http_ver) != 3) {
        ERR("sscanf() fail", 0);
        goto end;
    };
	DBG("-  method: '%s'", req.method);
	DBG("-  url: '%s'", req.url);
	DBG("-  http_ver: '%s'", req.http_ver);
    
    char *headers = strstr(request, "\r\n");
    char *end_of_req = strstr(headers, "\r\n\r\n");

    if (!end_of_req) {
        ERR("CRLFCRLF does not found", 0);
        goto end;
    }
    end_of_req[4] = '\0'; // terminate request by 0 char

    if (headers) {
        strncpy(req.headers, headers, sizeof(req.headers)-1);
        DBG("-  headers: '%s'", req.headers);
    }

    if ( strcmp("CONNECT", req.method) == 0 ) {
        if (sscanf(req.url, "%s", req.url_host) < 1) {
            ERR("sscanf() fail", 0);
            goto end;
        }
        req.connect = 1;
    } else {
        req.port = 80;
        if (sscanf(req.url, "%[^:]://%[^/]%[^\r\n]", req.scheme, req.url_host, req.url_path) < 2) {
            ERR("sscanf() fail", 0);
            goto end;
        }
    }

    char *colon;
    if ((colon = strchr(req.url_host, ':'))) {
        colon++;
        req.port = atoi(colon);
        if ( req.port <= 0 ) {
            ERR("bad port %d", req.port);
            goto end;
        }
    }

    if (!parse_hostname()) {
        ERR("parse_hostname() fail", 0);
        goto end;
    }
    result = 1;
	DBG("-  req.scheme: '%s'", req.scheme);
	DBG("-  req.url_host: '%s'", req.url_host);
	DBG("-  req.url_path: '%s'", req.url_path);
	DBG("-  req.port: '%d'", req.port);
	DBG("-  req.hostname: '%s'", req.hostname);
end:
    if (!result) {
        LOG_HEXDUMP("BAD REQUEST", (unsigned char*)request, strlen(request)+1);
    }
    return result;
}