new retransmit part 2
[cor_2_6_31.git] / net / cor / forward.c
blob580baa91e20cb8f93e47ef8f823eacc9b8009acd
1 /*
2 * Connection oriented routing
3 * Copyright (C) 2007-2008 Michael Blizek
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA.
21 #include <linux/mutex.h>
23 #include "cor.h"
25 struct kmem_cache *data_buf_item_slab;
27 #define PAGESIZE (1 << PAGE_SHIFT)
29 void databuf_init(struct data_buf *data)
31 memset(data, 0, sizeof(struct data_buf));
32 INIT_LIST_HEAD(&(data->items));
35 static void databuf_item_free(struct data_buf_item *item)
37 if (item->type == TYPE_BUF) {
38 kfree(item->data.buf.buf);
39 } else if (item->type == TYPE_SKB) {
40 kfree_skb(item->data.skb);
41 } else {
42 BUG();
45 list_del(&(item->buf_list));
47 kmem_cache_free(data_buf_item_slab, item);
50 void databuf_free(struct data_buf *data)
52 while (!list_empty(&(data->items))) {
53 struct data_buf_item *item = container_of(data->items.next,
54 struct data_buf_item, buf_list);
55 databuf_item_free(item);
59 static void databuf_nextreadchunk(struct data_buf *data)
61 if (data->lastread == 0) {
62 BUG_ON(data->last_read_offset != 0);
63 BUG_ON(list_empty(&(data->items)));
64 data->lastread = container_of(data->items.next,
65 struct data_buf_item, buf_list);
66 } else if (&(data->lastread->buf_list) != data->items.prev) {
67 data->lastread = container_of(data->lastread->buf_list.next,
68 struct data_buf_item, buf_list);
70 data->last_read_offset = 0;
74 int _databuf_pull(struct data_buf *data, char *dst, int len, int userbuf)
76 int totalcpy = 0;
78 BUG_ON(data->read_remaining < len);
80 if (data->lastread == 0)
81 databuf_nextreadchunk(data);
83 while(len > 0) {
84 int rc = 0;
85 int cpy = len;
87 char *srcbuf = 0;
88 int srcbuflen = 0;
90 char *srcbufcpystart = 0;
91 int srcbufcpylen = 0;
93 BUG_ON(data->lastread == 0);
95 if (data->lastread->type == TYPE_BUF) {
96 srcbuf = data->lastread->data.buf.buf;
97 srcbuflen = data->lastread->data.buf.datalen;
98 } else if (data->lastread->type == TYPE_SKB) {
99 srcbuf = data->lastread->data.skb->data;
100 srcbuflen = data->lastread->data.skb->len;
101 } else {
102 BUG();
105 srcbufcpystart = srcbuf + data->last_read_offset;
106 srcbufcpylen = srcbuflen - data->last_read_offset;
108 if (cpy > srcbufcpylen)
109 cpy = srcbufcpylen;
111 if (userbuf) {
112 int notcopied = copy_to_user(dst, srcbufcpystart, cpy);
113 cpy -= notcopied;
114 if (unlikely(notcopied > 0))
115 rc = -EFAULT;
116 } else {
117 memcpy(dst, srcbufcpystart, cpy);
120 dst += cpy;
121 len -= cpy;
122 totalcpy += cpy;
124 data->read_remaining -= cpy;
125 data->last_read_offset += cpy;
127 if (cpy == srcbufcpylen)
128 databuf_nextreadchunk(data);
130 if (unlikely(rc < 0)) {
131 if (totalcpy == 0)
132 totalcpy = rc;
133 break;
137 return totalcpy;
140 void databuf_pull(struct data_buf *data, char *dst, int len)
142 _databuf_pull(data, dst, len, 0);
145 size_t databuf_pulluser(struct conn *sconn, struct msghdr *msg)
147 size_t copied = 0;
148 int iovidx = 0;
149 int iovread = 0;
151 while (iovidx < msg->msg_iovlen) {
152 int rc;
154 struct iovec *iov = msg->msg_iov + iovidx;
155 __user char *msg = iov->iov_base + iovread;
156 unsigned int len = iov->iov_len - iovread;
158 if (len == 0) {
159 iovidx++;
160 iovread = 0;
161 continue;
164 if (sconn->buf.read_remaining == 0) {
165 if (sconn->sourcetype == SOURCE_NONE)
166 rc = -EPIPE;
167 else
168 rc = -EAGAIN;
169 } else {
170 if (len > sconn->buf.read_remaining)
171 len = sconn->buf.read_remaining;
173 rc = _databuf_pull(&(sconn->buf), msg, len, 1);
176 BUG_ON(rc == 0);
178 if (rc < 0) {
179 if (copied == 0)
180 copied = rc;
181 break;
184 copied += rc;
185 iovread += rc;
188 return copied;
191 void databuf_pullold(struct data_buf *data, __u32 startpos, char *dst, int len)
193 __u32 pos = data->first_offset;
194 struct data_buf_item *dbi = container_of(data->items.next,
195 struct data_buf_item, buf_list);
196 while(1) {
197 int srcbuflen;
199 BUG_ON(&(dbi->buf_list) == &(data->items));
201 if (data->lastread->type == TYPE_BUF) {
202 srcbuflen = dbi->data.buf.datalen;
203 } else if (data->lastread->type == TYPE_SKB) {
204 srcbuflen = dbi->data.skb->len;
205 } else {
206 BUG();
209 if (pos + srcbuflen > len)
210 break;
211 pos += srcbuflen;
212 dbi = container_of(dbi->buf_list.next, struct data_buf_item,
213 buf_list);
216 while (len > 0) {
217 int cpy = len;
219 char *srcbuf = 0;
220 int srcbuflen = 0;
222 char *srcbufcpystart = 0;
223 int srcbufcpylen = 0;
225 BUG_ON(&(dbi->buf_list) == &(data->items));
227 if (data->lastread->type == TYPE_BUF) {
228 srcbuf = data->lastread->data.buf.buf;
229 srcbuflen = data->lastread->data.buf.datalen;
230 } else if (data->lastread->type == TYPE_SKB) {
231 srcbuf = data->lastread->data.skb->data;
232 srcbuflen = data->lastread->data.skb->len;
233 } else {
234 BUG();
237 srcbufcpystart = srcbuf + (startpos - pos);
238 srcbufcpylen = srcbuflen - (startpos - pos);
239 if (cpy > srcbufcpylen)
240 cpy = srcbufcpylen;
242 memcpy(dst, srcbufcpystart, cpy);
244 dst += cpy;
245 len -= cpy;
246 startpos += cpy;
248 pos += srcbuflen;
249 dbi = container_of(dbi->buf_list.next, struct data_buf_item,
250 buf_list);
254 /* ack up to *not* including pos */
255 void databuf_ack(struct data_buf *buf, __u32 pos)
257 while (!list_empty(&(buf->items))) {
258 struct data_buf_item *firstitem = container_of(buf->items.next,
259 struct data_buf_item, buf_list);
260 int firstlen = 0;
262 if (firstitem == buf->lastread)
263 break;
265 if (firstitem->type == TYPE_BUF) {
266 firstlen = firstitem->data.buf.datalen;
267 } else if (firstitem->type == TYPE_SKB) {
268 firstlen = firstitem->data.skb->len;
269 } else {
270 BUG();
273 if (((__s32)(buf->first_offset + firstlen - pos)) > 0)
274 break;
276 buf->first_offset += firstlen;
278 databuf_item_free(firstitem);
282 void databuf_ackread(struct data_buf *buf)
284 while (!list_empty(&(buf->items)) && buf->lastread != 0) {
285 struct data_buf_item *firstitem = container_of(buf->items.next,
286 struct data_buf_item, buf_list);
288 if (firstitem == buf->lastread)
289 break;
291 if (firstitem->type == TYPE_BUF) {
292 buf->first_offset += firstitem->data.buf.datalen;
293 } else if (firstitem->type == TYPE_SKB) {
294 buf->first_offset += firstitem->data.skb->len;
295 } else {
296 BUG();
299 databuf_item_free(firstitem);
303 int databuf_maypush(struct data_buf *buf)
305 return 16384 - buf->read_remaining;
308 void flush_buf(struct conn *rconn)
310 switch (rconn->targettype) {
311 case TARGET_UNCONNECTED:
312 parse(rconn);
313 if (rconn->targettype != TARGET_UNCONNECTED)
314 flush_buf(rconn);
315 break;
316 case TARGET_SOCK:
317 wake_up_interruptible(&(rconn->target.sock.wait));
318 break;
319 case TARGET_OUT:
320 flush_out(rconn);
321 break;
322 default:
323 BUG();
327 static int _receive_buf(struct conn *rconn, char *buf, int len, int userbuf)
329 struct data_buf_item *item = 0;
331 int totalcpy = 0;
333 BUG_ON(databuf_maypush(&(rconn->buf)) < len);
335 if (list_empty(&(rconn->buf.items)) == 0) {
336 struct list_head *last = rconn->buf.items.prev;
337 item = container_of(last, struct data_buf_item, buf_list);
339 if (item->type != TYPE_BUF || rconn->buf.last_buflen <=
340 item->data.buf.datalen)
341 item = 0;
344 while (len > 0) {
345 int rc = 0;
346 int cpy = len;
347 if (item == 0) {
348 __u32 buflen = PAGESIZE;
349 if (buflen > 32768)
350 buflen = 32768;
351 item = kmem_cache_alloc(data_buf_item_slab, GFP_KERNEL);
352 if (unlikely(item == 0)) {
353 rc = -ENOMEM;
354 goto error;
356 memset(item, 0, sizeof(item));
357 item->type = TYPE_BUF;
358 item->data.buf.buf = kmalloc(buflen, GFP_KERNEL);
361 if (unlikely(item->data.buf.buf == 0)) {
362 kmem_cache_free(data_buf_item_slab, item);
363 rc = -ENOMEM;
364 goto error;
366 item->data.buf.datalen = 0;
367 list_add_tail(&(item->buf_list), &(rconn->buf.items));
368 rconn->buf.last_buflen = buflen;
371 BUG_ON(item->type != TYPE_BUF);
372 BUG_ON(rconn->buf.last_buflen <= item->data.buf.datalen);
374 if (rconn->buf.last_buflen - item->data.buf.datalen < cpy)
375 cpy = (rconn->buf.last_buflen - item->data.buf.datalen);
377 if (userbuf) {
378 int notcopied = copy_from_user(item->data.buf.buf +
379 item->data.buf.datalen, buf, cpy);
380 cpy -= notcopied;
381 if (unlikely(notcopied > 0))
382 rc = -EFAULT;
383 } else {
384 memcpy(item->data.buf.buf + item->data.buf.datalen,
385 buf, cpy);
388 buf += cpy;
389 len -= cpy;
390 totalcpy += cpy;
392 item->data.buf.datalen += cpy;
394 error:
395 if (unlikely(rc < 0)) {
396 if (totalcpy == 0)
397 return rc;
398 break;
402 rconn->buf.read_remaining += totalcpy;
404 return totalcpy;
407 int receive_userbuf(struct conn *rconn, struct msghdr *msg)
409 int copied = 0;
410 int iovidx = 0;
411 int iovread = 0;
413 if (databuf_maypush(&(rconn->buf)) <= 0)
414 return -EAGAIN;
416 while (iovidx < msg->msg_iovlen) {
417 struct iovec *iov = msg->msg_iov + iovidx;
418 __user char *userbuf = iov->iov_base + iovread;
419 int len = iov->iov_len - iovread;
420 int rc;
421 int pushlimit;
423 if (len == 0) {
424 iovidx++;
425 iovread = 0;
426 continue;
429 pushlimit = databuf_maypush(&(rconn->buf));
431 if (pushlimit <= 0) {
432 if (rconn->targettype == TARGET_UNCONNECTED)
433 rc = -EPIPE;
434 else
435 rc = -EAGAIN;
436 } else {
437 if (pushlimit < len)
438 len = pushlimit;
440 rc = _receive_buf(rconn, userbuf, len, 1);
443 if (rc < 0) {
444 if (copied == 0)
445 copied = rc;
446 break;
449 copied += rc;
450 iovread += rc;
453 if (copied > 0)
454 flush_buf(rconn);;
456 return copied;
459 void receive_buf(struct conn *rconn, char *buf, int len)
461 BUG_ON(databuf_maypush(&(rconn->buf)) < len);
462 _receive_buf(rconn, buf, len, 0);
463 flush_buf(rconn);
466 int receive_skb(struct conn *rconn, struct sk_buff *skb)
468 struct data_buf_item *item;
470 if (databuf_maypush(&(rconn->buf)) < skb->len)
471 return 1;
473 item = kmem_cache_alloc(data_buf_item_slab, GFP_KERNEL);
475 if (unlikely(item == 0))
476 return 1;
478 item->data.skb = skb;
479 item->type = TYPE_SKB;
480 list_add_tail(&(item->buf_list), &(rconn->buf.items));
481 rconn->buf.read_remaining += skb->len;
482 rconn->buf.last_buflen = 0;
484 flush_buf(rconn);
486 return 0;
489 void wake_sender(struct conn *rconn)
491 switch (rconn->sourcetype) {
492 case SOURCE_NONE:
493 /* nothing */
494 break;
495 case SOURCE_SOCK:
496 wake_up_interruptible(&(rconn->source.sock.wait));
497 break;
498 case SOURCE_IN:
499 drain_ooo_queue(rconn);
500 break;
501 default:
502 BUG();
506 void forward_init(void)
508 data_buf_item_slab = kmem_cache_create("cor_data_buf_item",
509 sizeof(struct data_buf_item), 8, 0, 0);