Ejemplo n.º 1
0
/** Finalizes setting up the SKB and delivers it
 *
 * We first pass the incoming frame to WLP substack for verification. It
 * may also be a WLP association frame in which case WLP will take over the
 * processing. If WLP does not take it over it will still verify it, if the
 * frame is invalid the skb will be freed by WLP and we will not continue
 * parsing.
 * */
static
void i1480u_skb_deliver(struct i1480u *i1480u)
{
	int should_parse;
	struct net_device *net_dev = i1480u->net_dev;
	struct device *dev = &i1480u->usb_iface->dev;

	d_printf(6, dev, "RX delivered pre skb(%p), %u bytes\n",
		 i1480u->rx_skb, i1480u->rx_skb->len);
	d_dump(7, dev, i1480u->rx_skb->data, i1480u->rx_skb->len);
	should_parse = wlp_receive_frame(dev, &i1480u->wlp, i1480u->rx_skb,
					 &i1480u->rx_srcaddr);
	if (!should_parse)
		goto out;
	i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev);
	d_printf(5, dev, "RX delivered skb(%p), %u bytes\n",
		 i1480u->rx_skb, i1480u->rx_skb->len);
	d_dump(7, dev, i1480u->rx_skb->data,
	       i1480u->rx_skb->len > 72 ? 72 : i1480u->rx_skb->len);
	i1480u->stats.rx_packets++;
	i1480u->stats.rx_bytes += i1480u->rx_untd_pkt_size;
	net_dev->last_rx = jiffies;
	/* FIXME: flow control: check netif_rx() retval */

	netif_rx(i1480u->rx_skb);		/* deliver */
out:
	i1480u->rx_skb = NULL;
	i1480u->rx_untd_pkt_size = 0;
}
Ejemplo n.º 2
0
/*
 * i2400m_net_erx - pass a network packet to the stack (extended version)
 *
 * @i2400m: device descriptor
 * @skb: the skb where the packet is - the skb should be set to point
 *     at the IP packet; this function will add ethernet headers if
 *     needed.
 * @cs: packet type
 *
 * This is only used now for firmware >= v1.4. Note it is quite
 * similar to i2400m_net_rx() (used only for v1.3 firmware).
 *
 * This function is normally run from a thread context. However, we
 * still use netif_rx() instead of netif_receive_skb() as was
 * recommended in the mailing list. Reason is in some stress tests
 * when sending/receiving a lot of data we seem to hit a softlock in
 * the kernel's TCP implementation [aroudn tcp_delay_timer()]. Using
 * netif_rx() took care of the issue.
 *
 * This is, of course, still open to do more research on why running
 * with netif_receive_skb() hits this softlock. FIXME.
 */
void i2400m_net_erx(struct i2400m *i2400m, struct sk_buff *skb,
		    enum i2400m_cs cs)
{
	struct net_device *net_dev = i2400m->wimax_dev.net_dev;
	struct device *dev = i2400m_dev(i2400m);
	int protocol;

	d_fnstart(2, dev, "(i2400m %p skb %p [%u] cs %d)\n",
		  i2400m, skb, skb->len, cs);
	switch(cs) {
	case I2400M_CS_IPV4_0:
	case I2400M_CS_IPV4:
		protocol = ETH_P_IP;
		i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev,
					  skb->data - ETH_HLEN,
					  cpu_to_be16(ETH_P_IP));
		skb_set_mac_header(skb, -ETH_HLEN);
		skb->dev = i2400m->wimax_dev.net_dev;
		skb->protocol = htons(ETH_P_IP);
		net_dev->stats.rx_packets++;
		net_dev->stats.rx_bytes += skb->len;
		break;
	default:
		dev_err(dev, "ERX: BUG? CS type %u unsupported\n", cs);
		goto error;

	}
	d_printf(3, dev, "ERX: receiving %d bytes to the network stack\n",
		 skb->len);
	d_dump(4, dev, skb->data, skb->len);
	netif_rx_ni(skb);	/* see notes in function header */
error:
	d_fnend(2, dev, "(i2400m %p skb %p [%u] cs %d) = void\n",
		i2400m, skb, skb->len, cs);
}
Ejemplo n.º 3
0
/*
 * Get the next TX message in the TX FIFO and send it to the device
 *
 * Note we exit the loop if i2400mu_tx() fails; that funtion only
 * fails on hard error (failing to tx a buffer not being one of them,
 * see its doc).
 *
 * Return: 0
 */
static
int i2400mu_txd(void *_i2400mu)
{
	int result = 0;
	struct i2400mu *i2400mu = _i2400mu;
	struct i2400m *i2400m = &i2400mu->i2400m;
	struct device *dev = &i2400mu->usb_iface->dev;
	struct i2400m_msg_hdr *tx_msg;
	size_t tx_msg_size;

	d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);

	while (1) {
		d_printf(2, dev, "TX: waiting for messages\n");
		tx_msg = NULL;
		wait_event_interruptible(
			i2400mu->tx_wq,
			(kthread_should_stop()	/* check this first! */
			 || (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size)))
			);
		if (kthread_should_stop())
			break;
		WARN_ON(tx_msg == NULL);	/* should not happen...*/
		d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size);
		d_dump(5, dev, tx_msg, tx_msg_size);
		/* Yeah, we ignore errors ... not much we can do */
		i2400mu_tx(i2400mu, tx_msg, tx_msg_size);
		i2400m_tx_msg_sent(i2400m);	/* ack it, advance the FIFO */
		if (result < 0)
			break;
	}
	d_fnend(4, dev, "(i2400mu %p) = %d\n", i2400mu, result);
	return result;
}
Ejemplo n.º 4
0
int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
{
	struct device *dev = wimax_dev_to_dev(wimax_dev);
	void *msg = skb->data;
	size_t size = skb->len;
	might_sleep();

	d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size);
	d_dump(2, dev, msg, size);
	genlmsg_multicast(skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
	d_printf(1, dev, "CTX: genl multicast done\n");
	return 0;
}
Ejemplo n.º 5
0
ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *i2400m,
				const struct i2400m_bootrom_header *_cmd,
				size_t cmd_size, int flags)
{
	ssize_t result;
	struct device *dev = i2400m_dev(i2400m);
	struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
	int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd);
	struct i2400m_bootrom_header *cmd;
	
	size_t cmd_size_a = ALIGN(cmd_size, I2400MS_BLK_SIZE);

	d_fnstart(5, dev, "(i2400m %p cmd %p size %zu)\n",
		  i2400m, _cmd, cmd_size);
	result = -E2BIG;
	if (cmd_size > I2400M_BM_CMD_BUF_SIZE)
		goto error_too_big;

	if (_cmd != i2400m->bm_cmd_buf)
		memmove(i2400m->bm_cmd_buf, _cmd, cmd_size);
	cmd = i2400m->bm_cmd_buf;
	if (cmd_size_a > cmd_size)			
		memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size);
	if ((flags & I2400M_BM_CMD_RAW) == 0) {
		if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0))
			dev_warn(dev, "SW BUG: response_required == 0\n");
		i2400m_bm_cmd_prepare(cmd);
	}
	d_printf(4, dev, "BM cmd %d: %zu bytes (%zu padded)\n",
		 opcode, cmd_size, cmd_size_a);
	d_dump(5, dev, cmd, cmd_size);

	sdio_claim_host(i2400ms->func);			
	result = sdio_memcpy_toio(i2400ms->func, I2400MS_DATA_ADDR,
				  i2400m->bm_cmd_buf, cmd_size_a);
	sdio_release_host(i2400ms->func);
	if (result < 0) {
		dev_err(dev, "BM cmd %d: cannot send: %ld\n",
			opcode, (long) result);
		goto error_cmd_send;
	}
	result = cmd_size;
error_cmd_send:
error_too_big:
	d_fnend(5, dev, "(i2400m %p cmd %p size %zu) = %d\n",
		i2400m, _cmd, cmd_size, (int) result);
	return result;
}
Ejemplo n.º 6
0
/**
 * wimax_msg_send - Send a pre-allocated message to user space
 *
 * @wimax_dev: WiMAX device descriptor
 *
 * @skb: &struct sk_buff returned by wimax_msg_alloc(). Note the
 *     ownership of @skb is transferred to this function.
 *
 * Returns: 0 if ok, < 0 errno code on error
 *
 * Description:
 *
 * Sends a free-form message that was preallocated with
 * wimax_msg_alloc() and filled up.
 *
 * Assumes that once you pass an skb to this function for sending, it
 * owns it and will release it when done (on success).
 *
 * IMPORTANT:
 *
 * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as
 * wimax_msg_send() depends on skb->data being placed at the
 * beginning of the user message.
 */
int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
{
	int result;
	struct device *dev = wimax_dev->net_dev->dev.parent;
	void *msg = skb->data;
	size_t size = skb->len;
	might_sleep();

	d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size);
	d_dump(2, dev, msg, size);
	result = genlmsg_multicast(skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
	d_printf(1, dev, "CTX: genl multicast result %d\n", result);
	if (result == -ESRCH)	/* Nobody connected, ignore it */
		result = 0;	/* btw, the skb is freed already */
	return result;
}
Ejemplo n.º 7
0
/*
 * TX an skb to an idle device
 *
 * When the device is in basestation-idle mode, we need to wake it up
 * and then TX. So we queue a work_struct for doing so.
 *
 * We need to get an extra ref for the skb (so it is not dropped), as
 * well as be careful not to queue more than one request (won't help
 * at all). If more than one request comes or there are errors, we
 * just drop the packets (see i2400m_hard_start_xmit()).
 */
static
int i2400m_net_wake_tx(struct i2400m *i2400m, struct net_device *net_dev,
		       struct sk_buff *skb)
{
	int result;
	struct device *dev = i2400m_dev(i2400m);
	unsigned long flags;

	d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev);
	if (net_ratelimit()) {
		d_printf(3, dev, "WAKE&NETTX: "
			 "skb %p sending %d bytes to radio\n",
			 skb, skb->len);
		d_dump(4, dev, skb->data, skb->len);
	}
	/* We hold a ref count for i2400m and skb, so when
	 * stopping() the device, we need to cancel that work
	 * and if pending, release those resources. */
	result = 0;
	spin_lock_irqsave(&i2400m->tx_lock, flags);
	if (!i2400m->wake_tx_skb) {
		netif_stop_queue(net_dev);
		i2400m_get(i2400m);
		i2400m->wake_tx_skb = skb_get(skb);	/* transfer ref count */
		i2400m_tx_prep_header(skb);
		result = schedule_work(&i2400m->wake_tx_ws);
		WARN_ON(result == 0);
	}
	spin_unlock_irqrestore(&i2400m->tx_lock, flags);
	if (result == 0) {
		/* Yes, this happens even if we stopped the
		 * queue -- blame the queue disciplines that
		 * queue without looking -- I guess there is a reason
		 * for that. */
		if (net_ratelimit())
			d_printf(1, dev, "NETTX: device exiting idle, "
				 "dropping skb %p, queue running %d\n",
				 skb, netif_queue_stopped(net_dev));
		result = -EBUSY;
	}
	d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result);
	return result;
}
Ejemplo n.º 8
0
static
int i2400mu_txd(void *_i2400mu)
{
	struct i2400mu *i2400mu = _i2400mu;
	struct i2400m *i2400m = &i2400mu->i2400m;
	struct device *dev = &i2400mu->usb_iface->dev;
	struct i2400m_msg_hdr *tx_msg;
	size_t tx_msg_size;
	unsigned long flags;

	d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);

	spin_lock_irqsave(&i2400m->tx_lock, flags);
	BUG_ON(i2400mu->tx_kthread != NULL);
	i2400mu->tx_kthread = current;
	spin_unlock_irqrestore(&i2400m->tx_lock, flags);

	while (1) {
		d_printf(2, dev, "TX: waiting for messages\n");
		tx_msg = NULL;
		wait_event_interruptible(
			i2400mu->tx_wq,
			(kthread_should_stop()	/*                   */
			 || (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size)))
			);
		if (kthread_should_stop())
			break;
		WARN_ON(tx_msg == NULL);	/*                     */
		d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size);
		d_dump(5, dev, tx_msg, tx_msg_size);
		/*                                               */
		i2400mu_tx(i2400mu, tx_msg, tx_msg_size);
		i2400m_tx_msg_sent(i2400m);	/*                          */
	}

	spin_lock_irqsave(&i2400m->tx_lock, flags);
	i2400mu->tx_kthread = NULL;
	spin_unlock_irqrestore(&i2400m->tx_lock, flags);

	d_fnend(4, dev, "(i2400mu %p)\n", i2400mu);
	return 0;
}
Ejemplo n.º 9
0
/*
 * Transmit a packet to the base station on behalf of the network stack.
 *
 * Returns: 0 if ok, < 0 errno code on error.
 *
 * We need to pull the ethernet header and add the hardware header,
 * which is currently set to all zeroes and reserved.
 */
static
int i2400m_net_tx(struct i2400m *i2400m, struct net_device *net_dev,
		  struct sk_buff *skb)
{
	int result;
	struct device *dev = i2400m_dev(i2400m);

	d_fnstart(3, dev, "(i2400m %p net_dev %p skb %p)\n",
		  i2400m, net_dev, skb);
	/* FIXME: check eth hdr, only IPv4 is routed by the device as of now */
	net_dev->trans_start = jiffies;
	i2400m_tx_prep_header(skb);
	d_printf(3, dev, "NETTX: skb %p sending %d bytes to radio\n",
		 skb, skb->len);
	d_dump(4, dev, skb->data, skb->len);
	result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA);
	d_fnend(3, dev, "(i2400m %p net_dev %p skb %p) = %d\n",
		i2400m, net_dev, skb, result);
	return result;
}
Ejemplo n.º 10
0
/*
 * i2400m_net_rx - pass a network packet to the stack
 *
 * @i2400m: device instance
 * @skb_rx: the skb where the buffer pointed to by @buf is
 * @i: 1 if payload is the only one
 * @buf: pointer to the buffer containing the data
 * @len: buffer's length
 *
 * This is only used now for the v1.3 firmware. It will be deprecated
 * in >= 2.6.31.
 *
 * Note that due to firmware limitations, we don't have space to add
 * an ethernet header, so we need to copy each packet. Firmware
 * versions >= v1.4 fix this [see i2400m_net_erx()].
 *
 * We just clone the skb and set it up so that it's skb->data pointer
 * points to "buf" and it's length.
 *
 * Note that if the payload is the last (or the only one) in a
 * multi-payload message, we don't clone the SKB but just reuse it.
 *
 * This function is normally run from a thread context. However, we
 * still use netif_rx() instead of netif_receive_skb() as was
 * recommended in the mailing list. Reason is in some stress tests
 * when sending/receiving a lot of data we seem to hit a softlock in
 * the kernel's TCP implementation [aroudn tcp_delay_timer()]. Using
 * netif_rx() took care of the issue.
 *
 * This is, of course, still open to do more research on why running
 * with netif_receive_skb() hits this softlock. FIXME.
 *
 * FIXME: currently we don't do any efforts at distinguishing if what
 * we got was an IPv4 or IPv6 header, to setup the protocol field
 * correctly.
 */
void i2400m_net_rx(struct i2400m *i2400m, struct sk_buff *skb_rx,
		   unsigned i, const void *buf, int buf_len)
{
	struct net_device *net_dev = i2400m->wimax_dev.net_dev;
	struct device *dev = i2400m_dev(i2400m);
	struct sk_buff *skb;

	d_fnstart(2, dev, "(i2400m %p buf %p buf_len %d)\n",
		  i2400m, buf, buf_len);
	if (i) {
		skb = skb_get(skb_rx);
		d_printf(2, dev, "RX: reusing first payload skb %p\n", skb);
		skb_pull(skb, buf - (void *) skb->data);
		skb_trim(skb, (void *) skb_end_pointer(skb) - buf);
	} else {
		/* Yes, this is bad -- a lot of overhead -- see
		 * comments at the top of the file */
		skb = __netdev_alloc_skb(net_dev, buf_len, GFP_KERNEL);
		if (skb == NULL) {
			dev_err(dev, "NETRX: no memory to realloc skb\n");
			net_dev->stats.rx_dropped++;
			goto error_skb_realloc;
		}
		memcpy(skb_put(skb, buf_len), buf, buf_len);
	}
	i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev,
				  skb->data - ETH_HLEN,
				  cpu_to_be16(ETH_P_IP));
	skb_set_mac_header(skb, -ETH_HLEN);
	skb->dev = i2400m->wimax_dev.net_dev;
	skb->protocol = htons(ETH_P_IP);
	net_dev->stats.rx_packets++;
	net_dev->stats.rx_bytes += buf_len;
	d_printf(3, dev, "NETRX: receiving %d bytes to network stack\n",
		buf_len);
	d_dump(4, dev, buf, buf_len);
	netif_rx_ni(skb);	/* see notes in function header */
error_skb_realloc:
	d_fnend(2, dev, "(i2400m %p buf %p buf_len %d) = void\n",
		i2400m, buf, buf_len);
}
Ejemplo n.º 11
0
/**
 * i2400m_msg_to_dev - Send a control message to the device and get a response
 *
 * @i2400m: device descriptor
 *
 * @msg_skb: an skb  *
 *
 * @buf: pointer to the buffer containing the message to be sent; it
 *           has to start with a &struct i2400M_l3l4_hdr and then
 *           followed by the payload. Once this function returns, the
 *           buffer can be reused.
 *
 * @buf_len: buffer size
 *
 * Returns:
 *
 * Pointer to skb containing the ack message. You need to check the
 * pointer with IS_ERR(), as it might be an error code. Error codes
 * could happen because:
 *
 *  - the message wasn't formatted correctly
 *  - couldn't send the message
 *  - failed waiting for a response
 *  - the ack message wasn't formatted correctly
 *
 * The returned skb has been allocated with wimax_msg_to_user_alloc(),
 * it contains the response in a netlink attribute and is ready to be
 * passed up to user space with wimax_msg_to_user_send(). To access
 * the payload and its length, use wimax_msg_{data,len}() on the skb.
 *
 * The skb has to be freed with kfree_skb() once done.
 *
 * Description:
 *
 * This function delivers a message/command to the device and waits
 * for an ack to be received. The format is described in
 * linux/wimax/i2400m.h. In summary, a command/get/set is followed by an
 * ack.
 *
 * This function will not check the ack status, that's left up to the
 * caller.  Once done with the ack skb, it has to be kfree_skb()ed.
 *
 * The i2400m handles only one message at the same time, thus we need
 * the mutex to exclude other players.
 *
 * We write the message and then wait for an answer to come back. The
 * RX path intercepts control messages and handles them in
 * i2400m_rx_ctl(). Reports (notifications) are (maybe) processed
 * locally and then forwarded (as needed) to user space on the WiMAX
 * stack message pipe. Acks are saved and passed back to us through an
 * skb in i2400m->ack_skb which is ready to be given to generic
 * netlink if need be.
 */
struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
				  const void *buf, size_t buf_len)
{
	int result;
	struct device *dev = i2400m_dev(i2400m);
	const struct i2400m_l3l4_hdr *msg_l3l4_hdr;
	struct sk_buff *ack_skb;
	const struct i2400m_l3l4_hdr *ack_l3l4_hdr;
	size_t ack_len;
	int ack_timeout;
	unsigned msg_type;
	unsigned long flags;

	d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n",
		  i2400m, buf, buf_len);

	rmb();		/* Make sure we see what i2400m_dev_reset_handle() */
	if (i2400m->boot_mode)
		return ERR_PTR(-EL3RST);

	msg_l3l4_hdr = buf;
	/* Check msg & payload consistency */
	result = i2400m_msg_size_check(i2400m, msg_l3l4_hdr, buf_len);
	if (result < 0)
		goto error_bad_msg;
	msg_type = le16_to_cpu(msg_l3l4_hdr->type);
	d_printf(1, dev, "CMD/GET/SET 0x%04x %zu bytes\n",
		 msg_type, buf_len);
	d_dump(2, dev, buf, buf_len);

	/* Setup the completion, ack_skb ("we are waiting") and send
	 * the message to the device */
	mutex_lock(&i2400m->msg_mutex);
	spin_lock_irqsave(&i2400m->rx_lock, flags);
	i2400m->ack_skb = ERR_PTR(-EINPROGRESS);
	spin_unlock_irqrestore(&i2400m->rx_lock, flags);
	init_completion(&i2400m->msg_completion);
	result = i2400m_tx(i2400m, buf, buf_len, I2400M_PT_CTRL);
	if (result < 0) {
		dev_err(dev, "can't send message 0x%04x: %d\n",
			le16_to_cpu(msg_l3l4_hdr->type), result);
		goto error_tx;
	}

	/* Some commands take longer to execute because of crypto ops,
	 * so we give them some more leeway on timeout */
	switch (msg_type) {
	case I2400M_MT_GET_TLS_OPERATION_RESULT:
	case I2400M_MT_CMD_SEND_EAP_RESPONSE:
		ack_timeout = 5 * HZ;
		break;
	default:
		ack_timeout = HZ;
	}

	if (unlikely(i2400m->trace_msg_from_user))
		wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL);
	/* The RX path in rx.c will put any response for this message
	 * in i2400m->ack_skb and wake us up. If we cancel the wait,
	 * we need to change the value of i2400m->ack_skb to something
	 * not -EINPROGRESS so RX knows there is no one waiting. */
	result = wait_for_completion_interruptible_timeout(
		&i2400m->msg_completion, ack_timeout);
	if (result == 0) {
		dev_err(dev, "timeout waiting for reply to message 0x%04x\n",
			msg_type);
		result = -ETIMEDOUT;
		i2400m_msg_to_dev_cancel_wait(i2400m, result);
		goto error_wait_for_completion;
	} else if (result < 0) {
		dev_err(dev, "error waiting for reply to message 0x%04x: %d\n",
			msg_type, result);
		i2400m_msg_to_dev_cancel_wait(i2400m, result);
		goto error_wait_for_completion;
	}

	/* Pull out the ack data from i2400m->ack_skb -- see if it is
	 * an error and act accordingly */
	spin_lock_irqsave(&i2400m->rx_lock, flags);
	ack_skb = i2400m->ack_skb;
	if (IS_ERR(ack_skb))
		result = PTR_ERR(ack_skb);
	else
		result = 0;
	i2400m->ack_skb = NULL;
	spin_unlock_irqrestore(&i2400m->rx_lock, flags);
	if (result < 0)
		goto error_ack_status;
	ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len);

	/* Check the ack and deliver it if it is ok */
	if (unlikely(i2400m->trace_msg_from_user))
		wimax_msg(&i2400m->wimax_dev, "echo",
			  ack_l3l4_hdr, ack_len, GFP_KERNEL);
	result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len);
	if (result < 0) {
		dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n",
			msg_type, result);
		goto error_bad_ack_len;
	}
	if (msg_type != le16_to_cpu(ack_l3l4_hdr->type)) {
		dev_err(dev, "HW BUG? bad reply 0x%04x to message 0x%04x\n",
			le16_to_cpu(ack_l3l4_hdr->type), msg_type);
		result = -EIO;
		goto error_bad_ack_type;
	}
	i2400m_msg_ack_hook(i2400m, ack_l3l4_hdr, ack_len);
	mutex_unlock(&i2400m->msg_mutex);
	d_fnend(3, dev, "(i2400m %p buf %p len %zu) = %p\n",
		i2400m, buf, buf_len, ack_skb);
	return ack_skb;

error_bad_ack_type:
error_bad_ack_len:
	kfree_skb(ack_skb);
error_ack_status:
error_wait_for_completion:
error_tx:
	mutex_unlock(&i2400m->msg_mutex);
error_bad_msg:
	d_fnend(3, dev, "(i2400m %p buf %p len %zu) = %d\n",
		i2400m, buf, buf_len, result);
	return ERR_PTR(result);
}
Ejemplo n.º 12
0
static
int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info)
{
	int result, ifindex;
	struct wimax_dev *wimax_dev;
	struct device *dev;
	struct nlmsghdr *nlh = info->nlhdr;
	char *pipe_name;
	void *msg_buf;
	size_t msg_len;

	might_sleep();
	d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
	result = -ENODEV;
	if (info->attrs[WIMAX_GNL_MSG_IFIDX] == NULL) {
		printk(KERN_ERR "WIMAX_GNL_MSG_FROM_USER: can't find IFIDX "
		       "attribute\n");
		goto error_no_wimax_dev;
	}
	ifindex = nla_get_u32(info->attrs[WIMAX_GNL_MSG_IFIDX]);
	wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
	if (wimax_dev == NULL)
		goto error_no_wimax_dev;
	dev = wimax_dev_to_dev(wimax_dev);

	/*                  */
	result = -EINVAL;
	if (info->attrs[WIMAX_GNL_MSG_DATA] == NULL) {
		dev_err(dev, "WIMAX_GNL_MSG_FROM_USER: can't find MSG_DATA "
			"attribute\n");
		goto error_no_data;
	}
	msg_buf = nla_data(info->attrs[WIMAX_GNL_MSG_DATA]);
	msg_len = nla_len(info->attrs[WIMAX_GNL_MSG_DATA]);

	if (info->attrs[WIMAX_GNL_MSG_PIPE_NAME] == NULL)
		pipe_name = NULL;
	else {
		struct nlattr *attr = info->attrs[WIMAX_GNL_MSG_PIPE_NAME];
		size_t attr_len = nla_len(attr);
		/*                                               */
		result = -ENOMEM;
		pipe_name = kstrndup(nla_data(attr), attr_len + 1, GFP_KERNEL);
		if (pipe_name == NULL)
			goto error_alloc;
		pipe_name[attr_len] = 0;
	}
	mutex_lock(&wimax_dev->mutex);
	result = wimax_dev_is_ready(wimax_dev);
	if (result == -ENOMEDIUM)
		result = 0;
	if (result < 0)
		goto error_not_ready;
	result = -ENOSYS;
	if (wimax_dev->op_msg_from_user == NULL)
		goto error_noop;

	d_printf(1, dev,
		 "CRX: nlmsghdr len %u type %u flags 0x%04x seq 0x%x pid %u\n",
		 nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags,
		 nlh->nlmsg_seq, nlh->nlmsg_pid);
	d_printf(1, dev, "CRX: wimax message %zu bytes\n", msg_len);
	d_dump(2, dev, msg_buf, msg_len);

	result = wimax_dev->op_msg_from_user(wimax_dev, pipe_name,
					     msg_buf, msg_len, info);
error_noop:
error_not_ready:
	mutex_unlock(&wimax_dev->mutex);
error_alloc:
	kfree(pipe_name);
error_no_data:
	dev_put(wimax_dev->net_dev);
error_no_wimax_dev:
	d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
	return result;
}
Ejemplo n.º 13
0
Archivo: fw.c Proyecto: 020gzh/linux
/**
 * i2400m_bootrom_init - Reboots a powered device into boot mode
 *
 * @i2400m: device descriptor
 * @flags:
 *      I2400M_BRI_SOFT: a reboot barker has been seen
 *          already, so don't wait for it.
 *
 *      I2400M_BRI_NO_REBOOT: Don't send a reboot command, but wait
 *          for a reboot barker notification. This is a one shot; if
 *          the state machine needs to send a reboot command it will.
 *
 * Returns:
 *
 *     < 0 errno code on error, 0 if ok.
 *
 * Description:
 *
 * Tries hard enough to put the device in boot-mode. There are two
 * main phases to this:
 *
 * a. (1) send a reboot command and (2) get a reboot barker
 *
 * b. (1) echo/ack the reboot sending the reboot barker back and (2)
 *        getting an ack barker in return
 *
 * We want to skip (a) in some cases [soft]. The state machine is
 * horrible, but it is basically: on each phase, send what has to be
 * sent (if any), wait for the answer and act on the answer. We might
 * have to backtrack and retry, so we keep a max tries counter for
 * that.
 *
 * It sucks because we don't know ahead of time which is going to be
 * the reboot barker (the device might send different ones depending
 * on its EEPROM config) and once the device reboots and waits for the
 * echo/ack reboot barker being sent back, it doesn't understand
 * anything else. So we can be left at the point where we don't know
 * what to send to it -- cold reset and bus reset seem to have little
 * effect. So the function iterates (in this case) through all the
 * known barkers and tries them all until an ACK is
 * received. Otherwise, it gives up.
 *
 * If we get a timeout after sending a warm reset, we do it again.
 */
int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags)
{
	int result;
	struct device *dev = i2400m_dev(i2400m);
	struct i2400m_bootrom_header *cmd;
	struct i2400m_bootrom_header ack;
	int count = i2400m->bus_bm_retries;
	int ack_timeout_cnt = 1;
	unsigned i;

	BUILD_BUG_ON(sizeof(*cmd) != sizeof(i2400m_barker_db[0].data));
	BUILD_BUG_ON(sizeof(ack) != sizeof(i2400m_ACK_BARKER));

	d_fnstart(4, dev, "(i2400m %p flags 0x%08x)\n", i2400m, flags);
	result = -ENOMEM;
	cmd = i2400m->bm_cmd_buf;
	if (flags & I2400M_BRI_SOFT)
		goto do_reboot_ack;
do_reboot:
	ack_timeout_cnt = 1;
	if (--count < 0)
		goto error_timeout;
	d_printf(4, dev, "device reboot: reboot command [%d # left]\n",
		 count);
	if ((flags & I2400M_BRI_NO_REBOOT) == 0)
		i2400m_reset(i2400m, I2400M_RT_WARM);
	result = i2400m_bm_cmd(i2400m, NULL, 0, &ack, sizeof(ack),
			       I2400M_BM_CMD_RAW);
	flags &= ~I2400M_BRI_NO_REBOOT;
	switch (result) {
	case -ERESTARTSYS:
		/*
		 * at this point, i2400m_bm_cmd(), through
		 * __i2400m_bm_ack_process(), has updated
		 * i2400m->barker and we are good to go.
		 */
		d_printf(4, dev, "device reboot: got reboot barker\n");
		break;
	case -EISCONN:	/* we don't know how it got here...but we follow it */
		d_printf(4, dev, "device reboot: got ack barker - whatever\n");
		goto do_reboot;
	case -ETIMEDOUT:
		/*
		 * Device has timed out, we might be in boot mode
		 * already and expecting an ack; if we don't know what
		 * the barker is, we just send them all. Cold reset
		 * and bus reset don't work. Beats me.
		 */
		if (i2400m->barker != NULL) {
			dev_err(dev, "device boot: reboot barker timed out, "
				"trying (set) %08x echo/ack\n",
				le32_to_cpu(i2400m->barker->data[0]));
			goto do_reboot_ack;
		}
		for (i = 0; i < i2400m_barker_db_used; i++) {
			struct i2400m_barker_db *barker = &i2400m_barker_db[i];
			memcpy(cmd, barker->data, sizeof(barker->data));
			result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
					       &ack, sizeof(ack),
					       I2400M_BM_CMD_RAW);
			if (result == -EISCONN) {
				dev_warn(dev, "device boot: got ack barker "
					 "after sending echo/ack barker "
					 "#%d/%08x; rebooting j.i.c.\n",
					 i, le32_to_cpu(barker->data[0]));
				flags &= ~I2400M_BRI_NO_REBOOT;
				goto do_reboot;
			}
		}
		dev_err(dev, "device boot: tried all the echo/acks, could "
			"not get device to respond; giving up");
		result = -ESHUTDOWN;
	case -EPROTO:
	case -ESHUTDOWN:	/* dev is gone */
	case -EINTR:		/* user cancelled */
		goto error_dev_gone;
	default:
		dev_err(dev, "device reboot: error %d while waiting "
			"for reboot barker - rebooting\n", result);
		d_dump(1, dev, &ack, result);
		goto do_reboot;
	}
	/* At this point we ack back with 4 REBOOT barkers and expect
	 * 4 ACK barkers. This is ugly, as we send a raw command --
	 * hence the cast. _bm_cmd() will catch the reboot ack
	 * notification and report it as -EISCONN. */
do_reboot_ack:
	d_printf(4, dev, "device reboot ack: sending ack [%d # left]\n", count);
	memcpy(cmd, i2400m->barker->data, sizeof(i2400m->barker->data));
	result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
			       &ack, sizeof(ack), I2400M_BM_CMD_RAW);
	switch (result) {
	case -ERESTARTSYS:
		d_printf(4, dev, "reboot ack: got reboot barker - retrying\n");
		if (--count < 0)
			goto error_timeout;
		goto do_reboot_ack;
	case -EISCONN:
		d_printf(4, dev, "reboot ack: got ack barker - good\n");
		break;
	case -ETIMEDOUT:	/* no response, maybe it is the other type? */
		if (ack_timeout_cnt-- < 0) {
			d_printf(4, dev, "reboot ack timedout: retrying\n");
			goto do_reboot_ack;
		} else {
			dev_err(dev, "reboot ack timedout too long: "
				"trying reboot\n");
			goto do_reboot;
		}
		break;
	case -EPROTO:
	case -ESHUTDOWN:	/* dev is gone */
		goto error_dev_gone;
	default:
		dev_err(dev, "device reboot ack: error %d while waiting for "
			"reboot ack barker - rebooting\n", result);
		goto do_reboot;
	}
	d_printf(2, dev, "device reboot ack: got ack barker - boot done\n");
	result = 0;
exit_timeout:
error_dev_gone:
	d_fnend(4, dev, "(i2400m %p flags 0x%08x) = %d\n",
		i2400m, flags, result);
	return result;

error_timeout:
	dev_err(dev, "Timed out waiting for reboot ack\n");
	result = -ETIMEDOUT;
	goto exit_timeout;
}
Ejemplo n.º 14
0
struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
				  const void *buf, size_t buf_len)
{
	int result;
	struct device *dev = i2400m_dev(i2400m);
	const struct i2400m_l3l4_hdr *msg_l3l4_hdr;
	struct sk_buff *ack_skb;
	const struct i2400m_l3l4_hdr *ack_l3l4_hdr;
	size_t ack_len;
	int ack_timeout;
	unsigned msg_type;
	unsigned long flags;

	d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n",
		  i2400m, buf, buf_len);

	rmb();		
	if (i2400m->boot_mode)
		return ERR_PTR(-EL3RST);

	msg_l3l4_hdr = buf;
	
	result = i2400m_msg_size_check(i2400m, msg_l3l4_hdr, buf_len);
	if (result < 0)
		goto error_bad_msg;
	msg_type = le16_to_cpu(msg_l3l4_hdr->type);
	d_printf(1, dev, "CMD/GET/SET 0x%04x %zu bytes\n",
		 msg_type, buf_len);
	d_dump(2, dev, buf, buf_len);

	mutex_lock(&i2400m->msg_mutex);
	spin_lock_irqsave(&i2400m->rx_lock, flags);
	i2400m->ack_skb = ERR_PTR(-EINPROGRESS);
	spin_unlock_irqrestore(&i2400m->rx_lock, flags);
	init_completion(&i2400m->msg_completion);
	result = i2400m_tx(i2400m, buf, buf_len, I2400M_PT_CTRL);
	if (result < 0) {
		dev_err(dev, "can't send message 0x%04x: %d\n",
			le16_to_cpu(msg_l3l4_hdr->type), result);
		goto error_tx;
	}

	switch (msg_type) {
	case I2400M_MT_GET_TLS_OPERATION_RESULT:
	case I2400M_MT_CMD_SEND_EAP_RESPONSE:
		ack_timeout = 5 * HZ;
		break;
	default:
		ack_timeout = HZ;
	}

	if (unlikely(i2400m->trace_msg_from_user))
		wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL);
	result = wait_for_completion_interruptible_timeout(
		&i2400m->msg_completion, ack_timeout);
	if (result == 0) {
		dev_err(dev, "timeout waiting for reply to message 0x%04x\n",
			msg_type);
		result = -ETIMEDOUT;
		i2400m_msg_to_dev_cancel_wait(i2400m, result);
		goto error_wait_for_completion;
	} else if (result < 0) {
		dev_err(dev, "error waiting for reply to message 0x%04x: %d\n",
			msg_type, result);
		i2400m_msg_to_dev_cancel_wait(i2400m, result);
		goto error_wait_for_completion;
	}

	spin_lock_irqsave(&i2400m->rx_lock, flags);
	ack_skb = i2400m->ack_skb;
	if (IS_ERR(ack_skb))
		result = PTR_ERR(ack_skb);
	else
		result = 0;
	i2400m->ack_skb = NULL;
	spin_unlock_irqrestore(&i2400m->rx_lock, flags);
	if (result < 0)
		goto error_ack_status;
	ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len);

	
	if (unlikely(i2400m->trace_msg_from_user))
		wimax_msg(&i2400m->wimax_dev, "echo",
			  ack_l3l4_hdr, ack_len, GFP_KERNEL);
	result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len);
	if (result < 0) {
		dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n",
			msg_type, result);
		goto error_bad_ack_len;
	}
	if (msg_type != le16_to_cpu(ack_l3l4_hdr->type)) {
		dev_err(dev, "HW BUG? bad reply 0x%04x to message 0x%04x\n",
			le16_to_cpu(ack_l3l4_hdr->type), msg_type);
		result = -EIO;
		goto error_bad_ack_type;
	}
	i2400m_msg_ack_hook(i2400m, ack_l3l4_hdr, ack_len);
	mutex_unlock(&i2400m->msg_mutex);
	d_fnend(3, dev, "(i2400m %p buf %p len %zu) = %p\n",
		i2400m, buf, buf_len, ack_skb);
	return ack_skb;

error_bad_ack_type:
error_bad_ack_len:
	kfree_skb(ack_skb);
error_ack_status:
error_wait_for_completion:
error_tx:
	mutex_unlock(&i2400m->msg_mutex);
error_bad_msg:
	d_fnend(3, dev, "(i2400m %p buf %p len %zu) = %d\n",
		i2400m, buf, buf_len, result);
	return ERR_PTR(result);
}