From 21d0c83302fb742b7ffb6089d40196166102f5ed Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 19 Sep 2007 10:45:02 -0700 Subject: [PPP] pppoe: Fix double-free on skb after transmit failure When I got rid of the second packet in __pppoe_xmit I created a double-free on the skb because of the goto abort on failure. This patch removes that. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/pppoe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 0d7f570b9a5..9b30cd600a6 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -879,8 +879,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) dev->hard_header(skb, dev, ETH_P_PPP_SES, po->pppoe_pa.remote, NULL, data_len); - if (dev_queue_xmit(skb) < 0) - goto abort; + dev_queue_xmit(skb); return 1; -- cgit v1.2.3 From a14d6abc947a5504e8d0f934da57b5bc4cea59ca Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 18 Sep 2007 13:18:17 -0700 Subject: [PPP] L2TP: Disallow non-UDP datagram sockets With the addition of UDP-Lite we need to refine the socket check so that only genuine UDP sockets are allowed through. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/pppol2tp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 266e8b38fe1..ed8ead432d7 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -1326,12 +1326,14 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id, goto err; } + sk = sock->sk; + /* Quick sanity checks */ - err = -ESOCKTNOSUPPORT; - if (sock->type != SOCK_DGRAM) { + err = -EPROTONOSUPPORT; + if (sk->sk_protocol != IPPROTO_UDP) { PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR, - "tunl %hu: fd %d wrong type, got %d, expected %d\n", - tunnel_id, fd, sock->type, SOCK_DGRAM); + "tunl %hu: fd %d wrong protocol, got %d, expected %d\n", + tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP); goto err; } err = -EAFNOSUPPORT; @@ -1343,7 +1345,6 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id, } err = -ENOTCONN; - sk = sock->sk; /* Check if this socket has already been prepped */ tunnel = (struct pppol2tp_tunnel *)sk->sk_user_data; -- cgit v1.2.3 From 7a70e39b6633ad85936b029463134ee2599600f1 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 18 Sep 2007 13:18:42 -0700 Subject: [PPP] L2TP: Fix skb handling in pppol2tp_recv_core The function pppol2tp_recv_core doesn't handle non-linear packets properly. It also fails to check the remote offset field. This patch fixes these problems. It also removes an unnecessary check on the UDP header which has already been performed by the UDP layer. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/pppol2tp.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index ed8ead432d7..440e190778a 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -491,44 +491,46 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) u16 hdrflags; u16 tunnel_id, session_id; int length; - struct udphdr *uh; + int offset; tunnel = pppol2tp_sock_to_tunnel(sock); if (tunnel == NULL) goto error; + /* UDP always verifies the packet length. */ + __skb_pull(skb, sizeof(struct udphdr)); + /* Short packet? */ - if (skb->len < sizeof(struct udphdr)) { + if (!pskb_may_pull(skb, 12)) { PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO, "%s: recv short packet (len=%d)\n", tunnel->name, skb->len); goto error; } /* Point to L2TP header */ - ptr = skb->data + sizeof(struct udphdr); + ptr = skb->data; /* Get L2TP header flags */ hdrflags = ntohs(*(__be16*)ptr); /* Trace packet contents, if enabled */ if (tunnel->debug & PPPOL2TP_MSG_DATA) { + length = min(16u, skb->len); + if (!pskb_may_pull(skb, length)) + goto error; + printk(KERN_DEBUG "%s: recv: ", tunnel->name); - for (length = 0; length < 16; length++) - printk(" %02X", ptr[length]); + offset = 0; + do { + printk(" %02X", ptr[offset]); + } while (++offset < length); + printk("\n"); } /* Get length of L2TP packet */ - uh = (struct udphdr *) skb_transport_header(skb); - length = ntohs(uh->len) - sizeof(struct udphdr); - - /* Too short? */ - if (length < 12) { - PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO, - "%s: recv short L2TP packet (len=%d)\n", tunnel->name, length); - goto error; - } + length = skb->len; /* If type is control packet, it is handled by userspace. */ if (hdrflags & L2TP_HDRFLAG_T) { @@ -606,7 +608,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) "%s: recv data has no seq numbers when required. " "Discarding\n", session->name); session->stats.rx_seq_discards++; - session->stats.rx_errors++; goto discard; } @@ -625,7 +626,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) "%s: recv data has no seq numbers when required. " "Discarding\n", session->name); session->stats.rx_seq_discards++; - session->stats.rx_errors++; goto discard; } @@ -634,10 +634,14 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) } /* If offset bit set, skip it. */ - if (hdrflags & L2TP_HDRFLAG_O) - ptr += 2 + ntohs(*(__be16 *) ptr); + if (hdrflags & L2TP_HDRFLAG_O) { + offset = ntohs(*(__be16 *)ptr); + skb->transport_header += 2 + offset; + if (!pskb_may_pull(skb, skb_transport_offset(skb) + 2)) + goto discard; + } - skb_pull(skb, ptr - skb->data); + __skb_pull(skb, skb_transport_offset(skb)); /* Skip PPP header, if present. In testing, Microsoft L2TP clients * don't send the PPP header (PPP header compression enabled), but @@ -673,7 +677,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) */ if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) { session->stats.rx_seq_discards++; - session->stats.rx_errors++; PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, "%s: oos pkt %hu len %d discarded, " "waiting for %hu, reorder_q_len=%d\n", @@ -698,6 +701,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) return 0; discard: + session->stats.rx_errors++; kfree_skb(skb); sock_put(session->sock); -- cgit v1.2.3 From f3d5e3a4155b6f42f6f6f0a2cc95ca0adbabe1af Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 19 Sep 2007 10:46:28 -0700 Subject: [PPP] L2TP: Fix skb handling in pppol2tp_xmit This patch makes pppol2tp_xmit call skb_cow_head so that we don't modify cloned skb data. It also gets rid of skb2 we only need to preserve the original skb for congestion notification, which is only applicable for ppp_async and ppp_sync. The other semantic change made here is the removal of socket accounting for data tranmitted out of pppol2tp_xmit. The original code leaked any existing socket skb accounting. We could fix this by dropping the original skb owner. However, this is undesirable as the packet has not physically left the host yet. In fact, all other tunnels in the kernel do not account skb's passing through to their own socket. In partciular, ESP over UDP does not do so and it is the closest tunnel type to PPPoL2TP. So this patch simply removes the socket accounting in pppol2tp_xmit. The accounting still applies to control packets of course. I've also added a reminder that the outgoing checksum here doesn't work. I suppose existing deployments don't actually enable checksums. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/pppol2tp.c | 63 ++++++++++++++++++-------------------------------- 1 file changed, 23 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 440e190778a..abe91cb595f 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -962,7 +962,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) int data_len = skb->len; struct inet_sock *inet; __wsum csum = 0; - struct sk_buff *skb2 = NULL; struct udphdr *uh; unsigned int len; @@ -993,41 +992,30 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) */ headroom = NET_SKB_PAD + sizeof(struct iphdr) + sizeof(struct udphdr) + hdr_len + sizeof(ppph); - if (skb_headroom(skb) < headroom) { - skb2 = skb_realloc_headroom(skb, headroom); - if (skb2 == NULL) - goto abort; - } else - skb2 = skb; - - /* Check that the socket has room */ - if (atomic_read(&sk_tun->sk_wmem_alloc) < sk_tun->sk_sndbuf) - skb_set_owner_w(skb2, sk_tun); - else - goto discard; + if (skb_cow_head(skb, headroom)) + goto abort; /* Setup PPP header */ - skb_push(skb2, sizeof(ppph)); - skb2->data[0] = ppph[0]; - skb2->data[1] = ppph[1]; + __skb_push(skb, sizeof(ppph)); + skb->data[0] = ppph[0]; + skb->data[1] = ppph[1]; /* Setup L2TP header */ - skb_push(skb2, hdr_len); - pppol2tp_build_l2tp_header(session, skb2->data); + pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len)); /* Setup UDP header */ inet = inet_sk(sk_tun); - skb_push(skb2, sizeof(struct udphdr)); - skb_reset_transport_header(skb2); - uh = (struct udphdr *) skb2->data; + __skb_push(skb, sizeof(*uh)); + skb_reset_transport_header(skb); + uh = udp_hdr(skb); uh->source = inet->sport; uh->dest = inet->dport; uh->len = htons(sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len); uh->check = 0; - /* Calculate UDP checksum if configured to do so */ + /* *BROKEN* Calculate UDP checksum if configured to do so */ if (sk_tun->sk_no_check != UDP_CSUM_NOXMIT) - csum = udp_csum_outgoing(sk_tun, skb2); + csum = udp_csum_outgoing(sk_tun, skb); /* Debug */ if (session->send_seq) @@ -1040,7 +1028,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) if (session->debug & PPPOL2TP_MSG_DATA) { int i; - unsigned char *datap = skb2->data; + unsigned char *datap = skb->data; printk(KERN_DEBUG "%s: xmit:", session->name); for (i = 0; i < data_len; i++) { @@ -1053,18 +1041,18 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) printk("\n"); } - memset(&(IPCB(skb2)->opt), 0, sizeof(IPCB(skb2)->opt)); - IPCB(skb2)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | - IPSKB_REROUTED); - nf_reset(skb2); + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); + IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | + IPSKB_REROUTED); + nf_reset(skb); /* Get routing info from the tunnel socket */ - dst_release(skb2->dst); - skb2->dst = sk_dst_get(sk_tun); + dst_release(skb->dst); + skb->dst = sk_dst_get(sk_tun); /* Queue the packet to IP for output */ - len = skb2->len; - rc = ip_queue_xmit(skb2, 1); + len = skb->len; + rc = ip_queue_xmit(skb, 1); /* Update stats */ if (rc >= 0) { @@ -1077,17 +1065,12 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) session->stats.tx_errors++; } - /* Free the original skb */ - kfree_skb(skb); - return 1; -discard: - /* Free the new skb. Caller will free original skb. */ - if (skb2 != skb) - kfree_skb(skb2); abort: - return 0; + /* Free the original skb */ + kfree_skb(skb); + return 1; } /***************************************************************************** -- cgit v1.2.3 From cd46171c7297739dc7e46d885862e98023eab9c7 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 20 Sep 2007 11:04:58 -0700 Subject: [BNX2]: Add PHY workaround for 5709 A1. Add the DIS_EARLY_DAC PHY workaround for 5709 A1. Without it, link sometimes does not come up. Update version to 1.6.5. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 854d80c330e..66eed22cbd2 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -54,8 +54,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.6.4" -#define DRV_MODULE_RELDATE "August 3, 2007" +#define DRV_MODULE_VERSION "1.6.5" +#define DRV_MODULE_RELDATE "September 20, 2007" #define RUN_AT(x) (jiffies + (x)) @@ -6727,7 +6727,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) } else if (CHIP_NUM(bp) == CHIP_NUM_5706 || CHIP_NUM(bp) == CHIP_NUM_5708) bp->phy_flags |= PHY_CRC_FIX_FLAG; - else if (CHIP_ID(bp) == CHIP_ID_5709_A0) + else if (CHIP_ID(bp) == CHIP_ID_5709_A0 || + CHIP_ID(bp) == CHIP_ID_5709_A1) bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG; if ((CHIP_ID(bp) == CHIP_ID_5708_A0) || -- cgit v1.2.3