mbed OS5

Fork of UIPEthernet by Zoltan Hudak

Committer:
hudakz
Date:
Thu Nov 20 21:26:54 2014 +0000
Revision:
1:01c2344f98a3
Parent:
uitility/uip.c@0:5350a66d5279
rev. 01

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:5350a66d5279 1 #define DEBUG_PRINTF(...) /*printf(__VA_ARGS__)*/
hudakz 0:5350a66d5279 2
hudakz 0:5350a66d5279 3 /**
hudakz 0:5350a66d5279 4 * \defgroup uip The uIP TCP/IP stack
hudakz 0:5350a66d5279 5 * @{
hudakz 0:5350a66d5279 6 *
hudakz 0:5350a66d5279 7 * uIP is an implementation of the TCP/IP protocol stack intended for
hudakz 0:5350a66d5279 8 * small 8-bit and 16-bit microcontrollers.
hudakz 0:5350a66d5279 9 *
hudakz 0:5350a66d5279 10 * uIP provides the necessary protocols for Internet communication,
hudakz 0:5350a66d5279 11 * with a very small code footprint and RAM requirements - the uIP
hudakz 0:5350a66d5279 12 * code size is on the order of a few kilobytes and RAM usage is on
hudakz 0:5350a66d5279 13 * the order of a few hundred bytes.
hudakz 0:5350a66d5279 14 */
hudakz 0:5350a66d5279 15
hudakz 0:5350a66d5279 16 /**
hudakz 0:5350a66d5279 17 * \file
hudakz 0:5350a66d5279 18 * The uIP TCP/IP stack code.
hudakz 0:5350a66d5279 19 * \author Adam Dunkels <adam@dunkels.com>
hudakz 0:5350a66d5279 20 */
hudakz 0:5350a66d5279 21 /*
hudakz 0:5350a66d5279 22 * Copyright (c) 2001-2003, Adam Dunkels.
hudakz 0:5350a66d5279 23 * All rights reserved.
hudakz 0:5350a66d5279 24 *
hudakz 0:5350a66d5279 25 * Redistribution and use in source and binary forms, with or without
hudakz 0:5350a66d5279 26 * modification, are permitted provided that the following conditions
hudakz 0:5350a66d5279 27 * are met:
hudakz 0:5350a66d5279 28 * 1. Redistributions of source code must retain the above copyright
hudakz 0:5350a66d5279 29 * notice, this list of conditions and the following disclaimer.
hudakz 0:5350a66d5279 30 * 2. Redistributions in binary form must reproduce the above copyright
hudakz 0:5350a66d5279 31 * notice, this list of conditions and the following disclaimer in the
hudakz 0:5350a66d5279 32 * documentation and/or other materials provided with the distribution.
hudakz 0:5350a66d5279 33 * 3. The name of the author may not be used to endorse or promote
hudakz 0:5350a66d5279 34 * products derived from this software without specific prior
hudakz 0:5350a66d5279 35 * written permission.
hudakz 0:5350a66d5279 36 *
hudakz 0:5350a66d5279 37 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
hudakz 0:5350a66d5279 38 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
hudakz 0:5350a66d5279 39 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
hudakz 0:5350a66d5279 40 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
hudakz 0:5350a66d5279 41 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
hudakz 0:5350a66d5279 42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
hudakz 0:5350a66d5279 43 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
hudakz 0:5350a66d5279 44 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
hudakz 0:5350a66d5279 45 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
hudakz 0:5350a66d5279 46 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
hudakz 0:5350a66d5279 47 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
hudakz 0:5350a66d5279 48 *
hudakz 0:5350a66d5279 49 * This file is part of the uIP TCP/IP stack.
hudakz 0:5350a66d5279 50 *
hudakz 0:5350a66d5279 51 * $Id: uip.c,v 1.65 2006/06/11 21:46:39 adam Exp $
hudakz 0:5350a66d5279 52 *
hudakz 0:5350a66d5279 53 */
hudakz 0:5350a66d5279 54 /*
hudakz 0:5350a66d5279 55 * uIP is a small implementation of the IP, UDP and TCP protocols (as
hudakz 0:5350a66d5279 56 * well as some basic ICMP stuff). The implementation couples the IP,
hudakz 0:5350a66d5279 57 * UDP, TCP and the application layers very tightly. To keep the size
hudakz 0:5350a66d5279 58 * of the compiled code down, this code frequently uses the goto
hudakz 0:5350a66d5279 59 * statement. While it would be possible to break the uip_process()
hudakz 0:5350a66d5279 60 * function into many smaller functions, this would increase the code
hudakz 0:5350a66d5279 61 * size because of the overhead of parameter passing and the fact that
hudakz 0:5350a66d5279 62 * the optimier would not be as efficient.
hudakz 0:5350a66d5279 63 *
hudakz 0:5350a66d5279 64 * The principle is that we have a small buffer, called the uip_buf,
hudakz 0:5350a66d5279 65 * in which the device driver puts an incoming packet. The TCP/IP
hudakz 0:5350a66d5279 66 * stack parses the headers in the packet, and calls the
hudakz 0:5350a66d5279 67 * application. If the remote host has sent data to the application,
hudakz 0:5350a66d5279 68 * this data is present in the uip_buf and the application read the
hudakz 0:5350a66d5279 69 * data from there. It is up to the application to put this data into
hudakz 0:5350a66d5279 70 * a byte stream if needed. The application will not be fed with data
hudakz 0:5350a66d5279 71 * that is out of sequence.
hudakz 0:5350a66d5279 72 *
hudakz 0:5350a66d5279 73 * If the application whishes to send data to the peer, it should put
hudakz 0:5350a66d5279 74 * its data into the uip_buf. The uip_appdata pointer points to the
hudakz 0:5350a66d5279 75 * first available byte. The TCP/IP stack will calculate the
hudakz 0:5350a66d5279 76 * checksums, and fill in the necessary header fields and finally send
hudakz 0:5350a66d5279 77 * the packet back to the peer.
hudakz 0:5350a66d5279 78 */
hudakz 0:5350a66d5279 79 #include "uip.h"
hudakz 0:5350a66d5279 80 #include "uipopt.h"
hudakz 0:5350a66d5279 81 #include "uip_arch.h"
hudakz 0:5350a66d5279 82
hudakz 0:5350a66d5279 83 #if UIP_CONF_IPV6
hudakz 0:5350a66d5279 84 #include "uip-neighbor.h"
hudakz 0:5350a66d5279 85 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 86
hudakz 0:5350a66d5279 87 #include <string.h>
hudakz 0:5350a66d5279 88
hudakz 0:5350a66d5279 89 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 90
hudakz 0:5350a66d5279 91 /* Variable definitions. */
hudakz 0:5350a66d5279 92 /* The IP address of this host. If it is defined to be fixed (by
hudakz 0:5350a66d5279 93 setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set
hudakz 0:5350a66d5279 94 here. Otherwise, the address */
hudakz 0:5350a66d5279 95 #if UIP_FIXEDADDR > 0
hudakz 0:5350a66d5279 96 const uip_ipaddr_t uip_hostaddr = { HTONS((UIP_IPADDR0 << 8) | UIP_IPADDR1), HTONS
hudakz 0:5350a66d5279 97 ((UIP_IPADDR2 << 8) | UIP_IPADDR3) };
hudakz 0:5350a66d5279 98 const uip_ipaddr_t uip_draddr =
hudakz 0:5350a66d5279 99 {
hudakz 0:5350a66d5279 100 HTONS((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1),
hudakz 0:5350a66d5279 101 HTONS((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3)
hudakz 0:5350a66d5279 102 };
hudakz 0:5350a66d5279 103 const uip_ipaddr_t uip_netmask =
hudakz 0:5350a66d5279 104 {
hudakz 0:5350a66d5279 105 HTONS((UIP_NETMASK0 << 8) | UIP_NETMASK1),
hudakz 0:5350a66d5279 106 HTONS((UIP_NETMASK2 << 8) | UIP_NETMASK3)
hudakz 0:5350a66d5279 107 };
hudakz 0:5350a66d5279 108 #else
hudakz 0:5350a66d5279 109 uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
hudakz 0:5350a66d5279 110 #endif /* UIP_FIXEDADDR */
hudakz 0:5350a66d5279 111
hudakz 0:5350a66d5279 112 static const uip_ipaddr_t all_ones_addr =
hudakz 0:5350a66d5279 113 #if UIP_CONF_IPV6
hudakz 0:5350a66d5279 114 { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff };
hudakz 0:5350a66d5279 115 #else /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 116 {
hudakz 0:5350a66d5279 117 0xffff, 0xffff
hudakz 0:5350a66d5279 118 };
hudakz 0:5350a66d5279 119 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 120 static const uip_ipaddr_t all_zeroes_addr =
hudakz 0:5350a66d5279 121 #if UIP_CONF_IPV6
hudakz 0:5350a66d5279 122 { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
hudakz 0:5350a66d5279 123 #else /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 124 {
hudakz 0:5350a66d5279 125 0x0000, 0x0000
hudakz 0:5350a66d5279 126 };
hudakz 0:5350a66d5279 127 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 128
hudakz 0:5350a66d5279 129 #if UIP_FIXEDETHADDR
hudakz 0:5350a66d5279 130 const struct uip_eth_addr uip_ethaddr =
hudakz 0:5350a66d5279 131 {
hudakz 0:5350a66d5279 132 { UIP_ETHADDR0, UIP_ETHADDR1, UIP_ETHADDR2, UIP_ETHADDR3, UIP_ETHADDR4, UIP_ETHADDR5 }
hudakz 0:5350a66d5279 133 };
hudakz 0:5350a66d5279 134 #else
hudakz 0:5350a66d5279 135 struct uip_eth_addr uip_ethaddr = { { 0, 0, 0, 0, 0, 0 } };
hudakz 0:5350a66d5279 136 #endif
hudakz 0:5350a66d5279 137 #ifndef UIP_CONF_EXTERNAL_BUFFER
hudakz 0:5350a66d5279 138 u8_t uip_buf[UIP_BUFSIZE + 2]; /* The packet buffer that contains
hudakz 0:5350a66d5279 139 incoming packets. */
hudakz 0:5350a66d5279 140 #endif /* UIP_CONF_EXTERNAL_BUFFER */
hudakz 0:5350a66d5279 141
hudakz 0:5350a66d5279 142 void* uip_appdata; /* The uip_appdata pointer points to
hudakz 0:5350a66d5279 143 application data. */
hudakz 0:5350a66d5279 144 void* uip_sappdata; /* The uip_appdata pointer points to
hudakz 0:5350a66d5279 145 the application data which is to
hudakz 0:5350a66d5279 146 be sent. */
hudakz 0:5350a66d5279 147 #if UIP_URGDATA > 0
hudakz 0:5350a66d5279 148 void* uip_urgdata; /* The uip_urgdata pointer points to
hudakz 0:5350a66d5279 149 urgent data (out-of-band data), if
hudakz 0:5350a66d5279 150 present. */
hudakz 0:5350a66d5279 151 u16_t uip_urglen, uip_surglen;
hudakz 0:5350a66d5279 152 #endif /* UIP_URGDATA > 0 */
hudakz 0:5350a66d5279 153
hudakz 0:5350a66d5279 154 u16_t uip_len, uip_slen;
hudakz 0:5350a66d5279 155
hudakz 0:5350a66d5279 156 /* The uip_len is either 8 or 16 bits,
hudakz 0:5350a66d5279 157 depending on the maximum packet
hudakz 0:5350a66d5279 158 size. */
hudakz 0:5350a66d5279 159 u8_t uip_flags; /* The uip_flags variable is used for
hudakz 0:5350a66d5279 160 communication between the TCP/IP stack
hudakz 0:5350a66d5279 161 and the application program. */
hudakz 0:5350a66d5279 162 struct uip_conn* uip_conn; /* uip_conn always points to the current
hudakz 0:5350a66d5279 163 connection. */
hudakz 0:5350a66d5279 164
hudakz 0:5350a66d5279 165 struct uip_conn uip_conns[UIP_CONNS];
hudakz 0:5350a66d5279 166
hudakz 0:5350a66d5279 167 /* The uip_conns array holds all TCP
hudakz 0:5350a66d5279 168 connections. */
hudakz 0:5350a66d5279 169 u16_t uip_listenports[UIP_LISTENPORTS];
hudakz 0:5350a66d5279 170
hudakz 0:5350a66d5279 171 /* The uip_listenports list all currently
hudakz 0:5350a66d5279 172 listning ports. */
hudakz 0:5350a66d5279 173 #if UIP_UDP
hudakz 0:5350a66d5279 174 struct uip_udp_conn* uip_udp_conn;
hudakz 0:5350a66d5279 175 struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
hudakz 0:5350a66d5279 176 #endif /* UIP_UDP */
hudakz 0:5350a66d5279 177
hudakz 0:5350a66d5279 178 static u16_t ipid; /* Ths ipid variable is an increasing
hudakz 0:5350a66d5279 179 number that is used for the IP ID
hudakz 0:5350a66d5279 180 field. */
hudakz 0:5350a66d5279 181
hudakz 0:5350a66d5279 182 /**
hudakz 0:5350a66d5279 183 * @brief
hudakz 0:5350a66d5279 184 * @note
hudakz 0:5350a66d5279 185 * @param
hudakz 0:5350a66d5279 186 * @retval
hudakz 0:5350a66d5279 187 */
hudakz 0:5350a66d5279 188 void uip_setipid(u16_t id) {
hudakz 0:5350a66d5279 189 ipid = id;
hudakz 0:5350a66d5279 190 }
hudakz 0:5350a66d5279 191
hudakz 0:5350a66d5279 192 static u8_t iss[4]; /* The iss variable is used for the TCP
hudakz 0:5350a66d5279 193 initial sequence number. */
hudakz 0:5350a66d5279 194
hudakz 0:5350a66d5279 195 #if UIP_ACTIVE_OPEN
hudakz 0:5350a66d5279 196 static u16_t lastport; /* Keeps track of the last port used for
hudakz 0:5350a66d5279 197 a new connection. */
hudakz 0:5350a66d5279 198 #endif /* UIP_ACTIVE_OPEN */
hudakz 0:5350a66d5279 199
hudakz 0:5350a66d5279 200 /* Temporary variables. */
hudakz 0:5350a66d5279 201
hudakz 0:5350a66d5279 202 u8_t uip_acc32[4];
hudakz 0:5350a66d5279 203 static u8_t c, opt;
hudakz 0:5350a66d5279 204 static u16_t tmp16;
hudakz 0:5350a66d5279 205
hudakz 0:5350a66d5279 206 /* Structures and definitions. */
hudakz 0:5350a66d5279 207
hudakz 0:5350a66d5279 208 #define TCP_FIN 0x01
hudakz 0:5350a66d5279 209 #define TCP_SYN 0x02
hudakz 0:5350a66d5279 210 #define TCP_RST 0x04
hudakz 0:5350a66d5279 211 #define TCP_PSH 0x08
hudakz 0:5350a66d5279 212 #define TCP_ACK 0x10
hudakz 0:5350a66d5279 213 #define TCP_URG 0x20
hudakz 0:5350a66d5279 214 #define TCP_CTL 0x3f
hudakz 0:5350a66d5279 215
hudakz 0:5350a66d5279 216 #define TCP_OPT_END 0 /* End of TCP options list */
hudakz 0:5350a66d5279 217
hudakz 0:5350a66d5279 218 #define TCP_OPT_NOOP 1 /* "No-operation" TCP option */
hudakz 0:5350a66d5279 219
hudakz 0:5350a66d5279 220 #define TCP_OPT_MSS 2 /* Maximum segment size TCP option */
hudakz 0:5350a66d5279 221
hudakz 0:5350a66d5279 222 #define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */
hudakz 0:5350a66d5279 223
hudakz 0:5350a66d5279 224 #define ICMP_ECHO_REPLY 0
hudakz 0:5350a66d5279 225 #define ICMP_ECHO 8
hudakz 0:5350a66d5279 226
hudakz 0:5350a66d5279 227 #define ICMP6_ECHO_REPLY 129
hudakz 0:5350a66d5279 228 #define ICMP6_ECHO 128
hudakz 0:5350a66d5279 229 #define ICMP6_NEIGHBOR_SOLICITATION 135
hudakz 0:5350a66d5279 230 #define ICMP6_NEIGHBOR_ADVERTISEMENT 136
hudakz 0:5350a66d5279 231
hudakz 0:5350a66d5279 232 #define ICMP6_FLAG_S (1 << 6)
hudakz 0:5350a66d5279 233 #define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1
hudakz 0:5350a66d5279 234 #define ICMP6_OPTION_TARGET_LINK_ADDRESS 2
hudakz 0:5350a66d5279 235
hudakz 0:5350a66d5279 236 /* Macros. */
hudakz 0:5350a66d5279 237
hudakz 0:5350a66d5279 238 #define BUF ((struct uip_tcpip_hdr*) &uip_buf[UIP_LLH_LEN])
hudakz 0:5350a66d5279 239 #define FBUF ((struct uip_tcpip_hdr*) &uip_reassbuf[0])
hudakz 0:5350a66d5279 240 #define ICMPBUF ((struct uip_icmpip_hdr*) &uip_buf[UIP_LLH_LEN])
hudakz 0:5350a66d5279 241 #define UDPBUF ((struct uip_udpip_hdr*) &uip_buf[UIP_LLH_LEN])
hudakz 0:5350a66d5279 242 #if UIP_STATISTICS == 1
hudakz 0:5350a66d5279 243 struct uip_stats uip_stat;
hudakz 0:5350a66d5279 244 #define UIP_STAT(s) s
hudakz 0:5350a66d5279 245 #else
hudakz 0:5350a66d5279 246 #define UIP_STAT(s)
hudakz 0:5350a66d5279 247 #endif /* UIP_STATISTICS == 1 */
hudakz 0:5350a66d5279 248
hudakz 0:5350a66d5279 249 #if UIP_LOGGING == 1
hudakz 0:5350a66d5279 250 #include <stdio.h>
hudakz 0:5350a66d5279 251 void uip_log(char* msg);
hudakz 0:5350a66d5279 252 #define UIP_LOG(m) uip_log(m)
hudakz 0:5350a66d5279 253 #else
hudakz 0:5350a66d5279 254 #define UIP_LOG(m)
hudakz 0:5350a66d5279 255 #endif /* UIP_LOGGING == 1 */
hudakz 0:5350a66d5279 256
hudakz 0:5350a66d5279 257 #if !UIP_ARCH_ADD32
hudakz 0:5350a66d5279 258
hudakz 0:5350a66d5279 259 /**
hudakz 0:5350a66d5279 260 * @brief
hudakz 0:5350a66d5279 261 * @note
hudakz 0:5350a66d5279 262 * @param
hudakz 0:5350a66d5279 263 * @retval
hudakz 0:5350a66d5279 264 */
hudakz 0:5350a66d5279 265 void uip_add32(u8_t* op32, u16_t op16) {
hudakz 0:5350a66d5279 266 uip_acc32[3] = op32[3] + (op16 & 0xff);
hudakz 0:5350a66d5279 267 uip_acc32[2] = op32[2] + (op16 >> 8);
hudakz 0:5350a66d5279 268 uip_acc32[1] = op32[1];
hudakz 0:5350a66d5279 269 uip_acc32[0] = op32[0];
hudakz 0:5350a66d5279 270
hudakz 0:5350a66d5279 271 if(uip_acc32[2] < (op16 >> 8)) {
hudakz 0:5350a66d5279 272 ++uip_acc32[1];
hudakz 0:5350a66d5279 273 if(uip_acc32[1] == 0) {
hudakz 0:5350a66d5279 274 ++uip_acc32[0];
hudakz 0:5350a66d5279 275 }
hudakz 0:5350a66d5279 276 }
hudakz 0:5350a66d5279 277
hudakz 0:5350a66d5279 278 if(uip_acc32[3] < (op16 & 0xff)) {
hudakz 0:5350a66d5279 279 ++uip_acc32[2];
hudakz 0:5350a66d5279 280 if(uip_acc32[2] == 0) {
hudakz 0:5350a66d5279 281 ++uip_acc32[1];
hudakz 0:5350a66d5279 282 if(uip_acc32[1] == 0) {
hudakz 0:5350a66d5279 283 ++uip_acc32[0];
hudakz 0:5350a66d5279 284 }
hudakz 0:5350a66d5279 285 }
hudakz 0:5350a66d5279 286 }
hudakz 0:5350a66d5279 287 }
hudakz 0:5350a66d5279 288 #endif /* UIP_ARCH_ADD32 */
hudakz 0:5350a66d5279 289
hudakz 0:5350a66d5279 290 #if !UIP_ARCH_CHKSUM
hudakz 0:5350a66d5279 291
hudakz 0:5350a66d5279 292 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 293 static u16_t chksum(u16_t sum, const u8_t* data, u16_t len) {
hudakz 0:5350a66d5279 294 u16_t t;
hudakz 0:5350a66d5279 295 const u8_t* dataptr;
hudakz 0:5350a66d5279 296 const u8_t* last_byte;
hudakz 0:5350a66d5279 297
hudakz 0:5350a66d5279 298 dataptr = data;
hudakz 0:5350a66d5279 299 last_byte = data + len - 1;
hudakz 0:5350a66d5279 300
hudakz 0:5350a66d5279 301 while(dataptr < last_byte) {
hudakz 0:5350a66d5279 302
hudakz 0:5350a66d5279 303 /* At least two more bytes */
hudakz 0:5350a66d5279 304 t = (dataptr[0] << 8) + dataptr[1];
hudakz 0:5350a66d5279 305 sum += t;
hudakz 0:5350a66d5279 306 if(sum < t) {
hudakz 0:5350a66d5279 307 sum++; /* carry */
hudakz 0:5350a66d5279 308 }
hudakz 0:5350a66d5279 309
hudakz 0:5350a66d5279 310 dataptr += 2;
hudakz 0:5350a66d5279 311 }
hudakz 0:5350a66d5279 312
hudakz 0:5350a66d5279 313 if(dataptr == last_byte) {
hudakz 0:5350a66d5279 314 t = (dataptr[0] << 8) + 0;
hudakz 0:5350a66d5279 315 sum += t;
hudakz 0:5350a66d5279 316 if(sum < t) {
hudakz 0:5350a66d5279 317 sum++; /* carry */
hudakz 0:5350a66d5279 318 }
hudakz 0:5350a66d5279 319 }
hudakz 0:5350a66d5279 320
hudakz 0:5350a66d5279 321 /* Return sum in host byte order. */
hudakz 0:5350a66d5279 322 return sum;
hudakz 0:5350a66d5279 323 }
hudakz 0:5350a66d5279 324
hudakz 0:5350a66d5279 325 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 326 u16_t uip_chksum(u16_t* data, u16_t len) {
hudakz 0:5350a66d5279 327 return htons(chksum(0, (u8_t*)data, len));
hudakz 0:5350a66d5279 328 }
hudakz 0:5350a66d5279 329
hudakz 0:5350a66d5279 330 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 331 #ifndef UIP_ARCH_IPCHKSUM
hudakz 0:5350a66d5279 332
hudakz 0:5350a66d5279 333 /**
hudakz 0:5350a66d5279 334 * @brief
hudakz 0:5350a66d5279 335 * @note
hudakz 0:5350a66d5279 336 * @param
hudakz 0:5350a66d5279 337 * @retval
hudakz 0:5350a66d5279 338 */
hudakz 0:5350a66d5279 339 u16_t uip_ipchksum(void) {
hudakz 0:5350a66d5279 340 u16_t sum;
hudakz 0:5350a66d5279 341
hudakz 0:5350a66d5279 342 sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN);
hudakz 0:5350a66d5279 343 DEBUG_PRINTF("uip_ipchksum: sum 0x%04x\n", sum);
hudakz 0:5350a66d5279 344 return(sum == 0) ? 0xffff : htons(sum);
hudakz 0:5350a66d5279 345 }
hudakz 0:5350a66d5279 346 #endif
hudakz 0:5350a66d5279 347
hudakz 0:5350a66d5279 348 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 349 static u16_t upper_layer_chksum(u8_t proto) {
hudakz 0:5350a66d5279 350 u16_t upper_layer_len;
hudakz 0:5350a66d5279 351 u16_t sum;
hudakz 0:5350a66d5279 352
hudakz 0:5350a66d5279 353 #if UIP_CONF_IPV6
hudakz 0:5350a66d5279 354 upper_layer_len = (((u16_t) (BUF->len[0]) << 8) + BUF->len[1]);
hudakz 0:5350a66d5279 355 #else /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 356 upper_layer_len = (((u16_t) (BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN;
hudakz 0:5350a66d5279 357 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 358
hudakz 0:5350a66d5279 359 /* First sum pseudoheader. */
hudakz 0:5350a66d5279 360
hudakz 0:5350a66d5279 361 /* IP protocol and length fields. This addition cannot carry. */
hudakz 0:5350a66d5279 362 sum = upper_layer_len + proto;
hudakz 0:5350a66d5279 363
hudakz 0:5350a66d5279 364 /* Sum IP source and destination addresses. */
hudakz 0:5350a66d5279 365 sum = chksum(sum, (u8_t*) &BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t));
hudakz 0:5350a66d5279 366
hudakz 0:5350a66d5279 367 /* Sum TCP header and data. */
hudakz 0:5350a66d5279 368 sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_len);
hudakz 0:5350a66d5279 369
hudakz 0:5350a66d5279 370 return(sum == 0) ? 0xffff : htons(sum);
hudakz 0:5350a66d5279 371 }
hudakz 0:5350a66d5279 372
hudakz 0:5350a66d5279 373 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 374 #if UIP_CONF_IPV6
hudakz 0:5350a66d5279 375
hudakz 0:5350a66d5279 376 /**
hudakz 0:5350a66d5279 377 * @brief
hudakz 0:5350a66d5279 378 * @note
hudakz 0:5350a66d5279 379 * @param
hudakz 0:5350a66d5279 380 * @retval
hudakz 0:5350a66d5279 381 */
hudakz 0:5350a66d5279 382 u16_t uip_icmp6chksum(void) {
hudakz 0:5350a66d5279 383 return upper_layer_chksum(UIP_PROTO_ICMP6);
hudakz 0:5350a66d5279 384 }
hudakz 0:5350a66d5279 385 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 386
hudakz 0:5350a66d5279 387 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 388 u16_t uip_tcpchksum(void) {
hudakz 0:5350a66d5279 389 return upper_layer_chksum(UIP_PROTO_TCP);
hudakz 0:5350a66d5279 390 }
hudakz 0:5350a66d5279 391
hudakz 0:5350a66d5279 392 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 393 #if UIP_UDP_CHECKSUMS
hudakz 0:5350a66d5279 394
hudakz 0:5350a66d5279 395 /**
hudakz 0:5350a66d5279 396 * @brief
hudakz 0:5350a66d5279 397 * @note
hudakz 0:5350a66d5279 398 * @param
hudakz 0:5350a66d5279 399 * @retval
hudakz 0:5350a66d5279 400 */
hudakz 0:5350a66d5279 401 u16_t uip_udpchksum(void) {
hudakz 0:5350a66d5279 402 return upper_layer_chksum(UIP_PROTO_UDP);
hudakz 0:5350a66d5279 403 }
hudakz 0:5350a66d5279 404 #endif /* UIP_UDP_CHECKSUMS */
hudakz 0:5350a66d5279 405 #endif /* UIP_ARCH_CHKSUM */
hudakz 0:5350a66d5279 406
hudakz 0:5350a66d5279 407 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 408 void uip_init(void) {
hudakz 0:5350a66d5279 409 for(c = 0; c < UIP_LISTENPORTS; ++c) {
hudakz 0:5350a66d5279 410 uip_listenports[c] = 0;
hudakz 0:5350a66d5279 411 }
hudakz 0:5350a66d5279 412
hudakz 0:5350a66d5279 413 for(c = 0; c < UIP_CONNS; ++c) {
hudakz 0:5350a66d5279 414 uip_conns[c].tcpstateflags = UIP_CLOSED;
hudakz 0:5350a66d5279 415 }
hudakz 0:5350a66d5279 416
hudakz 0:5350a66d5279 417 #if UIP_ACTIVE_OPEN
hudakz 0:5350a66d5279 418 lastport = 1024;
hudakz 0:5350a66d5279 419 #endif /* UIP_ACTIVE_OPEN */
hudakz 0:5350a66d5279 420
hudakz 0:5350a66d5279 421 #if UIP_UDP
hudakz 0:5350a66d5279 422 for(c = 0; c < UIP_UDP_CONNS; ++c) {
hudakz 0:5350a66d5279 423 uip_udp_conns[c].lport = 0;
hudakz 0:5350a66d5279 424 }
hudakz 0:5350a66d5279 425 #endif /* UIP_UDP */
hudakz 0:5350a66d5279 426
hudakz 0:5350a66d5279 427 /* IPv4 initialization. */
hudakz 0:5350a66d5279 428
hudakz 0:5350a66d5279 429 #if UIP_FIXEDADDR == 0
hudakz 0:5350a66d5279 430 /* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/
hudakz 0:5350a66d5279 431 #endif /* UIP_FIXEDADDR */
hudakz 0:5350a66d5279 432 }
hudakz 0:5350a66d5279 433
hudakz 0:5350a66d5279 434 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 435 #if UIP_ACTIVE_OPEN
hudakz 0:5350a66d5279 436
hudakz 0:5350a66d5279 437 /**
hudakz 0:5350a66d5279 438 * @brief
hudakz 0:5350a66d5279 439 * @note
hudakz 0:5350a66d5279 440 * @param
hudakz 0:5350a66d5279 441 * @retval
hudakz 0:5350a66d5279 442 */
hudakz 0:5350a66d5279 443 struct uip_conn* uip_connect(uip_ipaddr_t* ripaddr, u16_t rport) {
hudakz 0:5350a66d5279 444 register struct uip_conn* conn, *cconn;
hudakz 0:5350a66d5279 445
hudakz 0:5350a66d5279 446 /* Find an unused local port. */
hudakz 0:5350a66d5279 447
hudakz 0:5350a66d5279 448 again:
hudakz 0:5350a66d5279 449 ++lastport;
hudakz 0:5350a66d5279 450
hudakz 0:5350a66d5279 451 if(lastport >= 32000) {
hudakz 0:5350a66d5279 452 lastport = 4096;
hudakz 0:5350a66d5279 453 }
hudakz 0:5350a66d5279 454
hudakz 0:5350a66d5279 455 /* Check if this port is already in use, and if so try to find
hudakz 0:5350a66d5279 456 another one. */
hudakz 0:5350a66d5279 457 for(c = 0; c < UIP_CONNS; ++c) {
hudakz 0:5350a66d5279 458 conn = &uip_conns[c];
hudakz 0:5350a66d5279 459 if(conn->tcpstateflags != UIP_CLOSED && conn->lport == htons(lastport)) {
hudakz 0:5350a66d5279 460 goto again;
hudakz 0:5350a66d5279 461 }
hudakz 0:5350a66d5279 462 }
hudakz 0:5350a66d5279 463
hudakz 0:5350a66d5279 464 conn = 0;
hudakz 0:5350a66d5279 465 for(c = 0; c < UIP_CONNS; ++c) {
hudakz 0:5350a66d5279 466 cconn = &uip_conns[c];
hudakz 0:5350a66d5279 467 if(cconn->tcpstateflags == UIP_CLOSED) {
hudakz 0:5350a66d5279 468 conn = cconn;
hudakz 0:5350a66d5279 469 break;
hudakz 0:5350a66d5279 470 }
hudakz 0:5350a66d5279 471
hudakz 0:5350a66d5279 472 if(cconn->tcpstateflags == UIP_TIME_WAIT) {
hudakz 0:5350a66d5279 473 if(conn == 0 || cconn->timer > conn->timer) {
hudakz 0:5350a66d5279 474 conn = cconn;
hudakz 0:5350a66d5279 475 }
hudakz 0:5350a66d5279 476 }
hudakz 0:5350a66d5279 477 }
hudakz 0:5350a66d5279 478
hudakz 0:5350a66d5279 479 if(conn == 0) {
hudakz 0:5350a66d5279 480 return 0;
hudakz 0:5350a66d5279 481 }
hudakz 0:5350a66d5279 482
hudakz 0:5350a66d5279 483 conn->tcpstateflags = UIP_SYN_SENT;
hudakz 0:5350a66d5279 484
hudakz 0:5350a66d5279 485 conn->snd_nxt[0] = iss[0];
hudakz 0:5350a66d5279 486 conn->snd_nxt[1] = iss[1];
hudakz 0:5350a66d5279 487 conn->snd_nxt[2] = iss[2];
hudakz 0:5350a66d5279 488 conn->snd_nxt[3] = iss[3];
hudakz 0:5350a66d5279 489
hudakz 0:5350a66d5279 490 conn->initialmss = conn->mss = UIP_TCP_MSS;
hudakz 0:5350a66d5279 491
hudakz 0:5350a66d5279 492 conn->len = 1; /* TCP length of the SYN is one. */
hudakz 0:5350a66d5279 493 conn->nrtx = 0;
hudakz 0:5350a66d5279 494 conn->timer = 1; /* Send the SYN next time around. */
hudakz 0:5350a66d5279 495 conn->rto = UIP_RTO;
hudakz 0:5350a66d5279 496 conn->sa = 0;
hudakz 0:5350a66d5279 497 conn->sv = 16; /* Initial value of the RTT variance. */
hudakz 0:5350a66d5279 498 conn->lport = htons(lastport);
hudakz 0:5350a66d5279 499 conn->rport = rport;
hudakz 0:5350a66d5279 500 uip_ipaddr_copy(&conn->ripaddr, ripaddr);
hudakz 0:5350a66d5279 501
hudakz 0:5350a66d5279 502 return conn;
hudakz 0:5350a66d5279 503 }
hudakz 0:5350a66d5279 504 #endif /* UIP_ACTIVE_OPEN */
hudakz 0:5350a66d5279 505
hudakz 0:5350a66d5279 506 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 507
hudakz 0:5350a66d5279 508 #if UIP_UDP
hudakz 0:5350a66d5279 509
hudakz 0:5350a66d5279 510 /**
hudakz 0:5350a66d5279 511 * @brief
hudakz 0:5350a66d5279 512 * @note
hudakz 0:5350a66d5279 513 * @param
hudakz 0:5350a66d5279 514 * @retval
hudakz 0:5350a66d5279 515 */
hudakz 0:5350a66d5279 516 struct uip_udp_conn* uip_udp_new(uip_ipaddr_t* ripaddr, u16_t rport) {
hudakz 0:5350a66d5279 517 register struct uip_udp_conn* conn;
hudakz 0:5350a66d5279 518
hudakz 0:5350a66d5279 519 /* Find an unused local port. */
hudakz 0:5350a66d5279 520
hudakz 0:5350a66d5279 521 again:
hudakz 0:5350a66d5279 522 ++lastport;
hudakz 0:5350a66d5279 523
hudakz 0:5350a66d5279 524 if(lastport >= 32000) {
hudakz 0:5350a66d5279 525 lastport = 4096;
hudakz 0:5350a66d5279 526 }
hudakz 0:5350a66d5279 527
hudakz 0:5350a66d5279 528 for(c = 0; c < UIP_UDP_CONNS; ++c) {
hudakz 0:5350a66d5279 529 if(uip_udp_conns[c].lport == htons(lastport)) {
hudakz 0:5350a66d5279 530 goto again;
hudakz 0:5350a66d5279 531 }
hudakz 0:5350a66d5279 532 }
hudakz 0:5350a66d5279 533
hudakz 0:5350a66d5279 534 conn = 0;
hudakz 0:5350a66d5279 535 for(c = 0; c < UIP_UDP_CONNS; ++c) {
hudakz 0:5350a66d5279 536 if(uip_udp_conns[c].lport == 0) {
hudakz 0:5350a66d5279 537 conn = &uip_udp_conns[c];
hudakz 0:5350a66d5279 538 break;
hudakz 0:5350a66d5279 539 }
hudakz 0:5350a66d5279 540 }
hudakz 0:5350a66d5279 541
hudakz 0:5350a66d5279 542 if(conn == 0) {
hudakz 0:5350a66d5279 543 return 0;
hudakz 0:5350a66d5279 544 }
hudakz 0:5350a66d5279 545
hudakz 0:5350a66d5279 546 conn->lport = HTONS(lastport);
hudakz 0:5350a66d5279 547 conn->rport = rport;
hudakz 0:5350a66d5279 548 if(ripaddr == NULL) {
hudakz 0:5350a66d5279 549 memset(conn->ripaddr, 0, sizeof(uip_ipaddr_t));
hudakz 0:5350a66d5279 550 }
hudakz 0:5350a66d5279 551 else {
hudakz 0:5350a66d5279 552 uip_ipaddr_copy(&conn->ripaddr, ripaddr);
hudakz 0:5350a66d5279 553 }
hudakz 0:5350a66d5279 554
hudakz 0:5350a66d5279 555 conn->ttl = UIP_TTL;
hudakz 0:5350a66d5279 556
hudakz 0:5350a66d5279 557 return conn;
hudakz 0:5350a66d5279 558 }
hudakz 0:5350a66d5279 559 #endif /* UIP_UDP */
hudakz 0:5350a66d5279 560
hudakz 0:5350a66d5279 561 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 562 void uip_unlisten(u16_t port) {
hudakz 0:5350a66d5279 563 for(c = 0; c < UIP_LISTENPORTS; ++c) {
hudakz 0:5350a66d5279 564 if(uip_listenports[c] == port) {
hudakz 0:5350a66d5279 565 uip_listenports[c] = 0;
hudakz 0:5350a66d5279 566 return;
hudakz 0:5350a66d5279 567 }
hudakz 0:5350a66d5279 568 }
hudakz 0:5350a66d5279 569 }
hudakz 0:5350a66d5279 570
hudakz 0:5350a66d5279 571 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 572 void uip_listen(u16_t port) {
hudakz 0:5350a66d5279 573 for(c = 0; c < UIP_LISTENPORTS; ++c) {
hudakz 0:5350a66d5279 574 if(uip_listenports[c] == 0) {
hudakz 0:5350a66d5279 575 uip_listenports[c] = port;
hudakz 0:5350a66d5279 576 return;
hudakz 0:5350a66d5279 577 }
hudakz 0:5350a66d5279 578 }
hudakz 0:5350a66d5279 579 }
hudakz 0:5350a66d5279 580
hudakz 0:5350a66d5279 581 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 582 /* XXX: IP fragment reassembly: not well-tested. */
hudakz 0:5350a66d5279 583 #if UIP_REASSEMBLY && !UIP_CONF_IPV6
hudakz 0:5350a66d5279 584 #define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
hudakz 0:5350a66d5279 585 static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
hudakz 0:5350a66d5279 586 static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
hudakz 0:5350a66d5279 587 static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
hudakz 0:5350a66d5279 588 static u16_t uip_reasslen;
hudakz 0:5350a66d5279 589 static u8_t uip_reassflags;
hudakz 0:5350a66d5279 590 #define UIP_REASS_FLAG_LASTFRAG 0x01
hudakz 0:5350a66d5279 591 static u8_t uip_reasstmr;
hudakz 0:5350a66d5279 592
hudakz 0:5350a66d5279 593 #define IP_MF 0x20
hudakz 0:5350a66d5279 594
hudakz 0:5350a66d5279 595 /**
hudakz 0:5350a66d5279 596 * @brief
hudakz 0:5350a66d5279 597 * @note
hudakz 0:5350a66d5279 598 * @param
hudakz 0:5350a66d5279 599 * @retval
hudakz 0:5350a66d5279 600 */
hudakz 0:5350a66d5279 601 static u8_t uip_reass(void) {
hudakz 0:5350a66d5279 602 u16_t offset, len;
hudakz 0:5350a66d5279 603 u16_t i;
hudakz 0:5350a66d5279 604
hudakz 0:5350a66d5279 605 /* If ip_reasstmr is zero, no packet is present in the buffer, so we
hudakz 0:5350a66d5279 606 write the IP header of the fragment into the reassembly
hudakz 0:5350a66d5279 607 buffer. The timer is updated with the maximum age. */
hudakz 0:5350a66d5279 608
hudakz 0:5350a66d5279 609 if(uip_reasstmr == 0) {
hudakz 0:5350a66d5279 610 memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN);
hudakz 0:5350a66d5279 611 uip_reasstmr = UIP_REASS_MAXAGE;
hudakz 0:5350a66d5279 612 uip_reassflags = 0;
hudakz 0:5350a66d5279 613
hudakz 0:5350a66d5279 614 /* Clear the bitmap. */
hudakz 0:5350a66d5279 615 memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap));
hudakz 0:5350a66d5279 616 }
hudakz 0:5350a66d5279 617
hudakz 0:5350a66d5279 618 /* Check if the incoming fragment matches the one currently present
hudakz 0:5350a66d5279 619 in the reasembly buffer. If so, we proceed with copying the
hudakz 0:5350a66d5279 620 fragment into the buffer. */
hudakz 0:5350a66d5279 621 if
hudakz 0:5350a66d5279 622 (
hudakz 0:5350a66d5279 623 BUF->srcipaddr[0] == FBUF->srcipaddr[0]
hudakz 0:5350a66d5279 624 && BUF->srcipaddr[1] == FBUF->srcipaddr[1]
hudakz 0:5350a66d5279 625 && BUF->destipaddr[0] == FBUF->destipaddr[0]
hudakz 0:5350a66d5279 626 && BUF->destipaddr[1] == FBUF->destipaddr[1]
hudakz 0:5350a66d5279 627 && BUF->ipid[0] == FBUF->ipid[0]
hudakz 0:5350a66d5279 628 && BUF->ipid[1] == FBUF->ipid[1]
hudakz 0:5350a66d5279 629 ) {
hudakz 0:5350a66d5279 630 len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4;
hudakz 0:5350a66d5279 631 offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8;
hudakz 0:5350a66d5279 632
hudakz 0:5350a66d5279 633 /* If the offset or the offset + fragment length overflows the
hudakz 0:5350a66d5279 634 reassembly buffer, we discard the entire packet. */
hudakz 0:5350a66d5279 635 if(offset > UIP_REASS_BUFSIZE || offset + len > UIP_REASS_BUFSIZE) {
hudakz 0:5350a66d5279 636 uip_reasstmr = 0;
hudakz 0:5350a66d5279 637 goto nullreturn;
hudakz 0:5350a66d5279 638 }
hudakz 0:5350a66d5279 639
hudakz 0:5350a66d5279 640 /* Copy the fragment into the reassembly buffer, at the right
hudakz 0:5350a66d5279 641 offset. */
hudakz 0:5350a66d5279 642 memcpy(&uip_reassbuf[UIP_IPH_LEN + offset], (char*)BUF + (int)((BUF->vhl & 0x0f) * 4), len);
hudakz 0:5350a66d5279 643
hudakz 0:5350a66d5279 644 /* Update the bitmap. */
hudakz 0:5350a66d5279 645 if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
hudakz 0:5350a66d5279 646
hudakz 0:5350a66d5279 647 /* If the two endpoints are in the same byte, we only update
hudakz 0:5350a66d5279 648 that byte. */
hudakz 0:5350a66d5279 649 uip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7] &~bitmap_bits[((offset + len) / 8) & 7];
hudakz 0:5350a66d5279 650 }
hudakz 0:5350a66d5279 651 else {
hudakz 0:5350a66d5279 652
hudakz 0:5350a66d5279 653 /* If the two endpoints are in different bytes, we update the
hudakz 0:5350a66d5279 654 bytes in the endpoints and fill the stuff inbetween with
hudakz 0:5350a66d5279 655 0xff. */
hudakz 0:5350a66d5279 656 uip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7];
hudakz 0:5350a66d5279 657 for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
hudakz 0:5350a66d5279 658 uip_reassbitmap[i] = 0xff;
hudakz 0:5350a66d5279 659 }
hudakz 0:5350a66d5279 660
hudakz 0:5350a66d5279 661 uip_reassbitmap[(offset + len) / (8 * 8)] |= ~bitmap_bits[((offset + len) / 8) & 7];
hudakz 0:5350a66d5279 662 }
hudakz 0:5350a66d5279 663
hudakz 0:5350a66d5279 664 /* If this fragment has the More Fragments flag set to zero, we
hudakz 0:5350a66d5279 665 know that this is the last fragment, so we can calculate the
hudakz 0:5350a66d5279 666 size of the entire packet. We also set the
hudakz 0:5350a66d5279 667 IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
hudakz 0:5350a66d5279 668 the final fragment. */
hudakz 0:5350a66d5279 669 if((BUF->ipoffset[0] & IP_MF) == 0) {
hudakz 0:5350a66d5279 670 uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
hudakz 0:5350a66d5279 671 uip_reasslen = offset + len;
hudakz 0:5350a66d5279 672 }
hudakz 0:5350a66d5279 673
hudakz 0:5350a66d5279 674 /* Finally, we check if we have a full packet in the buffer. We do
hudakz 0:5350a66d5279 675 this by checking if we have the last fragment and if all bits
hudakz 0:5350a66d5279 676 in the bitmap are set. */
hudakz 0:5350a66d5279 677 if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
hudakz 0:5350a66d5279 678
hudakz 0:5350a66d5279 679 /* Check all bytes up to and including all but the last byte in
hudakz 0:5350a66d5279 680 the bitmap. */
hudakz 0:5350a66d5279 681 for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
hudakz 0:5350a66d5279 682 if(uip_reassbitmap[i] != 0xff) {
hudakz 0:5350a66d5279 683 goto nullreturn;
hudakz 0:5350a66d5279 684 }
hudakz 0:5350a66d5279 685 }
hudakz 0:5350a66d5279 686
hudakz 0:5350a66d5279 687 /* Check the last byte in the bitmap. It should contain just the
hudakz 0:5350a66d5279 688 right amount of bits. */
hudakz 0:5350a66d5279 689 if(uip_reassbitmap[uip_reasslen / (8 * 8)] != (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
hudakz 0:5350a66d5279 690 goto nullreturn;
hudakz 0:5350a66d5279 691 }
hudakz 0:5350a66d5279 692
hudakz 0:5350a66d5279 693 /* If we have come this far, we have a full packet in the
hudakz 0:5350a66d5279 694 buffer, so we allocate a pbuf and copy the packet into it. We
hudakz 0:5350a66d5279 695 also reset the timer. */
hudakz 0:5350a66d5279 696 uip_reasstmr = 0;
hudakz 0:5350a66d5279 697 memcpy(BUF, FBUF, uip_reasslen);
hudakz 0:5350a66d5279 698
hudakz 0:5350a66d5279 699 /* Pretend to be a "normal" (i.e., not fragmented) IP packet
hudakz 0:5350a66d5279 700 from now on. */
hudakz 0:5350a66d5279 701 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
hudakz 0:5350a66d5279 702 BUF->len[0] = uip_reasslen >> 8;
hudakz 0:5350a66d5279 703 BUF->len[1] = uip_reasslen & 0xff;
hudakz 0:5350a66d5279 704 BUF->ipchksum = 0;
hudakz 0:5350a66d5279 705 BUF->ipchksum = ~(uip_ipchksum());
hudakz 0:5350a66d5279 706
hudakz 0:5350a66d5279 707 return uip_reasslen;
hudakz 0:5350a66d5279 708 }
hudakz 0:5350a66d5279 709 }
hudakz 0:5350a66d5279 710
hudakz 0:5350a66d5279 711 nullreturn:
hudakz 0:5350a66d5279 712 return 0;
hudakz 0:5350a66d5279 713 }
hudakz 0:5350a66d5279 714 #endif /* UIP_REASSEMBLY */
hudakz 0:5350a66d5279 715
hudakz 0:5350a66d5279 716 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 717 static void uip_add_rcv_nxt(u16_t n) {
hudakz 0:5350a66d5279 718 uip_add32(uip_conn->rcv_nxt, n);
hudakz 0:5350a66d5279 719 uip_conn->rcv_nxt[0] = uip_acc32[0];
hudakz 0:5350a66d5279 720 uip_conn->rcv_nxt[1] = uip_acc32[1];
hudakz 0:5350a66d5279 721 uip_conn->rcv_nxt[2] = uip_acc32[2];
hudakz 0:5350a66d5279 722 uip_conn->rcv_nxt[3] = uip_acc32[3];
hudakz 0:5350a66d5279 723 }
hudakz 0:5350a66d5279 724
hudakz 0:5350a66d5279 725 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 726 void uip_process(u8_t flag) {
hudakz 0:5350a66d5279 727 register struct uip_conn* uip_connr = uip_conn;
hudakz 0:5350a66d5279 728
hudakz 0:5350a66d5279 729 #if UIP_UDP
hudakz 0:5350a66d5279 730 if(flag == UIP_UDP_SEND_CONN) {
hudakz 0:5350a66d5279 731 goto udp_send;
hudakz 0:5350a66d5279 732 }
hudakz 0:5350a66d5279 733 #endif /* UIP_UDP */
hudakz 0:5350a66d5279 734
hudakz 0:5350a66d5279 735 uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];
hudakz 0:5350a66d5279 736
hudakz 0:5350a66d5279 737 /* Check if we were invoked because of a poll request for a
hudakz 0:5350a66d5279 738 particular connection. */
hudakz 0:5350a66d5279 739 if(flag == UIP_POLL_REQUEST) {
hudakz 0:5350a66d5279 740 if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED && !uip_outstanding(uip_connr)) {
hudakz 0:5350a66d5279 741 uip_flags = UIP_POLL;
hudakz 0:5350a66d5279 742 UIP_APPCALL();
hudakz 0:5350a66d5279 743 goto appsend;
hudakz 0:5350a66d5279 744 }
hudakz 0:5350a66d5279 745
hudakz 0:5350a66d5279 746 goto drop;
hudakz 0:5350a66d5279 747
hudakz 0:5350a66d5279 748 /* Check if we were invoked because of the perodic timer fireing. */
hudakz 0:5350a66d5279 749 }
hudakz 0:5350a66d5279 750 else
hudakz 0:5350a66d5279 751 if(flag == UIP_TIMER)
hudakz 0:5350a66d5279 752 {
hudakz 0:5350a66d5279 753 #if UIP_REASSEMBLY
hudakz 0:5350a66d5279 754 if(uip_reasstmr != 0) {
hudakz 0:5350a66d5279 755 --uip_reasstmr;
hudakz 0:5350a66d5279 756 }
hudakz 0:5350a66d5279 757 #endif /* UIP_REASSEMBLY */
hudakz 0:5350a66d5279 758
hudakz 0:5350a66d5279 759 /* Increase the initial sequence number. */
hudakz 0:5350a66d5279 760
hudakz 0:5350a66d5279 761 if(++iss[3] == 0) {
hudakz 0:5350a66d5279 762 if(++iss[2] == 0) {
hudakz 0:5350a66d5279 763 if(++iss[1] == 0) {
hudakz 0:5350a66d5279 764 ++iss[0];
hudakz 0:5350a66d5279 765 }
hudakz 0:5350a66d5279 766 }
hudakz 0:5350a66d5279 767 }
hudakz 0:5350a66d5279 768
hudakz 0:5350a66d5279 769 /* Reset the length variables. */
hudakz 0:5350a66d5279 770 uip_len = 0;
hudakz 0:5350a66d5279 771 uip_slen = 0;
hudakz 0:5350a66d5279 772
hudakz 0:5350a66d5279 773 /* Check if the connection is in a state in which we simply wait
hudakz 0:5350a66d5279 774 for the connection to time out. If so, we increase the
hudakz 0:5350a66d5279 775 connection's timer and remove the connection if it times
hudakz 0:5350a66d5279 776 out. */
hudakz 0:5350a66d5279 777 if(uip_connr->tcpstateflags == UIP_TIME_WAIT || uip_connr->tcpstateflags == UIP_FIN_WAIT_2) {
hudakz 0:5350a66d5279 778 ++(uip_connr->timer);
hudakz 0:5350a66d5279 779 if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
hudakz 0:5350a66d5279 780 uip_connr->tcpstateflags = UIP_CLOSED;
hudakz 0:5350a66d5279 781 }
hudakz 0:5350a66d5279 782 }
hudakz 0:5350a66d5279 783 else
hudakz 0:5350a66d5279 784 if(uip_connr->tcpstateflags != UIP_CLOSED) {
hudakz 0:5350a66d5279 785
hudakz 0:5350a66d5279 786 /* If the connection has outstanding data, we increase the
hudakz 0:5350a66d5279 787 connection's timer and see if it has reached the RTO value
hudakz 0:5350a66d5279 788 in which case we retransmit. */
hudakz 0:5350a66d5279 789 if(uip_outstanding(uip_connr)) {
hudakz 0:5350a66d5279 790 if(uip_connr->timer-- == 0) {
hudakz 0:5350a66d5279 791 if
hudakz 0:5350a66d5279 792 (
hudakz 0:5350a66d5279 793 uip_connr->nrtx == UIP_MAXRTX
hudakz 0:5350a66d5279 794 || (
hudakz 0:5350a66d5279 795 (uip_connr->tcpstateflags == UIP_SYN_SENT || uip_connr->tcpstateflags == UIP_SYN_RCVD)
hudakz 0:5350a66d5279 796 && uip_connr->nrtx == UIP_MAXSYNRTX
hudakz 0:5350a66d5279 797 )
hudakz 0:5350a66d5279 798 ) {
hudakz 0:5350a66d5279 799 uip_connr->tcpstateflags = UIP_CLOSED;
hudakz 0:5350a66d5279 800
hudakz 0:5350a66d5279 801 /* We call UIP_APPCALL() with uip_flags set to
hudakz 0:5350a66d5279 802 UIP_TIMEDOUT to inform the application that the
hudakz 0:5350a66d5279 803 connection has timed out. */
hudakz 0:5350a66d5279 804 uip_flags = UIP_TIMEDOUT;
hudakz 0:5350a66d5279 805 UIP_APPCALL();
hudakz 0:5350a66d5279 806
hudakz 0:5350a66d5279 807 /* We also send a reset packet to the remote host. */
hudakz 0:5350a66d5279 808 BUF->flags = TCP_RST | TCP_ACK;
hudakz 0:5350a66d5279 809 goto tcp_send_nodata;
hudakz 0:5350a66d5279 810 }
hudakz 0:5350a66d5279 811
hudakz 0:5350a66d5279 812 /* Exponential backoff. */
hudakz 0:5350a66d5279 813 uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4 ? 4 : uip_connr->nrtx);
hudakz 0:5350a66d5279 814 ++(uip_connr->nrtx);
hudakz 0:5350a66d5279 815
hudakz 0:5350a66d5279 816 /* Ok, so we need to retransmit. We do this differently
hudakz 0:5350a66d5279 817 depending on which state we are in. In ESTABLISHED, we
hudakz 0:5350a66d5279 818 call upon the application so that it may prepare the
hudakz 0:5350a66d5279 819 data for the retransmit. In SYN_RCVD, we resend the
hudakz 0:5350a66d5279 820 SYNACK that we sent earlier and in LAST_ACK we have to
hudakz 0:5350a66d5279 821 retransmit our FINACK. */
hudakz 0:5350a66d5279 822 UIP_STAT(++uip_stat.tcp.rexmit);
hudakz 0:5350a66d5279 823 switch(uip_connr->tcpstateflags & UIP_TS_MASK) {
hudakz 0:5350a66d5279 824 case UIP_SYN_RCVD:
hudakz 0:5350a66d5279 825 /* In the SYN_RCVD state, we should retransmit our
hudakz 0:5350a66d5279 826 SYNACK. */
hudakz 0:5350a66d5279 827 goto tcp_send_synack;
hudakz 0:5350a66d5279 828
hudakz 0:5350a66d5279 829 #if UIP_ACTIVE_OPEN
hudakz 0:5350a66d5279 830
hudakz 0:5350a66d5279 831 case UIP_SYN_SENT:
hudakz 0:5350a66d5279 832 /* In the SYN_SENT state, we retransmit out SYN. */
hudakz 0:5350a66d5279 833 BUF->flags = 0;
hudakz 0:5350a66d5279 834 goto tcp_send_syn;
hudakz 0:5350a66d5279 835 #endif /* UIP_ACTIVE_OPEN */
hudakz 0:5350a66d5279 836
hudakz 0:5350a66d5279 837 case UIP_ESTABLISHED:
hudakz 0:5350a66d5279 838 /* In the ESTABLISHED state, we call upon the application
hudakz 0:5350a66d5279 839 to do the actual retransmit after which we jump into
hudakz 0:5350a66d5279 840 the code for sending out the packet (the apprexmit
hudakz 0:5350a66d5279 841 label). */
hudakz 0:5350a66d5279 842 uip_flags = UIP_REXMIT;
hudakz 0:5350a66d5279 843 UIP_APPCALL();
hudakz 0:5350a66d5279 844 goto apprexmit;
hudakz 0:5350a66d5279 845
hudakz 0:5350a66d5279 846 case UIP_FIN_WAIT_1:
hudakz 0:5350a66d5279 847 case UIP_CLOSING:
hudakz 0:5350a66d5279 848 case UIP_LAST_ACK:
hudakz 0:5350a66d5279 849 /* In all these states we should retransmit a FINACK. */
hudakz 0:5350a66d5279 850 goto tcp_send_finack;
hudakz 0:5350a66d5279 851 }
hudakz 0:5350a66d5279 852 }
hudakz 0:5350a66d5279 853 }
hudakz 0:5350a66d5279 854 else
hudakz 0:5350a66d5279 855 if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) {
hudakz 0:5350a66d5279 856
hudakz 0:5350a66d5279 857 /* If there was no need for a retransmission, we poll the
hudakz 0:5350a66d5279 858 application for new data. */
hudakz 0:5350a66d5279 859 uip_flags = UIP_POLL;
hudakz 0:5350a66d5279 860 UIP_APPCALL();
hudakz 0:5350a66d5279 861 goto appsend;
hudakz 0:5350a66d5279 862 }
hudakz 0:5350a66d5279 863 }
hudakz 0:5350a66d5279 864
hudakz 0:5350a66d5279 865 goto drop;
hudakz 0:5350a66d5279 866 }
hudakz 0:5350a66d5279 867
hudakz 0:5350a66d5279 868 #if UIP_UDP
hudakz 0:5350a66d5279 869 if(flag == UIP_UDP_TIMER) {
hudakz 0:5350a66d5279 870 if(uip_udp_conn->lport != 0) {
hudakz 0:5350a66d5279 871 uip_conn = NULL;
hudakz 0:5350a66d5279 872 uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
hudakz 0:5350a66d5279 873 uip_len = uip_slen = 0;
hudakz 0:5350a66d5279 874 uip_flags = UIP_POLL;
hudakz 0:5350a66d5279 875 UIP_UDP_APPCALL();
hudakz 0:5350a66d5279 876 goto udp_send;
hudakz 0:5350a66d5279 877 }
hudakz 0:5350a66d5279 878 else {
hudakz 0:5350a66d5279 879 goto drop;
hudakz 0:5350a66d5279 880 }
hudakz 0:5350a66d5279 881 }
hudakz 0:5350a66d5279 882 #endif
hudakz 0:5350a66d5279 883 /* This is where the input processing starts. */
hudakz 0:5350a66d5279 884
hudakz 0:5350a66d5279 885 UIP_STAT(++uip_stat.ip.recv);
hudakz 0:5350a66d5279 886
hudakz 0:5350a66d5279 887 /* Start of IP input header processing code. */
hudakz 0:5350a66d5279 888 #if UIP_CONF_IPV6
hudakz 0:5350a66d5279 889 /* Check validity of the IP header. */
hudakz 0:5350a66d5279 890
hudakz 0:5350a66d5279 891 if((BUF->vtc & 0xf0) != 0x60) {
hudakz 0:5350a66d5279 892
hudakz 0:5350a66d5279 893 /* IP version and header length. */
hudakz 0:5350a66d5279 894 UIP_STAT(++uip_stat.ip.drop);
hudakz 0:5350a66d5279 895 UIP_STAT(++uip_stat.ip.vhlerr);
hudakz 0:5350a66d5279 896 UIP_LOG("ipv6: invalid version.");
hudakz 0:5350a66d5279 897 goto drop;
hudakz 0:5350a66d5279 898 }
hudakz 0:5350a66d5279 899
hudakz 0:5350a66d5279 900 #else /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 901 /* Check validity of the IP header. */
hudakz 0:5350a66d5279 902
hudakz 0:5350a66d5279 903 if(BUF->vhl != 0x45) {
hudakz 0:5350a66d5279 904
hudakz 0:5350a66d5279 905 /* IP version and header length. */
hudakz 0:5350a66d5279 906 UIP_STAT(++uip_stat.ip.drop);
hudakz 0:5350a66d5279 907 UIP_STAT(++uip_stat.ip.vhlerr);
hudakz 0:5350a66d5279 908 UIP_LOG("ip: invalid version or header length.");
hudakz 0:5350a66d5279 909 goto drop;
hudakz 0:5350a66d5279 910 }
hudakz 0:5350a66d5279 911 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 912
hudakz 0:5350a66d5279 913 /* Check the size of the packet. If the size reported to us in
hudakz 0:5350a66d5279 914 uip_len is smaller the size reported in the IP header, we assume
hudakz 0:5350a66d5279 915 that the packet has been corrupted in transit. If the size of
hudakz 0:5350a66d5279 916 uip_len is larger than the size reported in the IP packet header,
hudakz 0:5350a66d5279 917 the packet has been padded and we set uip_len to the correct
hudakz 0:5350a66d5279 918 value.. */
hudakz 0:5350a66d5279 919
hudakz 0:5350a66d5279 920 if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) {
hudakz 0:5350a66d5279 921 uip_len = (BUF->len[0] << 8) + BUF->len[1];
hudakz 0:5350a66d5279 922 #if UIP_CONF_IPV6
hudakz 0:5350a66d5279 923 uip_len += 40; /* The length reported in the IPv6 header is the
hudakz 0:5350a66d5279 924 length of the payload that follows the
hudakz 0:5350a66d5279 925 header. However, uIP uses the uip_len variable
hudakz 0:5350a66d5279 926 for holding the size of the entire packet,
hudakz 0:5350a66d5279 927 including the IP header. For IPv4 this is not a
hudakz 0:5350a66d5279 928 problem as the length field in the IPv4 header
hudakz 0:5350a66d5279 929 contains the length of the entire packet. But
hudakz 0:5350a66d5279 930 for IPv6 we need to add the size of the IPv6
hudakz 0:5350a66d5279 931 header (40 bytes). */
hudakz 0:5350a66d5279 932 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 933 }
hudakz 0:5350a66d5279 934 else {
hudakz 0:5350a66d5279 935 UIP_LOG("ip: packet shorter than reported in IP header.");
hudakz 0:5350a66d5279 936 goto drop;
hudakz 0:5350a66d5279 937 }
hudakz 0:5350a66d5279 938
hudakz 0:5350a66d5279 939 #if !UIP_CONF_IPV6
hudakz 0:5350a66d5279 940 /* Check the fragment flag. */
hudakz 0:5350a66d5279 941
hudakz 0:5350a66d5279 942 if((BUF->ipoffset[0] & 0x3f) != 0 || BUF->ipoffset[1] != 0)
hudakz 0:5350a66d5279 943 {
hudakz 0:5350a66d5279 944 #if UIP_REASSEMBLY
hudakz 0:5350a66d5279 945 uip_len = uip_reass();
hudakz 0:5350a66d5279 946 if(uip_len == 0) {
hudakz 0:5350a66d5279 947 goto drop;
hudakz 0:5350a66d5279 948 }
hudakz 0:5350a66d5279 949
hudakz 0:5350a66d5279 950 #else /* UIP_REASSEMBLY */
hudakz 0:5350a66d5279 951 UIP_STAT(++uip_stat.ip.drop);
hudakz 0:5350a66d5279 952 UIP_STAT(++uip_stat.ip.fragerr);
hudakz 0:5350a66d5279 953 UIP_LOG("ip: fragment dropped.");
hudakz 0:5350a66d5279 954 goto drop;
hudakz 0:5350a66d5279 955 #endif /* UIP_REASSEMBLY */
hudakz 0:5350a66d5279 956 }
hudakz 0:5350a66d5279 957 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 958
hudakz 0:5350a66d5279 959 if(uip_ipaddr_cmp(uip_hostaddr, all_zeroes_addr))
hudakz 0:5350a66d5279 960 {
hudakz 0:5350a66d5279 961 /* If we are configured to use ping IP address configuration and
hudakz 0:5350a66d5279 962 hasn't been assigned an IP address yet, we accept all ICMP
hudakz 0:5350a66d5279 963 packets. */
hudakz 0:5350a66d5279 964 #if UIP_PINGADDRCONF && !UIP_CONF_IPV6
hudakz 0:5350a66d5279 965 if(BUF->proto == UIP_PROTO_ICMP) {
hudakz 0:5350a66d5279 966 UIP_LOG("ip: possible ping config packet received.");
hudakz 0:5350a66d5279 967 goto icmp_input;
hudakz 0:5350a66d5279 968 }
hudakz 0:5350a66d5279 969 else {
hudakz 0:5350a66d5279 970 UIP_LOG("ip: packet dropped since no address assigned.");
hudakz 0:5350a66d5279 971 goto drop;
hudakz 0:5350a66d5279 972 }
hudakz 0:5350a66d5279 973 #endif /* UIP_PINGADDRCONF */
hudakz 0:5350a66d5279 974 }
hudakz 0:5350a66d5279 975 else
hudakz 0:5350a66d5279 976 {
hudakz 0:5350a66d5279 977 /* If IP broadcast support is configured, we check for a broadcast
hudakz 0:5350a66d5279 978 UDP packet, which may be destined to us. */
hudakz 0:5350a66d5279 979 #if UIP_BROADCAST
hudakz 0:5350a66d5279 980 DEBUG_PRINTF("UDP IP checksum 0x%04x\n", uip_ipchksum());
hudakz 0:5350a66d5279 981 if
hudakz 0:5350a66d5279 982 (
hudakz 0:5350a66d5279 983 BUF->proto == UIP_PROTO_UDP
hudakz 0:5350a66d5279 984 && uip_ipaddr_cmp(BUF->destipaddr, all_ones_addr) /*&&
hudakz 0:5350a66d5279 985 uip_ipchksum() == 0xffff*/
hudakz 0:5350a66d5279 986 ) {
hudakz 0:5350a66d5279 987 goto udp_input;
hudakz 0:5350a66d5279 988 }
hudakz 0:5350a66d5279 989 #endif /* UIP_BROADCAST */
hudakz 0:5350a66d5279 990
hudakz 0:5350a66d5279 991 /* Check if the packet is destined for our IP address. */
hudakz 0:5350a66d5279 992
hudakz 0:5350a66d5279 993 #if !UIP_CONF_IPV6
hudakz 0:5350a66d5279 994 if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr)) {
hudakz 0:5350a66d5279 995 UIP_STAT(++uip_stat.ip.drop);
hudakz 0:5350a66d5279 996 goto drop;
hudakz 0:5350a66d5279 997 }
hudakz 0:5350a66d5279 998
hudakz 0:5350a66d5279 999 #else /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 1000 /* For IPv6, packet reception is a little trickier as we need to
hudakz 0:5350a66d5279 1001 make sure that we listen to certain multicast addresses (all
hudakz 0:5350a66d5279 1002 hosts multicast address, and the solicited-node multicast
hudakz 0:5350a66d5279 1003 address) as well. However, we will cheat here and accept all
hudakz 0:5350a66d5279 1004 multicast packets that are sent to the ff02::/16 addresses. */
hudakz 0:5350a66d5279 1005
hudakz 0:5350a66d5279 1006 if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr) && BUF->destipaddr[0] != HTONS(0xff02)) {
hudakz 0:5350a66d5279 1007 UIP_STAT(++uip_stat.ip.drop);
hudakz 0:5350a66d5279 1008 goto drop;
hudakz 0:5350a66d5279 1009 }
hudakz 0:5350a66d5279 1010 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 1011 }
hudakz 0:5350a66d5279 1012
hudakz 0:5350a66d5279 1013 #if !UIP_CONF_IPV6
hudakz 0:5350a66d5279 1014 if(uip_ipchksum() != 0xffff) {
hudakz 0:5350a66d5279 1015
hudakz 0:5350a66d5279 1016 /* Compute and check the IP header
hudakz 0:5350a66d5279 1017 checksum. */
hudakz 0:5350a66d5279 1018 UIP_STAT(++uip_stat.ip.drop);
hudakz 0:5350a66d5279 1019 UIP_STAT(++uip_stat.ip.chkerr);
hudakz 0:5350a66d5279 1020 UIP_LOG("ip: bad checksum.");
hudakz 0:5350a66d5279 1021 goto drop;
hudakz 0:5350a66d5279 1022 }
hudakz 0:5350a66d5279 1023 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 1024
hudakz 0:5350a66d5279 1025 if(BUF->proto == UIP_PROTO_TCP) {
hudakz 0:5350a66d5279 1026
hudakz 0:5350a66d5279 1027 /* Check for TCP packet. If so,
hudakz 0:5350a66d5279 1028 proceed with TCP input
hudakz 0:5350a66d5279 1029 processing. */
hudakz 0:5350a66d5279 1030 goto tcp_input;
hudakz 0:5350a66d5279 1031 }
hudakz 0:5350a66d5279 1032
hudakz 0:5350a66d5279 1033 #if UIP_UDP
hudakz 0:5350a66d5279 1034 if(BUF->proto == UIP_PROTO_UDP) {
hudakz 0:5350a66d5279 1035 goto udp_input;
hudakz 0:5350a66d5279 1036 }
hudakz 0:5350a66d5279 1037 #endif /* UIP_UDP */
hudakz 0:5350a66d5279 1038
hudakz 0:5350a66d5279 1039 #if !UIP_CONF_IPV6
hudakz 0:5350a66d5279 1040 /* ICMPv4 processing code follows. */
hudakz 0:5350a66d5279 1041
hudakz 0:5350a66d5279 1042 if(BUF->proto != UIP_PROTO_ICMP) {
hudakz 0:5350a66d5279 1043
hudakz 0:5350a66d5279 1044 /* We only allow ICMP packets from
hudakz 0:5350a66d5279 1045 here. */
hudakz 0:5350a66d5279 1046 UIP_STAT(++uip_stat.ip.drop);
hudakz 0:5350a66d5279 1047 UIP_STAT(++uip_stat.ip.protoerr);
hudakz 0:5350a66d5279 1048 UIP_LOG("ip: neither tcp nor icmp.");
hudakz 0:5350a66d5279 1049 goto drop;
hudakz 0:5350a66d5279 1050 }
hudakz 0:5350a66d5279 1051
hudakz 0:5350a66d5279 1052 #if UIP_PINGADDRCONF
hudakz 0:5350a66d5279 1053 icmp_input :
hudakz 0:5350a66d5279 1054 #endif /* UIP_PINGADDRCONF */
hudakz 0:5350a66d5279 1055
hudakz 0:5350a66d5279 1056 UIP_STAT(++uip_stat.icmp.recv);
hudakz 0:5350a66d5279 1057
hudakz 0:5350a66d5279 1058 /* ICMP echo (i.e., ping) processing. This is simple, we only change
hudakz 0:5350a66d5279 1059 the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
hudakz 0:5350a66d5279 1060 checksum before we return the packet. */
hudakz 0:5350a66d5279 1061 if(ICMPBUF->type != ICMP_ECHO) {
hudakz 0:5350a66d5279 1062 UIP_STAT(++uip_stat.icmp.drop);
hudakz 0:5350a66d5279 1063 UIP_STAT(++uip_stat.icmp.typeerr);
hudakz 0:5350a66d5279 1064 UIP_LOG("icmp: not icmp echo.");
hudakz 0:5350a66d5279 1065 goto drop;
hudakz 0:5350a66d5279 1066 }
hudakz 0:5350a66d5279 1067
hudakz 0:5350a66d5279 1068 /* If we are configured to use ping IP address assignment, we use
hudakz 0:5350a66d5279 1069 the destination IP address of this ping packet and assign it to
hudakz 0:5350a66d5279 1070 ourself. */
hudakz 0:5350a66d5279 1071 #if UIP_PINGADDRCONF
hudakz 0:5350a66d5279 1072 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
hudakz 0:5350a66d5279 1073 uip_hostaddr[0] = BUF->destipaddr[0];
hudakz 0:5350a66d5279 1074 uip_hostaddr[1] = BUF->destipaddr[1];
hudakz 0:5350a66d5279 1075 }
hudakz 0:5350a66d5279 1076 #endif /* UIP_PINGADDRCONF */
hudakz 0:5350a66d5279 1077
hudakz 0:5350a66d5279 1078 ICMPBUF->type = ICMP_ECHO_REPLY;
hudakz 0:5350a66d5279 1079
hudakz 0:5350a66d5279 1080 if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) {
hudakz 0:5350a66d5279 1081 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1;
hudakz 0:5350a66d5279 1082 }
hudakz 0:5350a66d5279 1083 else {
hudakz 0:5350a66d5279 1084 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8);
hudakz 0:5350a66d5279 1085 }
hudakz 0:5350a66d5279 1086
hudakz 0:5350a66d5279 1087 /* Swap IP addresses. */
hudakz 0:5350a66d5279 1088 uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr);
hudakz 0:5350a66d5279 1089 uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
hudakz 0:5350a66d5279 1090
hudakz 0:5350a66d5279 1091 UIP_STAT(++uip_stat.icmp.sent);
hudakz 0:5350a66d5279 1092 goto send;
hudakz 0:5350a66d5279 1093
hudakz 0:5350a66d5279 1094 /* End of IPv4 input header processing code. */
hudakz 0:5350a66d5279 1095 #else /* !UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 1096 /* This is IPv6 ICMPv6 processing code. */
hudakz 0:5350a66d5279 1097
hudakz 0:5350a66d5279 1098 DEBUG_PRINTF("icmp6_input: length %d\n", uip_len);
hudakz 0:5350a66d5279 1099
hudakz 0:5350a66d5279 1100 if(BUF->proto != UIP_PROTO_ICMP6) {
hudakz 0:5350a66d5279 1101
hudakz 0:5350a66d5279 1102 /* We only allow ICMPv6 packets from
hudakz 0:5350a66d5279 1103 here. */
hudakz 0:5350a66d5279 1104 UIP_STAT(++uip_stat.ip.drop);
hudakz 0:5350a66d5279 1105 UIP_STAT(++uip_stat.ip.protoerr);
hudakz 0:5350a66d5279 1106 UIP_LOG("ip: neither tcp nor icmp6.");
hudakz 0:5350a66d5279 1107 goto drop;
hudakz 0:5350a66d5279 1108 }
hudakz 0:5350a66d5279 1109
hudakz 0:5350a66d5279 1110 UIP_STAT(++uip_stat.icmp.recv);
hudakz 0:5350a66d5279 1111
hudakz 0:5350a66d5279 1112 /* If we get a neighbor solicitation for our address we should send
hudakz 0:5350a66d5279 1113 a neighbor advertisement message back. */
hudakz 0:5350a66d5279 1114 if(ICMPBUF->type == ICMP6_NEIGHBOR_SOLICITATION) {
hudakz 0:5350a66d5279 1115 if(uip_ipaddr_cmp(ICMPBUF->icmp6data, uip_hostaddr)) {
hudakz 0:5350a66d5279 1116 if(ICMPBUF->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) {
hudakz 0:5350a66d5279 1117
hudakz 0:5350a66d5279 1118 /* Save the sender's address in our neighbor list. */
hudakz 0:5350a66d5279 1119 uip_neighbor_add(ICMPBUF->srcipaddr, &(ICMPBUF->options[2]));
hudakz 0:5350a66d5279 1120 }
hudakz 0:5350a66d5279 1121
hudakz 0:5350a66d5279 1122 /* We should now send a neighbor advertisement back to where the
hudakz 0:5350a66d5279 1123 neighbor solicication came from. */
hudakz 0:5350a66d5279 1124 ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT;
hudakz 0:5350a66d5279 1125 ICMPBUF->flags = ICMP6_FLAG_S; /* Solicited flag. */
hudakz 0:5350a66d5279 1126
hudakz 0:5350a66d5279 1127 ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0;
hudakz 0:5350a66d5279 1128
hudakz 0:5350a66d5279 1129 uip_ipaddr_copy(ICMPBUF->destipaddr, ICMPBUF->srcipaddr);
hudakz 0:5350a66d5279 1130 uip_ipaddr_copy(ICMPBUF->srcipaddr, uip_hostaddr);
hudakz 0:5350a66d5279 1131 ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS;
hudakz 0:5350a66d5279 1132 ICMPBUF->options[1] = 1; /* Options length, 1 = 8 bytes. */
hudakz 0:5350a66d5279 1133 memcpy(&(ICMPBUF->options[2]), &uip_ethaddr, sizeof(uip_ethaddr));
hudakz 0:5350a66d5279 1134 ICMPBUF->icmpchksum = 0;
hudakz 0:5350a66d5279 1135 ICMPBUF->icmpchksum = ~uip_icmp6chksum();
hudakz 0:5350a66d5279 1136 goto send;
hudakz 0:5350a66d5279 1137 }
hudakz 0:5350a66d5279 1138
hudakz 0:5350a66d5279 1139 goto drop;
hudakz 0:5350a66d5279 1140 }
hudakz 0:5350a66d5279 1141 else
hudakz 0:5350a66d5279 1142 if(ICMPBUF->type == ICMP6_ECHO) {
hudakz 0:5350a66d5279 1143
hudakz 0:5350a66d5279 1144 /* ICMP echo (i.e., ping) processing. This is simple, we only
hudakz 0:5350a66d5279 1145 change the ICMP type from ECHO to ECHO_REPLY and update the
hudakz 0:5350a66d5279 1146 ICMP checksum before we return the packet. */
hudakz 0:5350a66d5279 1147 ICMPBUF->type = ICMP6_ECHO_REPLY;
hudakz 0:5350a66d5279 1148
hudakz 0:5350a66d5279 1149 uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr);
hudakz 0:5350a66d5279 1150 uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
hudakz 0:5350a66d5279 1151 ICMPBUF->icmpchksum = 0;
hudakz 0:5350a66d5279 1152 ICMPBUF->icmpchksum = ~uip_icmp6chksum();
hudakz 0:5350a66d5279 1153
hudakz 0:5350a66d5279 1154 UIP_STAT(++uip_stat.icmp.sent);
hudakz 0:5350a66d5279 1155 goto send;
hudakz 0:5350a66d5279 1156 }
hudakz 0:5350a66d5279 1157 else {
hudakz 0:5350a66d5279 1158 DEBUG_PRINTF("Unknown icmp6 message type %d\n", ICMPBUF->type);
hudakz 0:5350a66d5279 1159 UIP_STAT(++uip_stat.icmp.drop);
hudakz 0:5350a66d5279 1160 UIP_STAT(++uip_stat.icmp.typeerr);
hudakz 0:5350a66d5279 1161 UIP_LOG("icmp: unknown ICMP message.");
hudakz 0:5350a66d5279 1162 goto drop;
hudakz 0:5350a66d5279 1163 }
hudakz 0:5350a66d5279 1164
hudakz 0:5350a66d5279 1165 /* End of IPv6 ICMP processing. */
hudakz 0:5350a66d5279 1166 #endif /* !UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 1167
hudakz 0:5350a66d5279 1168 #if UIP_UDP
hudakz 0:5350a66d5279 1169 /* UDP input processing. */
hudakz 0:5350a66d5279 1170
hudakz 0:5350a66d5279 1171 udp_input :
hudakz 0:5350a66d5279 1172 /* UDP processing is really just a hack. We don't do anything to the
hudakz 0:5350a66d5279 1173 UDP/IP headers, but let the UDP application do all the hard
hudakz 0:5350a66d5279 1174 work. If the application sets uip_slen, it has a packet to
hudakz 0:5350a66d5279 1175 send. */
hudakz 0:5350a66d5279 1176 #if UIP_UDP_CHECKSUMS
hudakz 0:5350a66d5279 1177 uip_len = uip_len - UIP_IPUDPH_LEN;
hudakz 0:5350a66d5279 1178 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
hudakz 0:5350a66d5279 1179 if(UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff) {
hudakz 0:5350a66d5279 1180 UIP_STAT(++uip_stat.udp.drop);
hudakz 0:5350a66d5279 1181 UIP_STAT(++uip_stat.udp.chkerr);
hudakz 0:5350a66d5279 1182 UIP_LOG("udp: bad checksum.");
hudakz 0:5350a66d5279 1183 goto drop;
hudakz 0:5350a66d5279 1184 }
hudakz 0:5350a66d5279 1185
hudakz 0:5350a66d5279 1186 #else /* UIP_UDP_CHECKSUMS */
hudakz 0:5350a66d5279 1187 uip_len = uip_len - UIP_IPUDPH_LEN;
hudakz 0:5350a66d5279 1188 #endif /* UIP_UDP_CHECKSUMS */
hudakz 0:5350a66d5279 1189
hudakz 0:5350a66d5279 1190 /* Demultiplex this UDP packet between the UDP "connections". */
hudakz 0:5350a66d5279 1191
hudakz 0:5350a66d5279 1192 for(uip_udp_conn = &uip_udp_conns[0]; uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS]; ++uip_udp_conn) {
hudakz 0:5350a66d5279 1193
hudakz 0:5350a66d5279 1194 /* If the local UDP port is non-zero, the connection is considered
hudakz 0:5350a66d5279 1195 to be used. If so, the local port number is checked against the
hudakz 0:5350a66d5279 1196 destination port number in the received packet. If the two port
hudakz 0:5350a66d5279 1197 numbers match, the remote port number is checked if the
hudakz 0:5350a66d5279 1198 connection is bound to a remote port. Finally, if the
hudakz 0:5350a66d5279 1199 connection is bound to a remote IP address, the source IP
hudakz 0:5350a66d5279 1200 address of the packet is checked. */
hudakz 0:5350a66d5279 1201 if
hudakz 0:5350a66d5279 1202 (
hudakz 0:5350a66d5279 1203 uip_udp_conn->lport != 0
hudakz 0:5350a66d5279 1204 && UDPBUF->destport == uip_udp_conn->lport
hudakz 0:5350a66d5279 1205 && (uip_udp_conn->rport == 0 || UDPBUF->srcport == uip_udp_conn->rport)
hudakz 0:5350a66d5279 1206 && (
hudakz 0:5350a66d5279 1207 uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_zeroes_addr)
hudakz 0:5350a66d5279 1208 || uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_ones_addr)
hudakz 0:5350a66d5279 1209 || uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr)
hudakz 0:5350a66d5279 1210 )
hudakz 0:5350a66d5279 1211 ) {
hudakz 0:5350a66d5279 1212 goto udp_found;
hudakz 0:5350a66d5279 1213 }
hudakz 0:5350a66d5279 1214 }
hudakz 0:5350a66d5279 1215
hudakz 0:5350a66d5279 1216 UIP_LOG("udp: no matching connection found");
hudakz 0:5350a66d5279 1217 goto drop;
hudakz 0:5350a66d5279 1218
hudakz 0:5350a66d5279 1219 udp_found:
hudakz 0:5350a66d5279 1220 uip_conn = NULL;
hudakz 0:5350a66d5279 1221 uip_flags = UIP_NEWDATA;
hudakz 0:5350a66d5279 1222 uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
hudakz 0:5350a66d5279 1223 uip_slen = 0;
hudakz 0:5350a66d5279 1224 UIP_UDP_APPCALL();
hudakz 0:5350a66d5279 1225 udp_send:
hudakz 0:5350a66d5279 1226 if(uip_slen == 0) {
hudakz 0:5350a66d5279 1227 goto drop;
hudakz 0:5350a66d5279 1228 }
hudakz 0:5350a66d5279 1229
hudakz 0:5350a66d5279 1230 uip_len = uip_slen + UIP_IPUDPH_LEN;
hudakz 0:5350a66d5279 1231
hudakz 0:5350a66d5279 1232 #if UIP_CONF_IPV6
hudakz 0:5350a66d5279 1233 /* For IPv6, the IP length field does not include the IPv6 IP header
hudakz 0:5350a66d5279 1234 length. */
hudakz 0:5350a66d5279 1235
hudakz 0:5350a66d5279 1236 BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
hudakz 0:5350a66d5279 1237 BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
hudakz 0:5350a66d5279 1238 #else /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 1239 BUF->len[0] = (uip_len >> 8);
hudakz 0:5350a66d5279 1240 BUF->len[1] = (uip_len & 0xff);
hudakz 0:5350a66d5279 1241 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 1242
hudakz 0:5350a66d5279 1243 BUF->ttl = uip_udp_conn->ttl;
hudakz 0:5350a66d5279 1244 BUF->proto = UIP_PROTO_UDP;
hudakz 0:5350a66d5279 1245
hudakz 0:5350a66d5279 1246 UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN);
hudakz 0:5350a66d5279 1247 UDPBUF->udpchksum = 0;
hudakz 0:5350a66d5279 1248
hudakz 0:5350a66d5279 1249 BUF->srcport = uip_udp_conn->lport;
hudakz 0:5350a66d5279 1250 BUF->destport = uip_udp_conn->rport;
hudakz 0:5350a66d5279 1251
hudakz 0:5350a66d5279 1252 uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
hudakz 0:5350a66d5279 1253 uip_ipaddr_copy(BUF->destipaddr, uip_udp_conn->ripaddr);
hudakz 0:5350a66d5279 1254
hudakz 0:5350a66d5279 1255 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
hudakz 0:5350a66d5279 1256
hudakz 0:5350a66d5279 1257 #if UIP_UDP_CHECKSUMS
hudakz 0:5350a66d5279 1258 /* Calculate UDP checksum. */
hudakz 0:5350a66d5279 1259
hudakz 0:5350a66d5279 1260 UDPBUF->udpchksum = ~(uip_udpchksum());
hudakz 0:5350a66d5279 1261 if(UDPBUF->udpchksum == 0) {
hudakz 0:5350a66d5279 1262 UDPBUF->udpchksum = 0xffff;
hudakz 0:5350a66d5279 1263 }
hudakz 0:5350a66d5279 1264 #endif /* UIP_UDP_CHECKSUMS */
hudakz 0:5350a66d5279 1265
hudakz 0:5350a66d5279 1266 goto ip_send_nolen;
hudakz 0:5350a66d5279 1267 #endif /* UIP_UDP */
hudakz 0:5350a66d5279 1268
hudakz 0:5350a66d5279 1269 /* TCP input processing. */
hudakz 0:5350a66d5279 1270
hudakz 0:5350a66d5279 1271 tcp_input : UIP_STAT(++uip_stat.tcp.recv);
hudakz 0:5350a66d5279 1272
hudakz 0:5350a66d5279 1273 /* Start of TCP input header processing code. */
hudakz 0:5350a66d5279 1274 if(uip_tcpchksum() != 0xffff) {
hudakz 0:5350a66d5279 1275
hudakz 0:5350a66d5279 1276 /* Compute and check the TCP
hudakz 0:5350a66d5279 1277 checksum. */
hudakz 0:5350a66d5279 1278 UIP_STAT(++uip_stat.tcp.drop);
hudakz 0:5350a66d5279 1279 UIP_STAT(++uip_stat.tcp.chkerr);
hudakz 0:5350a66d5279 1280 UIP_LOG("tcp: bad checksum.");
hudakz 0:5350a66d5279 1281 goto drop;
hudakz 0:5350a66d5279 1282 }
hudakz 0:5350a66d5279 1283
hudakz 0:5350a66d5279 1284 /* Demultiplex this segment. */
hudakz 0:5350a66d5279 1285 /* First check any active connections. */
hudakz 0:5350a66d5279 1286 for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1]; ++uip_connr) {
hudakz 0:5350a66d5279 1287 if
hudakz 0:5350a66d5279 1288 (
hudakz 0:5350a66d5279 1289 uip_connr->tcpstateflags != UIP_CLOSED
hudakz 0:5350a66d5279 1290 && BUF->destport == uip_connr->lport
hudakz 0:5350a66d5279 1291 && BUF->srcport == uip_connr->rport
hudakz 0:5350a66d5279 1292 && uip_ipaddr_cmp(BUF->srcipaddr, uip_connr->ripaddr)
hudakz 0:5350a66d5279 1293 ) {
hudakz 0:5350a66d5279 1294 goto found;
hudakz 0:5350a66d5279 1295 }
hudakz 0:5350a66d5279 1296 }
hudakz 0:5350a66d5279 1297
hudakz 0:5350a66d5279 1298 /* If we didn't find and active connection that expected the packet,
hudakz 0:5350a66d5279 1299 either this packet is an old duplicate, or this is a SYN packet
hudakz 0:5350a66d5279 1300 destined for a connection in LISTEN. If the SYN flag isn't set,
hudakz 0:5350a66d5279 1301 it is an old packet and we send a RST. */
hudakz 0:5350a66d5279 1302 if((BUF->flags & TCP_CTL) != TCP_SYN) {
hudakz 0:5350a66d5279 1303 goto reset;
hudakz 0:5350a66d5279 1304 }
hudakz 0:5350a66d5279 1305
hudakz 0:5350a66d5279 1306 tmp16 = BUF->destport;
hudakz 0:5350a66d5279 1307
hudakz 0:5350a66d5279 1308 /* Next, check listening connections. */
hudakz 0:5350a66d5279 1309 for(c = 0; c < UIP_LISTENPORTS; ++c) {
hudakz 0:5350a66d5279 1310 if(tmp16 == uip_listenports[c])
hudakz 0:5350a66d5279 1311 goto found_listen;
hudakz 0:5350a66d5279 1312 }
hudakz 0:5350a66d5279 1313
hudakz 0:5350a66d5279 1314 /* No matching connection found, so we send a RST packet. */
hudakz 0:5350a66d5279 1315 UIP_STAT(++uip_stat.tcp.synrst);
hudakz 0:5350a66d5279 1316 reset:
hudakz 0:5350a66d5279 1317 /* We do not send resets in response to resets. */
hudakz 0:5350a66d5279 1318 if(BUF->flags & TCP_RST) {
hudakz 0:5350a66d5279 1319 goto drop;
hudakz 0:5350a66d5279 1320 }
hudakz 0:5350a66d5279 1321
hudakz 0:5350a66d5279 1322 UIP_STAT(++uip_stat.tcp.rst);
hudakz 0:5350a66d5279 1323
hudakz 0:5350a66d5279 1324 BUF->flags = TCP_RST | TCP_ACK;
hudakz 0:5350a66d5279 1325 uip_len = UIP_IPTCPH_LEN;
hudakz 0:5350a66d5279 1326 BUF->tcpoffset = 5 << 4;
hudakz 0:5350a66d5279 1327
hudakz 0:5350a66d5279 1328 /* Flip the seqno and ackno fields in the TCP header. */
hudakz 0:5350a66d5279 1329 c = BUF->seqno[3];
hudakz 0:5350a66d5279 1330 BUF->seqno[3] = BUF->ackno[3];
hudakz 0:5350a66d5279 1331 BUF->ackno[3] = c;
hudakz 0:5350a66d5279 1332
hudakz 0:5350a66d5279 1333 c = BUF->seqno[2];
hudakz 0:5350a66d5279 1334 BUF->seqno[2] = BUF->ackno[2];
hudakz 0:5350a66d5279 1335 BUF->ackno[2] = c;
hudakz 0:5350a66d5279 1336
hudakz 0:5350a66d5279 1337 c = BUF->seqno[1];
hudakz 0:5350a66d5279 1338 BUF->seqno[1] = BUF->ackno[1];
hudakz 0:5350a66d5279 1339 BUF->ackno[1] = c;
hudakz 0:5350a66d5279 1340
hudakz 0:5350a66d5279 1341 c = BUF->seqno[0];
hudakz 0:5350a66d5279 1342 BUF->seqno[0] = BUF->ackno[0];
hudakz 0:5350a66d5279 1343 BUF->ackno[0] = c;
hudakz 0:5350a66d5279 1344
hudakz 0:5350a66d5279 1345 /* We also have to increase the sequence number we are
hudakz 0:5350a66d5279 1346 acknowledging. If the least significant byte overflowed, we need
hudakz 0:5350a66d5279 1347 to propagate the carry to the other bytes as well. */
hudakz 0:5350a66d5279 1348 if(++BUF->ackno[3] == 0) {
hudakz 0:5350a66d5279 1349 if(++BUF->ackno[2] == 0) {
hudakz 0:5350a66d5279 1350 if(++BUF->ackno[1] == 0) {
hudakz 0:5350a66d5279 1351 ++BUF->ackno[0];
hudakz 0:5350a66d5279 1352 }
hudakz 0:5350a66d5279 1353 }
hudakz 0:5350a66d5279 1354 }
hudakz 0:5350a66d5279 1355
hudakz 0:5350a66d5279 1356 /* Swap port numbers. */
hudakz 0:5350a66d5279 1357 tmp16 = BUF->srcport;
hudakz 0:5350a66d5279 1358 BUF->srcport = BUF->destport;
hudakz 0:5350a66d5279 1359 BUF->destport = tmp16;
hudakz 0:5350a66d5279 1360
hudakz 0:5350a66d5279 1361 /* Swap IP addresses. */
hudakz 0:5350a66d5279 1362 uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr);
hudakz 0:5350a66d5279 1363 uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
hudakz 0:5350a66d5279 1364
hudakz 0:5350a66d5279 1365 /* And send out the RST packet! */
hudakz 0:5350a66d5279 1366 goto tcp_send_noconn;
hudakz 0:5350a66d5279 1367
hudakz 0:5350a66d5279 1368 /* This label will be jumped to if we matched the incoming packet
hudakz 0:5350a66d5279 1369 with a connection in LISTEN. In that case, we should create a new
hudakz 0:5350a66d5279 1370 connection and send a SYNACK in return. */
hudakz 0:5350a66d5279 1371 found_listen:
hudakz 0:5350a66d5279 1372 /* First we check if there are any connections avaliable. Unused
hudakz 0:5350a66d5279 1373 connections are kept in the same table as used connections, but
hudakz 0:5350a66d5279 1374 unused ones have the tcpstate set to CLOSED. Also, connections in
hudakz 0:5350a66d5279 1375 TIME_WAIT are kept track of and we'll use the oldest one if no
hudakz 0:5350a66d5279 1376 CLOSED connections are found. Thanks to Eddie C. Dost for a very
hudakz 0:5350a66d5279 1377 nice algorithm for the TIME_WAIT search. */
hudakz 0:5350a66d5279 1378 uip_connr = 0;
hudakz 0:5350a66d5279 1379 for(c = 0; c < UIP_CONNS; ++c) {
hudakz 0:5350a66d5279 1380 if(uip_conns[c].tcpstateflags == UIP_CLOSED) {
hudakz 0:5350a66d5279 1381 uip_connr = &uip_conns[c];
hudakz 0:5350a66d5279 1382 break;
hudakz 0:5350a66d5279 1383 }
hudakz 0:5350a66d5279 1384
hudakz 0:5350a66d5279 1385 if(uip_conns[c].tcpstateflags == UIP_TIME_WAIT) {
hudakz 0:5350a66d5279 1386 if(uip_connr == 0 || uip_conns[c].timer > uip_connr->timer) {
hudakz 0:5350a66d5279 1387 uip_connr = &uip_conns[c];
hudakz 0:5350a66d5279 1388 }
hudakz 0:5350a66d5279 1389 }
hudakz 0:5350a66d5279 1390 }
hudakz 0:5350a66d5279 1391
hudakz 0:5350a66d5279 1392 if(uip_connr == 0) {
hudakz 0:5350a66d5279 1393
hudakz 0:5350a66d5279 1394 /* All connections are used already, we drop packet and hope that
hudakz 0:5350a66d5279 1395 the remote end will retransmit the packet at a time when we
hudakz 0:5350a66d5279 1396 have more spare connections. */
hudakz 0:5350a66d5279 1397 UIP_STAT(++uip_stat.tcp.syndrop);
hudakz 0:5350a66d5279 1398 UIP_LOG("tcp: found no unused connections.");
hudakz 0:5350a66d5279 1399 goto drop;
hudakz 0:5350a66d5279 1400 }
hudakz 0:5350a66d5279 1401
hudakz 0:5350a66d5279 1402 uip_conn = uip_connr;
hudakz 0:5350a66d5279 1403
hudakz 0:5350a66d5279 1404 /* Fill in the necessary fields for the new connection. */
hudakz 0:5350a66d5279 1405 uip_connr->rto = uip_connr->timer = UIP_RTO;
hudakz 0:5350a66d5279 1406 uip_connr->sa = 0;
hudakz 0:5350a66d5279 1407 uip_connr->sv = 4;
hudakz 0:5350a66d5279 1408 uip_connr->nrtx = 0;
hudakz 0:5350a66d5279 1409 uip_connr->lport = BUF->destport;
hudakz 0:5350a66d5279 1410 uip_connr->rport = BUF->srcport;
hudakz 0:5350a66d5279 1411 uip_ipaddr_copy(uip_connr->ripaddr, BUF->srcipaddr);
hudakz 0:5350a66d5279 1412 uip_connr->tcpstateflags = UIP_SYN_RCVD;
hudakz 0:5350a66d5279 1413
hudakz 0:5350a66d5279 1414 uip_connr->snd_nxt[0] = iss[0];
hudakz 0:5350a66d5279 1415 uip_connr->snd_nxt[1] = iss[1];
hudakz 0:5350a66d5279 1416 uip_connr->snd_nxt[2] = iss[2];
hudakz 0:5350a66d5279 1417 uip_connr->snd_nxt[3] = iss[3];
hudakz 0:5350a66d5279 1418 uip_connr->len = 1;
hudakz 0:5350a66d5279 1419
hudakz 0:5350a66d5279 1420 /* rcv_nxt should be the seqno from the incoming packet + 1. */
hudakz 0:5350a66d5279 1421 uip_connr->rcv_nxt[3] = BUF->seqno[3];
hudakz 0:5350a66d5279 1422 uip_connr->rcv_nxt[2] = BUF->seqno[2];
hudakz 0:5350a66d5279 1423 uip_connr->rcv_nxt[1] = BUF->seqno[1];
hudakz 0:5350a66d5279 1424 uip_connr->rcv_nxt[0] = BUF->seqno[0];
hudakz 0:5350a66d5279 1425 uip_add_rcv_nxt(1);
hudakz 0:5350a66d5279 1426
hudakz 0:5350a66d5279 1427 /* Parse the TCP MSS option, if present. */
hudakz 0:5350a66d5279 1428 if((BUF->tcpoffset & 0xf0) > 0x50) {
hudakz 0:5350a66d5279 1429 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2;) {
hudakz 0:5350a66d5279 1430 opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
hudakz 0:5350a66d5279 1431 if(opt == TCP_OPT_END) {
hudakz 0:5350a66d5279 1432
hudakz 0:5350a66d5279 1433 /* End of options. */
hudakz 0:5350a66d5279 1434 break;
hudakz 0:5350a66d5279 1435 }
hudakz 0:5350a66d5279 1436 else
hudakz 0:5350a66d5279 1437 if(opt == TCP_OPT_NOOP) {
hudakz 0:5350a66d5279 1438 ++c;
hudakz 0:5350a66d5279 1439
hudakz 0:5350a66d5279 1440 /* NOP option. */
hudakz 0:5350a66d5279 1441 }
hudakz 0:5350a66d5279 1442 else
hudakz 0:5350a66d5279 1443 if(opt == TCP_OPT_MSS && uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
hudakz 0:5350a66d5279 1444
hudakz 0:5350a66d5279 1445 /* An MSS option with the right option length. */
hudakz 0:5350a66d5279 1446 tmp16 = ((u16_t) uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | (u16_t) uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c];
hudakz 0:5350a66d5279 1447 uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS ? UIP_TCP_MSS : tmp16;
hudakz 0:5350a66d5279 1448
hudakz 0:5350a66d5279 1449 /* And we are done processing options. */
hudakz 0:5350a66d5279 1450 break;
hudakz 0:5350a66d5279 1451 }
hudakz 0:5350a66d5279 1452 else {
hudakz 0:5350a66d5279 1453
hudakz 0:5350a66d5279 1454 /* All other options have a length field, so that we easily
hudakz 0:5350a66d5279 1455 can skip past them. */
hudakz 0:5350a66d5279 1456 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
hudakz 0:5350a66d5279 1457
hudakz 0:5350a66d5279 1458 /* If the length field is zero, the options are malformed
hudakz 0:5350a66d5279 1459 and we don't process them further. */
hudakz 0:5350a66d5279 1460 break;
hudakz 0:5350a66d5279 1461 }
hudakz 0:5350a66d5279 1462
hudakz 0:5350a66d5279 1463 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
hudakz 0:5350a66d5279 1464 }
hudakz 0:5350a66d5279 1465 }
hudakz 0:5350a66d5279 1466 }
hudakz 0:5350a66d5279 1467
hudakz 0:5350a66d5279 1468 /* Our response will be a SYNACK. */
hudakz 0:5350a66d5279 1469 #if UIP_ACTIVE_OPEN
hudakz 0:5350a66d5279 1470 tcp_send_synack : BUF->flags = TCP_ACK;
hudakz 0:5350a66d5279 1471
hudakz 0:5350a66d5279 1472 tcp_send_syn:
hudakz 0:5350a66d5279 1473 BUF->flags |= TCP_SYN;
hudakz 0:5350a66d5279 1474 #else /* UIP_ACTIVE_OPEN */
hudakz 0:5350a66d5279 1475 tcp_send_synack : BUF->flags = TCP_SYN | TCP_ACK;
hudakz 0:5350a66d5279 1476 #endif /* UIP_ACTIVE_OPEN */
hudakz 0:5350a66d5279 1477
hudakz 0:5350a66d5279 1478 /* We send out the TCP Maximum Segment Size option with our
hudakz 0:5350a66d5279 1479 SYNACK. */
hudakz 0:5350a66d5279 1480
hudakz 0:5350a66d5279 1481 BUF->optdata[0] = TCP_OPT_MSS;
hudakz 0:5350a66d5279 1482 BUF->optdata[1] = TCP_OPT_MSS_LEN;
hudakz 0:5350a66d5279 1483 BUF->optdata[2] = (UIP_TCP_MSS) / 256;
hudakz 0:5350a66d5279 1484 BUF->optdata[3] = (UIP_TCP_MSS) & 255;
hudakz 0:5350a66d5279 1485 uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN;
hudakz 0:5350a66d5279 1486 BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4;
hudakz 0:5350a66d5279 1487 goto tcp_send;
hudakz 0:5350a66d5279 1488
hudakz 0:5350a66d5279 1489 /* This label will be jumped to if we found an active connection. */
hudakz 0:5350a66d5279 1490 found:
hudakz 0:5350a66d5279 1491 uip_conn = uip_connr;
hudakz 0:5350a66d5279 1492 uip_flags = 0;
hudakz 0:5350a66d5279 1493
hudakz 0:5350a66d5279 1494 /* We do a very naive form of TCP reset processing; we just accept
hudakz 0:5350a66d5279 1495 any RST and kill our connection. We should in fact check if the
hudakz 0:5350a66d5279 1496 sequence number of this reset is wihtin our advertised window
hudakz 0:5350a66d5279 1497 before we accept the reset. */
hudakz 0:5350a66d5279 1498 if(BUF->flags & TCP_RST) {
hudakz 0:5350a66d5279 1499 uip_connr->tcpstateflags = UIP_CLOSED;
hudakz 0:5350a66d5279 1500 UIP_LOG("tcp: got reset, aborting connection.");
hudakz 0:5350a66d5279 1501 uip_flags = UIP_ABORT;
hudakz 0:5350a66d5279 1502 UIP_APPCALL();
hudakz 0:5350a66d5279 1503 goto drop;
hudakz 0:5350a66d5279 1504 }
hudakz 0:5350a66d5279 1505
hudakz 0:5350a66d5279 1506 /* Calculated the length of the data, if the application has sent
hudakz 0:5350a66d5279 1507 any data to us. */
hudakz 0:5350a66d5279 1508 c = (BUF->tcpoffset >> 4) << 2;
hudakz 0:5350a66d5279 1509
hudakz 0:5350a66d5279 1510 /* uip_len will contain the length of the actual TCP data. This is
hudakz 0:5350a66d5279 1511 calculated by subtracing the length of the TCP header (in
hudakz 0:5350a66d5279 1512 c) and the length of the IP header (20 bytes). */
hudakz 0:5350a66d5279 1513 uip_len = uip_len - c - UIP_IPH_LEN;
hudakz 0:5350a66d5279 1514
hudakz 0:5350a66d5279 1515 /* First, check if the sequence number of the incoming packet is
hudakz 0:5350a66d5279 1516 what we're expecting next. If not, we send out an ACK with the
hudakz 0:5350a66d5279 1517 correct numbers in. */
hudakz 0:5350a66d5279 1518 if(!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) && ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) {
hudakz 0:5350a66d5279 1519 if
hudakz 0:5350a66d5279 1520 (
hudakz 0:5350a66d5279 1521 (uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0))
hudakz 0:5350a66d5279 1522 && (
hudakz 0:5350a66d5279 1523 BUF->seqno[0] != uip_connr->rcv_nxt[0]
hudakz 0:5350a66d5279 1524 || BUF->seqno[1] != uip_connr->rcv_nxt[1]
hudakz 0:5350a66d5279 1525 || BUF->seqno[2] != uip_connr->rcv_nxt[2]
hudakz 0:5350a66d5279 1526 || BUF->seqno[3] != uip_connr->rcv_nxt[3]
hudakz 0:5350a66d5279 1527 )
hudakz 0:5350a66d5279 1528 ) {
hudakz 0:5350a66d5279 1529 goto tcp_send_ack;
hudakz 0:5350a66d5279 1530 }
hudakz 0:5350a66d5279 1531 }
hudakz 0:5350a66d5279 1532
hudakz 0:5350a66d5279 1533 /* Next, check if the incoming segment acknowledges any outstanding
hudakz 0:5350a66d5279 1534 data. If so, we update the sequence number, reset the length of
hudakz 0:5350a66d5279 1535 the outstanding data, calculate RTT estimations, and reset the
hudakz 0:5350a66d5279 1536 retransmission timer. */
hudakz 0:5350a66d5279 1537 if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
hudakz 0:5350a66d5279 1538 uip_add32(uip_connr->snd_nxt, uip_connr->len);
hudakz 0:5350a66d5279 1539
hudakz 0:5350a66d5279 1540 if
hudakz 0:5350a66d5279 1541 (
hudakz 0:5350a66d5279 1542 BUF->ackno[0] == uip_acc32[0]
hudakz 0:5350a66d5279 1543 && BUF->ackno[1] == uip_acc32[1]
hudakz 0:5350a66d5279 1544 && BUF->ackno[2] == uip_acc32[2]
hudakz 0:5350a66d5279 1545 && BUF->ackno[3] == uip_acc32[3]
hudakz 0:5350a66d5279 1546 ) {
hudakz 0:5350a66d5279 1547
hudakz 0:5350a66d5279 1548 /* Update sequence number. */
hudakz 0:5350a66d5279 1549 uip_connr->snd_nxt[0] = uip_acc32[0];
hudakz 0:5350a66d5279 1550 uip_connr->snd_nxt[1] = uip_acc32[1];
hudakz 0:5350a66d5279 1551 uip_connr->snd_nxt[2] = uip_acc32[2];
hudakz 0:5350a66d5279 1552 uip_connr->snd_nxt[3] = uip_acc32[3];
hudakz 0:5350a66d5279 1553
hudakz 0:5350a66d5279 1554 /* Do RTT estimation, unless we have done retransmissions. */
hudakz 0:5350a66d5279 1555 if(uip_connr->nrtx == 0) {
hudakz 0:5350a66d5279 1556 signed char m;
hudakz 0:5350a66d5279 1557 m = uip_connr->rto - uip_connr->timer;
hudakz 0:5350a66d5279 1558
hudakz 0:5350a66d5279 1559 /* This is taken directly from VJs original code in his paper */
hudakz 0:5350a66d5279 1560 m = m - (uip_connr->sa >> 3);
hudakz 0:5350a66d5279 1561 uip_connr->sa += m;
hudakz 0:5350a66d5279 1562 if(m < 0) {
hudakz 0:5350a66d5279 1563 m = -m;
hudakz 0:5350a66d5279 1564 }
hudakz 0:5350a66d5279 1565
hudakz 0:5350a66d5279 1566 m = m - (uip_connr->sv >> 2);
hudakz 0:5350a66d5279 1567 uip_connr->sv += m;
hudakz 0:5350a66d5279 1568 uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
hudakz 0:5350a66d5279 1569 }
hudakz 0:5350a66d5279 1570
hudakz 0:5350a66d5279 1571 /* Set the acknowledged flag. */
hudakz 0:5350a66d5279 1572 uip_flags = UIP_ACKDATA;
hudakz 0:5350a66d5279 1573
hudakz 0:5350a66d5279 1574 /* Reset the retransmission timer. */
hudakz 0:5350a66d5279 1575 uip_connr->timer = uip_connr->rto;
hudakz 0:5350a66d5279 1576
hudakz 0:5350a66d5279 1577 /* Reset length of outstanding data. */
hudakz 0:5350a66d5279 1578 uip_connr->len = 0;
hudakz 0:5350a66d5279 1579 }
hudakz 0:5350a66d5279 1580 }
hudakz 0:5350a66d5279 1581
hudakz 0:5350a66d5279 1582 /* Do different things depending on in what state the connection is. */
hudakz 0:5350a66d5279 1583 switch(uip_connr->tcpstateflags & UIP_TS_MASK) {
hudakz 0:5350a66d5279 1584 /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
hudakz 0:5350a66d5279 1585 implemented, since we force the application to close when the
hudakz 0:5350a66d5279 1586 peer sends a FIN (hence the application goes directly from
hudakz 0:5350a66d5279 1587 ESTABLISHED to LAST_ACK). */
hudakz 0:5350a66d5279 1588 case UIP_SYN_RCVD:
hudakz 0:5350a66d5279 1589 /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
hudakz 0:5350a66d5279 1590 we are waiting for an ACK that acknowledges the data we sent
hudakz 0:5350a66d5279 1591 out the last time. Therefore, we want to have the UIP_ACKDATA
hudakz 0:5350a66d5279 1592 flag set. If so, we enter the ESTABLISHED state. */
hudakz 0:5350a66d5279 1593 if(uip_flags & UIP_ACKDATA) {
hudakz 0:5350a66d5279 1594 uip_connr->tcpstateflags = UIP_ESTABLISHED;
hudakz 0:5350a66d5279 1595 uip_flags = UIP_CONNECTED;
hudakz 0:5350a66d5279 1596 uip_connr->len = 0;
hudakz 0:5350a66d5279 1597 if(uip_len > 0) {
hudakz 0:5350a66d5279 1598 uip_flags |= UIP_NEWDATA;
hudakz 0:5350a66d5279 1599 uip_add_rcv_nxt(uip_len);
hudakz 0:5350a66d5279 1600 }
hudakz 0:5350a66d5279 1601
hudakz 0:5350a66d5279 1602 uip_slen = 0;
hudakz 0:5350a66d5279 1603 UIP_APPCALL();
hudakz 0:5350a66d5279 1604 goto appsend;
hudakz 0:5350a66d5279 1605 }
hudakz 0:5350a66d5279 1606
hudakz 0:5350a66d5279 1607 goto drop;
hudakz 0:5350a66d5279 1608 #if UIP_ACTIVE_OPEN
hudakz 0:5350a66d5279 1609
hudakz 0:5350a66d5279 1610 case UIP_SYN_SENT:
hudakz 0:5350a66d5279 1611 /* In SYN_SENT, we wait for a SYNACK that is sent in response to
hudakz 0:5350a66d5279 1612 our SYN. The rcv_nxt is set to sequence number in the SYNACK
hudakz 0:5350a66d5279 1613 plus one, and we send an ACK. We move into the ESTABLISHED
hudakz 0:5350a66d5279 1614 state. */
hudakz 0:5350a66d5279 1615 if((uip_flags & UIP_ACKDATA) && (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) {
hudakz 0:5350a66d5279 1616
hudakz 0:5350a66d5279 1617 /* Parse the TCP MSS option, if present. */
hudakz 0:5350a66d5279 1618 if((BUF->tcpoffset & 0xf0) > 0x50) {
hudakz 0:5350a66d5279 1619 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2;) {
hudakz 0:5350a66d5279 1620 opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c];
hudakz 0:5350a66d5279 1621 if(opt == TCP_OPT_END) {
hudakz 0:5350a66d5279 1622
hudakz 0:5350a66d5279 1623 /* End of options. */
hudakz 0:5350a66d5279 1624 break;
hudakz 0:5350a66d5279 1625 }
hudakz 0:5350a66d5279 1626 else
hudakz 0:5350a66d5279 1627 if(opt == TCP_OPT_NOOP) {
hudakz 0:5350a66d5279 1628 ++c;
hudakz 0:5350a66d5279 1629
hudakz 0:5350a66d5279 1630 /* NOP option. */
hudakz 0:5350a66d5279 1631 }
hudakz 0:5350a66d5279 1632 else
hudakz 0:5350a66d5279 1633 if(opt == TCP_OPT_MSS && uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
hudakz 0:5350a66d5279 1634
hudakz 0:5350a66d5279 1635 /* An MSS option with the right option length. */
hudakz 0:5350a66d5279 1636 tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
hudakz 0:5350a66d5279 1637 uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS ? UIP_TCP_MSS : tmp16;
hudakz 0:5350a66d5279 1638
hudakz 0:5350a66d5279 1639 /* And we are done processing options. */
hudakz 0:5350a66d5279 1640 break;
hudakz 0:5350a66d5279 1641 }
hudakz 0:5350a66d5279 1642 else {
hudakz 0:5350a66d5279 1643
hudakz 0:5350a66d5279 1644 /* All other options have a length field, so that we easily
hudakz 0:5350a66d5279 1645 can skip past them. */
hudakz 0:5350a66d5279 1646 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
hudakz 0:5350a66d5279 1647
hudakz 0:5350a66d5279 1648 /* If the length field is zero, the options are malformed
hudakz 0:5350a66d5279 1649 and we don't process them further. */
hudakz 0:5350a66d5279 1650 break;
hudakz 0:5350a66d5279 1651 }
hudakz 0:5350a66d5279 1652
hudakz 0:5350a66d5279 1653 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
hudakz 0:5350a66d5279 1654 }
hudakz 0:5350a66d5279 1655 }
hudakz 0:5350a66d5279 1656 }
hudakz 0:5350a66d5279 1657
hudakz 0:5350a66d5279 1658 uip_connr->tcpstateflags = UIP_ESTABLISHED;
hudakz 0:5350a66d5279 1659 uip_connr->rcv_nxt[0] = BUF->seqno[0];
hudakz 0:5350a66d5279 1660 uip_connr->rcv_nxt[1] = BUF->seqno[1];
hudakz 0:5350a66d5279 1661 uip_connr->rcv_nxt[2] = BUF->seqno[2];
hudakz 0:5350a66d5279 1662 uip_connr->rcv_nxt[3] = BUF->seqno[3];
hudakz 0:5350a66d5279 1663 uip_add_rcv_nxt(1);
hudakz 0:5350a66d5279 1664 uip_flags = UIP_CONNECTED | UIP_NEWDATA;
hudakz 0:5350a66d5279 1665 uip_connr->len = 0;
hudakz 0:5350a66d5279 1666 uip_len = 0;
hudakz 0:5350a66d5279 1667 uip_slen = 0;
hudakz 0:5350a66d5279 1668 UIP_APPCALL();
hudakz 0:5350a66d5279 1669 goto appsend;
hudakz 0:5350a66d5279 1670 }
hudakz 0:5350a66d5279 1671
hudakz 0:5350a66d5279 1672 /* Inform the application that the connection failed */
hudakz 0:5350a66d5279 1673 uip_flags = UIP_ABORT;
hudakz 0:5350a66d5279 1674 UIP_APPCALL();
hudakz 0:5350a66d5279 1675
hudakz 0:5350a66d5279 1676 /* The connection is closed after we send the RST */
hudakz 0:5350a66d5279 1677 uip_conn->tcpstateflags = UIP_CLOSED;
hudakz 0:5350a66d5279 1678 goto reset;
hudakz 0:5350a66d5279 1679 #endif /* UIP_ACTIVE_OPEN */
hudakz 0:5350a66d5279 1680
hudakz 0:5350a66d5279 1681 case UIP_ESTABLISHED:
hudakz 0:5350a66d5279 1682 /* In the ESTABLISHED state, we call upon the application to feed
hudakz 0:5350a66d5279 1683 data into the uip_buf. If the UIP_ACKDATA flag is set, the
hudakz 0:5350a66d5279 1684 application should put new data into the buffer, otherwise we are
hudakz 0:5350a66d5279 1685 retransmitting an old segment, and the application should put that
hudakz 0:5350a66d5279 1686 data into the buffer.
hudakz 0:5350a66d5279 1687
hudakz 0:5350a66d5279 1688 If the incoming packet is a FIN, we should close the connection on
hudakz 0:5350a66d5279 1689 this side as well, and we send out a FIN and enter the LAST_ACK
hudakz 0:5350a66d5279 1690 state. We require that there is no outstanding data; otherwise the
hudakz 0:5350a66d5279 1691 sequence numbers will be screwed up. */
hudakz 0:5350a66d5279 1692 if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
hudakz 0:5350a66d5279 1693 if(uip_outstanding(uip_connr)) {
hudakz 0:5350a66d5279 1694 goto drop;
hudakz 0:5350a66d5279 1695 }
hudakz 0:5350a66d5279 1696
hudakz 0:5350a66d5279 1697 uip_add_rcv_nxt(1 + uip_len);
hudakz 0:5350a66d5279 1698 uip_flags |= UIP_CLOSE;
hudakz 0:5350a66d5279 1699 if(uip_len > 0) {
hudakz 0:5350a66d5279 1700 uip_flags |= UIP_NEWDATA;
hudakz 0:5350a66d5279 1701 }
hudakz 0:5350a66d5279 1702
hudakz 0:5350a66d5279 1703 UIP_APPCALL();
hudakz 0:5350a66d5279 1704 uip_connr->len = 1;
hudakz 0:5350a66d5279 1705 uip_connr->tcpstateflags = UIP_LAST_ACK;
hudakz 0:5350a66d5279 1706 uip_connr->nrtx = 0;
hudakz 0:5350a66d5279 1707 tcp_send_finack:
hudakz 0:5350a66d5279 1708 BUF->flags = TCP_FIN | TCP_ACK;
hudakz 0:5350a66d5279 1709 goto tcp_send_nodata;
hudakz 0:5350a66d5279 1710 }
hudakz 0:5350a66d5279 1711
hudakz 0:5350a66d5279 1712 /* Check the URG flag. If this is set, the segment carries urgent
hudakz 0:5350a66d5279 1713 data that we must pass to the application. */
hudakz 0:5350a66d5279 1714 if((BUF->flags & TCP_URG) != 0)
hudakz 0:5350a66d5279 1715 {
hudakz 0:5350a66d5279 1716 #if UIP_URGDATA > 0
hudakz 0:5350a66d5279 1717 uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
hudakz 0:5350a66d5279 1718 if(uip_urglen > uip_len) {
hudakz 0:5350a66d5279 1719
hudakz 0:5350a66d5279 1720 /* There is more urgent data in the next segment to come. */
hudakz 0:5350a66d5279 1721 uip_urglen = uip_len;
hudakz 0:5350a66d5279 1722 }
hudakz 0:5350a66d5279 1723
hudakz 0:5350a66d5279 1724 uip_add_rcv_nxt(uip_urglen);
hudakz 0:5350a66d5279 1725 uip_len -= uip_urglen;
hudakz 0:5350a66d5279 1726 uip_urgdata = uip_appdata;
hudakz 0:5350a66d5279 1727 uip_appdata += uip_urglen;
hudakz 0:5350a66d5279 1728 }
hudakz 0:5350a66d5279 1729 else {
hudakz 0:5350a66d5279 1730 uip_urglen = 0;
hudakz 0:5350a66d5279 1731 #else /* UIP_URGDATA > 0 */
hudakz 0:5350a66d5279 1732 uip_appdata = ((char*)uip_appdata) + ((BUF->urgp[0] << 8) | BUF->urgp[1]);
hudakz 0:5350a66d5279 1733 uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
hudakz 0:5350a66d5279 1734 #endif /* UIP_URGDATA > 0 */
hudakz 0:5350a66d5279 1735 }
hudakz 0:5350a66d5279 1736
hudakz 0:5350a66d5279 1737 /* If uip_len > 0 we have TCP data in the packet, and we flag this
hudakz 0:5350a66d5279 1738 by setting the UIP_NEWDATA flag and update the sequence number
hudakz 0:5350a66d5279 1739 we acknowledge. If the application has stopped the dataflow
hudakz 0:5350a66d5279 1740 using uip_stop(), we must not accept any data packets from the
hudakz 0:5350a66d5279 1741 remote host. */
hudakz 0:5350a66d5279 1742 if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
hudakz 0:5350a66d5279 1743 uip_flags |= UIP_NEWDATA;
hudakz 0:5350a66d5279 1744 uip_add_rcv_nxt(uip_len);
hudakz 0:5350a66d5279 1745 }
hudakz 0:5350a66d5279 1746
hudakz 0:5350a66d5279 1747 /* Check if the available buffer space advertised by the other end
hudakz 0:5350a66d5279 1748 is smaller than the initial MSS for this connection. If so, we
hudakz 0:5350a66d5279 1749 set the current MSS to the window size to ensure that the
hudakz 0:5350a66d5279 1750 application does not send more data than the other end can
hudakz 0:5350a66d5279 1751 handle.
hudakz 0:5350a66d5279 1752
hudakz 0:5350a66d5279 1753 If the remote host advertises a zero window, we set the MSS to
hudakz 0:5350a66d5279 1754 the initial MSS so that the application will send an entire MSS
hudakz 0:5350a66d5279 1755 of data. This data will not be acknowledged by the receiver,
hudakz 0:5350a66d5279 1756 and the application will retransmit it. This is called the
hudakz 0:5350a66d5279 1757 "persistent timer" and uses the retransmission mechanim.
hudakz 0:5350a66d5279 1758 */
hudakz 0:5350a66d5279 1759 tmp16 = ((u16_t) BUF->wnd[0] << 8) + (u16_t) BUF->wnd[1];
hudakz 0:5350a66d5279 1760 if(tmp16 > uip_connr->initialmss || tmp16 == 0) {
hudakz 0:5350a66d5279 1761 tmp16 = uip_connr->initialmss;
hudakz 0:5350a66d5279 1762 }
hudakz 0:5350a66d5279 1763
hudakz 0:5350a66d5279 1764 uip_connr->mss = tmp16;
hudakz 0:5350a66d5279 1765
hudakz 0:5350a66d5279 1766 /* If this packet constitutes an ACK for outstanding data (flagged
hudakz 0:5350a66d5279 1767 by the UIP_ACKDATA flag, we should call the application since it
hudakz 0:5350a66d5279 1768 might want to send more data. If the incoming packet had data
hudakz 0:5350a66d5279 1769 from the peer (as flagged by the UIP_NEWDATA flag), the
hudakz 0:5350a66d5279 1770 application must also be notified.
hudakz 0:5350a66d5279 1771
hudakz 0:5350a66d5279 1772 When the application is called, the global variable uip_len
hudakz 0:5350a66d5279 1773 contains the length of the incoming data. The application can
hudakz 0:5350a66d5279 1774 access the incoming data through the global pointer
hudakz 0:5350a66d5279 1775 uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN
hudakz 0:5350a66d5279 1776 bytes into the uip_buf array.
hudakz 0:5350a66d5279 1777
hudakz 0:5350a66d5279 1778 If the application wishes to send any data, this data should be
hudakz 0:5350a66d5279 1779 put into the uip_appdata and the length of the data should be
hudakz 0:5350a66d5279 1780 put into uip_len. If the application don't have any data to
hudakz 0:5350a66d5279 1781 send, uip_len must be set to 0. */
hudakz 0:5350a66d5279 1782 if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
hudakz 0:5350a66d5279 1783 uip_slen = 0;
hudakz 0:5350a66d5279 1784 UIP_APPCALL();
hudakz 0:5350a66d5279 1785
hudakz 0:5350a66d5279 1786 appsend:
hudakz 0:5350a66d5279 1787 if(uip_flags & UIP_ABORT) {
hudakz 0:5350a66d5279 1788 uip_slen = 0;
hudakz 0:5350a66d5279 1789 uip_connr->tcpstateflags = UIP_CLOSED;
hudakz 0:5350a66d5279 1790 BUF->flags = TCP_RST | TCP_ACK;
hudakz 0:5350a66d5279 1791 goto tcp_send_nodata;
hudakz 0:5350a66d5279 1792 }
hudakz 0:5350a66d5279 1793
hudakz 0:5350a66d5279 1794 if(uip_flags & UIP_CLOSE) {
hudakz 0:5350a66d5279 1795 uip_slen = 0;
hudakz 0:5350a66d5279 1796 uip_connr->len = 1;
hudakz 0:5350a66d5279 1797 uip_connr->tcpstateflags = UIP_FIN_WAIT_1;
hudakz 0:5350a66d5279 1798 uip_connr->nrtx = 0;
hudakz 0:5350a66d5279 1799 BUF->flags = TCP_FIN | TCP_ACK;
hudakz 0:5350a66d5279 1800 goto tcp_send_nodata;
hudakz 0:5350a66d5279 1801 }
hudakz 0:5350a66d5279 1802
hudakz 0:5350a66d5279 1803 /* If uip_slen > 0, the application has data to be sent. */
hudakz 0:5350a66d5279 1804 if(uip_slen > 0) {
hudakz 0:5350a66d5279 1805
hudakz 0:5350a66d5279 1806 /* If the connection has acknowledged data, the contents of
hudakz 0:5350a66d5279 1807 the ->len variable should be discarded. */
hudakz 0:5350a66d5279 1808 if((uip_flags & UIP_ACKDATA) != 0) {
hudakz 0:5350a66d5279 1809 uip_connr->len = 0;
hudakz 0:5350a66d5279 1810 }
hudakz 0:5350a66d5279 1811
hudakz 0:5350a66d5279 1812 /* If the ->len variable is non-zero the connection has
hudakz 0:5350a66d5279 1813 already data in transit and cannot send anymore right
hudakz 0:5350a66d5279 1814 now. */
hudakz 0:5350a66d5279 1815 if(uip_connr->len == 0) {
hudakz 0:5350a66d5279 1816
hudakz 0:5350a66d5279 1817 /* The application cannot send more than what is allowed by
hudakz 0:5350a66d5279 1818 the mss (the minumum of the MSS and the available
hudakz 0:5350a66d5279 1819 window). */
hudakz 0:5350a66d5279 1820 if(uip_slen > uip_connr->mss) {
hudakz 0:5350a66d5279 1821 uip_slen = uip_connr->mss;
hudakz 0:5350a66d5279 1822 }
hudakz 0:5350a66d5279 1823
hudakz 0:5350a66d5279 1824 /* Remember how much data we send out now so that we know
hudakz 0:5350a66d5279 1825 when everything has been acknowledged. */
hudakz 0:5350a66d5279 1826 uip_connr->len = uip_slen;
hudakz 0:5350a66d5279 1827 }
hudakz 0:5350a66d5279 1828 else {
hudakz 0:5350a66d5279 1829
hudakz 0:5350a66d5279 1830 /* If the application already had unacknowledged data, we
hudakz 0:5350a66d5279 1831 make sure that the application does not send (i.e.,
hudakz 0:5350a66d5279 1832 retransmit) out more than it previously sent out. */
hudakz 0:5350a66d5279 1833 uip_slen = uip_connr->len;
hudakz 0:5350a66d5279 1834 }
hudakz 0:5350a66d5279 1835 }
hudakz 0:5350a66d5279 1836
hudakz 0:5350a66d5279 1837 uip_connr->nrtx = 0;
hudakz 0:5350a66d5279 1838 apprexmit:
hudakz 0:5350a66d5279 1839 uip_appdata = uip_sappdata;
hudakz 0:5350a66d5279 1840
hudakz 0:5350a66d5279 1841 /* If the application has data to be sent, or if the incoming
hudakz 0:5350a66d5279 1842 packet had new data in it, we must send out a packet. */
hudakz 0:5350a66d5279 1843 if(uip_slen > 0 && uip_connr->len > 0) {
hudakz 0:5350a66d5279 1844
hudakz 0:5350a66d5279 1845 /* Add the length of the IP and TCP headers. */
hudakz 0:5350a66d5279 1846 uip_len = uip_connr->len + UIP_TCPIP_HLEN;
hudakz 0:5350a66d5279 1847
hudakz 0:5350a66d5279 1848 /* We always set the ACK flag in response packets. */
hudakz 0:5350a66d5279 1849 BUF->flags = TCP_ACK | TCP_PSH;
hudakz 0:5350a66d5279 1850
hudakz 0:5350a66d5279 1851 /* Send the packet. */
hudakz 0:5350a66d5279 1852 goto tcp_send_noopts;
hudakz 0:5350a66d5279 1853 }
hudakz 0:5350a66d5279 1854
hudakz 0:5350a66d5279 1855 /* If there is no data to send, just send out a pure ACK if
hudakz 0:5350a66d5279 1856 there is newdata. */
hudakz 0:5350a66d5279 1857 if(uip_flags & UIP_NEWDATA) {
hudakz 0:5350a66d5279 1858 uip_len = UIP_TCPIP_HLEN;
hudakz 0:5350a66d5279 1859 BUF->flags = TCP_ACK;
hudakz 0:5350a66d5279 1860 goto tcp_send_noopts;
hudakz 0:5350a66d5279 1861 }
hudakz 0:5350a66d5279 1862 }
hudakz 0:5350a66d5279 1863
hudakz 0:5350a66d5279 1864 goto drop;
hudakz 0:5350a66d5279 1865
hudakz 0:5350a66d5279 1866 case UIP_LAST_ACK:
hudakz 0:5350a66d5279 1867 /* We can close this connection if the peer has acknowledged our
hudakz 0:5350a66d5279 1868 FIN. This is indicated by the UIP_ACKDATA flag. */
hudakz 0:5350a66d5279 1869 if(uip_flags & UIP_ACKDATA) {
hudakz 0:5350a66d5279 1870 uip_connr->tcpstateflags = UIP_CLOSED;
hudakz 0:5350a66d5279 1871 uip_flags = UIP_CLOSE;
hudakz 0:5350a66d5279 1872 UIP_APPCALL();
hudakz 0:5350a66d5279 1873 }
hudakz 0:5350a66d5279 1874 break;
hudakz 0:5350a66d5279 1875
hudakz 0:5350a66d5279 1876 case UIP_FIN_WAIT_1:
hudakz 0:5350a66d5279 1877 /* The application has closed the connection, but the remote host
hudakz 0:5350a66d5279 1878 hasn't closed its end yet. Thus we do nothing but wait for a
hudakz 0:5350a66d5279 1879 FIN from the other side. */
hudakz 0:5350a66d5279 1880 if(uip_len > 0) {
hudakz 0:5350a66d5279 1881 uip_add_rcv_nxt(uip_len);
hudakz 0:5350a66d5279 1882 }
hudakz 0:5350a66d5279 1883
hudakz 0:5350a66d5279 1884 if(BUF->flags & TCP_FIN) {
hudakz 0:5350a66d5279 1885 if(uip_flags & UIP_ACKDATA) {
hudakz 0:5350a66d5279 1886 uip_connr->tcpstateflags = UIP_TIME_WAIT;
hudakz 0:5350a66d5279 1887 uip_connr->timer = 0;
hudakz 0:5350a66d5279 1888 uip_connr->len = 0;
hudakz 0:5350a66d5279 1889 }
hudakz 0:5350a66d5279 1890 else {
hudakz 0:5350a66d5279 1891 uip_connr->tcpstateflags = UIP_CLOSING;
hudakz 0:5350a66d5279 1892 }
hudakz 0:5350a66d5279 1893
hudakz 0:5350a66d5279 1894 uip_add_rcv_nxt(1);
hudakz 0:5350a66d5279 1895 uip_flags = UIP_CLOSE;
hudakz 0:5350a66d5279 1896 UIP_APPCALL();
hudakz 0:5350a66d5279 1897 goto tcp_send_ack;
hudakz 0:5350a66d5279 1898 }
hudakz 0:5350a66d5279 1899 else
hudakz 0:5350a66d5279 1900 if(uip_flags & UIP_ACKDATA) {
hudakz 0:5350a66d5279 1901 uip_connr->tcpstateflags = UIP_FIN_WAIT_2;
hudakz 0:5350a66d5279 1902 uip_connr->len = 0;
hudakz 0:5350a66d5279 1903 goto drop;
hudakz 0:5350a66d5279 1904 }
hudakz 0:5350a66d5279 1905
hudakz 0:5350a66d5279 1906 if(uip_len > 0) {
hudakz 0:5350a66d5279 1907 goto tcp_send_ack;
hudakz 0:5350a66d5279 1908 }
hudakz 0:5350a66d5279 1909
hudakz 0:5350a66d5279 1910 goto drop;
hudakz 0:5350a66d5279 1911
hudakz 0:5350a66d5279 1912 case UIP_FIN_WAIT_2:
hudakz 0:5350a66d5279 1913 if(uip_len > 0) {
hudakz 0:5350a66d5279 1914 uip_add_rcv_nxt(uip_len);
hudakz 0:5350a66d5279 1915 }
hudakz 0:5350a66d5279 1916
hudakz 0:5350a66d5279 1917 if(BUF->flags & TCP_FIN) {
hudakz 0:5350a66d5279 1918 uip_connr->tcpstateflags = UIP_TIME_WAIT;
hudakz 0:5350a66d5279 1919 uip_connr->timer = 0;
hudakz 0:5350a66d5279 1920 uip_add_rcv_nxt(1);
hudakz 0:5350a66d5279 1921 uip_flags = UIP_CLOSE;
hudakz 0:5350a66d5279 1922 UIP_APPCALL();
hudakz 0:5350a66d5279 1923 goto tcp_send_ack;
hudakz 0:5350a66d5279 1924 }
hudakz 0:5350a66d5279 1925
hudakz 0:5350a66d5279 1926 if(uip_len > 0) {
hudakz 0:5350a66d5279 1927 goto tcp_send_ack;
hudakz 0:5350a66d5279 1928 }
hudakz 0:5350a66d5279 1929
hudakz 0:5350a66d5279 1930 goto drop;
hudakz 0:5350a66d5279 1931
hudakz 0:5350a66d5279 1932 case UIP_TIME_WAIT:
hudakz 0:5350a66d5279 1933 goto tcp_send_ack;
hudakz 0:5350a66d5279 1934
hudakz 0:5350a66d5279 1935 case UIP_CLOSING:
hudakz 0:5350a66d5279 1936 if(uip_flags & UIP_ACKDATA) {
hudakz 0:5350a66d5279 1937 uip_connr->tcpstateflags = UIP_TIME_WAIT;
hudakz 0:5350a66d5279 1938 uip_connr->timer = 0;
hudakz 0:5350a66d5279 1939 }
hudakz 0:5350a66d5279 1940 }
hudakz 0:5350a66d5279 1941
hudakz 0:5350a66d5279 1942 goto drop;
hudakz 0:5350a66d5279 1943
hudakz 0:5350a66d5279 1944 /* We jump here when we are ready to send the packet, and just want
hudakz 0:5350a66d5279 1945 to set the appropriate TCP sequence numbers in the TCP header. */
hudakz 0:5350a66d5279 1946 tcp_send_ack:
hudakz 0:5350a66d5279 1947 BUF->flags = TCP_ACK;
hudakz 0:5350a66d5279 1948 tcp_send_nodata:
hudakz 0:5350a66d5279 1949 uip_len = UIP_IPTCPH_LEN;
hudakz 0:5350a66d5279 1950 tcp_send_noopts:
hudakz 0:5350a66d5279 1951 BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4;
hudakz 0:5350a66d5279 1952 tcp_send:
hudakz 0:5350a66d5279 1953 /* We're done with the input processing. We are now ready to send a
hudakz 0:5350a66d5279 1954 reply. Our job is to fill in all the fields of the TCP and IP
hudakz 0:5350a66d5279 1955 headers before calculating the checksum and finally send the
hudakz 0:5350a66d5279 1956 packet. */
hudakz 0:5350a66d5279 1957 BUF->ackno[0] = uip_connr->rcv_nxt[0];
hudakz 0:5350a66d5279 1958 BUF->ackno[1] = uip_connr->rcv_nxt[1];
hudakz 0:5350a66d5279 1959 BUF->ackno[2] = uip_connr->rcv_nxt[2];
hudakz 0:5350a66d5279 1960 BUF->ackno[3] = uip_connr->rcv_nxt[3];
hudakz 0:5350a66d5279 1961
hudakz 0:5350a66d5279 1962 BUF->seqno[0] = uip_connr->snd_nxt[0];
hudakz 0:5350a66d5279 1963 BUF->seqno[1] = uip_connr->snd_nxt[1];
hudakz 0:5350a66d5279 1964 BUF->seqno[2] = uip_connr->snd_nxt[2];
hudakz 0:5350a66d5279 1965 BUF->seqno[3] = uip_connr->snd_nxt[3];
hudakz 0:5350a66d5279 1966
hudakz 0:5350a66d5279 1967 BUF->proto = UIP_PROTO_TCP;
hudakz 0:5350a66d5279 1968
hudakz 0:5350a66d5279 1969 BUF->srcport = uip_connr->lport;
hudakz 0:5350a66d5279 1970 BUF->destport = uip_connr->rport;
hudakz 0:5350a66d5279 1971
hudakz 0:5350a66d5279 1972 uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr);
hudakz 0:5350a66d5279 1973 uip_ipaddr_copy(BUF->destipaddr, uip_connr->ripaddr);
hudakz 0:5350a66d5279 1974
hudakz 0:5350a66d5279 1975 if(uip_connr->tcpstateflags & UIP_STOPPED) {
hudakz 0:5350a66d5279 1976
hudakz 0:5350a66d5279 1977 /* If the connection has issued uip_stop(), we advertise a zero
hudakz 0:5350a66d5279 1978 window so that the remote host will stop sending data. */
hudakz 0:5350a66d5279 1979 BUF->wnd[0] = BUF->wnd[1] = 0;
hudakz 0:5350a66d5279 1980 }
hudakz 0:5350a66d5279 1981 else {
hudakz 0:5350a66d5279 1982 BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
hudakz 0:5350a66d5279 1983 BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
hudakz 0:5350a66d5279 1984 }
hudakz 0:5350a66d5279 1985
hudakz 0:5350a66d5279 1986 tcp_send_noconn:
hudakz 0:5350a66d5279 1987 BUF->ttl = UIP_TTL;
hudakz 0:5350a66d5279 1988 #if UIP_CONF_IPV6
hudakz 0:5350a66d5279 1989 /* For IPv6, the IP length field does not include the IPv6 IP header
hudakz 0:5350a66d5279 1990 length. */
hudakz 0:5350a66d5279 1991
hudakz 0:5350a66d5279 1992 BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
hudakz 0:5350a66d5279 1993 BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
hudakz 0:5350a66d5279 1994 #else /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 1995 BUF->len[0] = (uip_len >> 8);
hudakz 0:5350a66d5279 1996 BUF->len[1] = (uip_len & 0xff);
hudakz 0:5350a66d5279 1997 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 1998
hudakz 0:5350a66d5279 1999 BUF->urgp[0] = BUF->urgp[1] = 0;
hudakz 0:5350a66d5279 2000
hudakz 0:5350a66d5279 2001 /* Calculate TCP checksum. */
hudakz 0:5350a66d5279 2002 BUF->tcpchksum = 0;
hudakz 0:5350a66d5279 2003 BUF->tcpchksum = ~(uip_tcpchksum());
hudakz 0:5350a66d5279 2004
hudakz 0:5350a66d5279 2005 ip_send_nolen:
hudakz 0:5350a66d5279 2006 #if UIP_CONF_IPV6
hudakz 0:5350a66d5279 2007 BUF->vtc = 0x60;
hudakz 0:5350a66d5279 2008 BUF->tcflow = 0x00;
hudakz 0:5350a66d5279 2009 BUF->flow = 0x00;
hudakz 0:5350a66d5279 2010 #else /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 2011 BUF->vhl = 0x45;
hudakz 0:5350a66d5279 2012 BUF->tos = 0;
hudakz 0:5350a66d5279 2013 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
hudakz 0:5350a66d5279 2014 ++ipid;
hudakz 0:5350a66d5279 2015 BUF->ipid[0] = ipid >> 8;
hudakz 0:5350a66d5279 2016 BUF->ipid[1] = ipid & 0xff;
hudakz 0:5350a66d5279 2017
hudakz 0:5350a66d5279 2018 /* Calculate IP checksum. */
hudakz 0:5350a66d5279 2019 BUF->ipchksum = 0;
hudakz 0:5350a66d5279 2020 BUF->ipchksum = ~(uip_ipchksum());
hudakz 0:5350a66d5279 2021 DEBUG_PRINTF("uip ip_send_nolen: chkecum 0x%04x\n", uip_ipchksum());
hudakz 0:5350a66d5279 2022 #endif /* UIP_CONF_IPV6 */
hudakz 0:5350a66d5279 2023
hudakz 0:5350a66d5279 2024 UIP_STAT(++uip_stat.tcp.sent);
hudakz 0:5350a66d5279 2025 send:
hudakz 0:5350a66d5279 2026 DEBUG_PRINTF("Sending packet with length %d (%d)\n", uip_len, (BUF->len[0] << 8) | BUF->len[1]);
hudakz 0:5350a66d5279 2027
hudakz 0:5350a66d5279 2028 UIP_STAT(++uip_stat.ip.sent);
hudakz 0:5350a66d5279 2029
hudakz 0:5350a66d5279 2030 /* Return and let the caller do the actual transmission. */
hudakz 0:5350a66d5279 2031 uip_flags = 0;
hudakz 0:5350a66d5279 2032 return;
hudakz 0:5350a66d5279 2033 drop:
hudakz 0:5350a66d5279 2034 uip_len = 0;
hudakz 0:5350a66d5279 2035 uip_flags = 0;
hudakz 0:5350a66d5279 2036 return;
hudakz 0:5350a66d5279 2037 }
hudakz 0:5350a66d5279 2038
hudakz 0:5350a66d5279 2039 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 2040 u16_t htons(u16_t val) {
hudakz 0:5350a66d5279 2041 return HTONS(val);
hudakz 0:5350a66d5279 2042 }
hudakz 0:5350a66d5279 2043
hudakz 0:5350a66d5279 2044 /*---------------------------------------------------------------------------*/
hudakz 0:5350a66d5279 2045 void uip_send(const void* data, int len) {
hudakz 0:5350a66d5279 2046 uip_slen = len;
hudakz 0:5350a66d5279 2047 if(len > 0) {
hudakz 0:5350a66d5279 2048 if(data != uip_sappdata) {
hudakz 0:5350a66d5279 2049 memcpy(uip_sappdata, (data), uip_slen);
hudakz 0:5350a66d5279 2050 }
hudakz 0:5350a66d5279 2051 }
hudakz 0:5350a66d5279 2052 }
hudakz 0:5350a66d5279 2053
hudakz 0:5350a66d5279 2054 /** @} */