diff options
Diffstat (limited to 'net/tipc/msg.c')
| -rw-r--r-- | net/tipc/msg.c | 153 | 
1 files changed, 106 insertions, 47 deletions
| diff --git a/net/tipc/msg.c b/net/tipc/msg.c index a687b30a699c..b6eb90cd3ef7 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -34,6 +34,7 @@   * POSSIBILITY OF SUCH DAMAGE.   */ +#include <net/sock.h>  #include "core.h"  #include "msg.h"  #include "addr.h" @@ -46,25 +47,48 @@ static unsigned int align(unsigned int i)  	return (i + 3) & ~3u;  } -void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, -		   u32 destnode) +/** + * tipc_buf_acquire - creates a TIPC message buffer + * @size: message size (including TIPC header) + * + * Returns a new buffer with data pointers set to the specified size. + * + * NOTE: Headroom is reserved to allow prepending of a data link header. + *       There may also be unrequested tailroom present at the buffer's end. + */ +struct sk_buff *tipc_buf_acquire(u32 size) +{ +	struct sk_buff *skb; +	unsigned int buf_size = (BUF_HEADROOM + size + 3) & ~3u; + +	skb = alloc_skb_fclone(buf_size, GFP_ATOMIC); +	if (skb) { +		skb_reserve(skb, BUF_HEADROOM); +		skb_put(skb, size); +		skb->next = NULL; +	} +	return skb; +} + +void tipc_msg_init(u32 own_node, struct tipc_msg *m, u32 user, u32 type, +		   u32 hsize, u32 dnode)  {  	memset(m, 0, hsize);  	msg_set_version(m);  	msg_set_user(m, user);  	msg_set_hdr_sz(m, hsize);  	msg_set_size(m, hsize); -	msg_set_prevnode(m, tipc_own_addr); +	msg_set_prevnode(m, own_node);  	msg_set_type(m, type);  	if (hsize > SHORT_H_SIZE) { -		msg_set_orignode(m, tipc_own_addr); -		msg_set_destnode(m, destnode); +		msg_set_orignode(m, own_node); +		msg_set_destnode(m, dnode);  	}  } -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 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; @@ -74,9 +98,8 @@ struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,  		return NULL;  	msg = buf_msg(buf); -	tipc_msg_init(msg, user, type, hdr_sz, dnode); +	tipc_msg_init(onode, 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); @@ -163,15 +186,14 @@ err:   * tipc_msg_build - create buffer chain containing specified header and data   * @mhdr: Message header, to be prepended to 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   * @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 msghdr *m, int offset, -		   int dsz, int pktmax, struct sk_buff_head *list) +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; @@ -191,19 +213,19 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,  		skb = tipc_buf_acquire(msz);  		if (unlikely(!skb))  			return -ENOMEM; +		skb_orphan(skb);  		__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)) +		if (copy_from_iter(pktpos, dsz, &m->msg_iter) == dsz)  			return dsz;  		rc = -EFAULT;  		goto error;  	}  	/* Prepare reusable fragment header */ -	tipc_msg_init(&pkthdr, MSG_FRAGMENTER, FIRST_FRAGMENT, -		      INT_H_SIZE, msg_destnode(mhdr)); +	tipc_msg_init(msg_prevnode(mhdr), &pkthdr, MSG_FRAGMENTER, +		      FIRST_FRAGMENT, INT_H_SIZE, msg_destnode(mhdr));  	msg_set_size(&pkthdr, pktmax);  	msg_set_fragm_no(&pkthdr, pktno); @@ -211,6 +233,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,  	skb = tipc_buf_acquire(pktmax);  	if (!skb)  		return -ENOMEM; +	skb_orphan(skb);  	__skb_queue_tail(list, skb);  	pktpos = skb->data;  	skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE); @@ -224,12 +247,11 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,  		if (drem < pktrem)  			pktrem = drem; -		if (memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset, pktrem)) { +		if (copy_from_iter(pktpos, pktrem, &m->msg_iter) != pktrem) {  			rc = -EFAULT;  			goto error;  		}  		drem -= pktrem; -		offset += pktrem;  		if (!drem)  			break; @@ -244,6 +266,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,  			rc = -ENOMEM;  			goto error;  		} +		skb_orphan(skb);  		__skb_queue_tail(list, skb);  		msg_set_type(&pkthdr, FRAGMENT);  		msg_set_size(&pkthdr, pktsz); @@ -304,6 +327,40 @@ bool tipc_msg_bundle(struct sk_buff_head *list, struct sk_buff *skb, u32 mtu)  }  /** + *  tipc_msg_extract(): extract bundled inner packet from buffer + *  @skb: linear outer buffer, to be extracted from. + *  @iskb: extracted inner buffer, to be returned + *  @pos: position of msg to be extracted. Returns with pointer of next msg + *  Consumes outer buffer when last packet extracted + *  Returns true when when there is an extracted buffer, otherwise false + */ +bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos) +{ +	struct tipc_msg *msg = buf_msg(skb); +	int imsz; +	struct tipc_msg *imsg = (struct tipc_msg *)(msg_data(msg) + *pos); + +	/* Is there space left for shortest possible message? */ +	if (*pos > (msg_data_sz(msg) - SHORT_H_SIZE)) +		goto none; +	imsz = msg_size(imsg); + +	/* Is there space left for current message ? */ +	if ((*pos + imsz) > msg_data_sz(msg)) +		goto none; +	*iskb = tipc_buf_acquire(imsz); +	if (!*iskb) +		goto none; +	skb_copy_to_linear_data(*iskb, imsg, imsz); +	*pos += align(imsz); +	return true; +none: +	kfree_skb(skb); +	*iskb = NULL; +	return false; +} + +/**   * tipc_msg_make_bundle(): Create bundle buf and append message to its tail   * @list: the buffer chain   * @skb: buffer to be appended and replaced @@ -312,8 +369,8 @@ bool tipc_msg_bundle(struct sk_buff_head *list, struct sk_buff *skb, u32 mtu)   * Replaces buffer if successful   * Returns true if success, otherwise false   */ -bool tipc_msg_make_bundle(struct sk_buff_head *list, struct sk_buff *skb, -			  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 *bskb;  	struct tipc_msg *bmsg; @@ -336,7 +393,8 @@ bool tipc_msg_make_bundle(struct sk_buff_head *list, struct sk_buff *skb,  	skb_trim(bskb, INT_H_SIZE);  	bmsg = buf_msg(bskb); -	tipc_msg_init(bmsg, MSG_BUNDLER, 0, INT_H_SIZE, dnode); +	tipc_msg_init(msg_prevnode(msg), 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)); @@ -353,7 +411,8 @@ bool tipc_msg_make_bundle(struct sk_buff_head *list, struct sk_buff *skb,   * Consumes buffer if failure   * Returns true if success, otherwise false   */ -bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err) +bool tipc_msg_reverse(u32 own_addr,  struct sk_buff *buf, u32 *dnode, +		      int err)  {  	struct tipc_msg *msg = buf_msg(buf);  	uint imp = msg_importance(msg); @@ -374,7 +433,7 @@ bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err)  	msg_set_errcode(msg, err);  	msg_set_origport(msg, msg_destport(&ohdr));  	msg_set_destport(msg, msg_origport(&ohdr)); -	msg_set_prevnode(msg, tipc_own_addr); +	msg_set_prevnode(msg, own_addr);  	if (!msg_short(msg)) {  		msg_set_orignode(msg, msg_destnode(&ohdr));  		msg_set_destnode(msg, msg_orignode(&ohdr)); @@ -386,43 +445,43 @@ bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err)  	return true;  exit:  	kfree_skb(buf); +	*dnode = 0;  	return false;  }  /** - * tipc_msg_eval: determine fate of message that found no destination - * @buf: the buffer containing the message. - * @dnode: return value: next-hop node, if message to be forwarded - * @err: error code to use, if message to be rejected - * + * tipc_msg_lookup_dest(): try to find new destination for named message + * @skb: the buffer containing the message. + * @dnode: return value: next-hop node, if destination found + * @err: return value: error code to use, if message to be rejected   * Does not consume buffer - * Returns 0 (TIPC_OK) if message ok and we can try again, -TIPC error - * code if message to be rejected + * Returns true if a destination is found, false otherwise   */ -int tipc_msg_eval(struct sk_buff *buf, u32 *dnode) +bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, +			  u32 *dnode, int *err)  { -	struct tipc_msg *msg = buf_msg(buf); +	struct tipc_msg *msg = buf_msg(skb);  	u32 dport; -	if (msg_type(msg) != TIPC_NAMED_MSG) -		return -TIPC_ERR_NO_PORT; -	if (skb_linearize(buf)) -		return -TIPC_ERR_NO_NAME; -	if (msg_data_sz(msg) > MAX_FORWARD_SIZE) -		return -TIPC_ERR_NO_NAME; +	if (!msg_isdata(msg)) +		return false; +	if (!msg_named(msg)) +		return false; +	*err = -TIPC_ERR_NO_NAME; +	if (skb_linearize(skb)) +		return false;  	if (msg_reroute_cnt(msg) > 0) -		return -TIPC_ERR_NO_NAME; - -	*dnode = addr_domain(msg_lookup_scope(msg)); -	dport = tipc_nametbl_translate(msg_nametype(msg), -				       msg_nameinst(msg), -				       dnode); +		return false; +	*dnode = addr_domain(net, msg_lookup_scope(msg)); +	dport = tipc_nametbl_translate(net, msg_nametype(msg), +				       msg_nameinst(msg), dnode);  	if (!dport) -		return -TIPC_ERR_NO_NAME; +		return false;  	msg_incr_reroute_cnt(msg);  	msg_set_destnode(msg, *dnode);  	msg_set_destport(msg, dport); -	return TIPC_OK; +	*err = TIPC_OK; +	return true;  }  /* tipc_msg_reassemble() - clone a buffer chain of fragments and | 
