diff options
| author | David S. Miller <davem@davemloft.net> | 2010-07-07 15:59:38 -0700 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-07-07 15:59:38 -0700 | 
| commit | 597e608a8492d662736c9bc6aa507dbf1cadc17d (patch) | |
| tree | 6c330cdd0a4809f67dd191b37e34f5b4318cef78 | |
| parent | acbc0f039ff4b93da737c91937b7c70018ded39f (diff) | |
| parent | 33b665eeeb85956ccbdf31c4c31a4e2a31133c44 (diff) | |
| download | olio-linux-3.10-597e608a8492d662736c9bc6aa507dbf1cadc17d.tar.xz olio-linux-3.10-597e608a8492d662736c9bc6aa507dbf1cadc17d.zip  | |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
46 files changed, 734 insertions, 435 deletions
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 6f907ebed2d..6d34f405a2f 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -37,7 +37,7 @@  #include <linux/wait.h>  #include <linux/skbuff.h> -#include <asm/io.h> +#include <linux/io.h>  #include <pcmcia/cs_types.h>  #include <pcmcia/cs.h> diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 40aec0fb859..42d69d4de05 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -244,7 +244,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,  	if (rel) {  		hdr[0] |= 0x80 + bcsp->msgq_txseq;  		BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); -		bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; +		bcsp->msgq_txseq = (bcsp->msgq_txseq + 1) & 0x07;  	}  	if (bcsp->use_crc) diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index c5016bd2d94..c3b1dc3a13a 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -126,26 +126,6 @@ static unsigned lock_loop(unsigned numbytes, struct inbuf_t *inbuf)  	return numbytes;  } -/* set up next receive skb for data mode - */ -static void new_rcv_skb(struct bc_state *bcs) -{ -	struct cardstate *cs = bcs->cs; -	unsigned short hw_hdr_len = cs->hw_hdr_len; - -	if (bcs->ignore) { -		bcs->skb = NULL; -		return; -	} - -	bcs->skb = dev_alloc_skb(SBUFSIZE + hw_hdr_len); -	if (bcs->skb == NULL) { -		dev_warn(cs->dev, "could not allocate new skb\n"); -		return; -	} -	skb_reserve(bcs->skb, hw_hdr_len); -} -  /* process a block of received bytes in HDLC data mode   * (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 == L2_HDLC)   * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes. @@ -159,8 +139,8 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf)  	struct cardstate *cs = inbuf->cs;  	struct bc_state *bcs = cs->bcs;  	int inputstate = bcs->inputstate; -	__u16 fcs = bcs->fcs; -	struct sk_buff *skb = bcs->skb; +	__u16 fcs = bcs->rx_fcs; +	struct sk_buff *skb = bcs->rx_skb;  	unsigned char *src = inbuf->data + inbuf->head;  	unsigned procbytes = 0;  	unsigned char c; @@ -245,8 +225,7 @@ byte_stuff:  				/* prepare reception of next frame */  				inputstate &= ~INS_have_data; -				new_rcv_skb(bcs); -				skb = bcs->skb; +				skb = gigaset_new_rx_skb(bcs);  			} else {  				/* empty frame (7E 7E) */  #ifdef CONFIG_GIGASET_DEBUG @@ -255,8 +234,7 @@ byte_stuff:  				if (!skb) {  					/* skipped (?) */  					gigaset_isdn_rcv_err(bcs); -					new_rcv_skb(bcs); -					skb = bcs->skb; +					skb = gigaset_new_rx_skb(bcs);  				}  			} @@ -279,11 +257,11 @@ byte_stuff:  #endif  		inputstate |= INS_have_data;  		if (skb) { -			if (skb->len == SBUFSIZE) { +			if (skb->len >= bcs->rx_bufsize) {  				dev_warn(cs->dev, "received packet too long\n");  				dev_kfree_skb_any(skb);  				/* skip remainder of packet */ -				bcs->skb = skb = NULL; +				bcs->rx_skb = skb = NULL;  			} else {  				*__skb_put(skb, 1) = c;  				fcs = crc_ccitt_byte(fcs, c); @@ -292,7 +270,7 @@ byte_stuff:  	}  	bcs->inputstate = inputstate; -	bcs->fcs = fcs; +	bcs->rx_fcs = fcs;  	return procbytes;  } @@ -308,18 +286,18 @@ static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf)  	struct cardstate *cs = inbuf->cs;  	struct bc_state *bcs = cs->bcs;  	int inputstate = bcs->inputstate; -	struct sk_buff *skb = bcs->skb; +	struct sk_buff *skb = bcs->rx_skb;  	unsigned char *src = inbuf->data + inbuf->head;  	unsigned procbytes = 0;  	unsigned char c;  	if (!skb) {  		/* skip this block */ -		new_rcv_skb(bcs); +		gigaset_new_rx_skb(bcs);  		return numbytes;  	} -	while (procbytes < numbytes && skb->len < SBUFSIZE) { +	while (procbytes < numbytes && skb->len < bcs->rx_bufsize) {  		c = *src++;  		procbytes++; @@ -343,7 +321,7 @@ static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf)  	if (inputstate & INS_have_data) {  		gigaset_skb_rcvd(bcs, skb);  		inputstate &= ~INS_have_data; -		new_rcv_skb(bcs); +		gigaset_new_rx_skb(bcs);  	}  	bcs->inputstate = inputstate; diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 8f78f15c8ef..6fbe8999c41 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -70,7 +70,7 @@  #define MAX_NUMBER_DIGITS 20  #define MAX_FMT_IE_LEN 20 -/* values for gigaset_capi_appl.connected */ +/* values for bcs->apconnstate */  #define APCONN_NONE	0	/* inactive/listening */  #define APCONN_SETUP	1	/* connecting */  #define APCONN_ACTIVE	2	/* B channel up */ @@ -80,10 +80,10 @@ struct gigaset_capi_appl {  	struct list_head ctrlist;  	struct gigaset_capi_appl *bcnext;  	u16 id; +	struct capi_register_params rp;  	u16 nextMessageNumber;  	u32 listenInfoMask;  	u32 listenCIPmask; -	int connected;  };  /* CAPI specific controller data structure */ @@ -319,6 +319,39 @@ static const char *format_ie(const char *ie)  	return result;  } +/* + * emit DATA_B3_CONF message + */ +static void send_data_b3_conf(struct cardstate *cs, struct capi_ctr *ctr, +			      u16 appl, u16 msgid, int channel, +			      u16 handle, u16 info) +{ +	struct sk_buff *cskb; +	u8 *msg; + +	cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); +	if (!cskb) { +		dev_err(cs->dev, "%s: out of memory\n", __func__); +		return; +	} +	/* frequent message, avoid _cmsg overhead */ +	msg = __skb_put(cskb, CAPI_DATA_B3_CONF_LEN); +	CAPIMSG_SETLEN(msg, CAPI_DATA_B3_CONF_LEN); +	CAPIMSG_SETAPPID(msg, appl); +	CAPIMSG_SETCOMMAND(msg, CAPI_DATA_B3); +	CAPIMSG_SETSUBCOMMAND(msg,  CAPI_CONF); +	CAPIMSG_SETMSGID(msg, msgid); +	CAPIMSG_SETCONTROLLER(msg, ctr->cnr); +	CAPIMSG_SETPLCI_PART(msg, channel); +	CAPIMSG_SETNCCI_PART(msg, 1); +	CAPIMSG_SETHANDLE_CONF(msg, handle); +	CAPIMSG_SETINFO_CONF(msg, info); + +	/* emit message */ +	dump_rawmsg(DEBUG_MCMD, __func__, msg); +	capi_ctr_handle_message(ctr, appl, cskb); +} +  /*   * driver interface functions @@ -339,7 +372,6 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb)  	struct gigaset_capi_ctr *iif = cs->iif;  	struct gigaset_capi_appl *ap = bcs->ap;  	unsigned char *req = skb_mac_header(dskb); -	struct sk_buff *cskb;  	u16 flags;  	/* update statistics */ @@ -351,39 +383,22 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb)  	}  	/* don't send further B3 messages if disconnected */ -	if (ap->connected < APCONN_ACTIVE) { +	if (bcs->apconnstate < APCONN_ACTIVE) {  		gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack");  		return;  	} -	/* ToDo: honor unset "delivery confirmation" bit */ +	/* +	 * send DATA_B3_CONF if "delivery confirmation" bit was set in request; +	 * otherwise it has already been sent by do_data_b3_req() +	 */  	flags = CAPIMSG_FLAGS(req); - -	/* build DATA_B3_CONF message */ -	cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); -	if (!cskb) { -		dev_err(cs->dev, "%s: out of memory\n", __func__); -		return; -	} -	/* frequent message, avoid _cmsg overhead */ -	CAPIMSG_SETLEN(cskb->data, CAPI_DATA_B3_CONF_LEN); -	CAPIMSG_SETAPPID(cskb->data, ap->id); -	CAPIMSG_SETCOMMAND(cskb->data, CAPI_DATA_B3); -	CAPIMSG_SETSUBCOMMAND(cskb->data,  CAPI_CONF); -	CAPIMSG_SETMSGID(cskb->data, CAPIMSG_MSGID(req)); -	CAPIMSG_SETCONTROLLER(cskb->data, iif->ctr.cnr); -	CAPIMSG_SETPLCI_PART(cskb->data, bcs->channel + 1); -	CAPIMSG_SETNCCI_PART(cskb->data, 1); -	CAPIMSG_SETHANDLE_CONF(cskb->data, CAPIMSG_HANDLE_REQ(req)); -	if (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) -		CAPIMSG_SETINFO_CONF(cskb->data, -				     CapiFlagsNotSupportedByProtocol); -	else -		CAPIMSG_SETINFO_CONF(cskb->data, CAPI_NOERROR); - -	/* emit message */ -	dump_rawmsg(DEBUG_LLDATA, "DATA_B3_CONF", cskb->data); -	capi_ctr_handle_message(&iif->ctr, ap->id, cskb); +	if (flags & CAPI_FLAGS_DELIVERY_CONFIRMATION) +		send_data_b3_conf(cs, &iif->ctr, ap->id, CAPIMSG_MSGID(req), +				  bcs->channel + 1, CAPIMSG_HANDLE_REQ(req), +				  (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) ? +					CapiFlagsNotSupportedByProtocol : +					CAPI_NOERROR);  }  EXPORT_SYMBOL_GPL(gigaset_skb_sent); @@ -412,7 +427,7 @@ void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)  	}  	/* don't send further B3 messages if disconnected */ -	if (ap->connected < APCONN_ACTIVE) { +	if (bcs->apconnstate < APCONN_ACTIVE) {  		gig_dbg(DEBUG_LLDATA, "disconnected, discarding data");  		dev_kfree_skb_any(skb);  		return; @@ -484,6 +499,7 @@ int gigaset_isdn_icall(struct at_state_t *at_state)  	u32 actCIPmask;  	struct sk_buff *skb;  	unsigned int msgsize; +	unsigned long flags;  	int i;  	/* @@ -608,7 +624,14 @@ int gigaset_isdn_icall(struct at_state_t *at_state)  		format_ie(iif->hcmsg.CalledPartyNumber));  	/* scan application list for matching listeners */ -	bcs->ap = NULL; +	spin_lock_irqsave(&bcs->aplock, flags); +	if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) { +		dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", +			 __func__, bcs->ap, bcs->apconnstate); +		bcs->ap = NULL; +		bcs->apconnstate = APCONN_NONE; +	} +	spin_unlock_irqrestore(&bcs->aplock, flags);  	actCIPmask = 1 | (1 << iif->hcmsg.CIPValue);  	list_for_each_entry(ap, &iif->appls, ctrlist)  		if (actCIPmask & ap->listenCIPmask) { @@ -626,10 +649,12 @@ int gigaset_isdn_icall(struct at_state_t *at_state)  			dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);  			/* add to listeners on this B channel, update state */ +			spin_lock_irqsave(&bcs->aplock, flags);  			ap->bcnext = bcs->ap;  			bcs->ap = ap;  			bcs->chstate |= CHS_NOTIFY_LL; -			ap->connected = APCONN_SETUP; +			bcs->apconnstate = APCONN_SETUP; +			spin_unlock_irqrestore(&bcs->aplock, flags);  			/* emit message */  			capi_ctr_handle_message(&iif->ctr, ap->id, skb); @@ -654,7 +679,7 @@ static void send_disconnect_ind(struct bc_state *bcs,  	struct gigaset_capi_ctr *iif = cs->iif;  	struct sk_buff *skb; -	if (ap->connected == APCONN_NONE) +	if (bcs->apconnstate == APCONN_NONE)  		return;  	capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT, CAPI_IND, @@ -668,7 +693,6 @@ static void send_disconnect_ind(struct bc_state *bcs,  	}  	capi_cmsg2message(&iif->hcmsg, __skb_put(skb, CAPI_DISCONNECT_IND_LEN));  	dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); -	ap->connected = APCONN_NONE;  	capi_ctr_handle_message(&iif->ctr, ap->id, skb);  } @@ -685,9 +709,9 @@ static void send_disconnect_b3_ind(struct bc_state *bcs,  	struct sk_buff *skb;  	/* nothing to do if no logical connection active */ -	if (ap->connected < APCONN_ACTIVE) +	if (bcs->apconnstate < APCONN_ACTIVE)  		return; -	ap->connected = APCONN_SETUP; +	bcs->apconnstate = APCONN_SETUP;  	capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND,  			 ap->nextMessageNumber++, @@ -714,14 +738,25 @@ void gigaset_isdn_connD(struct bc_state *bcs)  {  	struct cardstate *cs = bcs->cs;  	struct gigaset_capi_ctr *iif = cs->iif; -	struct gigaset_capi_appl *ap = bcs->ap; +	struct gigaset_capi_appl *ap;  	struct sk_buff *skb;  	unsigned int msgsize; +	unsigned long flags; +	spin_lock_irqsave(&bcs->aplock, flags); +	ap = bcs->ap;  	if (!ap) { +		spin_unlock_irqrestore(&bcs->aplock, flags);  		dev_err(cs->dev, "%s: no application\n", __func__);  		return;  	} +	if (bcs->apconnstate == APCONN_NONE) { +		spin_unlock_irqrestore(&bcs->aplock, flags); +		dev_warn(cs->dev, "%s: application %u not connected\n", +			 __func__, ap->id); +		return; +	} +	spin_unlock_irqrestore(&bcs->aplock, flags);  	while (ap->bcnext) {  		/* this should never happen */  		dev_warn(cs->dev, "%s: dropping extra application %u\n", @@ -730,11 +765,6 @@ void gigaset_isdn_connD(struct bc_state *bcs)  				    CapiCallGivenToOtherApplication);  		ap->bcnext = ap->bcnext->bcnext;  	} -	if (ap->connected == APCONN_NONE) { -		dev_warn(cs->dev, "%s: application %u not connected\n", -			 __func__, ap->id); -		return; -	}  	/* prepare CONNECT_ACTIVE_IND message  	 * Note: LLC not supported by device @@ -772,17 +802,24 @@ void gigaset_isdn_connD(struct bc_state *bcs)  void gigaset_isdn_hupD(struct bc_state *bcs)  {  	struct gigaset_capi_appl *ap; +	unsigned long flags;  	/*  	 * ToDo: pass on reason code reported by device  	 * (requires ev-layer state machine extension to collect  	 * ZCAU device reply)  	 */ -	for (ap = bcs->ap; ap != NULL; ap = ap->bcnext) { +	spin_lock_irqsave(&bcs->aplock, flags); +	while (bcs->ap != NULL) { +		ap = bcs->ap; +		bcs->ap = ap->bcnext; +		spin_unlock_irqrestore(&bcs->aplock, flags);  		send_disconnect_b3_ind(bcs, ap);  		send_disconnect_ind(bcs, ap, 0); +		spin_lock_irqsave(&bcs->aplock, flags);  	} -	bcs->ap = NULL; +	bcs->apconnstate = APCONN_NONE; +	spin_unlock_irqrestore(&bcs->aplock, flags);  }  /** @@ -796,24 +833,21 @@ void gigaset_isdn_connB(struct bc_state *bcs)  {  	struct cardstate *cs = bcs->cs;  	struct gigaset_capi_ctr *iif = cs->iif; -	struct gigaset_capi_appl *ap = bcs->ap; +	struct gigaset_capi_appl *ap;  	struct sk_buff *skb; +	unsigned long flags;  	unsigned int msgsize;  	u8 command; +	spin_lock_irqsave(&bcs->aplock, flags); +	ap = bcs->ap;  	if (!ap) { +		spin_unlock_irqrestore(&bcs->aplock, flags);  		dev_err(cs->dev, "%s: no application\n", __func__);  		return;  	} -	while (ap->bcnext) { -		/* this should never happen */ -		dev_warn(cs->dev, "%s: dropping extra application %u\n", -			 __func__, ap->bcnext->id); -		send_disconnect_ind(bcs, ap->bcnext, -				    CapiCallGivenToOtherApplication); -		ap->bcnext = ap->bcnext->bcnext; -	} -	if (!ap->connected) { +	if (!bcs->apconnstate) { +		spin_unlock_irqrestore(&bcs->aplock, flags);  		dev_warn(cs->dev, "%s: application %u not connected\n",  			 __func__, ap->id);  		return; @@ -825,13 +859,26 @@ void gigaset_isdn_connB(struct bc_state *bcs)  	 * CONNECT_B3_ACTIVE_IND in reply to CONNECT_B3_RESP  	 * Parameters in both cases always: NCCI = 1, NCPI empty  	 */ -	if (ap->connected >= APCONN_ACTIVE) { +	if (bcs->apconnstate >= APCONN_ACTIVE) {  		command = CAPI_CONNECT_B3_ACTIVE;  		msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN;  	} else {  		command = CAPI_CONNECT_B3;  		msgsize = CAPI_CONNECT_B3_IND_BASELEN;  	} +	bcs->apconnstate = APCONN_ACTIVE; + +	spin_unlock_irqrestore(&bcs->aplock, flags); + +	while (ap->bcnext) { +		/* this should never happen */ +		dev_warn(cs->dev, "%s: dropping extra application %u\n", +			 __func__, ap->bcnext->id); +		send_disconnect_ind(bcs, ap->bcnext, +				    CapiCallGivenToOtherApplication); +		ap->bcnext = ap->bcnext->bcnext; +	} +  	capi_cmsg_header(&iif->hcmsg, ap->id, command, CAPI_IND,  			 ap->nextMessageNumber++,  			 iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16)); @@ -842,7 +889,6 @@ void gigaset_isdn_connB(struct bc_state *bcs)  	}  	capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize));  	dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); -	ap->connected = APCONN_ACTIVE;  	capi_ctr_handle_message(&iif->ctr, ap->id, skb);  } @@ -945,8 +991,64 @@ static void gigaset_register_appl(struct capi_ctr *ctr, u16 appl,  		return;  	}  	ap->id = appl; +	ap->rp = *rp;  	list_add(&ap->ctrlist, &iif->appls); +	dev_info(cs->dev, "application %u registered\n", ap->id); +} + +/* + * remove CAPI application from channel + * helper function to keep indentation levels down and stay in 80 columns + */ + +static inline void remove_appl_from_channel(struct bc_state *bcs, +					    struct gigaset_capi_appl *ap) +{ +	struct cardstate *cs = bcs->cs; +	struct gigaset_capi_appl *bcap; +	unsigned long flags; +	int prevconnstate; + +	spin_lock_irqsave(&bcs->aplock, flags); +	bcap = bcs->ap; +	if (bcap == NULL) { +		spin_unlock_irqrestore(&bcs->aplock, flags); +		return; +	} + +	/* check first application on channel */ +	if (bcap == ap) { +		bcs->ap = ap->bcnext; +		if (bcs->ap != NULL) { +			spin_unlock_irqrestore(&bcs->aplock, flags); +			return; +		} + +		/* none left, clear channel state */ +		prevconnstate = bcs->apconnstate; +		bcs->apconnstate = APCONN_NONE; +		spin_unlock_irqrestore(&bcs->aplock, flags); + +		if (prevconnstate == APCONN_ACTIVE) { +			dev_notice(cs->dev, "%s: hanging up channel %u\n", +				   __func__, bcs->channel); +			gigaset_add_event(cs, &bcs->at_state, +					  EV_HUP, NULL, 0, NULL); +			gigaset_schedule_event(cs); +		} +		return; +	} + +	/* check remaining list */ +	do { +		if (bcap->bcnext == ap) { +			bcap->bcnext = bcap->bcnext->bcnext; +			return; +		} +		bcap = bcap->bcnext; +	} while (bcap != NULL); +	spin_unlock_irqrestore(&bcs->aplock, flags);  }  /* @@ -958,19 +1060,19 @@ static void gigaset_release_appl(struct capi_ctr *ctr, u16 appl)  		= container_of(ctr, struct gigaset_capi_ctr, ctr);  	struct cardstate *cs = iif->ctr.driverdata;  	struct gigaset_capi_appl *ap, *tmp; +	unsigned ch;  	list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist)  		if (ap->id == appl) { -			if (ap->connected != APCONN_NONE) { -				dev_err(cs->dev, -					"%s: application %u still connected\n", -					__func__, ap->id); -				/* ToDo: clear active connection */ -			} +			/* remove from any channels */ +			for (ch = 0; ch < cs->channels; ch++) +				remove_appl_from_channel(&cs->bcs[ch], ap); + +			/* remove from registration list */  			list_del(&ap->ctrlist);  			kfree(ap); +			dev_info(cs->dev, "application %u released\n", appl);  		} -  }  /* @@ -1149,7 +1251,8 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,  	char **commands;  	char *s;  	u8 *pp; -	int i, l; +	unsigned long flags; +	int i, l, lbc, lhlc;  	u16 info;  	/* decode message */ @@ -1164,8 +1267,18 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,  		send_conf(iif, ap, skb, CapiNoPlciAvailable);  		return;  	} +	spin_lock_irqsave(&bcs->aplock, flags); +	if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) +		dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", +			 __func__, bcs->ap, bcs->apconnstate);  	ap->bcnext = NULL;  	bcs->ap = ap; +	bcs->apconnstate = APCONN_SETUP; +	spin_unlock_irqrestore(&bcs->aplock, flags); + +	bcs->rx_bufsize = ap->rp.datablklen; +	dev_kfree_skb(bcs->rx_skb); +	gigaset_new_rx_skb(bcs);  	cmsg->adr.adrPLCI |= (bcs->channel + 1) << 8;  	/* build command table */ @@ -1273,42 +1386,59 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,  		goto error;  	} -	/* check/encode parameter: BC */ -	if (cmsg->BC && cmsg->BC[0]) { -		/* explicit BC overrides CIP */ -		l = 2*cmsg->BC[0] + 7; +	/* +	 * check/encode parameters: BC & HLC +	 * must be encoded together as device doesn't accept HLC separately +	 * explicit parameters override values derived from CIP +	 */ + +	/* determine lengths */ +	if (cmsg->BC && cmsg->BC[0])		/* BC specified explicitly */ +		lbc = 2*cmsg->BC[0]; +	else if (cip2bchlc[cmsg->CIPValue].bc)	/* BC derived from CIP */ +		lbc = strlen(cip2bchlc[cmsg->CIPValue].bc); +	else					/* no BC */ +		lbc = 0; +	if (cmsg->HLC && cmsg->HLC[0])		/* HLC specified explicitly */ +		lhlc = 2*cmsg->HLC[0]; +	else if (cip2bchlc[cmsg->CIPValue].hlc)	/* HLC derived from CIP */ +		lhlc = strlen(cip2bchlc[cmsg->CIPValue].hlc); +	else					/* no HLC */ +		lhlc = 0; + +	if (lbc) { +		/* have BC: allocate and assemble command string */ +		l = lbc + 7;		/* "^SBC=" + value + "\r" + null byte */ +		if (lhlc) +			l += lhlc + 7;	/* ";^SHLC=" + value */  		commands[AT_BC] = kmalloc(l, GFP_KERNEL);  		if (!commands[AT_BC])  			goto oom;  		strcpy(commands[AT_BC], "^SBC="); -		decode_ie(cmsg->BC, commands[AT_BC]+5); +		if (cmsg->BC && cmsg->BC[0])	/* BC specified explicitly */ +			decode_ie(cmsg->BC, commands[AT_BC] + 5); +		else				/* BC derived from CIP */ +			strcpy(commands[AT_BC] + 5, +			       cip2bchlc[cmsg->CIPValue].bc); +		if (lhlc) { +			strcpy(commands[AT_BC] + lbc + 5, ";^SHLC="); +			if (cmsg->HLC && cmsg->HLC[0]) +				/* HLC specified explicitly */ +				decode_ie(cmsg->HLC, +					  commands[AT_BC] + lbc + 12); +			else	/* HLC derived from CIP */ +				strcpy(commands[AT_BC] + lbc + 12, +				       cip2bchlc[cmsg->CIPValue].hlc); +		}  		strcpy(commands[AT_BC] + l - 2, "\r"); -	} else if (cip2bchlc[cmsg->CIPValue].bc) { -		l = strlen(cip2bchlc[cmsg->CIPValue].bc) + 7; -		commands[AT_BC] = kmalloc(l, GFP_KERNEL); -		if (!commands[AT_BC]) -			goto oom; -		snprintf(commands[AT_BC], l, "^SBC=%s\r", -			 cip2bchlc[cmsg->CIPValue].bc); -	} - -	/* check/encode parameter: HLC */ -	if (cmsg->HLC && cmsg->HLC[0]) { -		/* explicit HLC overrides CIP */ -		l = 2*cmsg->HLC[0] + 7; -		commands[AT_HLC] = kmalloc(l, GFP_KERNEL); -		if (!commands[AT_HLC]) -			goto oom; -		strcpy(commands[AT_HLC], "^SHLC="); -		decode_ie(cmsg->HLC, commands[AT_HLC]+5); -		strcpy(commands[AT_HLC] + l - 2, "\r"); -	} else if (cip2bchlc[cmsg->CIPValue].hlc) { -		l = strlen(cip2bchlc[cmsg->CIPValue].hlc) + 7; -		commands[AT_HLC] = kmalloc(l, GFP_KERNEL); -		if (!commands[AT_HLC]) -			goto oom; -		snprintf(commands[AT_HLC], l, "^SHLC=%s\r", -			 cip2bchlc[cmsg->CIPValue].hlc); +	} else { +		/* no BC */ +		if (lhlc) { +			dev_notice(cs->dev, "%s: cannot set HLC without BC\n", +				   "CONNECT_REQ"); +			info = CapiIllMessageParmCoding; /* ? */ +			goto error; +		}  	}  	/* check/encode parameter: B Protocol */ @@ -1322,13 +1452,13 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,  			bcs->proto2 = L2_HDLC;  			break;  		case 1: -			bcs->proto2 = L2_BITSYNC; +			bcs->proto2 = L2_VOICE;  			break;  		default:  			dev_warn(cs->dev,  			    "B1 Protocol %u unsupported, using Transparent\n",  				 cmsg->B1protocol); -			bcs->proto2 = L2_BITSYNC; +			bcs->proto2 = L2_VOICE;  		}  		if (cmsg->B2protocol != 1)  			dev_warn(cs->dev, @@ -1382,7 +1512,6 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,  		goto error;  	}  	gigaset_schedule_event(cs); -	ap->connected = APCONN_SETUP;  	send_conf(iif, ap, skb, CapiSuccess);  	return; @@ -1410,6 +1539,7 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif,  	_cmsg *cmsg = &iif->acmsg;  	struct bc_state *bcs;  	struct gigaset_capi_appl *oap; +	unsigned long flags;  	int channel;  	/* decode message */ @@ -1429,12 +1559,24 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif,  	switch (cmsg->Reject) {  	case 0:		/* Accept */  		/* drop all competing applications, keep only this one */ -		for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) -			if (oap != ap) +		spin_lock_irqsave(&bcs->aplock, flags); +		while (bcs->ap != NULL) { +			oap = bcs->ap; +			bcs->ap = oap->bcnext; +			if (oap != ap) { +				spin_unlock_irqrestore(&bcs->aplock, flags);  				send_disconnect_ind(bcs, oap,  					CapiCallGivenToOtherApplication); +				spin_lock_irqsave(&bcs->aplock, flags); +			} +		}  		ap->bcnext = NULL;  		bcs->ap = ap; +		spin_unlock_irqrestore(&bcs->aplock, flags); + +		bcs->rx_bufsize = ap->rp.datablklen; +		dev_kfree_skb(bcs->rx_skb); +		gigaset_new_rx_skb(bcs);  		bcs->chstate |= CHS_NOTIFY_LL;  		/* check/encode B channel protocol */ @@ -1448,13 +1590,13 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif,  				bcs->proto2 = L2_HDLC;  				break;  			case 1: -				bcs->proto2 = L2_BITSYNC; +				bcs->proto2 = L2_VOICE;  				break;  			default:  				dev_warn(cs->dev,  			"B1 Protocol %u unsupported, using Transparent\n",  					 cmsg->B1protocol); -				bcs->proto2 = L2_BITSYNC; +				bcs->proto2 = L2_VOICE;  			}  			if (cmsg->B2protocol != 1)  				dev_warn(cs->dev, @@ -1502,31 +1644,45 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif,  		send_disconnect_ind(bcs, ap, 0);  		/* remove it from the list of listening apps */ +		spin_lock_irqsave(&bcs->aplock, flags);  		if (bcs->ap == ap) {  			bcs->ap = ap->bcnext; -			if (bcs->ap == NULL) +			if (bcs->ap == NULL) {  				/* last one: stop ev-layer hupD notifications */ +				bcs->apconnstate = APCONN_NONE;  				bcs->chstate &= ~CHS_NOTIFY_LL; +			} +			spin_unlock_irqrestore(&bcs->aplock, flags);  			return;  		}  		for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) {  			if (oap->bcnext == ap) {  				oap->bcnext = oap->bcnext->bcnext; +				spin_unlock_irqrestore(&bcs->aplock, flags);  				return;  			}  		} +		spin_unlock_irqrestore(&bcs->aplock, flags);  		dev_err(cs->dev, "%s: application %u not found\n",  			__func__, ap->id);  		return;  	default:		/* Reject */  		/* drop all competing applications, keep only this one */ -		for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) -			if (oap != ap) +		spin_lock_irqsave(&bcs->aplock, flags); +		while (bcs->ap != NULL) { +			oap = bcs->ap; +			bcs->ap = oap->bcnext; +			if (oap != ap) { +				spin_unlock_irqrestore(&bcs->aplock, flags);  				send_disconnect_ind(bcs, oap,  					CapiCallGivenToOtherApplication); +				spin_lock_irqsave(&bcs->aplock, flags); +			} +		}  		ap->bcnext = NULL;  		bcs->ap = ap; +		spin_unlock_irqrestore(&bcs->aplock, flags);  		/* reject call - will trigger DISCONNECT_IND for this app */  		dev_info(cs->dev, "%s: Reject=%x\n", @@ -1549,6 +1705,7 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif,  {  	struct cardstate *cs = iif->ctr.driverdata;  	_cmsg *cmsg = &iif->acmsg; +	struct bc_state *bcs;  	int channel;  	/* decode message */ @@ -1563,9 +1720,10 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif,  		send_conf(iif, ap, skb, CapiIllContrPlciNcci);  		return;  	} +	bcs = &cs->bcs[channel-1];  	/* mark logical connection active */ -	ap->connected = APCONN_ACTIVE; +	bcs->apconnstate = APCONN_ACTIVE;  	/* build NCCI: always 1 (one B3 connection only) */  	cmsg->adr.adrNCCI |= 1 << 16; @@ -1611,7 +1769,7 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif,  	if (cmsg->Reject) {  		/* Reject: clear B3 connect received flag */ -		ap->connected = APCONN_SETUP; +		bcs->apconnstate = APCONN_SETUP;  		/* trigger hangup, causing eventual DISCONNECT_IND */  		if (!gigaset_add_event(cs, &bcs->at_state, @@ -1683,11 +1841,11 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif,  	}  	/* skip if DISCONNECT_IND already sent */ -	if (!ap->connected) +	if (!bcs->apconnstate)  		return;  	/* check for active logical connection */ -	if (ap->connected >= APCONN_ACTIVE) { +	if (bcs->apconnstate >= APCONN_ACTIVE) {  		/*  		 * emit DISCONNECT_B3_IND with cause 0x3301  		 * use separate cmsg structure, as the content of iif->acmsg @@ -1736,6 +1894,7 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif,  {  	struct cardstate *cs = iif->ctr.driverdata;  	_cmsg *cmsg = &iif->acmsg; +	struct bc_state *bcs;  	int channel;  	/* decode message */ @@ -1751,17 +1910,17 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif,  		send_conf(iif, ap, skb, CapiIllContrPlciNcci);  		return;  	} +	bcs = &cs->bcs[channel-1];  	/* reject if logical connection not active */ -	if (ap->connected < APCONN_ACTIVE) { +	if (bcs->apconnstate < APCONN_ACTIVE) {  		send_conf(iif, ap, skb,  			  CapiMessageNotSupportedInCurrentState);  		return;  	}  	/* trigger hangup, causing eventual DISCONNECT_B3_IND */ -	if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state, -			       EV_HUP, NULL, 0, NULL)) { +	if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) {  		send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);  		return;  	} @@ -1782,11 +1941,14 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif,  			   struct sk_buff *skb)  {  	struct cardstate *cs = iif->ctr.driverdata; +	struct bc_state *bcs;  	int channel = CAPIMSG_PLCI_PART(skb->data);  	u16 ncci = CAPIMSG_NCCI_PART(skb->data);  	u16 msglen = CAPIMSG_LEN(skb->data);  	u16 datalen = CAPIMSG_DATALEN(skb->data);  	u16 flags = CAPIMSG_FLAGS(skb->data); +	u16 msgid = CAPIMSG_MSGID(skb->data); +	u16 handle = CAPIMSG_HANDLE_REQ(skb->data);  	/* frequent message, avoid _cmsg overhead */  	dump_rawmsg(DEBUG_LLDATA, "DATA_B3_REQ", skb->data); @@ -1802,6 +1964,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif,  		send_conf(iif, ap, skb, CapiIllContrPlciNcci);  		return;  	} +	bcs = &cs->bcs[channel-1];  	if (msglen != CAPI_DATA_B3_REQ_LEN && msglen != CAPI_DATA_B3_REQ_LEN64)  		dev_notice(cs->dev, "%s: unexpected length %d\n",  			   "DATA_B3_REQ", msglen); @@ -1821,7 +1984,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif,  	}  	/* reject if logical connection not active */ -	if (ap->connected < APCONN_ACTIVE) { +	if (bcs->apconnstate < APCONN_ACTIVE) {  		send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState);  		return;  	} @@ -1832,17 +1995,19 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif,  	skb_pull(skb, msglen);  	/* pass to device-specific module */ -	if (cs->ops->send_skb(&cs->bcs[channel-1], skb) < 0) { +	if (cs->ops->send_skb(bcs, skb) < 0) {  		send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);  		return;  	} -	/* DATA_B3_CONF reply will be sent by gigaset_skb_sent() */ -  	/* -	 * ToDo: honor unset "delivery confirmation" bit -	 * (send DATA_B3_CONF immediately?) +	 * DATA_B3_CONF will be sent by gigaset_skb_sent() only if "delivery +	 * confirmation" bit is set; otherwise we have to send it now  	 */ +	if (!(flags & CAPI_FLAGS_DELIVERY_CONFIRMATION)) +		send_data_b3_conf(cs, &iif->ctr, ap->id, msgid, channel, handle, +				  flags ? CapiFlagsNotSupportedByProtocol +					: CAPI_NOERROR);  }  /* diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index f6f45f22192..5d4befb8105 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -399,8 +399,8 @@ static void gigaset_freebcs(struct bc_state *bcs)  	gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel);  	clear_at_state(&bcs->at_state);  	gig_dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel); -	dev_kfree_skb(bcs->skb); -	bcs->skb = NULL; +	dev_kfree_skb(bcs->rx_skb); +	bcs->rx_skb = NULL;  	for (i = 0; i < AT_NUM; ++i) {  		kfree(bcs->commands[i]); @@ -634,19 +634,10 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,  	bcs->emptycount = 0;  #endif -	gig_dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel); -	bcs->fcs = PPP_INITFCS; +	bcs->rx_bufsize = 0; +	bcs->rx_skb = NULL; +	bcs->rx_fcs = PPP_INITFCS;  	bcs->inputstate = 0; -	if (cs->ignoreframes) { -		bcs->skb = NULL; -	} else { -		bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); -		if (bcs->skb != NULL) -			skb_reserve(bcs->skb, cs->hw_hdr_len); -		else -			pr_err("out of memory\n"); -	} -  	bcs->channel = channel;  	bcs->cs = cs; @@ -658,16 +649,15 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,  	for (i = 0; i < AT_NUM; ++i)  		bcs->commands[i] = NULL; +	spin_lock_init(&bcs->aplock); +	bcs->ap = NULL; +	bcs->apconnstate = 0; +  	gig_dbg(DEBUG_INIT, "  setting up bcs[%d]->hw", channel);  	if (cs->ops->initbcshw(bcs))  		return bcs;  	gig_dbg(DEBUG_INIT, "  failed"); - -	gig_dbg(DEBUG_INIT, "  freeing bcs[%d]->skb", channel); -	dev_kfree_skb(bcs->skb); -	bcs->skb = NULL; -  	return NULL;  } @@ -839,14 +829,12 @@ void gigaset_bcs_reinit(struct bc_state *bcs)  	bcs->emptycount = 0;  #endif -	bcs->fcs = PPP_INITFCS; +	bcs->rx_fcs = PPP_INITFCS;  	bcs->chstate = 0;  	bcs->ignore = cs->ignoreframes; -	if (bcs->ignore) { -		dev_kfree_skb(bcs->skb); -		bcs->skb = NULL; -	} +	dev_kfree_skb(bcs->rx_skb); +	bcs->rx_skb = NULL;  	cs->ops->reinitbcshw(bcs);  } diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 206c380c523..ceaef9a04a4 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -282,9 +282,7 @@ struct reply_t gigaset_tab_cid[] =  /* dial */  {EV_DIAL,	 -1,  -1, -1,			 -1, -1, {ACT_DIAL} },  {RSP_INIT,	  0,   0, SEQ_DIAL,		601,  5, {ACT_CMD+AT_BC} }, -{RSP_OK,	601, 601, -1,			602,  5, {ACT_CMD+AT_HLC} }, -{RSP_NULL,	602, 602, -1,			603,  5, {ACT_CMD+AT_PROTO} }, -{RSP_OK,	602, 602, -1,			603,  5, {ACT_CMD+AT_PROTO} }, +{RSP_OK,	601, 601, -1,			603,  5, {ACT_CMD+AT_PROTO} },  {RSP_OK,	603, 603, -1,			604,  5, {ACT_CMD+AT_TYPE} },  {RSP_OK,	604, 604, -1,			605,  5, {ACT_CMD+AT_MSN} },  {RSP_NULL,	605, 605, -1,			606,  5, {ACT_CMD+AT_CLIP} }, diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 05947f9c184..8738b0821fc 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -45,10 +45,6 @@  #define MAX_EVENTS 64		/* size of event queue */  #define RBUFSIZE 8192 -#define SBUFSIZE 4096		/* sk_buff payload size */ - -#define TRANSBUFSIZE 768	/* bytes per skb for transparent receive */ -#define MAX_BUF_SIZE (SBUFSIZE - 2)	/* Max. size of a data packet from LL */  /* compile time options */  #define GIG_MAJOR 0 @@ -190,10 +186,9 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,  #define AT_BC		3  #define AT_PROTO	4  #define AT_TYPE		5 -#define AT_HLC		6 -#define AT_CLIP		7 +#define AT_CLIP		6  /* total number */ -#define AT_NUM		8 +#define AT_NUM		7  /* variables in struct at_state_t */  #define VAR_ZSAU	0 @@ -380,8 +375,10 @@ struct bc_state {  	struct at_state_t at_state; -	__u16 fcs; -	struct sk_buff *skb; +	/* receive buffer */ +	unsigned rx_bufsize;		/* max size accepted by application */ +	struct sk_buff *rx_skb; +	__u16 rx_fcs;  	int inputstate;			/* see INS_XXXX */  	int channel; @@ -406,7 +403,9 @@ struct bc_state {  		struct bas_bc_state *bas;	/* usb hardware driver (base) */  	} hw; -	void *ap;			/* LL application structure */ +	void *ap;			/* associated LL application */ +	int apconnstate;		/* LL application connection state */ +	spinlock_t aplock;  };  struct cardstate { @@ -801,8 +800,23 @@ static inline void gigaset_bchannel_up(struct bc_state *bcs)  	gigaset_schedule_event(bcs->cs);  } -/* handling routines for sk_buff */ -/* ============================= */ +/* set up next receive skb for data mode */ +static inline struct sk_buff *gigaset_new_rx_skb(struct bc_state *bcs) +{ +	struct cardstate *cs = bcs->cs; +	unsigned short hw_hdr_len = cs->hw_hdr_len; + +	if (bcs->ignore) { +		bcs->rx_skb = NULL; +	} else { +		bcs->rx_skb = dev_alloc_skb(bcs->rx_bufsize + hw_hdr_len); +		if (bcs->rx_skb == NULL) +			dev_warn(cs->dev, "could not allocate skb\n"); +		else +			skb_reserve(bcs->rx_skb, hw_hdr_len); +	} +	return bcs->rx_skb; +}  /* append received bytes to inbuf */  int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index c22e5ace827..f01c3c2e2e4 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -16,7 +16,10 @@  #include "gigaset.h"  #include <linux/isdnif.h> +#define SBUFSIZE	4096	/* sk_buff payload size */ +#define TRANSBUFSIZE	768	/* bytes per skb for transparent receive */  #define HW_HDR_LEN	2	/* Header size used to store ack info */ +#define MAX_BUF_SIZE	(SBUFSIZE - HW_HDR_LEN)	/* max data packet from LL */  /* == Handling of I4L IO =====================================================*/ @@ -231,6 +234,15 @@ static int command_from_LL(isdn_ctrl *cntrl)  			dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n");  			return -EBUSY;  		} +		switch (bcs->proto2) { +		case L2_HDLC: +			bcs->rx_bufsize = SBUFSIZE; +			break; +		default:			/* assume transparent */ +			bcs->rx_bufsize = TRANSBUFSIZE; +		} +		dev_kfree_skb(bcs->rx_skb); +		gigaset_new_rx_skb(bcs);  		commands = kzalloc(AT_NUM*(sizeof *commands), GFP_ATOMIC);  		if (!commands) { @@ -314,6 +326,15 @@ static int command_from_LL(isdn_ctrl *cntrl)  			return -EINVAL;  		}  		bcs = cs->bcs + ch; +		switch (bcs->proto2) { +		case L2_HDLC: +			bcs->rx_bufsize = SBUFSIZE; +			break; +		default:			/* assume transparent */ +			bcs->rx_bufsize = TRANSBUFSIZE; +		} +		dev_kfree_skb(bcs->rx_skb); +		gigaset_new_rx_skb(bcs);  		if (!gigaset_add_event(cs, &bcs->at_state,  				       EV_ACCEPT, NULL, 0, NULL))  			return -ENOMEM; diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index 16fd3bd4888..2dfd346fc88 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -500,19 +500,18 @@ int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len)   */  static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs)  { -	bcs->fcs = crc_ccitt_byte(bcs->fcs, c); -	if (unlikely(bcs->skb == NULL)) { +	bcs->rx_fcs = crc_ccitt_byte(bcs->rx_fcs, c); +	if (bcs->rx_skb == NULL)  		/* skipping */  		return; -	} -	if (unlikely(bcs->skb->len == SBUFSIZE)) { +	if (bcs->rx_skb->len >= bcs->rx_bufsize) {  		dev_warn(bcs->cs->dev, "received oversized packet discarded\n");  		bcs->hw.bas->giants++; -		dev_kfree_skb_any(bcs->skb); -		bcs->skb = NULL; +		dev_kfree_skb_any(bcs->rx_skb); +		bcs->rx_skb = NULL;  		return;  	} -	*__skb_put(bcs->skb, 1) = c; +	*__skb_put(bcs->rx_skb, 1) = c;  }  /* hdlc_flush @@ -521,18 +520,13 @@ static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs)  static inline void hdlc_flush(struct bc_state *bcs)  {  	/* clear skb or allocate new if not skipping */ -	if (likely(bcs->skb != NULL)) -		skb_trim(bcs->skb, 0); -	else if (!bcs->ignore) { -		bcs->skb = dev_alloc_skb(SBUFSIZE + bcs->cs->hw_hdr_len); -		if (bcs->skb) -			skb_reserve(bcs->skb, bcs->cs->hw_hdr_len); -		else -			dev_err(bcs->cs->dev, "could not allocate skb\n"); -	} +	if (bcs->rx_skb != NULL) +		skb_trim(bcs->rx_skb, 0); +	else +		gigaset_new_rx_skb(bcs);  	/* reset packet state */ -	bcs->fcs = PPP_INITFCS; +	bcs->rx_fcs = PPP_INITFCS;  }  /* hdlc_done @@ -549,7 +543,7 @@ static inline void hdlc_done(struct bc_state *bcs)  		hdlc_flush(bcs);  		return;  	} -	procskb = bcs->skb; +	procskb = bcs->rx_skb;  	if (procskb == NULL) {  		/* previous error */  		gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__); @@ -560,8 +554,8 @@ static inline void hdlc_done(struct bc_state *bcs)  		bcs->hw.bas->runts++;  		dev_kfree_skb_any(procskb);  		gigaset_isdn_rcv_err(bcs); -	} else if (bcs->fcs != PPP_GOODFCS) { -		dev_notice(cs->dev, "frame check error (0x%04x)\n", bcs->fcs); +	} else if (bcs->rx_fcs != PPP_GOODFCS) { +		dev_notice(cs->dev, "frame check error\n");  		bcs->hw.bas->fcserrs++;  		dev_kfree_skb_any(procskb);  		gigaset_isdn_rcv_err(bcs); @@ -574,13 +568,8 @@ static inline void hdlc_done(struct bc_state *bcs)  		bcs->hw.bas->goodbytes += len;  		gigaset_skb_rcvd(bcs, procskb);  	} - -	bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); -	if (bcs->skb) -		skb_reserve(bcs->skb, cs->hw_hdr_len); -	else -		dev_err(cs->dev, "could not allocate skb\n"); -	bcs->fcs = PPP_INITFCS; +	gigaset_new_rx_skb(bcs); +	bcs->rx_fcs = PPP_INITFCS;  }  /* hdlc_frag @@ -597,8 +586,8 @@ static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits)  	dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits);  	bcs->hw.bas->alignerrs++;  	gigaset_isdn_rcv_err(bcs); -	__skb_trim(bcs->skb, 0); -	bcs->fcs = PPP_INITFCS; +	__skb_trim(bcs->rx_skb, 0); +	bcs->rx_fcs = PPP_INITFCS;  }  /* bit counts lookup table for HDLC bit unstuffing @@ -847,7 +836,6 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,  static inline void trans_receive(unsigned char *src, unsigned count,  				 struct bc_state *bcs)  { -	struct cardstate *cs = bcs->cs;  	struct sk_buff *skb;  	int dobytes;  	unsigned char *dst; @@ -857,17 +845,11 @@ static inline void trans_receive(unsigned char *src, unsigned count,  		hdlc_flush(bcs);  		return;  	} -	skb = bcs->skb; -	if (unlikely(skb == NULL)) { -		bcs->skb = skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); -		if (!skb) { -			dev_err(cs->dev, "could not allocate skb\n"); -			return; -		} -		skb_reserve(skb, cs->hw_hdr_len); -	} +	skb = bcs->rx_skb; +	if (skb == NULL) +		skb = gigaset_new_rx_skb(bcs);  	bcs->hw.bas->goodbytes += skb->len; -	dobytes = TRANSBUFSIZE - skb->len; +	dobytes = bcs->rx_bufsize - skb->len;  	while (count > 0) {  		dst = skb_put(skb, count < dobytes ? count : dobytes);  		while (count > 0 && dobytes > 0) { @@ -879,14 +861,10 @@ static inline void trans_receive(unsigned char *src, unsigned count,  			dump_bytes(DEBUG_STREAM_DUMP,  				   "rcv data", skb->data, skb->len);  			gigaset_skb_rcvd(bcs, skb); -			bcs->skb = skb = -				dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); -			if (!skb) { -				dev_err(cs->dev, "could not allocate skb\n"); +			skb = gigaset_new_rx_skb(bcs); +			if (skb == NULL)  				return; -			} -			skb_reserve(skb, cs->hw_hdr_len); -			dobytes = TRANSBUFSIZE; +			dobytes = bcs->rx_bufsize;  		}  	}  } diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index 72eb92647c1..feec8d89d71 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -187,12 +187,13 @@ void  hysdn_rx_netpkt(hysdn_card * card, unsigned char *buf, unsigned short len)  {  	struct net_local *lp = card->netif; -	struct net_device *dev = lp->dev; +	struct net_device *dev;  	struct sk_buff *skb;  	if (!lp)  		return;		/* non existing device */ +	dev = lp->dev;  	dev->stats.rx_bytes += len;  	skb = dev_alloc_skb(len); diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 25c14c6236f..3662d6e446a 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -333,7 +333,8 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)  	if ((client_info->assigned) &&  	    (client_info->ip_src == arp->ip_dst) && -	    (client_info->ip_dst == arp->ip_src)) { +	    (client_info->ip_dst == arp->ip_src) && +	    (compare_ether_addr_64bits(client_info->mac_dst, arp->mac_src))) {  		/* update the clients MAC address */  		memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN);  		client_info->ntt = 1; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 9bb9bfa225b..822808810a1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -176,7 +176,7 @@ static int arp_ip_count;  static int bond_mode	= BOND_MODE_ROUNDROBIN;  static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2;  static int lacp_fast; - +static int disable_netpoll = 1;  const struct bond_parm_tbl bond_lacp_tbl[] = {  {	"slow",		AD_LACP_SLOW}, @@ -1766,15 +1766,23 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)  	bond_set_carrier(bond);  #ifdef CONFIG_NET_POLL_CONTROLLER -	if (slaves_support_netpoll(bond_dev)) { -		bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; -		if (bond_dev->npinfo) -			slave_dev->npinfo = bond_dev->npinfo; -	} else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) { +	/* +	 * Netpoll and bonding is broken, make sure it is not initialized +	 * until it is fixed. +	 */ +	if (disable_netpoll) {  		bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; -		pr_info("New slave device %s does not support netpoll\n", -			slave_dev->name); -		pr_info("Disabling netpoll support for %s\n", bond_dev->name); +	} else { +		if (slaves_support_netpoll(bond_dev)) { +			bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; +			if (bond_dev->npinfo) +				slave_dev->npinfo = bond_dev->npinfo; +		} else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) { +			bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; +			pr_info("New slave device %s does not support netpoll\n", +				slave_dev->name); +			pr_info("Disabling netpoll support for %s\n", bond_dev->name); +		}  	}  #endif  	read_unlock(&bond->lock); @@ -1977,8 +1985,11 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)  #ifdef CONFIG_NET_POLL_CONTROLLER  	read_lock_bh(&bond->lock); -	if (slaves_support_netpoll(bond_dev)) -		bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL; + +	 /* Make sure netpoll over stays disabled until fixed. */ +	if (!disable_netpoll) +		if (slaves_support_netpoll(bond_dev)) +				bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;  	read_unlock_bh(&bond->lock);  	if (slave_dev->netdev_ops->ndo_netpoll_cleanup)  		slave_dev->netdev_ops->ndo_netpoll_cleanup(slave_dev); diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 1756d28250d..38de1a4f825 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -1181,7 +1181,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev)  		if (netif_msg_drv(priv))  			printk(KERN_ERR "%s: Could not attach to PHY\n",  			       dev->name); -		return PTR_ERR(priv->phy); +		rc = PTR_ERR(priv->phy); +		goto fail;  	}  	if ((rc = register_netdev(dev))) { diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 55099a50cca..b235aa16290 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3741,10 +3741,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter)  	/* signal that we are down to the interrupt handler */  	set_bit(__IXGBE_DOWN, &adapter->state); -	/* power down the optics */ -	if (hw->phy.multispeed_fiber) -		hw->mac.ops.disable_tx_laser(hw); -  	/* disable receive for all VFs and wait one second */  	if (adapter->num_vfs) {  		/* ping all the active vfs to let them know we are going down */ @@ -3799,6 +3795,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)  		                (IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &  		                 ~IXGBE_DMATXCTL_TE)); +	/* power down the optics */ +	if (hw->phy.multispeed_fiber) +		hw->mac.ops.disable_tx_laser(hw); +  	/* clear n-tuple filters that are cached */  	ethtool_ntuple_flush(netdev); @@ -4058,7 +4058,7 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)  done:  	/* Notify the stack of the (possibly) reduced Tx Queue count. */ -	adapter->netdev->real_num_tx_queues = adapter->num_tx_queues; +	netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues);  }  static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, @@ -5246,7 +5246,6 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake)  		ixgbe_free_all_tx_resources(adapter);  		ixgbe_free_all_rx_resources(adapter);  	} -	ixgbe_clear_interrupt_scheme(adapter);  #ifdef CONFIG_PM  	retval = pci_save_state(pdev); @@ -5281,6 +5280,8 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake)  	*enable_wake = !!wufc; +	ixgbe_clear_interrupt_scheme(adapter); +  	ixgbe_release_hw_control(adapter);  	pci_disable_device(pdev); @@ -6071,7 +6072,6 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,  static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb,  	              int queue, u32 tx_flags)  { -	/* Right now, we support IPv4 only */  	struct ixgbe_atr_input atr_input;  	struct tcphdr *th;  	struct iphdr *iph = ip_hdr(skb); @@ -6080,6 +6080,9 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb,  	u32 src_ipv4_addr, dst_ipv4_addr;  	u8 l4type = 0; +	/* Right now, we support IPv4 only */ +	if (skb->protocol != htons(ETH_P_IP)) +		return;  	/* check if we're UDP or TCP */  	if (iph->protocol == IPPROTO_TCP) {  		th = tcp_hdr(skb); diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 7b12d0e8f4b..fa303c881a4 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -985,7 +985,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)  	np = of_parse_phandle(op->dev.of_node, "llink-connected", 0);  	if (!np) {  		dev_err(&op->dev, "could not find DMA node\n"); -		goto nodev; +		goto err_iounmap;  	}  	/* Setup the DMA register accesses, could be DCR or memory mapped */ @@ -999,7 +999,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)  			dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs);  		} else {  			dev_err(&op->dev, "unable to map DMA registers\n"); -			goto nodev; +			goto err_iounmap;  		}  	} @@ -1008,7 +1008,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)  	if ((lp->rx_irq == NO_IRQ) || (lp->tx_irq == NO_IRQ)) {  		dev_err(&op->dev, "could not determine irqs\n");  		rc = -ENOMEM; -		goto nodev; +		goto err_iounmap_2;  	}  	of_node_put(np); /* Finished with the DMA node; drop the reference */ @@ -1018,7 +1018,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)  	if ((!addr) || (size != 6)) {  		dev_err(&op->dev, "could not find MAC address\n");  		rc = -ENODEV; -		goto nodev; +		goto err_iounmap_2;  	}  	temac_set_mac_address(ndev, (void *)addr); @@ -1034,7 +1034,7 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)  	rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group);  	if (rc) {  		dev_err(lp->dev, "Error creating sysfs files\n"); -		goto nodev; +		goto err_iounmap_2;  	}  	rc = register_netdev(lp->ndev); @@ -1047,6 +1047,11 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)   err_register_ndev:  	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group); + err_iounmap_2: +	if (lp->sdma_regs) +		iounmap(lp->sdma_regs); + err_iounmap: +	iounmap(lp->regs);   nodev:  	free_netdev(ndev);  	ndev = NULL; @@ -1065,6 +1070,9 @@ static int __devexit temac_of_remove(struct of_device *op)  		of_node_put(lp->phy_node);  	lp->phy_node = NULL;  	dev_set_drvdata(&op->dev, NULL); +	iounmap(lp->regs); +	if (lp->sdma_regs) +		iounmap(lp->sdma_regs);  	free_netdev(ndev);  	return 0;  } diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 82b720f29c7..af075af20e0 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -289,6 +289,7 @@ struct mv643xx_eth_shared_private {  	unsigned int t_clk;  	int extended_rx_coal_limit;  	int tx_bw_control; +	int tx_csum_limit;  };  #define TX_BW_CONTROL_ABSENT		0 @@ -776,13 +777,16 @@ static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb)  	l4i_chk = 0;  	if (skb->ip_summed == CHECKSUM_PARTIAL) { +		int hdr_len;  		int tag_bytes;  		BUG_ON(skb->protocol != htons(ETH_P_IP) &&  		       skb->protocol != htons(ETH_P_8021Q)); -		tag_bytes = (void *)ip_hdr(skb) - (void *)skb->data - ETH_HLEN; -		if (unlikely(tag_bytes & ~12)) { +		hdr_len = (void *)ip_hdr(skb) - (void *)skb->data; +		tag_bytes = hdr_len - ETH_HLEN; +		if (skb->len - hdr_len > mp->shared->tx_csum_limit || +		    unlikely(tag_bytes & ~12)) {  			if (skb_checksum_help(skb) == 0)  				goto no_csum;  			kfree_skb(skb); @@ -2671,6 +2675,7 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)  	 * Detect hardware parameters.  	 */  	msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000; +	msp->tx_csum_limit = pd->tx_csum_limit ? pd->tx_csum_limit : 9 * 1024;  	infer_hw_params(msp);  	platform_set_drvdata(pdev, msp); diff --git a/drivers/net/ne.c b/drivers/net/ne.c index b8e2923a1d6..1063093b3af 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -806,8 +806,10 @@ static int __init ne_drv_probe(struct platform_device *pdev)  		dev->base_addr = res->start;  		dev->irq = platform_get_irq(pdev, 0);  	} else { -		if (this_dev < 0 || this_dev >= MAX_NE_CARDS) +		if (this_dev < 0 || this_dev >= MAX_NE_CARDS) { +			free_netdev(dev);  			return -EINVAL; +		}  		dev->base_addr = io[this_dev];  		dev->irq = irq[this_dev];  		dev->mem_end = bad[this_dev]; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 64e6a84bbbb..307cd1721e9 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1505,12 +1505,20 @@ irq_done:  	writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR);  	writeb(cor, smc->base + MOT_LAN + CISREG_COR);      } -#ifdef DOES_NOT_WORK -    if (smc->base != NULL) { /* Megahertz MFC's */ -	readb(smc->base+MEGAHERTZ_ISR); -	readb(smc->base+MEGAHERTZ_ISR); + +    if ((smc->base != NULL) &&  /* Megahertz MFC's */ +	(smc->manfid == MANFID_MEGAHERTZ) && +	(smc->cardid == PRODID_MEGAHERTZ_EM3288)) { + +	u_char tmp; +	tmp = readb(smc->base+MEGAHERTZ_ISR); +	tmp = readb(smc->base+MEGAHERTZ_ISR); + +	/* Retrigger interrupt if needed */ +	writeb(tmp, smc->base + MEGAHERTZ_ISR); +	writeb(tmp, smc->base + MEGAHERTZ_ISR);      } -#endif +      spin_unlock(&smc->lock);      return IRQ_RETVAL(handled);  } diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c index dbd00345373..29c39ff85de 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c @@ -226,6 +226,7 @@ module_exit(lxt_exit);  static struct mdio_device_id lxt_tbl[] = {  	{ 0x78100000, 0xfffffff0 },  	{ 0x001378e0, 0xfffffff0 }, +	{ 0x00137a10, 0xfffffff0 },  	{ }  }; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index dd9e86ca7c5..8d63f69b27d 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -4642,8 +4642,7 @@ static void ql_timer(unsigned long data)  		return;  	} -	qdev->timer.expires = jiffies + (5*HZ); -	add_timer(&qdev->timer); +	mod_timer(&qdev->timer, jiffies + (5*HZ));  }  static int __devinit qlge_probe(struct pci_dev *pdev, @@ -4744,6 +4743,8 @@ static void ql_eeh_close(struct net_device *ndev)  		netif_stop_queue(ndev);  	} +	/* Disabling the timer */ +	del_timer_sync(&qdev->timer);  	if (test_bit(QL_ADAPTER_UP, &qdev->flags))  		cancel_delayed_work_sync(&qdev->asic_reset_work);  	cancel_delayed_work_sync(&qdev->mpi_reset_work); @@ -4839,8 +4840,7 @@ static void qlge_io_resume(struct pci_dev *pdev)  		netif_err(qdev, ifup, qdev->ndev,  			  "Device was not running prior to EEH.\n");  	} -	qdev->timer.expires = jiffies + (5*HZ); -	add_timer(&qdev->timer); +	mod_timer(&qdev->timer, jiffies + (5*HZ));  	netif_device_attach(ndev);  } @@ -4902,8 +4902,7 @@ static int qlge_resume(struct pci_dev *pdev)  			return err;  	} -	qdev->timer.expires = jiffies + (5*HZ); -	add_timer(&qdev->timer); +	mod_timer(&qdev->timer, jiffies + (5*HZ));  	netif_device_attach(ndev);  	return 0; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 22371f1dca5..d0af924ddd6 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -3129,7 +3129,6 @@ static void tx_intr_handler(struct fifo_info *fifo_data)  		pkt_cnt++;  		/* Updating the statistics block */ -		nic->dev->stats.tx_bytes += skb->len;  		swstats->mem_freed += skb->truesize;  		dev_kfree_skb_irq(skb); @@ -4900,48 +4899,81 @@ static void s2io_updt_stats(struct s2io_nic *sp)   *  Return value:   *  pointer to the updated net_device_stats structure.   */ -  static struct net_device_stats *s2io_get_stats(struct net_device *dev)  {  	struct s2io_nic *sp = netdev_priv(dev); -	struct config_param *config = &sp->config;  	struct mac_info *mac_control = &sp->mac_control;  	struct stat_block *stats = mac_control->stats_info; -	int i; +	u64 delta;  	/* Configure Stats for immediate updt */  	s2io_updt_stats(sp); -	/* Using sp->stats as a staging area, because reset (due to mtu -	   change, for example) will clear some hardware counters */ -	dev->stats.tx_packets += le32_to_cpu(stats->tmac_frms) - -		sp->stats.tx_packets; -	sp->stats.tx_packets = le32_to_cpu(stats->tmac_frms); +	/* A device reset will cause the on-adapter statistics to be zero'ed. +	 * This can be done while running by changing the MTU.  To prevent the +	 * system from having the stats zero'ed, the driver keeps a copy of the +	 * last update to the system (which is also zero'ed on reset).  This +	 * enables the driver to accurately know the delta between the last +	 * update and the current update. +	 */ +	delta = ((u64) le32_to_cpu(stats->rmac_vld_frms_oflow) << 32 | +		le32_to_cpu(stats->rmac_vld_frms)) - sp->stats.rx_packets; +	sp->stats.rx_packets += delta; +	dev->stats.rx_packets += delta; -	dev->stats.tx_errors += le32_to_cpu(stats->tmac_any_err_frms) - -		sp->stats.tx_errors; -	sp->stats.tx_errors = le32_to_cpu(stats->tmac_any_err_frms); +	delta = ((u64) le32_to_cpu(stats->tmac_frms_oflow) << 32 | +		le32_to_cpu(stats->tmac_frms)) - sp->stats.tx_packets; +	sp->stats.tx_packets += delta; +	dev->stats.tx_packets += delta; -	dev->stats.rx_errors += le64_to_cpu(stats->rmac_drop_frms) - -		sp->stats.rx_errors; -	sp->stats.rx_errors = le64_to_cpu(stats->rmac_drop_frms); +	delta = ((u64) le32_to_cpu(stats->rmac_data_octets_oflow) << 32 | +		le32_to_cpu(stats->rmac_data_octets)) - sp->stats.rx_bytes; +	sp->stats.rx_bytes += delta; +	dev->stats.rx_bytes += delta; -	dev->stats.multicast = le32_to_cpu(stats->rmac_vld_mcst_frms) - -		sp->stats.multicast; -	sp->stats.multicast = le32_to_cpu(stats->rmac_vld_mcst_frms); +	delta = ((u64) le32_to_cpu(stats->tmac_data_octets_oflow) << 32 | +		le32_to_cpu(stats->tmac_data_octets)) - sp->stats.tx_bytes; +	sp->stats.tx_bytes += delta; +	dev->stats.tx_bytes += delta; -	dev->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms) - -		sp->stats.rx_length_errors; -	sp->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms); +	delta = le64_to_cpu(stats->rmac_drop_frms) - sp->stats.rx_errors; +	sp->stats.rx_errors += delta; +	dev->stats.rx_errors += delta; -	/* collect per-ring rx_packets and rx_bytes */ -	dev->stats.rx_packets = dev->stats.rx_bytes = 0; -	for (i = 0; i < config->rx_ring_num; i++) { -		struct ring_info *ring = &mac_control->rings[i]; +	delta = ((u64) le32_to_cpu(stats->tmac_any_err_frms_oflow) << 32 | +		le32_to_cpu(stats->tmac_any_err_frms)) - sp->stats.tx_errors; +	sp->stats.tx_errors += delta; +	dev->stats.tx_errors += delta; -		dev->stats.rx_packets += ring->rx_packets; -		dev->stats.rx_bytes += ring->rx_bytes; -	} +	delta = le64_to_cpu(stats->rmac_drop_frms) - sp->stats.rx_dropped; +	sp->stats.rx_dropped += delta; +	dev->stats.rx_dropped += delta; + +	delta = le64_to_cpu(stats->tmac_drop_frms) - sp->stats.tx_dropped; +	sp->stats.tx_dropped += delta; +	dev->stats.tx_dropped += delta; + +	/* The adapter MAC interprets pause frames as multicast packets, but +	 * does not pass them up.  This erroneously increases the multicast +	 * packet count and needs to be deducted when the multicast frame count +	 * is queried. +	 */ +	delta = (u64) le32_to_cpu(stats->rmac_vld_mcst_frms_oflow) << 32 | +		le32_to_cpu(stats->rmac_vld_mcst_frms); +	delta -= le64_to_cpu(stats->rmac_pause_ctrl_frms); +	delta -= sp->stats.multicast; +	sp->stats.multicast += delta; +	dev->stats.multicast += delta; + +	delta = ((u64) le32_to_cpu(stats->rmac_usized_frms_oflow) << 32 | +		le32_to_cpu(stats->rmac_usized_frms)) + +		le64_to_cpu(stats->rmac_long_frms) - sp->stats.rx_length_errors; +	sp->stats.rx_length_errors += delta; +	dev->stats.rx_length_errors += delta; + +	delta = le64_to_cpu(stats->rmac_fcs_err_frms) - sp->stats.rx_crc_errors; +	sp->stats.rx_crc_errors += delta; +	dev->stats.rx_crc_errors += delta;  	return &dev->stats;  } @@ -7494,15 +7526,11 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)  		}  	} -	/* Updating statistics */ -	ring_data->rx_packets++;  	rxdp->Host_Control = 0;  	if (sp->rxd_mode == RXD_MODE_1) {  		int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2); -		ring_data->rx_bytes += len;  		skb_put(skb, len); -  	} else if (sp->rxd_mode == RXD_MODE_3B) {  		int get_block = ring_data->rx_curr_get_info.block_index;  		int get_off = ring_data->rx_curr_get_info.offset; @@ -7511,7 +7539,6 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)  		unsigned char *buff = skb_push(skb, buf0_len);  		struct buffAdd *ba = &ring_data->ba[get_block][get_off]; -		ring_data->rx_bytes += buf0_len + buf2_len;  		memcpy(buff, ba->ba_0, buf0_len);  		skb_put(skb, buf2_len);  	} diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 47c36e0994f..5e52c75892d 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -745,10 +745,6 @@ struct ring_info {  	/* Buffer Address store. */  	struct buffAdd **ba; - -	/* per-Ring statistics */ -	unsigned long rx_packets; -	unsigned long rx_bytes;  } ____cacheline_aligned;  /* Fifo specific structure */ diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 1f3acc3a5df..79eee306208 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2671,6 +2671,7 @@ static struct platform_driver sbmac_driver = {  	.remove = __exit_p(sbmac_remove),  	.driver = {  		.name = sbmac_string, +		.owner  = THIS_MODULE,  	},  }; diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 28d3ee175e7..dd8a4adf48c 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -104,10 +104,8 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg,  int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)  {  	struct cdc_state	*info = (void *) &dev->data; -	struct usb_cdc_notification notification;  	int			master_ifnum;  	int			retval; -	int			partial;  	unsigned		count;  	__le32			rsp;  	u32			xid = 0, msg_len, request_id; @@ -135,17 +133,13 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)  	if (unlikely(retval < 0 || xid == 0))  		return retval; -	/* Some devices don't respond on the control channel until -	 * polled on the status channel, so do that first. */ -	retval = usb_interrupt_msg( -		dev->udev, -		usb_rcvintpipe(dev->udev, dev->status->desc.bEndpointAddress), -		¬ification, sizeof(notification), &partial, -		RNDIS_CONTROL_TIMEOUT_MS); -	if (unlikely(retval < 0)) -		return retval; +	// FIXME Seems like some devices discard responses when +	// we time out and cancel our "get response" requests... +	// so, this is fragile.  Probably need to poll for status. -	/* Poll the control channel; the request probably completed immediately */ +	/* ignore status endpoint, just poll the control channel; +	 * the request probably completed immediately +	 */  	rsp = buf->msg_type | RNDIS_MSG_COMPLETION;  	for (count = 0; count < 10; count++) {  		memset(buf, 0, CONTROL_BUFFER_SIZE); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 44115eea57f..7eab4071ea2 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1293,6 +1293,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)  		goto out;  	} +	/* netdev_printk() needs this so do it as early as possible */ +	SET_NETDEV_DEV(net, &udev->dev); +  	dev = netdev_priv(net);  	dev->udev = xdev;  	dev->intf = udev; @@ -1377,8 +1380,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)  		dev->rx_urb_size = dev->hard_mtu;  	dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); -	SET_NETDEV_DEV(net, &udev->dev); -  	if ((dev->driver_info->flags & FLAG_WLAN) != 0)  		SET_NETDEV_DEVTYPE(net, &wlan_type);  	if ((dev->driver_info->flags & FLAG_WWAN) != 0) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 1edb7a61983..bb6b67f6b0c 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -415,7 +415,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp)  static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)  {  	int err; -	bool oom = false; +	bool oom;  	do {  		if (vi->mergeable_rx_bufs) @@ -425,10 +425,9 @@ static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)  		else  			err = add_recvbuf_small(vi, gfp); -		if (err < 0) { -			oom = true; +		oom = err == -ENOMEM; +		if (err < 0)  			break; -		}  		++vi->num;  	} while (err > 0);  	if (unlikely(vi->num > vi->max)) @@ -563,7 +562,6 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)  	struct virtnet_info *vi = netdev_priv(dev);  	int capacity; -again:  	/* Free up any pending old buffers before queueing new ones. */  	free_old_xmit_skbs(vi); @@ -572,14 +570,20 @@ again:  	/* This can happen with OOM and indirect buffers. */  	if (unlikely(capacity < 0)) { -		netif_stop_queue(dev); -		dev_warn(&dev->dev, "Unexpected full queue\n"); -		if (unlikely(!virtqueue_enable_cb(vi->svq))) { -			virtqueue_disable_cb(vi->svq); -			netif_start_queue(dev); -			goto again; +		if (net_ratelimit()) { +			if (likely(capacity == -ENOMEM)) { +				dev_warn(&dev->dev, +					 "TX queue failure: out of memory\n"); +			} else { +				dev->stats.tx_fifo_errors++; +				dev_warn(&dev->dev, +					 "Unexpected TX queue failure: %d\n", +					 capacity); +			}  		} -		return NETDEV_TX_BUSY; +		dev->stats.tx_dropped++; +		kfree_skb(skb); +		return NETDEV_TX_OK;  	}  	virtqueue_kick(vi->svq); diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 45c5dc22563..ed1786598c9 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -2262,7 +2262,8 @@ start:  		vxge_debug_init(VXGE_ERR,  			"%s: memory allocation failed",  			VXGE_DRIVER_NAME); -		return  -ENOMEM; +		ret = -ENOMEM; +		goto alloc_entries_failed;  	}  	vdev->vxge_entries = @@ -2271,8 +2272,8 @@ start:  	if (!vdev->vxge_entries) {  		vxge_debug_init(VXGE_ERR, "%s: memory allocation failed",  			VXGE_DRIVER_NAME); -		kfree(vdev->entries); -		return -ENOMEM; +		ret = -ENOMEM; +		goto alloc_vxge_entries_failed;  	}  	for (i = 0, j = 0; i < vdev->no_of_vpath; i++) { @@ -2303,22 +2304,32 @@ start:  		vxge_debug_init(VXGE_ERR,  			"%s: MSI-X enable failed for %d vectors, ret: %d",  			VXGE_DRIVER_NAME, vdev->intr_cnt, ret); +		if ((max_config_vpath != VXGE_USE_DEFAULT) || (ret < 3)) { +			ret = -ENODEV; +			goto enable_msix_failed; +		} +  		kfree(vdev->entries);  		kfree(vdev->vxge_entries);  		vdev->entries = NULL;  		vdev->vxge_entries = NULL; - -		if ((max_config_vpath != VXGE_USE_DEFAULT) || (ret < 3)) -			return -ENODEV;  		/* Try with less no of vector by reducing no of vpaths count */  		temp = (ret - 1)/2;  		vxge_close_vpaths(vdev, temp);  		vdev->no_of_vpath = temp;  		goto start; -	} else if (ret < 0) -		return -ENODEV; - +	} else if (ret < 0) { +		ret = -ENODEV; +		goto enable_msix_failed; +	}  	return 0; + +enable_msix_failed: +	kfree(vdev->vxge_entries); +alloc_vxge_entries_failed: +	kfree(vdev->entries); +alloc_entries_failed: +	return ret;  }  static int vxge_enable_msix(struct vxgedev *vdev) @@ -4515,9 +4526,9 @@ vxge_starter(void)  	char version[32];  	snprintf(version, 32, "%s", DRV_VERSION); -	printk(KERN_CRIT "%s: Copyright(c) 2002-2009 Neterion Inc\n", +	printk(KERN_INFO "%s: Copyright(c) 2002-2009 Neterion Inc\n",  		VXGE_DRIVER_NAME); -	printk(KERN_CRIT "%s: Driver version: %s\n", +	printk(KERN_INFO "%s: Driver version: %s\n",  			VXGE_DRIVER_NAME, version);  	verify_bandwidth(); diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 4c218e91063..107af9e61dc 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -98,7 +98,8 @@ static void tx_poll_start(struct vhost_net *net, struct socket *sock)  static void handle_tx(struct vhost_net *net)  {  	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX]; -	unsigned head, out, in, s; +	unsigned out, in, s; +	int head;  	struct msghdr msg = {  		.msg_name = NULL,  		.msg_namelen = 0, @@ -135,6 +136,9 @@ static void handle_tx(struct vhost_net *net)  					 ARRAY_SIZE(vq->iov),  					 &out, &in,  					 NULL, NULL); +		/* On error, stop handling until the next kick. */ +		if (unlikely(head < 0)) +			break;  		/* Nothing new?  Wait for eventfd to tell us they refilled. */  		if (head == vq->num) {  			wmem = atomic_read(&sock->sk->sk_wmem_alloc); @@ -192,7 +196,8 @@ static void handle_tx(struct vhost_net *net)  static void handle_rx(struct vhost_net *net)  {  	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX]; -	unsigned head, out, in, log, s; +	unsigned out, in, log, s; +	int head;  	struct vhost_log *vq_log;  	struct msghdr msg = {  		.msg_name = NULL, @@ -228,6 +233,9 @@ static void handle_rx(struct vhost_net *net)  					 ARRAY_SIZE(vq->iov),  					 &out, &in,  					 vq_log, &log); +		/* On error, stop handling until the next kick. */ +		if (unlikely(head < 0)) +			break;  		/* OK, now we need to know about added descriptors. */  		if (head == vq->num) {  			if (unlikely(vhost_enable_notify(vq))) { diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 04344b711c5..248ed2db071 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -736,12 +736,12 @@ static int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,  	mem = rcu_dereference(dev->memory);  	while ((u64)len > s) {  		u64 size; -		if (ret >= iov_size) { +		if (unlikely(ret >= iov_size)) {  			ret = -ENOBUFS;  			break;  		}  		reg = find_region(mem, addr, len); -		if (!reg) { +		if (unlikely(!reg)) {  			ret = -EFAULT;  			break;  		} @@ -780,18 +780,18 @@ static unsigned next_desc(struct vring_desc *desc)  	return next;  } -static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, -			     struct iovec iov[], unsigned int iov_size, -			     unsigned int *out_num, unsigned int *in_num, -			     struct vhost_log *log, unsigned int *log_num, -			     struct vring_desc *indirect) +static int get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, +			struct iovec iov[], unsigned int iov_size, +			unsigned int *out_num, unsigned int *in_num, +			struct vhost_log *log, unsigned int *log_num, +			struct vring_desc *indirect)  {  	struct vring_desc desc;  	unsigned int i = 0, count, found = 0;  	int ret;  	/* Sanity check */ -	if (indirect->len % sizeof desc) { +	if (unlikely(indirect->len % sizeof desc)) {  		vq_err(vq, "Invalid length in indirect descriptor: "  		       "len 0x%llx not multiple of 0x%zx\n",  		       (unsigned long long)indirect->len, @@ -801,7 +801,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,  	ret = translate_desc(dev, indirect->addr, indirect->len, vq->indirect,  			     ARRAY_SIZE(vq->indirect)); -	if (ret < 0) { +	if (unlikely(ret < 0)) {  		vq_err(vq, "Translation failure %d in indirect.\n", ret);  		return ret;  	} @@ -813,7 +813,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,  	count = indirect->len / sizeof desc;  	/* Buffers are chained via a 16 bit next field, so  	 * we can have at most 2^16 of these. */ -	if (count > USHRT_MAX + 1) { +	if (unlikely(count > USHRT_MAX + 1)) {  		vq_err(vq, "Indirect buffer length too big: %d\n",  		       indirect->len);  		return -E2BIG; @@ -821,19 +821,19 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,  	do {  		unsigned iov_count = *in_num + *out_num; -		if (++found > count) { +		if (unlikely(++found > count)) {  			vq_err(vq, "Loop detected: last one at %u "  			       "indirect size %u\n",  			       i, count);  			return -EINVAL;  		} -		if (memcpy_fromiovec((unsigned char *)&desc, vq->indirect, -				     sizeof desc)) { +		if (unlikely(memcpy_fromiovec((unsigned char *)&desc, vq->indirect, +					      sizeof desc))) {  			vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n",  			       i, (size_t)indirect->addr + i * sizeof desc);  			return -EINVAL;  		} -		if (desc.flags & VRING_DESC_F_INDIRECT) { +		if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) {  			vq_err(vq, "Nested indirect descriptor: idx %d, %zx\n",  			       i, (size_t)indirect->addr + i * sizeof desc);  			return -EINVAL; @@ -841,7 +841,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,  		ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count,  				     iov_size - iov_count); -		if (ret < 0) { +		if (unlikely(ret < 0)) {  			vq_err(vq, "Translation failure %d indirect idx %d\n",  			       ret, i);  			return ret; @@ -857,7 +857,7 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,  		} else {  			/* If it's an output descriptor, they're all supposed  			 * to come before any input descriptors. */ -			if (*in_num) { +			if (unlikely(*in_num)) {  				vq_err(vq, "Indirect descriptor "  				       "has out after in: idx %d\n", i);  				return -EINVAL; @@ -873,12 +873,13 @@ static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,   * number of output then some number of input descriptors, it's actually two   * iovecs, but we pack them into one and note how many of each there were.   * - * This function returns the descriptor number found, or vq->num (which - * is never a valid descriptor number) if none was found. */ -unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, -			   struct iovec iov[], unsigned int iov_size, -			   unsigned int *out_num, unsigned int *in_num, -			   struct vhost_log *log, unsigned int *log_num) + * This function returns the descriptor number found, or vq->num (which is + * never a valid descriptor number) if none was found.  A negative code is + * returned on error. */ +int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, +		      struct iovec iov[], unsigned int iov_size, +		      unsigned int *out_num, unsigned int *in_num, +		      struct vhost_log *log, unsigned int *log_num)  {  	struct vring_desc desc;  	unsigned int i, head, found = 0; @@ -887,16 +888,16 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,  	/* Check it isn't doing very strange things with descriptor numbers. */  	last_avail_idx = vq->last_avail_idx; -	if (get_user(vq->avail_idx, &vq->avail->idx)) { +	if (unlikely(get_user(vq->avail_idx, &vq->avail->idx))) {  		vq_err(vq, "Failed to access avail idx at %p\n",  		       &vq->avail->idx); -		return vq->num; +		return -EFAULT;  	} -	if ((u16)(vq->avail_idx - last_avail_idx) > vq->num) { +	if (unlikely((u16)(vq->avail_idx - last_avail_idx) > vq->num)) {  		vq_err(vq, "Guest moved used index from %u to %u",  		       last_avail_idx, vq->avail_idx); -		return vq->num; +		return -EFAULT;  	}  	/* If there's nothing new since last we looked, return invalid. */ @@ -908,18 +909,19 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,  	/* Grab the next descriptor number they're advertising, and increment  	 * the index we've seen. */ -	if (get_user(head, &vq->avail->ring[last_avail_idx % vq->num])) { +	if (unlikely(get_user(head, +			      &vq->avail->ring[last_avail_idx % vq->num]))) {  		vq_err(vq, "Failed to read head: idx %d address %p\n",  		       last_avail_idx,  		       &vq->avail->ring[last_avail_idx % vq->num]); -		return vq->num; +		return -EFAULT;  	}  	/* If their number is silly, that's an error. */ -	if (head >= vq->num) { +	if (unlikely(head >= vq->num)) {  		vq_err(vq, "Guest says index %u > %u is available",  		       head, vq->num); -		return vq->num; +		return -EINVAL;  	}  	/* When we start there are none of either input nor output. */ @@ -930,41 +932,41 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,  	i = head;  	do {  		unsigned iov_count = *in_num + *out_num; -		if (i >= vq->num) { +		if (unlikely(i >= vq->num)) {  			vq_err(vq, "Desc index is %u > %u, head = %u",  			       i, vq->num, head); -			return vq->num; +			return -EINVAL;  		} -		if (++found > vq->num) { +		if (unlikely(++found > vq->num)) {  			vq_err(vq, "Loop detected: last one at %u "  			       "vq size %u head %u\n",  			       i, vq->num, head); -			return vq->num; +			return -EINVAL;  		}  		ret = copy_from_user(&desc, vq->desc + i, sizeof desc); -		if (ret) { +		if (unlikely(ret)) {  			vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",  			       i, vq->desc + i); -			return vq->num; +			return -EFAULT;  		}  		if (desc.flags & VRING_DESC_F_INDIRECT) {  			ret = get_indirect(dev, vq, iov, iov_size,  					   out_num, in_num,  					   log, log_num, &desc); -			if (ret < 0) { +			if (unlikely(ret < 0)) {  				vq_err(vq, "Failure detected "  				       "in indirect descriptor at idx %d\n", i); -				return vq->num; +				return ret;  			}  			continue;  		}  		ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count,  				     iov_size - iov_count); -		if (ret < 0) { +		if (unlikely(ret < 0)) {  			vq_err(vq, "Translation failure %d descriptor idx %d\n",  			       ret, i); -			return vq->num; +			return ret;  		}  		if (desc.flags & VRING_DESC_F_WRITE) {  			/* If this is an input descriptor, @@ -978,10 +980,10 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,  		} else {  			/* If it's an output descriptor, they're all supposed  			 * to come before any input descriptors. */ -			if (*in_num) { +			if (unlikely(*in_num)) {  				vq_err(vq, "Descriptor has out after in: "  				       "idx %d\n", i); -				return vq->num; +				return -EINVAL;  			}  			*out_num += ret;  		} diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 44591ba9b07..11ee13dba0f 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -120,10 +120,10 @@ long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);  int vhost_vq_access_ok(struct vhost_virtqueue *vq);  int vhost_log_access_ok(struct vhost_dev *); -unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *, -			   struct iovec iov[], unsigned int iov_count, -			   unsigned int *out_num, unsigned int *in_num, -			   struct vhost_log *log, unsigned int *log_num); +int vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *, +		      struct iovec iov[], unsigned int iov_count, +		      unsigned int *out_num, unsigned int *in_num, +		      struct vhost_log *log, unsigned int *log_num);  void vhost_discard_vq_desc(struct vhost_virtqueue *);  int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len); diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index c1be61f3938..991269e5b15 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -379,6 +379,8 @@ struct ethtool_rxnfc {  	__u32				flow_type;  	/* The rx flow hash value or the rule DB size */  	__u64				data; +	/* The following fields are not valid and must not be used for +	 * the ETHTOOL_{G,X}RXFH commands. */  	struct ethtool_rx_flow_spec	fs;  	__u32				rule_cnt;  	__u32				rule_locs[0]; diff --git a/include/linux/mv643xx_eth.h b/include/linux/mv643xx_eth.h index cbbbe9bfeca..30b0c4e78f9 100644 --- a/include/linux/mv643xx_eth.h +++ b/include/linux/mv643xx_eth.h @@ -19,6 +19,11 @@ struct mv643xx_eth_shared_platform_data {  	struct mbus_dram_target_info	*dram;  	struct platform_device	*shared_smi;  	unsigned int		t_clk; +	/* +	 * Max packet size for Tx IP/Layer 4 checksum, when set to 0, default +	 * limit of 9KiB will be used. +	 */ +	int			tx_csum_limit;  };  #define MV643XX_ETH_PHY_ADDR_DEFAULT	0 diff --git a/include/linux/net.h b/include/linux/net.h index 2b4deeeb864..dee0b11a875 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -129,10 +129,9 @@ struct socket_wq {   *  @type: socket type (%SOCK_STREAM, etc)   *  @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc)   *  @ops: protocol specific socket operations - *  @fasync_list: Asynchronous wake up list   *  @file: File back pointer for gc   *  @sk: internal networking protocol agnostic socket representation - *  @wait: wait queue for several uses + *  @wq: wait queue for several uses   */  struct socket {  	socket_state		state; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 60de65316fd..8018f6bf305 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1674,6 +1674,9 @@ static inline int netif_is_multiqueue(const struct net_device *dev)  	return (dev->num_tx_queues > 1);  } +extern void netif_set_real_num_tx_queues(struct net_device *dev, +					 unsigned int txq); +  /* Use this variant when it is known for sure that it   * is executing from hardware interrupt context or with hardware interrupts   * disabled. @@ -2360,7 +2363,7 @@ do {								\  #endif  #if defined(VERBOSE_DEBUG) -#define netif_vdbg	netdev_dbg +#define netif_vdbg	netif_dbg  #else  #define netif_vdbg(priv, type, dev, format, args...)		\  ({								\ diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 977ec06ed0c..3c8728aaab4 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -336,12 +336,24 @@ extern void qdisc_calculate_pkt_len(struct sk_buff *skb,  extern void tcf_destroy(struct tcf_proto *tp);  extern void tcf_destroy_chain(struct tcf_proto **fl); -/* Reset all TX qdiscs of a device.  */ +/* Reset all TX qdiscs greater then index of a device.  */ +static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i) +{ +	struct Qdisc *qdisc; + +	for (; i < dev->num_tx_queues; i++) { +		qdisc = netdev_get_tx_queue(dev, i)->qdisc; +		if (qdisc) { +			spin_lock_bh(qdisc_lock(qdisc)); +			qdisc_reset(qdisc); +			spin_unlock_bh(qdisc_lock(qdisc)); +		} +	} +} +  static inline void qdisc_reset_all_tx(struct net_device *dev)  { -	unsigned int i; -	for (i = 0; i < dev->num_tx_queues; i++) -		qdisc_reset(netdev_get_tx_queue(dev, i)->qdisc); +	qdisc_reset_all_tx_gt(dev, 0);  }  /* Are all TX queues of the device empty?  */ diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 1913af67c43..fc8f36dd0f5 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1586,7 +1586,7 @@ static inline struct xfrm_state *xfrm_input_state(struct sk_buff *skb)  static inline int xfrm_mark_get(struct nlattr **attrs, struct xfrm_mark *m)  {  	if (attrs[XFRMA_MARK]) -		memcpy(m, nla_data(attrs[XFRMA_MARK]), sizeof(m)); +		memcpy(m, nla_data(attrs[XFRMA_MARK]), sizeof(struct xfrm_mark));  	else  		m->v = m->m = 0; diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index 0faad5ce6dc..8c100c9dae2 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -104,6 +104,8 @@ static void bnep_net_set_mc_list(struct net_device *dev)  				break;  			memcpy(__skb_put(skb, ETH_ALEN), ha->addr, ETH_ALEN);  			memcpy(__skb_put(skb, ETH_ALEN), ha->addr, ETH_ALEN); + +			i++;  		}  		r->len = htons(skb->len - len);  	} diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 9d21d98ae5f..27ae946363f 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -99,6 +99,15 @@ static struct net_bridge_mdb_entry *__br_mdb_ip_get(  	return NULL;  } +static struct net_bridge_mdb_entry *br_mdb_ip_get( +	struct net_bridge_mdb_htable *mdb, struct br_ip *dst) +{ +	if (!mdb) +		return NULL; + +	return __br_mdb_ip_get(mdb, dst, br_ip_hash(mdb, dst)); +} +  static struct net_bridge_mdb_entry *br_mdb_ip4_get(  	struct net_bridge_mdb_htable *mdb, __be32 dst)  { @@ -107,7 +116,7 @@ static struct net_bridge_mdb_entry *br_mdb_ip4_get(  	br_dst.u.ip4 = dst;  	br_dst.proto = htons(ETH_P_IP); -	return __br_mdb_ip_get(mdb, &br_dst, __br_ip4_hash(mdb, dst)); +	return br_mdb_ip_get(mdb, &br_dst);  }  #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) @@ -119,23 +128,17 @@ static struct net_bridge_mdb_entry *br_mdb_ip6_get(  	ipv6_addr_copy(&br_dst.u.ip6, dst);  	br_dst.proto = htons(ETH_P_IPV6); -	return __br_mdb_ip_get(mdb, &br_dst, __br_ip6_hash(mdb, dst)); +	return br_mdb_ip_get(mdb, &br_dst);  }  #endif -static struct net_bridge_mdb_entry *br_mdb_ip_get( -	struct net_bridge_mdb_htable *mdb, struct br_ip *dst) -{ -	return __br_mdb_ip_get(mdb, dst, br_ip_hash(mdb, dst)); -} -  struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,  					struct sk_buff *skb)  {  	struct net_bridge_mdb_htable *mdb = br->mdb;  	struct br_ip ip; -	if (!mdb || br->multicast_disabled) +	if (br->multicast_disabled)  		return NULL;  	if (BR_INPUT_SKB_CB(skb)->igmp) diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 9fdf1b116bd..2c911c0759c 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -598,6 +598,9 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,  	pskb_trim_rcsum(skb, len); +	/* BUG: Should really parse the IP options here. */ +	memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); +  	nf_bridge_put(skb->nf_bridge);  	if (!nf_bridge_alloc(skb))  		return NF_DROP; diff --git a/net/core/dev.c b/net/core/dev.c index 92482d7a87a..eb4201cf9c8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1550,6 +1550,24 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)  	rcu_read_unlock();  } +/* + * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues + * greater then real_num_tx_queues stale skbs on the qdisc must be flushed. + */ +void netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) +{ +	unsigned int real_num = dev->real_num_tx_queues; + +	if (unlikely(txq > dev->num_tx_queues)) +		; +	else if (txq > real_num) +		dev->real_num_tx_queues = txq; +	else if (txq < real_num) { +		dev->real_num_tx_queues = txq; +		qdisc_reset_all_tx_gt(dev, txq); +	} +} +EXPORT_SYMBOL(netif_set_real_num_tx_queues);  static inline void __netif_reschedule(struct Qdisc *q)  { diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 072d1d3796c..7a85367b3c2 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -300,23 +300,33 @@ out:  }  static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, -						void __user *useraddr) +						u32 cmd, void __user *useraddr)  { -	struct ethtool_rxnfc cmd; +	struct ethtool_rxnfc info; +	size_t info_size = sizeof(info);  	if (!dev->ethtool_ops->set_rxnfc)  		return -EOPNOTSUPP; -	if (copy_from_user(&cmd, useraddr, sizeof(cmd))) +	/* struct ethtool_rxnfc was originally defined for +	 * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data +	 * members.  User-space might still be using that +	 * definition. */ +	if (cmd == ETHTOOL_SRXFH) +		info_size = (offsetof(struct ethtool_rxnfc, data) + +			     sizeof(info.data)); + +	if (copy_from_user(&info, useraddr, info_size))  		return -EFAULT; -	return dev->ethtool_ops->set_rxnfc(dev, &cmd); +	return dev->ethtool_ops->set_rxnfc(dev, &info);  }  static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, -						void __user *useraddr) +						u32 cmd, void __user *useraddr)  {  	struct ethtool_rxnfc info; +	size_t info_size = sizeof(info);  	const struct ethtool_ops *ops = dev->ethtool_ops;  	int ret;  	void *rule_buf = NULL; @@ -324,13 +334,22 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,  	if (!ops->get_rxnfc)  		return -EOPNOTSUPP; -	if (copy_from_user(&info, useraddr, sizeof(info))) +	/* struct ethtool_rxnfc was originally defined for +	 * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data +	 * members.  User-space might still be using that +	 * definition. */ +	if (cmd == ETHTOOL_GRXFH) +		info_size = (offsetof(struct ethtool_rxnfc, data) + +			     sizeof(info.data)); + +	if (copy_from_user(&info, useraddr, info_size))  		return -EFAULT;  	if (info.cmd == ETHTOOL_GRXCLSRLALL) {  		if (info.rule_cnt > 0) { -			rule_buf = kmalloc(info.rule_cnt * sizeof(u32), -					   GFP_USER); +			if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32)) +				rule_buf = kmalloc(info.rule_cnt * sizeof(u32), +						   GFP_USER);  			if (!rule_buf)  				return -ENOMEM;  		} @@ -341,7 +360,7 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,  		goto err_out;  	ret = -EFAULT; -	if (copy_to_user(useraddr, &info, sizeof(info))) +	if (copy_to_user(useraddr, &info, info_size))  		goto err_out;  	if (rule_buf) { @@ -1572,12 +1591,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)  	case ETHTOOL_GRXCLSRLCNT:  	case ETHTOOL_GRXCLSRULE:  	case ETHTOOL_GRXCLSRLALL: -		rc = ethtool_get_rxnfc(dev, useraddr); +		rc = ethtool_get_rxnfc(dev, ethcmd, useraddr);  		break;  	case ETHTOOL_SRXFH:  	case ETHTOOL_SRXCLSRLDEL:  	case ETHTOOL_SRXCLSRLINS: -		rc = ethtool_set_rxnfc(dev, useraddr); +		rc = ethtool_set_rxnfc(dev, ethcmd, useraddr);  		break;  	case ETHTOOL_GGRO:  		rc = ethtool_get_gro(dev, useraddr); diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 349327092c9..869078d4eeb 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -108,6 +108,8 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)  	u8 *xprth = skb_network_header(skb) + iph->ihl * 4;  	memset(fl, 0, sizeof(struct flowi)); +	fl->mark = skb->mark; +  	if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) {  		switch (iph->protocol) {  		case IPPROTO_UDP: diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 1fc46fc60ef..58841c4ae94 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -586,6 +586,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,  		src_addr = solicited_addr;  		if (ifp->flags & IFA_F_OPTIMISTIC)  			override = 0; +		inc_opt |= ifp->idev->cnf.force_tllao;  		in6_ifa_put(ifp);  	} else {  		if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr, @@ -599,7 +600,6 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,  	icmp6h.icmp6_solicited = solicited;  	icmp6h.icmp6_override = override; -	inc_opt |= ifp->idev->cnf.force_tllao;  	__ndisc_send(dev, neigh, daddr, src_addr,  		     &icmp6h, solicited_addr,  		     inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 47d22771375..2933396e028 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -97,9 +97,11 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)  	fl.fl_ip_dport = otcph.source;  	security_skb_classify_flow(oldskb, &fl);  	dst = ip6_route_output(net, NULL, &fl); -	if (dst == NULL) +	if (dst == NULL || dst->error) { +		dst_release(dst);  		return; -	if (dst->error || xfrm_lookup(net, &dst, &fl, NULL, 0)) +	} +	if (xfrm_lookup(net, &dst, &fl, NULL, 0))  		return;  	hh_len = (dst->dev->hard_header_len + 15)&~15; diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 4a0e77e1446..6baeabbbca8 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -124,6 +124,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)  	u8 nexthdr = nh[IP6CB(skb)->nhoff];  	memset(fl, 0, sizeof(struct flowi)); +	fl->mark = skb->mark; +  	ipv6_addr_copy(&fl->fl6_dst, reverse ? &hdr->saddr : &hdr->daddr);  	ipv6_addr_copy(&fl->fl6_src, reverse ? &hdr->daddr : &hdr->saddr); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 593c06be6b6..037d956353e 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2300,7 +2300,8 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,  			return 0;  		if (xdst->xfrm_genid != dst->xfrm->genid)  			return 0; -		if (xdst->policy_genid != atomic_read(&xdst->pols[0]->genid)) +		if (xdst->num_pols > 0 && +		    xdst->policy_genid != atomic_read(&xdst->pols[0]->genid))  			return 0;  		if (strict && fl &&  |