📄 tcp_reass.c
字号:
/* * Roadrunner/pk * Copyright (C) 1989-2002 Cornfed Systems, Inc. * * The Roadrunner/pk operating system is free software; you can * redistribute and/or modify it under the terms of the GNU General * Public License, version 2, as published by the Free Software * Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * More information about the Roadrunner/pk operating system of * which this file is a part is available on the World-Wide Web * at: http://www.cornfed.com. * */#include <net/ether.h>#include <net/tcp.h>#if _DEBUG_TCP#include <stdio.h>#endif#include <stdlib.h>#include <sys/intr.h>inttcp_reass(buf_t b, tcb_t tcb){ buf_t p, q; etherhdr_t eh, qeh; iphdr_t ih, qih; tcphdr_t th, qth; int len, segcnt = 0; eh = (etherhdr_t) bstart(b); ih = (iphdr_t) eh->data; th = (tcphdr_t) (eh->data + IP_HLEN(ih)); len = ih->len - IP_HLEN(ih) - TCP_HLEN(th); disable; /* * Find reassembly queue position for new segment. q points to the * segment in the queue that should succeed the new segment or NULL * if the new segment belongs at the end of the queue. */ for (q = tcb->reass.h; q != NULL; q = q->next) { qeh = (etherhdr_t) bstart(q); qih = (iphdr_t) qeh->data; qth = (tcphdr_t) (qeh->data + IP_HLEN(qih)); if (SEQ_GT(qth->seq, th->seq)) break; } /* * p points to the segment that should precede the new segment or * NULL if the new segment belongs at the front of the queue. */ if (q == NULL) p = tcb->reass.t; else p = q->prev; /* Trim data from preceding segment if it overlaps the new segment */ if (p != NULL) { etherhdr_t peh = (etherhdr_t) bstart(p); iphdr_t pih = (iphdr_t) peh->data; tcphdr_t pth = (tcphdr_t) (peh->data + IP_HLEN(pih)); int n, plen; /* Conversion to integer type in n handles sequence wraparound */ plen = pih->len - IP_HLEN(pih) - TCP_HLEN(pth); n = pth->seq + plen - th->seq; if (n > 0) { if (n >= len) {#if _DEBUG_TCP kprintf("tcp_reass: preceding segment covers new segment\n");#endif enable; return (-1); } pih->len -= n; } } /* Trim data from new segment if it overlaps the succeeding segment */ if (q != NULL) { int n; /* Conversion to integer type in n handles sequence wraparound */ n = th->seq + len - qth->seq; if (n > 0) ih->len -= n; } /* Insert new segment in queue */ b->prev = p; b->next = q; if (p == NULL) tcb->reass.h = b; else p->next = b; if (q == NULL) tcb->reass.t = b; else q->prev = b;#if _DEBUG_TCP tcp_dump_reass("tcp_reass: new segment inserted", tcb->reass.h);#endif /* * Present data to user advancing tcb->rcv_nxt through the completed * sequence space */ if (TCPS_HAVERCVDSYN(tcb->state)) { int qlen; for (q = tcb->reass.h; q != NULL; q = tcb->reass.h) { qeh = (etherhdr_t) bstart(q); qih = (iphdr_t) qeh->data; qth = (tcphdr_t) (qeh->data + IP_HLEN(qih)); qlen = qih->len - IP_HLEN(qih) - TCP_HLEN(qth); if (qth->seq != tcb->rcv_nxt) break; /* Remove segment from head of reassembly queue */ tcb->reass.h = q->next; if (q->next == NULL) tcb->reass.t = NULL; else { q->next->prev = NULL; q->next = NULL; } /* Place segment in socket receive queue */ bstart(q) = (char *) qth + TCP_HLEN(qth); blen(q) = qlen; tcb->rcv_nxt += qlen; tcb->socket->rcv_cc += qlen; benq(q, &(tcb->socket->rcvq)); segcnt++; } if (segcnt > 0) { proc_t proc; /* Restart waiting receivers */ for (;;) { proc = remfirstq(&(tcb->socket->rcvr)); if (proc == NULL) break; proc->state = PS_READY; insq(proc, &ready); } } }#if _DEBUG_TCP tcp_dump_reass("tcp_reass: after segments presented to user", tcb->reass.h);#endif enable; return segcnt;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -