Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit edb1e967 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/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.
parents fa890d58 d9f30ec0
Loading
Loading
Loading
Loading
+28 −30
Original line number Diff line number Diff line
@@ -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)
	if (skb_cow_head(skb, PPP_HDRLEN))
		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;
	}

	pp = skb_push(skb, 2);
	proto = npindex_to_proto[npi];
	pp[0] = proto >> 8;
@@ -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)
@@ -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) {
@@ -1656,12 +1648,18 @@ 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 */
		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");
					printk(KERN_DEBUG "PPP: inbound frame "
					       "not passed\n");
				kfree_skb(skb);
				return;
			}
@@ -1669,10 +1667,10 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
			      && sk_run_filter(skb, ppp->active_filter,
					       ppp->active_len) == 0))
				ppp->last_recv = jiffies;
		skb_pull(skb, 2);
#else
		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) {
@@ -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 */
+22 −48
Original line number Diff line number Diff line
@@ -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);
@@ -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.
	/* Copy the data if there is no space for the header or if it's
	 * read-only.
	 */
		skb2 = skb_clone(skb, GFP_ATOMIC);

		if (skb2 == NULL)
	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;
}


+31 −9
Original line number Diff line number Diff line
@@ -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
@@ -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));
}

/**
+1 −0
Original line number Diff line number Diff line
@@ -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);
+9 −4
Original line number Diff line number Diff line
@@ -208,6 +208,9 @@ extern struct sctp_globals {
	 */
	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;

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

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


Loading