dp83640: Fix length check for event timestamp status messages

Event timestamp status messages have a variable length, ranging from
1 to 5 words (16 bit words). The current code however requires
a minimum message length of sizeof(*phy_txts). In most cases this
condition is fulfilled due to padding bytes. However, if several events
are signaled in a single message, padding bytes may not be present.
For short event timestamp status messages, the length check will fail,
and the event timestamp will be dropped.

Signed-off-by: Christian Riesch <christian.riesch@omicron.at>
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Christian Riesch 2014-08-21 15:17:04 +02:00 committed by David S. Miller
parent b4834c86e1
commit 13322f2e66

View File

@ -721,7 +721,7 @@ static inline u16 exts_chan_to_edata(int ch)
}
static int decode_evnt(struct dp83640_private *dp83640,
void *data, u16 ests)
void *data, int len, u16 ests)
{
struct phy_txts *phy_txts;
struct ptp_clock_event event;
@ -729,6 +729,16 @@ static int decode_evnt(struct dp83640_private *dp83640,
int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK;
u16 ext_status = 0;
/* calculate length of the event timestamp status message */
if (ests & MULT_EVNT)
parsed = (words + 2) * sizeof(u16);
else
parsed = (words + 1) * sizeof(u16);
/* check if enough data is available */
if (len < parsed)
return len;
if (ests & MULT_EVNT) {
ext_status = *(u16 *) data;
data += sizeof(ext_status);
@ -747,10 +757,7 @@ static int decode_evnt(struct dp83640_private *dp83640,
dp83640->edata.ns_lo = phy_txts->ns_lo;
}
if (ext_status) {
parsed = words + 2;
} else {
parsed = words + 1;
if (!ext_status) {
i = ((ests >> EVNT_NUM_SHIFT) & EVNT_NUM_MASK) - EXT_EVENT;
ext_status = exts_chan_to_edata(i);
}
@ -768,7 +775,7 @@ static int decode_evnt(struct dp83640_private *dp83640,
}
}
return parsed * sizeof(u16);
return parsed;
}
static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts)
@ -905,9 +912,9 @@ static void decode_status_frame(struct dp83640_private *dp83640,
decode_txts(dp83640, phy_txts);
size = sizeof(*phy_txts);
} else if (PSF_EVNT == type && len >= sizeof(*phy_txts)) {
} else if (PSF_EVNT == type) {
size = decode_evnt(dp83640, ptr, ests);
size = decode_evnt(dp83640, ptr, len, ests);
} else {
size = 0;