aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/msg.c')
-rw-r--r--net/tipc/msg.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index e02afc96edd7..4093b4c94d26 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -144,6 +144,108 @@ out_free:
144 return 0; 144 return 0;
145} 145}
146 146
147
148/**
149 * tipc_msg_build2 - create buffer chain containing specified header and data
150 * @mhdr: Message header, to be prepended to data
151 * @iov: User data
152 * @offset: Posision in iov to start copying from
153 * @dsz: Total length of user data
154 * @pktmax: Max packet size that can be used
155 * @chain: Buffer or chain of buffers to be returned to caller
156 * Returns message data size or errno: -ENOMEM, -EFAULT
157 */
158int tipc_msg_build2(struct tipc_msg *mhdr, struct iovec const *iov,
159 int offset, int dsz, int pktmax , struct sk_buff **chain)
160{
161 int mhsz = msg_hdr_sz(mhdr);
162 int msz = mhsz + dsz;
163 int pktno = 1;
164 int pktsz;
165 int pktrem = pktmax;
166 int drem = dsz;
167 struct tipc_msg pkthdr;
168 struct sk_buff *buf, *prev;
169 char *pktpos;
170 int rc;
171
172 msg_set_size(mhdr, msz);
173
174 /* No fragmentation needed? */
175 if (likely(msz <= pktmax)) {
176 buf = tipc_buf_acquire(msz);
177 *chain = buf;
178 if (unlikely(!buf))
179 return -ENOMEM;
180 skb_copy_to_linear_data(buf, mhdr, mhsz);
181 pktpos = buf->data + mhsz;
182 if (!dsz || !memcpy_fromiovecend(pktpos, iov, offset, dsz))
183 return dsz;
184 rc = -EFAULT;
185 goto error;
186 }
187
188 /* Prepare reusable fragment header */
189 tipc_msg_init(&pkthdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
190 INT_H_SIZE, msg_destnode(mhdr));
191 msg_set_size(&pkthdr, pktmax);
192 msg_set_fragm_no(&pkthdr, pktno);
193
194 /* Prepare first fragment */
195 *chain = buf = tipc_buf_acquire(pktmax);
196 if (!buf)
197 return -ENOMEM;
198 pktpos = buf->data;
199 skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE);
200 pktpos += INT_H_SIZE;
201 pktrem -= INT_H_SIZE;
202 skb_copy_to_linear_data_offset(buf, INT_H_SIZE, mhdr, mhsz);
203 pktpos += mhsz;
204 pktrem -= mhsz;
205
206 do {
207 if (drem < pktrem)
208 pktrem = drem;
209
210 if (memcpy_fromiovecend(pktpos, iov, offset, pktrem)) {
211 rc = -EFAULT;
212 goto error;
213 }
214 drem -= pktrem;
215 offset += pktrem;
216
217 if (!drem)
218 break;
219
220 /* Prepare new fragment: */
221 if (drem < (pktmax - INT_H_SIZE))
222 pktsz = drem + INT_H_SIZE;
223 else
224 pktsz = pktmax;
225 prev = buf;
226 buf = tipc_buf_acquire(pktsz);
227 if (!buf) {
228 rc = -ENOMEM;
229 goto error;
230 }
231 prev->next = buf;
232 msg_set_type(&pkthdr, FRAGMENT);
233 msg_set_size(&pkthdr, pktsz);
234 msg_set_fragm_no(&pkthdr, ++pktno);
235 skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE);
236 pktpos = buf->data + INT_H_SIZE;
237 pktrem = pktsz - INT_H_SIZE;
238
239 } while (1);
240
241 msg_set_type(buf_msg(buf), LAST_FRAGMENT);
242 return dsz;
243error:
244 kfree_skb_list(*chain);
245 *chain = NULL;
246 return rc;
247}
248
147/** 249/**
148 * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one 250 * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one
149 * @bbuf: the existing buffer ("bundle") 251 * @bbuf: the existing buffer ("bundle")