diff options
Diffstat (limited to 'net/tipc/msg.c')
-rw-r--r-- | net/tipc/msg.c | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/net/tipc/msg.c b/net/tipc/msg.c index e525f8ce1dee..8be6e94a1ca9 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * net/tipc/msg.c: TIPC message header routines | 2 | * net/tipc/msg.c: TIPC message header routines |
3 | * | 3 | * |
4 | * Copyright (c) 2000-2006, Ericsson AB | 4 | * Copyright (c) 2000-2006, 2014, Ericsson AB |
5 | * Copyright (c) 2005, 2010-2011, Wind River Systems | 5 | * Copyright (c) 2005, 2010-2011, Wind River Systems |
6 | * All rights reserved. | 6 | * All rights reserved. |
7 | * | 7 | * |
@@ -99,3 +99,56 @@ int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, | |||
99 | } | 99 | } |
100 | return dsz; | 100 | return dsz; |
101 | } | 101 | } |
102 | |||
103 | /* tipc_buf_append(): Append a buffer to the fragment list of another buffer | ||
104 | * Let first buffer become head buffer | ||
105 | * Returns 1 and sets *buf to headbuf if chain is complete, otherwise 0 | ||
106 | * Leaves headbuf pointer at NULL if failure | ||
107 | */ | ||
108 | int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) | ||
109 | { | ||
110 | struct sk_buff *head = *headbuf; | ||
111 | struct sk_buff *frag = *buf; | ||
112 | struct sk_buff *tail; | ||
113 | struct tipc_msg *msg = buf_msg(frag); | ||
114 | u32 fragid = msg_type(msg); | ||
115 | bool headstolen; | ||
116 | int delta; | ||
117 | |||
118 | skb_pull(frag, msg_hdr_sz(msg)); | ||
119 | |||
120 | if (fragid == FIRST_FRAGMENT) { | ||
121 | if (head || skb_unclone(frag, GFP_ATOMIC)) | ||
122 | goto out_free; | ||
123 | head = *headbuf = frag; | ||
124 | skb_frag_list_init(head); | ||
125 | return 0; | ||
126 | } | ||
127 | if (!head) | ||
128 | goto out_free; | ||
129 | tail = TIPC_SKB_CB(head)->tail; | ||
130 | if (skb_try_coalesce(head, frag, &headstolen, &delta)) { | ||
131 | kfree_skb_partial(frag, headstolen); | ||
132 | } else { | ||
133 | if (!skb_has_frag_list(head)) | ||
134 | skb_shinfo(head)->frag_list = frag; | ||
135 | else | ||
136 | tail->next = frag; | ||
137 | head->truesize += frag->truesize; | ||
138 | head->data_len += frag->len; | ||
139 | head->len += frag->len; | ||
140 | TIPC_SKB_CB(head)->tail = frag; | ||
141 | } | ||
142 | if (fragid == LAST_FRAGMENT) { | ||
143 | *buf = head; | ||
144 | TIPC_SKB_CB(head)->tail = NULL; | ||
145 | *headbuf = NULL; | ||
146 | return 1; | ||
147 | } | ||
148 | *buf = NULL; | ||
149 | return 0; | ||
150 | out_free: | ||
151 | pr_warn_ratelimited("Unable to build fragment list\n"); | ||
152 | kfree_skb(*buf); | ||
153 | return 0; | ||
154 | } | ||