blob: 4aef8c9fbce6e9e6c3540f0477bfaef19c16e51c [file] [log] [blame]
adamdunkelsa2f3c422004-09-12 20:24:53 +00001/*
2 * Copyright (c) 2004, Swedish Institute of Computer Science.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 *
31 * Author: Adam Dunkels <adam@sics.se>
32 *
adamdunkels3335cd92005-02-27 09:44:33 +000033 * $Id: tcpip.c,v 1.6 2005/02/27 09:44:33 adamdunkels Exp $
adamdunkelsa2f3c422004-09-12 20:24:53 +000034 */
adamdunkels454d3c92004-07-04 17:01:46 +000035#include "tcpip.h"
36
37#include "ek-service.h"
38
39#include "tcpip.h"
40
41#include "uip.h"
42#include "uip-fw.h"
43
44#include "timer.h"
45
46#include "packet-service.h"
47
adamdunkels475220c2004-08-09 20:47:32 +000048#include "uip-split.h"
49
adamdunkels454d3c92004-07-04 17:01:46 +000050#include <string.h>
51
52ek_event_t tcpip_event;
53
54EK_SERVICE(packetservice, PACKET_SERVICE_NAME);
55
56/**
57 * \internal Structure for holding a TCP port and a process ID.
58 */
59struct listenport {
60 u16_t port;
61 ek_id_t id;
62};
63
64/*static struct tcpip_event_args ev_args;*/
65
66static struct timer periodic;
67
68static struct internal_state {
69 struct listenport listenports[UIP_LISTENPORTS];
70 ek_event_t event;
71 ek_id_t id;
72} s;
73
74enum {
75 TCP_POLL,
76 UDP_POLL
77};
78
adamdunkels475220c2004-08-09 20:47:32 +000079static unsigned char forwarding = 0;
adamdunkels454d3c92004-07-04 17:01:46 +000080
81EK_EVENTHANDLER(eventhandler, ev, data);
82EK_POLLHANDLER(pollhandler);
83EK_PROCESS(proc, "TCP/IP stack", EK_PRIO_NORMAL,
84 eventhandler, pollhandler, NULL);
85/*---------------------------------------------------------------------------*/
86EK_PROCESS_INIT(tcpip_init, arg)
87{
88 uip_init();
89 ek_start(&proc);
adamdunkels475220c2004-08-09 20:47:32 +000090 forwarding = 0;
adamdunkels454d3c92004-07-04 17:01:46 +000091}
92/*---------------------------------------------------------------------------*/
93void
94tcpip_set_forwarding(unsigned char f)
95{
96 forwarding = f;
97}
98/*---------------------------------------------------------------------------*/
99void
100tcpip_input(void)
101{
102 if(uip_len > 0) {
103 if(forwarding) {
104 if(uip_fw_forward() == 0) {
105 uip_input();
106 if(uip_len > 0) {
adamdunkels475220c2004-08-09 20:47:32 +0000107#if UIP_CONF_TCP_SPLIT
108 uip_split_output();
109#else
adamdunkels454d3c92004-07-04 17:01:46 +0000110 tcpip_output();
adamdunkels475220c2004-08-09 20:47:32 +0000111#endif
adamdunkels454d3c92004-07-04 17:01:46 +0000112 }
113 }
114 } else {
115 uip_input();
116 if(uip_len > 0) {
adamdunkels475220c2004-08-09 20:47:32 +0000117#if UIP_CONF_TCP_SPLIT
118 uip_split_output();
119#else
adamdunkels454d3c92004-07-04 17:01:46 +0000120 tcpip_output();
adamdunkels475220c2004-08-09 20:47:32 +0000121#endif
adamdunkels454d3c92004-07-04 17:01:46 +0000122 }
123 }
124 }
125}
126/*---------------------------------------------------------------------------*/
127void
128tcpip_output(void)
129{
130 struct packet_service_state *state;
adamdunkels58efc012005-02-07 07:05:29 +0000131 u16_t hdrlen, datalen;
adamdunkels454d3c92004-07-04 17:01:46 +0000132
133 state = (struct packet_service_state *)ek_service_state(&packetservice);
adamdunkels58efc012005-02-07 07:05:29 +0000134
adamdunkels454d3c92004-07-04 17:01:46 +0000135 if(state != NULL &&
136 state->version == PACKET_SERVICE_VERSION) {
adamdunkels58efc012005-02-07 07:05:29 +0000137
adamdunkels454d3c92004-07-04 17:01:46 +0000138 hdrlen = UIP_TCPIP_HLEN;
139 if(uip_len < UIP_TCPIP_HLEN) {
140 hdrlen = uip_len;
141 datalen = 0;
142 } else {
143 datalen = uip_len - UIP_TCPIP_HLEN;
144 }
145
146 state->output(&uip_buf[UIP_LLH_LEN], hdrlen, uip_appdata, datalen);
147 }
148}
149/*---------------------------------------------------------------------------*/
150struct uip_conn *
151tcp_connect(u16_t *ripaddr, u16_t port, void *appstate)
152{
153 struct uip_conn *c;
adamdunkels475220c2004-08-09 20:47:32 +0000154
adamdunkels454d3c92004-07-04 17:01:46 +0000155 c = uip_connect(ripaddr, port);
156 if(c == NULL) {
157 return NULL;
158 }
159
160 ((struct tcpip_uipstate *)(c->appstate))->id = EK_PROC_ID(EK_CURRENT());
161 ((struct tcpip_uipstate *)(c->appstate))->state = appstate;
162
163 ek_post(s.id, TCP_POLL, c);
164
165 return c;
166}
167/*---------------------------------------------------------------------------*/
168void
adamdunkels475220c2004-08-09 20:47:32 +0000169tcp_unlisten(u16_t port)
170{
171 static unsigned char i;
172 struct listenport *l;
173
174 l = s.listenports;
175 for(i = 0; i < UIP_LISTENPORTS; ++i) {
176 if(l->port == port &&
177 l->id == EK_PROC_ID(EK_CURRENT())) {
178 l->port = 0;
179 uip_unlisten(port);
180 break;
181 }
182 ++l;
183 }
184}
185/*---------------------------------------------------------------------------*/
186void
adamdunkels454d3c92004-07-04 17:01:46 +0000187tcp_listen(u16_t port)
188{
189 static unsigned char i;
190 struct listenport *l;
191
192 l = s.listenports;
193 for(i = 0; i < UIP_LISTENPORTS; ++i) {
194 if(l->port == 0) {
195 l->port = port;
196 l->id = EK_PROC_ID(EK_CURRENT());
197 uip_listen(port);
198 break;
199 }
200 ++l;
201 }
202}
203/*---------------------------------------------------------------------------*/
204void
205tcp_markconn(struct uip_conn *conn,
206 void *appstate)
207{
adamdunkels475220c2004-08-09 20:47:32 +0000208 register struct tcpip_uipstate *s;
adamdunkels454d3c92004-07-04 17:01:46 +0000209
210 s = (struct tcpip_uipstate *)conn->appstate;
211 s->id = ek_current->id;
212 s->state = appstate;
213}
214/*---------------------------------------------------------------------------*/
215struct uip_udp_conn *
216udp_new(u16_t *ripaddr, u16_t port, void *appstate)
217{
218 struct uip_udp_conn *c;
219 struct tcpip_uipstate *s;
220
221 c = uip_udp_new(ripaddr, port);
222 if(c == NULL) {
223 return NULL;
224 }
225
226 s = (struct tcpip_uipstate *)c->appstate;
227 s->id = EK_PROC_ID(EK_CURRENT());
228 s->state = appstate;
229
230 return c;
231}
232/*---------------------------------------------------------------------------*/
233EK_EVENTHANDLER(eventhandler, ev, data)
234{
adamdunkels475220c2004-08-09 20:47:32 +0000235 static unsigned char i;
236 register struct listenport *l;
adamdunkels454d3c92004-07-04 17:01:46 +0000237 ek_id_t id;
238 struct internal_state *state;
239
240 switch(ev) {
241 case EK_EVENT_INIT:
242 for(i = 0; i < UIP_LISTENPORTS; ++i) {
243 s.listenports[i].port = 0;
244 }
245 s.id = EK_PROC_ID(EK_CURRENT());
246 tcpip_event = s.event = ek_alloc_event();
247 timer_set(&periodic, CLOCK_SECOND/2);
248 break;
249 case EK_EVENT_REPLACE:
250 memcpy(&s, data, sizeof(s));
251 arg_free(data);
252 break;
253 case EK_EVENT_REQUEST_REPLACE:
254 state = (struct internal_state *)arg_alloc(sizeof(s));
255 /* Copy state */
256 memcpy(state, &s, sizeof(s));
257 ek_replace((struct ek_proc *)data, state);
258 break;
259
260 case EK_EVENT_EXITED:
261 id = (ek_id_t)data;
262 l = s.listenports;
263 for(i = 0; i < UIP_LISTENPORTS; ++i) {
264 if(l->id == id) {
265 uip_unlisten(l->port);
266 l->port = 0;
267 l->id = EK_ID_NONE;
268 }
269 ++l;
270 }
adamdunkels475220c2004-08-09 20:47:32 +0000271 /* for(i = 0; i < UIP_CONNS; ++i) {
adamdunkels454d3c92004-07-04 17:01:46 +0000272 if(((struct tcpip_uipstate *)uip_conns[i].appstate)->id == id) {
adamdunkels475220c2004-08-09 20:47:32 +0000273 ((struct tcpip_uipstate *)uip_conns[i].appstate)->id = EK_ID_NONE;
adamdunkels454d3c92004-07-04 17:01:46 +0000274 uip_conns[i].tcpstateflags = CLOSED;
275 }
adamdunkels475220c2004-08-09 20:47:32 +0000276 }*/
277 {
278 register struct uip_conn *cptr;
279
280 for(cptr = &uip_conns[0]; cptr < &uip_conns[UIP_CONNS]; ++cptr) {
281 if(((struct tcpip_uipstate *)cptr->appstate)->id == id) {
282 ((struct tcpip_uipstate *)cptr->appstate)->id = EK_ID_NONE;
283 cptr->tcpstateflags = CLOSED;
284 }
285
286 }
287
adamdunkels454d3c92004-07-04 17:01:46 +0000288 }
289#if UIP_UDP
adamdunkels475220c2004-08-09 20:47:32 +0000290 {
291 register struct uip_udp_conn *cptr;
292 for(cptr = &uip_udp_conns[0];
293 cptr < &uip_udp_conns[UIP_UDP_CONNS]; ++cptr) {
294 if(((struct tcpip_uipstate *)cptr->appstate)->id == id) {
295 cptr->lport = 0;
296 }
297 }
298
299 }
300 /* for(i = 0; i < UIP_UDP_CONNS; ++i) {
adamdunkels454d3c92004-07-04 17:01:46 +0000301 if(((struct tcpip_uipstate *)uip_udp_conns[i].appstate)->id == id) {
302 uip_udp_conns[i].lport = 0;
303 }
adamdunkels475220c2004-08-09 20:47:32 +0000304 }*/
adamdunkels454d3c92004-07-04 17:01:46 +0000305#endif /* UIP_UDP */
306 break;
307 case TCP_POLL:
adamdunkels58efc012005-02-07 07:05:29 +0000308 if(data != NULL) {
adamdunkels3335cd92005-02-27 09:44:33 +0000309 uip_poll_conn(data);
adamdunkels58efc012005-02-07 07:05:29 +0000310 if(uip_len > 0) {
311 tcpip_output();
312 }
adamdunkels454d3c92004-07-04 17:01:46 +0000313 }
314 break;
315 case UDP_POLL:
adamdunkels58efc012005-02-07 07:05:29 +0000316 if(data != NULL) {
317 uip_udp_periodic_conn(data);
318 if(uip_len > 0) {
319 tcpip_output();
320 }
adamdunkels454d3c92004-07-04 17:01:46 +0000321 }
322 break;
323 };
324}
325/*---------------------------------------------------------------------------*/
326void
327tcpip_poll_udp(struct uip_udp_conn *conn)
328{
329 ek_post(s.id, UDP_POLL, conn);
330}
331/*---------------------------------------------------------------------------*/
332void
333tcpip_poll_tcp(struct uip_conn *conn)
334{
335 ek_post(s.id, TCP_POLL, conn);
336}
337/*---------------------------------------------------------------------------*/
338void
339tcpip_uipcall(void)
340{
341 register struct tcpip_uipstate *ts;
adamdunkels475220c2004-08-09 20:47:32 +0000342 static unsigned char i;
343 register struct listenport *l;
adamdunkels454d3c92004-07-04 17:01:46 +0000344
345 if(uip_conn != NULL) {
346 ts = (struct tcpip_uipstate *)uip_conn->appstate;
347 } else {
348 ts = (struct tcpip_uipstate *)uip_udp_conn->appstate;
349 }
350
351 /* If this is a connection request for a listening port, we must
352 mark the connection with the right process ID. */
353 if(uip_connected()) {
354 l = &s.listenports[0];
355 for(i = 0; i < UIP_LISTENPORTS; ++i) {
356 if(l->port == uip_conn->lport &&
357 l->id != EK_ID_NONE) {
358 ts->id = l->id;
359 ts->state = NULL;
360 break;
361 }
362 ++l;
363 }
364 }
365
366 ek_post_synch(ts->id, s.event, ts->state);
367}
368/*---------------------------------------------------------------------------*/
369EK_POLLHANDLER(pollhandler)
370{
adamdunkels475220c2004-08-09 20:47:32 +0000371 static unsigned char i;
adamdunkels454d3c92004-07-04 17:01:46 +0000372
373 /* Check the clock so see if we should call the periodic uIP
374 processing. */
375 if(timer_expired(&periodic)) {
adamdunkels58efc012005-02-07 07:05:29 +0000376 timer_restart(&periodic);
adamdunkels454d3c92004-07-04 17:01:46 +0000377 for(i = 0; i < UIP_CONNS; ++i) {
378 uip_periodic(i);
379 if(uip_len > 0) {
380 tcpip_output();
381 /* uip_fw_output();*/
382 }
383 }
384
385 for(i = 0; i < UIP_UDP_CONNS; i++) {
386 uip_udp_periodic(i);
387 if(uip_len > 0) {
388 tcpip_output();
389 /* uip_fw_output();*/
390 }
391 }
392 uip_fw_periodic();
393 }
394}
395/*---------------------------------------------------------------------------*/