00001 /* 00002 * Copyright (c) 2004, Swedish Institute of Computer Science. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the Institute nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 * 00029 * This file is part of the Contiki operating system. 00030 * 00031 * Author: Adam Dunkels <adam@sics.se> 00032 * 00033 * $Id: uip-split.c,v 1.3 2010/01/25 13:53:15 adamdunkels Exp $ 00034 */ 00035 00036 #include <string.h> 00037 00038 #include "net/uip-split.h" 00039 #include "net/uip.h" 00040 #include "net/uip-fw.h" 00041 #include "net/uip_arch.h" 00042 00043 #include "net/tcpip.h" 00044 00045 #define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) 00046 00047 /*-----------------------------------------------------------------------------*/ 00048 void 00049 uip_split_output(void) 00050 { 00051 #if UIP_TCP 00052 u16_t tcplen, len1, len2; 00053 00054 /* We only try to split maximum sized TCP segments. */ 00055 if(BUF->proto == UIP_PROTO_TCP && 00056 uip_len == UIP_TCP_MSS + UIP_TCPIP_HLEN) { 00057 00058 tcplen = uip_len - UIP_TCPIP_HLEN; 00059 /* Split the segment in two. If the original packet length was 00060 odd, we make the second packet one byte larger. */ 00061 len1 = len2 = tcplen / 2; 00062 if(len1 + len2 < tcplen) { 00063 ++len2; 00064 } 00065 00066 /* Create the first packet. This is done by altering the length 00067 field of the IP header and updating the checksums. */ 00068 uip_len = len1 + UIP_TCPIP_HLEN; 00069 #if UIP_CONF_IPV6 00070 /* For IPv6, the IP length field does not include the IPv6 IP header 00071 length. */ 00072 BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); 00073 BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); 00074 #else /* UIP_CONF_IPV6 */ 00075 BUF->len[0] = uip_len >> 8; 00076 BUF->len[1] = uip_len & 0xff; 00077 #endif /* UIP_CONF_IPV6 */ 00078 00079 /* Recalculate the TCP checksum. */ 00080 BUF->tcpchksum = 0; 00081 BUF->tcpchksum = ~(uip_tcpchksum()); 00082 00083 #if !UIP_CONF_IPV6 00084 /* Recalculate the IP checksum. */ 00085 BUF->ipchksum = 0; 00086 BUF->ipchksum = ~(uip_ipchksum()); 00087 #endif /* UIP_CONF_IPV6 */ 00088 00089 /* Transmit the first packet. */ 00090 /* uip_fw_output();*/ 00091 #if UIP_CONF_IPV6 00092 tcpip_ipv6_output(); 00093 #else 00094 tcpip_output(); 00095 #endif /* UIP_CONF_IPV6 */ 00096 00097 /* Now, create the second packet. To do this, it is not enough to 00098 just alter the length field, but we must also update the TCP 00099 sequence number and point the uip_appdata to a new place in 00100 memory. This place is detemined by the length of the first 00101 packet (len1). */ 00102 uip_len = len2 + UIP_TCPIP_HLEN; 00103 #if UIP_CONF_IPV6 00104 /* For IPv6, the IP length field does not include the IPv6 IP header 00105 length. */ 00106 BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); 00107 BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); 00108 #else /* UIP_CONF_IPV6 */ 00109 BUF->len[0] = uip_len >> 8; 00110 BUF->len[1] = uip_len & 0xff; 00111 #endif /* UIP_CONF_IPV6 */ 00112 00113 /* uip_appdata += len1;*/ 00114 memcpy(uip_appdata, (u8_t *)uip_appdata + len1, len2); 00115 00116 uip_add32(BUF->seqno, len1); 00117 BUF->seqno[0] = uip_acc32[0]; 00118 BUF->seqno[1] = uip_acc32[1]; 00119 BUF->seqno[2] = uip_acc32[2]; 00120 BUF->seqno[3] = uip_acc32[3]; 00121 00122 /* Recalculate the TCP checksum. */ 00123 BUF->tcpchksum = 0; 00124 BUF->tcpchksum = ~(uip_tcpchksum()); 00125 00126 #if !UIP_CONF_IPV6 00127 /* Recalculate the IP checksum. */ 00128 BUF->ipchksum = 0; 00129 BUF->ipchksum = ~(uip_ipchksum()); 00130 #endif /* UIP_CONF_IPV6 */ 00131 00132 /* Transmit the second packet. */ 00133 /* uip_fw_output();*/ 00134 #if UIP_CONF_IPV6 00135 tcpip_ipv6_output(); 00136 #else 00137 tcpip_output(); 00138 #endif /* UIP_CONF_IPV6 */ 00139 return; 00140 } 00141 #endif /* UIP_TCP */ 00142 00143 /* uip_fw_output();*/ 00144 #if UIP_CONF_IPV6 00145 tcpip_ipv6_output(); 00146 #else 00147 tcpip_output(); 00148 #endif /* UIP_CONF_IPV6 */ 00149 } 00150 00151 /*-----------------------------------------------------------------------------*/