dect
/
linux-2.6
Archived
13
0
Fork 0

Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

This commit is contained in:
David S. Miller 2010-07-07 15:59:38 -07:00
commit 597e608a84
46 changed files with 734 additions and 435 deletions

View File

@ -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>

View File

@ -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)

View File

@ -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;

View File

@ -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);
}
/*

View File

@ -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);
}

View File

@ -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} },

View File

@ -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,

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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))) {

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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];

View File

@ -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);
}

View File

@ -226,6 +226,7 @@ module_exit(lxt_exit);
static struct mdio_device_id lxt_tbl[] = {
{ 0x78100000, 0xfffffff0 },
{ 0x001378e0, 0xfffffff0 },
{ 0x00137a10, 0xfffffff0 },
{ }
};

View File

@ -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;

View File

@ -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);
}

View File

@ -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 */

View File

@ -2671,6 +2671,7 @@ static struct platform_driver sbmac_driver = {
.remove = __exit_p(sbmac_remove),
.driver = {
.name = sbmac_string,
.owner = THIS_MODULE,
},
};

View File

@ -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),
&notification, 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);

View File

@ -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)

View File

@ -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);

View File

@ -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();

View File

@ -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))) {

View File

@ -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;
}

View File

@ -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);

View File

@ -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];

View File

@ -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

View File

@ -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;

View File

@ -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...) \
({ \

View File

@ -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? */

View File

@ -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;

View File

@ -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);
}

View File

@ -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)

View File

@ -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;

View File

@ -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)
{

View File

@ -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);

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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 &&