Skip to content

Commit

Permalink
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/…
Browse files Browse the repository at this point in the history
…davem/net-2.6

* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
  [VLAN]: Fix net_device leak.
  [PPP] generic: Fix receive path data clobbering & non-linear handling
  [PPP] generic: Call skb_cow_head before scribbling over skb
  [NET] skbuff: Add skb_cow_head
  [BRIDGE]: Kill clone argument to br_flood_*
  [PPP] pppoe: Fill in header directly in __pppoe_xmit
  [PPP] pppoe: Fix data clobbering in __pppoe_xmit and return value
  [PPP] pppoe: Fix skb_unshare_check call position
  [SCTP]: Convert bind_addr_list locking to RCU
  [SCTP]: Add RCU synchronization around sctp_localaddr_list
  [PKT_SCHED]: sch_cbq.c: Shut up uninitialized variable warning
  [PKTGEN]: srcmac fix
  [IPV6]: Fix source address selection.
  [IPV4]: Just increment OutDatagrams once per a datagram.
  [IPV6]: Just increment OutDatagrams once per a datagram.
  [IPV6]: Fix unbalanced socket reference with MSG_CONFIRM.
  [NET_SCHED] protect action config/dump from irqs
  [NET]: Fix two issues wrt. SO_BINDTODEVICE.
  • Loading branch information
Linus Torvalds committed Sep 17, 2007
2 parents fa890d5 + d9f30ec commit edb1e96
Show file tree
Hide file tree
Showing 27 changed files with 398 additions and 404 deletions.
58 changes: 28 additions & 30 deletions drivers/net/ppp_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -899,17 +899,9 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)

/* Put the 2-byte PPP protocol number on the front,
making sure there is room for the address and control fields. */
if (skb_headroom(skb) < PPP_HDRLEN) {
struct sk_buff *ns;

ns = alloc_skb(skb->len + dev->hard_header_len, GFP_ATOMIC);
if (ns == 0)
goto outf;
skb_reserve(ns, dev->hard_header_len);
skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len);
kfree_skb(skb);
skb = ns;
}
if (skb_cow_head(skb, PPP_HDRLEN))
goto outf;

pp = skb_push(skb, 2);
proto = npindex_to_proto[npi];
pp[0] = proto >> 8;
Expand Down Expand Up @@ -1533,7 +1525,7 @@ ppp_input_error(struct ppp_channel *chan, int code)
static void
ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
{
if (skb->len >= 2) {
if (pskb_may_pull(skb, 2)) {
#ifdef CONFIG_PPP_MULTILINK
/* XXX do channel-level decompression here */
if (PPP_PROTO(skb) == PPP_MP)
Expand Down Expand Up @@ -1585,7 +1577,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
goto err;

if (skb_tailroom(skb) < 124) {
if (skb_tailroom(skb) < 124 || skb_cloned(skb)) {
/* copy to a new sk_buff with more tailroom */
ns = dev_alloc_skb(skb->len + 128);
if (ns == 0) {
Expand Down Expand Up @@ -1656,23 +1648,29 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
/* check if the packet passes the pass and active filters */
/* the filter instructions are constructed assuming
a four-byte PPP header on each packet */
*skb_push(skb, 2) = 0;
if (ppp->pass_filter
&& sk_run_filter(skb, ppp->pass_filter,
ppp->pass_len) == 0) {
if (ppp->debug & 1)
printk(KERN_DEBUG "PPP: inbound frame not passed\n");
kfree_skb(skb);
return;
}
if (!(ppp->active_filter
&& sk_run_filter(skb, ppp->active_filter,
ppp->active_len) == 0))
ppp->last_recv = jiffies;
skb_pull(skb, 2);
#else
ppp->last_recv = jiffies;
if (ppp->pass_filter || ppp->active_filter) {
if (skb_cloned(skb) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
goto err;

*skb_push(skb, 2) = 0;
if (ppp->pass_filter
&& sk_run_filter(skb, ppp->pass_filter,
ppp->pass_len) == 0) {
if (ppp->debug & 1)
printk(KERN_DEBUG "PPP: inbound frame "
"not passed\n");
kfree_skb(skb);
return;
}
if (!(ppp->active_filter
&& sk_run_filter(skb, ppp->active_filter,
ppp->active_len) == 0))
ppp->last_recv = jiffies;
__skb_pull(skb, 2);
} else
#endif /* CONFIG_PPP_FILTER */
ppp->last_recv = jiffies;

if ((ppp->dev->flags & IFF_UP) == 0
|| ppp->npmode[npi] != NPMODE_PASS) {
Expand Down Expand Up @@ -1770,7 +1768,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
struct channel *ch;
int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;

if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0)
if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0)
goto err; /* no good, throw it away */

/* Decode sequence number and begin/end bits */
Expand Down
70 changes: 22 additions & 48 deletions drivers/net/pppoe.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,12 +385,12 @@ static int pppoe_rcv(struct sk_buff *skb,
struct pppoe_hdr *ph;
struct pppox_sock *po;

if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
goto drop;

if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
goto out;

if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
goto drop;

ph = pppoe_hdr(skb);

po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
Expand Down Expand Up @@ -848,71 +848,45 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
{
struct pppox_sock *po = pppox_sk(sk);
struct net_device *dev = po->pppoe_dev;
struct pppoe_hdr hdr;
struct pppoe_hdr *ph;
int headroom = skb_headroom(skb);
int data_len = skb->len;
struct sk_buff *skb2;

if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
goto abort;

hdr.ver = 1;
hdr.type = 1;
hdr.code = 0;
hdr.sid = po->num;
hdr.length = htons(skb->len);

if (!dev)
goto abort;

/* Copy the skb if there is no space for the header. */
if (headroom < (sizeof(struct pppoe_hdr) + dev->hard_header_len)) {
skb2 = dev_alloc_skb(32+skb->len +
sizeof(struct pppoe_hdr) +
dev->hard_header_len);

if (skb2 == NULL)
goto abort;

skb_reserve(skb2, dev->hard_header_len + sizeof(struct pppoe_hdr));
skb_copy_from_linear_data(skb, skb_put(skb2, skb->len),
skb->len);
} else {
/* Make a clone so as to not disturb the original skb,
* give dev_queue_xmit something it can free.
*/
skb2 = skb_clone(skb, GFP_ATOMIC);

if (skb2 == NULL)
goto abort;
}
/* Copy the data if there is no space for the header or if it's
* read-only.
*/
if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len))
goto abort;

ph = (struct pppoe_hdr *) skb_push(skb2, sizeof(struct pppoe_hdr));
memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
skb2->protocol = __constant_htons(ETH_P_PPP_SES);
__skb_push(skb, sizeof(*ph));
skb_reset_network_header(skb);

skb_reset_network_header(skb2);
ph = pppoe_hdr(skb);
ph->ver = 1;
ph->type = 1;
ph->code = 0;
ph->sid = po->num;
ph->length = htons(data_len);

skb2->dev = dev;
skb->protocol = __constant_htons(ETH_P_PPP_SES);
skb->dev = dev;

dev->hard_header(skb2, dev, ETH_P_PPP_SES,
dev->hard_header(skb, dev, ETH_P_PPP_SES,
po->pppoe_pa.remote, NULL, data_len);

/* We're transmitting skb2, and assuming that dev_queue_xmit
* will free it. The generic ppp layer however, is expecting
* that we give back 'skb' (not 'skb2') in case of failure,
* but free it in case of success.
*/

if (dev_queue_xmit(skb2) < 0)
if (dev_queue_xmit(skb) < 0)
goto abort;

kfree_skb(skb);
return 1;

abort:
return 0;
kfree_skb(skb);
return 1;
}


Expand Down
40 changes: 31 additions & 9 deletions include/linux/skbuff.h
Original file line number Diff line number Diff line change
Expand Up @@ -1352,6 +1352,22 @@ static inline int skb_clone_writable(struct sk_buff *skb, int len)
skb_headroom(skb) + len <= skb->hdr_len;
}

static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom,
int cloned)
{
int delta = 0;

if (headroom < NET_SKB_PAD)
headroom = NET_SKB_PAD;
if (headroom > skb_headroom(skb))
delta = headroom - skb_headroom(skb);

if (delta || cloned)
return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0,
GFP_ATOMIC);
return 0;
}

/**
* skb_cow - copy header of skb when it is required
* @skb: buffer to cow
Expand All @@ -1366,16 +1382,22 @@ static inline int skb_clone_writable(struct sk_buff *skb, int len)
*/
static inline int skb_cow(struct sk_buff *skb, unsigned int headroom)
{
int delta = (headroom > NET_SKB_PAD ? headroom : NET_SKB_PAD) -
skb_headroom(skb);

if (delta < 0)
delta = 0;
return __skb_cow(skb, headroom, skb_cloned(skb));
}

if (delta || skb_cloned(skb))
return pskb_expand_head(skb, (delta + (NET_SKB_PAD-1)) &
~(NET_SKB_PAD-1), 0, GFP_ATOMIC);
return 0;
/**
* skb_cow_head - skb_cow but only making the head writable
* @skb: buffer to cow
* @headroom: needed headroom
*
* This function is identical to skb_cow except that we replace the
* skb_cloned check by skb_header_cloned. It should be used when
* you only need to push on some header and do not need to modify
* the data.
*/
static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom)
{
return __skb_cow(skb, headroom, skb_header_cloned(skb));
}

/**
Expand Down
1 change: 1 addition & 0 deletions include/net/sctp/sctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
* sctp/protocol.c
*/
extern struct sock *sctp_get_ctl_sock(void);
extern void sctp_local_addr_free(struct rcu_head *head);
extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
sctp_scope_t, gfp_t gfp,
int flags);
Expand Down
13 changes: 9 additions & 4 deletions include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ extern struct sctp_globals {
* It is a list of sctp_sockaddr_entry.
*/
struct list_head local_addr_list;

/* Lock that protects the local_addr_list writers */
spinlock_t addr_list_lock;

/* Flag to indicate if addip is enabled. */
int addip_enable;
Expand Down Expand Up @@ -242,6 +245,7 @@ extern struct sctp_globals {
#define sctp_port_alloc_lock (sctp_globals.port_alloc_lock)
#define sctp_port_hashtable (sctp_globals.port_hashtable)
#define sctp_local_addr_list (sctp_globals.local_addr_list)
#define sctp_local_addr_lock (sctp_globals.addr_list_lock)
#define sctp_addip_enable (sctp_globals.addip_enable)
#define sctp_prsctp_enable (sctp_globals.prsctp_enable)

Expand Down Expand Up @@ -737,8 +741,10 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk);
/* This is a structure for holding either an IPv6 or an IPv4 address. */
struct sctp_sockaddr_entry {
struct list_head list;
struct rcu_head rcu;
union sctp_addr a;
__u8 use_as_src;
__u8 valid;
};

typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *);
Expand Down Expand Up @@ -1149,7 +1155,9 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
int flags);
int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
__u8 use_as_src, gfp_t gfp);
int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
void (*rcu_call)(struct rcu_head *,
void (*func)(struct rcu_head *)));
int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
struct sctp_sock *);
union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
Expand Down Expand Up @@ -1220,9 +1228,6 @@ struct sctp_ep_common {
* bind_addr.address_list is our set of local IP addresses.
*/
struct sctp_bind_addr bind_addr;

/* Protection during address list comparisons. */
rwlock_t addr_lock;
};


Expand Down
2 changes: 0 additions & 2 deletions net/8021q/vlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,8 +562,6 @@ static int register_vlan_device(struct net_device *real_dev,
if (err < 0)
goto out_free_newdev;

/* Account for reference in struct vlan_dev_info */
dev_hold(real_dev);
#ifdef VLAN_DEBUG
printk(VLAN_DBG "Allocated new device successfully, returning.\n");
#endif
Expand Down
4 changes: 2 additions & 2 deletions net/bridge/br_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
skb_pull(skb, ETH_HLEN);

if (dest[0] & 1)
br_flood_deliver(br, skb, 0);
br_flood_deliver(br, skb);
else if ((dst = __br_fdb_get(br, dest)) != NULL)
br_deliver(dst->dst, skb);
else
br_flood_deliver(br, skb, 0);
br_flood_deliver(br, skb);

return 0;
}
Expand Down
21 changes: 5 additions & 16 deletions net/bridge/br_forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,24 +100,13 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
}

/* called under bridge lock */
static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
static void br_flood(struct net_bridge *br, struct sk_buff *skb,
void (*__packet_hook)(const struct net_bridge_port *p,
struct sk_buff *skb))
{
struct net_bridge_port *p;
struct net_bridge_port *prev;

if (clone) {
struct sk_buff *skb2;

if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
br->statistics.tx_dropped++;
return;
}

skb = skb2;
}

prev = NULL;

list_for_each_entry_rcu(p, &br->port_list, list) {
Expand Down Expand Up @@ -148,13 +137,13 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,


/* called with rcu_read_lock */
void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, int clone)
void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
{
br_flood(br, skb, clone, __br_deliver);
br_flood(br, skb, __br_deliver);
}

/* called under bridge lock */
void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, int clone)
void br_flood_forward(struct net_bridge *br, struct sk_buff *skb)
{
br_flood(br, skb, clone, __br_forward);
br_flood(br, skb, __br_forward);
}
Loading

0 comments on commit edb1e96

Please sign in to comment.