Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8324598d authored by Sujeet Kumar's avatar Sujeet Kumar Committed by Gerrit - the friendly Code Review server
Browse files

USB: rndis: Protect rndis response queue



RNDIS response queue addition and deletion can be
performed from rndis completion handler as well
as ioctl from netd to do eth stop. There is a chance
when response queue list can get corrupted by simultaneous
delete and addition performed from rndis_command_compete
and rndis_indicate_status_msg.

Protect access to response queue whenever addition
or deletion is performed by spinlock as the access
may be done from interrupt context as well.

Change-Id: I74525ee9c8b31bf85063f41ae7c52ab55e9a2b7a
Signed-off-by: default avatarSujeet Kumar <ksujeet@codeaurora.org>
Signed-off-by: default avatarAjay Agarwal <ajaya@codeaurora.org>
parent 41fc4953
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -932,6 +932,7 @@ struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v,
	}
#endif

	spin_lock_init(&params->lock);
	params->confignr = i;
	params->used = 1;
	params->state = RNDIS_UNINITIALIZED;
@@ -1096,29 +1097,36 @@ EXPORT_SYMBOL_GPL(rndis_add_hdr);
void rndis_free_response(struct rndis_params *params, u8 *buf)
{
	rndis_resp_t *r, *n;
	unsigned long flags;

	spin_lock_irqsave(&params->lock, flags);
	list_for_each_entry_safe(r, n, &params->resp_queue, list) {
		if (r->buf == buf) {
			list_del(&r->list);
			kfree(r);
		}
	}
	spin_unlock_irqrestore(&params->lock, flags);
}
EXPORT_SYMBOL_GPL(rndis_free_response);

u8 *rndis_get_next_response(struct rndis_params *params, u32 *length)
{
	rndis_resp_t *r, *n;
	unsigned long flags;

	if (!length) return NULL;

	spin_lock_irqsave(&params->lock, flags);
	list_for_each_entry_safe(r, n, &params->resp_queue, list) {
		if (!r->send) {
			r->send = 1;
			*length = r->length;
			spin_unlock_irqrestore(&params->lock, flags);
			return r->buf;
		}
	}
	spin_unlock_irqrestore(&params->lock, flags);

	return NULL;
}
@@ -1127,6 +1135,7 @@ EXPORT_SYMBOL_GPL(rndis_get_next_response);
static rndis_resp_t *rndis_add_response(struct rndis_params *params, u32 length)
{
	rndis_resp_t *r;
	unsigned long flags;

	/* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
	r = kmalloc(sizeof(rndis_resp_t) + length, GFP_ATOMIC);
@@ -1136,7 +1145,9 @@ static rndis_resp_t *rndis_add_response(struct rndis_params *params, u32 length)
	r->length = length;
	r->send = 0;

	spin_lock_irqsave(&params->lock, flags);
	list_add_tail(&r->list, &params->resp_queue);
	spin_unlock_irqrestore(&params->lock, flags);
	return r;
}

+1 −0
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ typedef struct rndis_params

	void			*v;
	struct list_head	resp_queue;
	spinlock_t		lock;
} rndis_params;

/* RNDIS Message parser and other useless functions */