diff options
Diffstat (limited to 'net/tipc/msg.c')
| -rw-r--r-- | net/tipc/msg.c | 159 | 
1 files changed, 94 insertions, 65 deletions
diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 9680be6d388a..a687b30a699c 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -56,15 +56,42 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,  	msg_set_size(m, hsize);  	msg_set_prevnode(m, tipc_own_addr);  	msg_set_type(m, type); -	msg_set_orignode(m, tipc_own_addr); -	msg_set_destnode(m, destnode); +	if (hsize > SHORT_H_SIZE) { +		msg_set_orignode(m, tipc_own_addr); +		msg_set_destnode(m, destnode); +	} +} + +struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz, +				uint data_sz, u32 dnode, u32 onode, +				u32 dport, u32 oport, int errcode) +{ +	struct tipc_msg *msg; +	struct sk_buff *buf; + +	buf = tipc_buf_acquire(hdr_sz + data_sz); +	if (unlikely(!buf)) +		return NULL; + +	msg = buf_msg(buf); +	tipc_msg_init(msg, user, type, hdr_sz, dnode); +	msg_set_size(msg, hdr_sz + data_sz); +	msg_set_prevnode(msg, onode); +	msg_set_origport(msg, oport); +	msg_set_destport(msg, dport); +	msg_set_errcode(msg, errcode); +	if (hdr_sz > SHORT_H_SIZE) { +		msg_set_orignode(msg, onode); +		msg_set_destnode(msg, dnode); +	} +	return buf;  }  /* tipc_buf_append(): Append a buffer to the fragment list of another buffer   * @*headbuf: in:  NULL for first frag, otherwise value returned from prev call   *            out: set when successful non-complete reassembly, otherwise NULL   * @*buf:     in:  the buffer to append. Always defined - *            out: head buf after sucessful complete reassembly, otherwise NULL + *            out: head buf after successful complete reassembly, otherwise NULL   * Returns 1 when reassembly complete, otherwise 0   */  int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) @@ -135,15 +162,16 @@ err:  /**   * tipc_msg_build - create buffer chain containing specified header and data   * @mhdr: Message header, to be prepended to data - * @iov: User data + * @m: User message   * @offset: Posision in iov to start copying from   * @dsz: Total length of user data   * @pktmax: Max packet size that can be used - * @chain: Buffer or chain of buffers to be returned to caller + * @list: Buffer or chain of buffers to be returned to caller + *   * Returns message data size or errno: -ENOMEM, -EFAULT   */ -int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, -		   int offset, int dsz, int pktmax , struct sk_buff **chain) +int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset, +		   int dsz, int pktmax, struct sk_buff_head *list)  {  	int mhsz = msg_hdr_sz(mhdr);  	int msz = mhsz + dsz; @@ -152,7 +180,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,  	int pktrem = pktmax;  	int drem = dsz;  	struct tipc_msg pkthdr; -	struct sk_buff *buf, *prev; +	struct sk_buff *skb;  	char *pktpos;  	int rc; @@ -160,13 +188,14 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,  	/* No fragmentation needed? */  	if (likely(msz <= pktmax)) { -		buf = tipc_buf_acquire(msz); -		*chain = buf; -		if (unlikely(!buf)) +		skb = tipc_buf_acquire(msz); +		if (unlikely(!skb))  			return -ENOMEM; -		skb_copy_to_linear_data(buf, mhdr, mhsz); -		pktpos = buf->data + mhsz; -		if (!dsz || !memcpy_fromiovecend(pktpos, iov, offset, dsz)) +		__skb_queue_tail(list, skb); +		skb_copy_to_linear_data(skb, mhdr, mhsz); +		pktpos = skb->data + mhsz; +		if (!dsz || !memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset, +						 dsz))  			return dsz;  		rc = -EFAULT;  		goto error; @@ -179,14 +208,15 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,  	msg_set_fragm_no(&pkthdr, pktno);  	/* Prepare first fragment */ -	*chain = buf = tipc_buf_acquire(pktmax); -	if (!buf) +	skb = tipc_buf_acquire(pktmax); +	if (!skb)  		return -ENOMEM; -	pktpos = buf->data; -	skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE); +	__skb_queue_tail(list, skb); +	pktpos = skb->data; +	skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE);  	pktpos += INT_H_SIZE;  	pktrem -= INT_H_SIZE; -	skb_copy_to_linear_data_offset(buf, INT_H_SIZE, mhdr, mhsz); +	skb_copy_to_linear_data_offset(skb, INT_H_SIZE, mhdr, mhsz);  	pktpos += mhsz;  	pktrem -= mhsz; @@ -194,7 +224,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,  		if (drem < pktrem)  			pktrem = drem; -		if (memcpy_fromiovecend(pktpos, iov, offset, pktrem)) { +		if (memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset, pktrem)) {  			rc = -EFAULT;  			goto error;  		} @@ -209,42 +239,41 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,  			pktsz = drem + INT_H_SIZE;  		else  			pktsz = pktmax; -		prev = buf; -		buf = tipc_buf_acquire(pktsz); -		if (!buf) { +		skb = tipc_buf_acquire(pktsz); +		if (!skb) {  			rc = -ENOMEM;  			goto error;  		} -		prev->next = buf; +		__skb_queue_tail(list, skb);  		msg_set_type(&pkthdr, FRAGMENT);  		msg_set_size(&pkthdr, pktsz);  		msg_set_fragm_no(&pkthdr, ++pktno); -		skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE); -		pktpos = buf->data + INT_H_SIZE; +		skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE); +		pktpos = skb->data + INT_H_SIZE;  		pktrem = pktsz - INT_H_SIZE;  	} while (1); - -	msg_set_type(buf_msg(buf), LAST_FRAGMENT); +	msg_set_type(buf_msg(skb), LAST_FRAGMENT);  	return dsz;  error: -	kfree_skb_list(*chain); -	*chain = NULL; +	__skb_queue_purge(list); +	__skb_queue_head_init(list);  	return rc;  }  /**   * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one - * @bbuf: the existing buffer ("bundle") - * @buf:  buffer to be appended + * @list: the buffer chain of the existing buffer ("bundle") + * @skb:  buffer to be appended   * @mtu:  max allowable size for the bundle buffer   * Consumes buffer if successful   * Returns true if bundling could be performed, otherwise false   */ -bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu) +bool tipc_msg_bundle(struct sk_buff_head *list, struct sk_buff *skb, u32 mtu)  { -	struct tipc_msg *bmsg = buf_msg(bbuf); -	struct tipc_msg *msg = buf_msg(buf); +	struct sk_buff *bskb = skb_peek_tail(list); +	struct tipc_msg *bmsg = buf_msg(bskb); +	struct tipc_msg *msg = buf_msg(skb);  	unsigned int bsz = msg_size(bmsg);  	unsigned int msz = msg_size(msg);  	u32 start = align(bsz); @@ -259,35 +288,36 @@ bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu)  		return false;  	if (likely(msg_user(bmsg) != MSG_BUNDLER))  		return false; -	if (likely(msg_type(bmsg) != BUNDLE_OPEN)) +	if (likely(!TIPC_SKB_CB(bskb)->bundling))  		return false; -	if (unlikely(skb_tailroom(bbuf) < (pad + msz))) +	if (unlikely(skb_tailroom(bskb) < (pad + msz)))  		return false;  	if (unlikely(max < (start + msz)))  		return false; -	skb_put(bbuf, pad + msz); -	skb_copy_to_linear_data_offset(bbuf, start, buf->data, msz); +	skb_put(bskb, pad + msz); +	skb_copy_to_linear_data_offset(bskb, start, skb->data, msz);  	msg_set_size(bmsg, start + msz);  	msg_set_msgcnt(bmsg, msg_msgcnt(bmsg) + 1); -	bbuf->next = buf->next; -	kfree_skb(buf); +	kfree_skb(skb);  	return true;  }  /**   * tipc_msg_make_bundle(): Create bundle buf and append message to its tail - * @buf:  buffer to be appended and replaced - * @mtu:  max allowable size for the bundle buffer, inclusive header + * @list: the buffer chain + * @skb: buffer to be appended and replaced + * @mtu: max allowable size for the bundle buffer, inclusive header   * @dnode: destination node for message. (Not always present in header)   * Replaces buffer if successful - * Returns true if sucess, otherwise false + * Returns true if success, otherwise false   */ -bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode) +bool tipc_msg_make_bundle(struct sk_buff_head *list, struct sk_buff *skb, +			  u32 mtu, u32 dnode)  { -	struct sk_buff *bbuf; +	struct sk_buff *bskb;  	struct tipc_msg *bmsg; -	struct tipc_msg *msg = buf_msg(*buf); +	struct tipc_msg *msg = buf_msg(skb);  	u32 msz = msg_size(msg);  	u32 max = mtu - INT_H_SIZE; @@ -300,20 +330,19 @@ bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode)  	if (msz > (max / 2))  		return false; -	bbuf = tipc_buf_acquire(max); -	if (!bbuf) +	bskb = tipc_buf_acquire(max); +	if (!bskb)  		return false; -	skb_trim(bbuf, INT_H_SIZE); -	bmsg = buf_msg(bbuf); -	tipc_msg_init(bmsg, MSG_BUNDLER, BUNDLE_OPEN, INT_H_SIZE, dnode); +	skb_trim(bskb, INT_H_SIZE); +	bmsg = buf_msg(bskb); +	tipc_msg_init(bmsg, MSG_BUNDLER, 0, INT_H_SIZE, dnode);  	msg_set_seqno(bmsg, msg_seqno(msg));  	msg_set_ack(bmsg, msg_ack(msg));  	msg_set_bcast_ack(bmsg, msg_bcast_ack(msg)); -	bbuf->next = (*buf)->next; -	tipc_msg_bundle(bbuf, *buf, mtu); -	*buf = bbuf; -	return true; +	TIPC_SKB_CB(bskb)->bundling = true; +	__skb_queue_tail(list, bskb); +	return tipc_msg_bundle(list, skb, mtu);  }  /** @@ -399,22 +428,23 @@ int tipc_msg_eval(struct sk_buff *buf, u32 *dnode)  /* tipc_msg_reassemble() - clone a buffer chain of fragments and   *                         reassemble the clones into one message   */ -struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain) +struct sk_buff *tipc_msg_reassemble(struct sk_buff_head *list)  { -	struct sk_buff *buf = chain; -	struct sk_buff *frag = buf; +	struct sk_buff *skb; +	struct sk_buff *frag = NULL;  	struct sk_buff *head = NULL;  	int hdr_sz;  	/* Copy header if single buffer */ -	if (!buf->next) { -		hdr_sz = skb_headroom(buf) + msg_hdr_sz(buf_msg(buf)); -		return __pskb_copy(buf, hdr_sz, GFP_ATOMIC); +	if (skb_queue_len(list) == 1) { +		skb = skb_peek(list); +		hdr_sz = skb_headroom(skb) + msg_hdr_sz(buf_msg(skb)); +		return __pskb_copy(skb, hdr_sz, GFP_ATOMIC);  	}  	/* Clone all fragments and reassemble */ -	while (buf) { -		frag = skb_clone(buf, GFP_ATOMIC); +	skb_queue_walk(list, skb) { +		frag = skb_clone(skb, GFP_ATOMIC);  		if (!frag)  			goto error;  		frag->next = NULL; @@ -422,7 +452,6 @@ struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain)  			break;  		if (!head)  			goto error; -		buf = buf->next;  	}  	return frag;  error:  | 
