OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Common/] [ethernet/] [lwIP_130/] [src/] [api/] [api_msg.c] - Blame information for rev 606

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 606 jeremybenn
/**
2
 * @file
3
 * Sequential API Internal module
4
 *
5
 */
6
 
7
/*
8
 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without modification,
12
 * are permitted provided that the following conditions are met:
13
 *
14
 * 1. Redistributions of source code must retain the above copyright notice,
15
 *    this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright notice,
17
 *    this list of conditions and the following disclaimer in the documentation
18
 *    and/or other materials provided with the distribution.
19
 * 3. The name of the author may not be used to endorse or promote products
20
 *    derived from this software without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31
 * OF SUCH DAMAGE.
32
 *
33
 * This file is part of the lwIP TCP/IP stack.
34
 *
35
 * Author: Adam Dunkels <adam@sics.se>
36
 *
37
 */
38
 
39
#include "lwip/opt.h"
40
 
41
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
42
 
43
#include "lwip/api_msg.h"
44
 
45
#include "lwip/ip.h"
46
#include "lwip/udp.h"
47
#include "lwip/tcp.h"
48
#include "lwip/raw.h"
49
 
50
#include "lwip/memp.h"
51
#include "lwip/tcpip.h"
52
#include "lwip/igmp.h"
53
#include "lwip/dns.h"
54
 
55
/* forward declarations */
56
#if LWIP_TCP
57
static err_t do_writemore(struct netconn *conn);
58
static void do_close_internal(struct netconn *conn);
59
#endif
60
 
61
#if LWIP_RAW
62
/**
63
 * Receive callback function for RAW netconns.
64
 * Doesn't 'eat' the packet, only references it and sends it to
65
 * conn->recvmbox
66
 *
67
 * @see raw.h (struct raw_pcb.recv) for parameters and return value
68
 */
69
static u8_t
70
recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
71
    struct ip_addr *addr)
72
{
73
  struct pbuf *q;
74
  struct netbuf *buf;
75
  struct netconn *conn;
76
#if LWIP_SO_RCVBUF
77
  int recv_avail;
78
#endif /* LWIP_SO_RCVBUF */
79
 
80
  LWIP_UNUSED_ARG(addr);
81
  conn = arg;
82
 
83
#if LWIP_SO_RCVBUF
84
  SYS_ARCH_GET(conn->recv_avail, recv_avail);
85
  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) &&
86
      ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) {
87
#else  /* LWIP_SO_RCVBUF */
88
  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) {
89
#endif /* LWIP_SO_RCVBUF */
90
    /* copy the whole packet into new pbufs */
91
    q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
92
    if(q != NULL) {
93
      if (pbuf_copy(q, p) != ERR_OK) {
94
        pbuf_free(q);
95
        q = NULL;
96
      }
97
    }
98
 
99
    if(q != NULL) {
100
      buf = memp_malloc(MEMP_NETBUF);
101
      if (buf == NULL) {
102
        pbuf_free(q);
103
        return 0;
104
      }
105
 
106
      buf->p = q;
107
      buf->ptr = q;
108
      buf->addr = &(((struct ip_hdr*)(q->payload))->src);
109
      buf->port = pcb->protocol;
110
 
111
      SYS_ARCH_INC(conn->recv_avail, q->tot_len);
112
      /* Register event with callback */
113
      API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);
114
      if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
115
        netbuf_delete(buf);
116
      }
117
    }
118
  }
119
 
120
  return 0; /* do not eat the packet */
121
}
122
#endif /* LWIP_RAW*/
123
 
124
#if LWIP_UDP
125
/**
126
 * Receive callback function for UDP netconns.
127
 * Posts the packet to conn->recvmbox or deletes it on memory error.
128
 *
129
 * @see udp.h (struct udp_pcb.recv) for parameters
130
 */
131
static void
132
recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
133
   struct ip_addr *addr, u16_t port)
134
{
135
  struct netbuf *buf;
136
  struct netconn *conn;
137
#if LWIP_SO_RCVBUF
138
  int recv_avail;
139
#endif /* LWIP_SO_RCVBUF */
140
 
141
  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
142
  LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
143
  LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
144
  conn = arg;
145
  LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
146
 
147
#if LWIP_SO_RCVBUF
148
  SYS_ARCH_GET(conn->recv_avail, recv_avail);
149
  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) ||
150
      ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
151
#else  /* LWIP_SO_RCVBUF */
152
  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
153
#endif /* LWIP_SO_RCVBUF */
154
    pbuf_free(p);
155
    return;
156
  }
157
 
158
  buf = memp_malloc(MEMP_NETBUF);
159
  if (buf == NULL) {
160
    pbuf_free(p);
161
    return;
162
  } else {
163
    buf->p = p;
164
    buf->ptr = p;
165
    buf->addr = addr;
166
    buf->port = port;
167
  }
168
 
169
  SYS_ARCH_INC(conn->recv_avail, p->tot_len);
170
  /* Register event with callback */
171
  API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
172
  if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
173
    netbuf_delete(buf);
174
    return;
175
  }
176
}
177
#endif /* LWIP_UDP */
178
 
179
#if LWIP_TCP
180
/**
181
 * Receive callback function for TCP netconns.
182
 * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
183
 *
184
 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
185
 */
186
static err_t
187
recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
188
{
189
  struct netconn *conn;
190
  u16_t len;
191
 
192
  LWIP_UNUSED_ARG(pcb);
193
  LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
194
  LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
195
  conn = arg;
196
  LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
197
 
198
  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
199
    return ERR_VAL;
200
  }
201
 
202
  conn->err = err;
203
  if (p != NULL) {
204
    len = p->tot_len;
205
    SYS_ARCH_INC(conn->recv_avail, len);
206
  } else {
207
    len = 0;
208
  }
209
  /* Register event with callback */
210
  API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
211
  if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {
212
    return ERR_MEM;
213
  }
214
 
215
  return ERR_OK;
216
}
217
 
218
/**
219
 * Poll callback function for TCP netconns.
220
 * Wakes up an application thread that waits for a connection to close
221
 * or data to be sent. The application thread then takes the
222
 * appropriate action to go on.
223
 *
224
 * Signals the conn->sem.
225
 * netconn_close waits for conn->sem if closing failed.
226
 *
227
 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
228
 */
229
static err_t
230
poll_tcp(void *arg, struct tcp_pcb *pcb)
231
{
232
  struct netconn *conn = arg;
233
 
234
  LWIP_UNUSED_ARG(pcb);
235
  LWIP_ASSERT("conn != NULL", (conn != NULL));
236
 
237
  if (conn->state == NETCONN_WRITE) {
238
    do_writemore(conn);
239
  } else if (conn->state == NETCONN_CLOSE) {
240
    do_close_internal(conn);
241
  }
242
 
243
  return ERR_OK;
244
}
245
 
246
/**
247
 * Sent callback function for TCP netconns.
248
 * Signals the conn->sem and calls API_EVENT.
249
 * netconn_write waits for conn->sem if send buffer is low.
250
 *
251
 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
252
 */
253
static err_t
254
sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
255
{
256
  struct netconn *conn = arg;
257
 
258
  LWIP_UNUSED_ARG(pcb);
259
  LWIP_ASSERT("conn != NULL", (conn != NULL));
260
 
261
  if (conn->state == NETCONN_WRITE) {
262
    LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
263
    do_writemore(conn);
264
  } else if (conn->state == NETCONN_CLOSE) {
265
    do_close_internal(conn);
266
  }
267
 
268
  if (conn) {
269
    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) {
270
      API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
271
    }
272
  }
273
 
274
  return ERR_OK;
275
}
276
 
277
/**
278
 * Error callback function for TCP netconns.
279
 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
280
 * The application thread has then to decide what to do.
281
 *
282
 * @see tcp.h (struct tcp_pcb.err) for parameters
283
 */
284
static void
285
err_tcp(void *arg, err_t err)
286
{
287
  struct netconn *conn;
288
 
289
  conn = arg;
290
  LWIP_ASSERT("conn != NULL", (conn != NULL));
291
 
292
  conn->pcb.tcp = NULL;
293
 
294
  conn->err = err;
295
  if (conn->recvmbox != SYS_MBOX_NULL) {
296
    /* Register event with callback */
297
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
298
    sys_mbox_post(conn->recvmbox, NULL);
299
  }
300
  if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) {
301
    conn->state = NETCONN_NONE;
302
    sys_sem_signal(conn->op_completed);
303
  }
304
  if (conn->acceptmbox != SYS_MBOX_NULL) {
305
    /* Register event with callback */
306
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
307
    sys_mbox_post(conn->acceptmbox, NULL);
308
  }
309
  if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {
310
    /* calling do_writemore/do_close_internal is not necessary
311
       since the pcb has already been deleted! */
312
    conn->state = NETCONN_NONE;
313
    /* wake up the waiting task */
314
    sys_sem_signal(conn->op_completed);
315
  }
316
}
317
 
318
/**
319
 * Setup a tcp_pcb with the correct callback function pointers
320
 * and their arguments.
321
 *
322
 * @param conn the TCP netconn to setup
323
 */
324
static void
325
setup_tcp(struct netconn *conn)
326
{
327
  struct tcp_pcb *pcb;
328
 
329
  pcb = conn->pcb.tcp;
330
  tcp_arg(pcb, conn);
331
  tcp_recv(pcb, recv_tcp);
332
  tcp_sent(pcb, sent_tcp);
333
  tcp_poll(pcb, poll_tcp, 4);
334
  tcp_err(pcb, err_tcp);
335
}
336
 
337
/**
338
 * Accept callback function for TCP netconns.
339
 * Allocates a new netconn and posts that to conn->acceptmbox.
340
 *
341
 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
342
 */
343
static err_t
344
accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
345
{
346
  struct netconn *newconn;
347
  struct netconn *conn;
348
 
349
#if API_MSG_DEBUG
350
#if TCP_DEBUG
351
  tcp_debug_print_state(newpcb->state);
352
#endif /* TCP_DEBUG */
353
#endif /* API_MSG_DEBUG */
354
  conn = (struct netconn *)arg;
355
 
356
  LWIP_ERROR("accept_function: invalid conn->acceptmbox",
357
             conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;);
358
 
359
  /* We have to set the callback here even though
360
   * the new socket is unknown. conn->socket is marked as -1. */
361
  newconn = netconn_alloc(conn->type, conn->callback);
362
  if (newconn == NULL) {
363
    return ERR_MEM;
364
  }
365
  newconn->pcb.tcp = newpcb;
366
  setup_tcp(newconn);
367
  newconn->err = err;
368
  /* Register event with callback */
369
  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
370
 
371
  if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
372
    /* When returning != ERR_OK, the connection is aborted in tcp_process(),
373
       so do nothing here! */
374
    newconn->pcb.tcp = NULL;
375
    netconn_free(newconn);
376
    return ERR_MEM;
377
  }
378
  return ERR_OK;
379
}
380
#endif /* LWIP_TCP */
381
 
382
/**
383
 * Create a new pcb of a specific type.
384
 * Called from do_newconn().
385
 *
386
 * @param msg the api_msg_msg describing the connection type
387
 * @return msg->conn->err, but the return value is currently ignored
388
 */
389
static err_t
390
pcb_new(struct api_msg_msg *msg)
391
{
392
   msg->conn->err = ERR_OK;
393
 
394
   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
395
 
396
   /* Allocate a PCB for this connection */
397
   switch(NETCONNTYPE_GROUP(msg->conn->type)) {
398
#if LWIP_RAW
399
   case NETCONN_RAW:
400
     msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
401
     if(msg->conn->pcb.raw == NULL) {
402
       msg->conn->err = ERR_MEM;
403
       break;
404
     }
405
     raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
406
     break;
407
#endif /* LWIP_RAW */
408
#if LWIP_UDP
409
   case NETCONN_UDP:
410
     msg->conn->pcb.udp = udp_new();
411
     if(msg->conn->pcb.udp == NULL) {
412
       msg->conn->err = ERR_MEM;
413
       break;
414
     }
415
#if LWIP_UDPLITE
416
     if (msg->conn->type==NETCONN_UDPLITE) {
417
       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
418
     }
419
#endif /* LWIP_UDPLITE */
420
     if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
421
       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
422
     }
423
     udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
424
     break;
425
#endif /* LWIP_UDP */
426
#if LWIP_TCP
427
   case NETCONN_TCP:
428
     msg->conn->pcb.tcp = tcp_new();
429
     if(msg->conn->pcb.tcp == NULL) {
430
       msg->conn->err = ERR_MEM;
431
       break;
432
     }
433
     setup_tcp(msg->conn);
434
     break;
435
#endif /* LWIP_TCP */
436
   default:
437
     /* Unsupported netconn type, e.g. protocol disabled */
438
     msg->conn->err = ERR_VAL;
439
     break;
440
   }
441
 
442
  return msg->conn->err;
443
}
444
 
445
/**
446
 * Create a new pcb of a specific type inside a netconn.
447
 * Called from netconn_new_with_proto_and_callback.
448
 *
449
 * @param msg the api_msg_msg describing the connection type
450
 */
451
void
452
do_newconn(struct api_msg_msg *msg)
453
{
454
   if(msg->conn->pcb.tcp == NULL) {
455
     pcb_new(msg);
456
   }
457
   /* Else? This "new" connection already has a PCB allocated. */
458
   /* Is this an error condition? Should it be deleted? */
459
   /* We currently just are happy and return. */
460
 
461
   TCPIP_APIMSG_ACK(msg);
462
}
463
 
464
/**
465
 * Create a new netconn (of a specific type) that has a callback function.
466
 * The corresponding pcb is NOT created!
467
 *
468
 * @param t the type of 'connection' to create (@see enum netconn_type)
469
 * @param proto the IP protocol for RAW IP pcbs
470
 * @param callback a function to call on status changes (RX available, TX'ed)
471
 * @return a newly allocated struct netconn or
472
 *         NULL on memory error
473
 */
474
struct netconn*
475
netconn_alloc(enum netconn_type t, netconn_callback callback)
476
{
477
  struct netconn *conn;
478
  int size;
479
 
480
  conn = memp_malloc(MEMP_NETCONN);
481
  if (conn == NULL) {
482
    return NULL;
483
  }
484
 
485
  conn->err = ERR_OK;
486
  conn->type = t;
487
  conn->pcb.tcp = NULL;
488
 
489
#if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \
490
    (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)
491
  size = DEFAULT_RAW_RECVMBOX_SIZE;
492
#else
493
  switch(NETCONNTYPE_GROUP(t)) {
494
#if LWIP_RAW
495
  case NETCONN_RAW:
496
    size = DEFAULT_RAW_RECVMBOX_SIZE;
497
    break;
498
#endif /* LWIP_RAW */
499
#if LWIP_UDP
500
  case NETCONN_UDP:
501
    size = DEFAULT_UDP_RECVMBOX_SIZE;
502
    break;
503
#endif /* LWIP_UDP */
504
#if LWIP_TCP
505
  case NETCONN_TCP:
506
    size = DEFAULT_TCP_RECVMBOX_SIZE;
507
    break;
508
#endif /* LWIP_TCP */
509
  default:
510
    LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
511
    break;
512
  }
513
#endif
514
 
515
  if ((conn->op_completed = sys_sem_new(0)) == SYS_SEM_NULL) {
516
    memp_free(MEMP_NETCONN, conn);
517
    return NULL;
518
  }
519
  if ((conn->recvmbox = sys_mbox_new(size)) == SYS_MBOX_NULL) {
520
    sys_sem_free(conn->op_completed);
521
    memp_free(MEMP_NETCONN, conn);
522
    return NULL;
523
  }
524
 
525
  conn->acceptmbox   = SYS_MBOX_NULL;
526
  conn->state        = NETCONN_NONE;
527
  /* initialize socket to -1 since 0 is a valid socket */
528
  conn->socket       = -1;
529
  conn->callback     = callback;
530
  conn->recv_avail   = 0;
531
#if LWIP_SO_RCVTIMEO
532
  conn->recv_timeout = 0;
533
#endif /* LWIP_SO_RCVTIMEO */
534
#if LWIP_SO_RCVBUF
535
  conn->recv_bufsize = INT_MAX;
536
#endif /* LWIP_SO_RCVBUF */
537
  return conn;
538
}
539
 
540
/**
541
 * Delete a netconn and all its resources.
542
 * The pcb is NOT freed (since we might not be in the right thread context do this).
543
 *
544
 * @param conn the netconn to free
545
 */
546
void
547
netconn_free(struct netconn *conn)
548
{
549
  void *mem;
550
  LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
551
 
552
  /* Drain the recvmbox. */
553
  if (conn->recvmbox != SYS_MBOX_NULL) {
554
    while (sys_mbox_tryfetch(conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
555
      if (conn->type == NETCONN_TCP) {
556
        if(mem != NULL) {
557
          pbuf_free((struct pbuf *)mem);
558
        }
559
      } else {
560
        netbuf_delete((struct netbuf *)mem);
561
      }
562
    }
563
    sys_mbox_free(conn->recvmbox);
564
    conn->recvmbox = SYS_MBOX_NULL;
565
  }
566
 
567
  /* Drain the acceptmbox. */
568
  if (conn->acceptmbox != SYS_MBOX_NULL) {
569
    while (sys_mbox_tryfetch(conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
570
      netconn_delete((struct netconn *)mem);
571
    }
572
    sys_mbox_free(conn->acceptmbox);
573
    conn->acceptmbox = SYS_MBOX_NULL;
574
  }
575
 
576
  sys_sem_free(conn->op_completed);
577
  conn->op_completed = SYS_SEM_NULL;
578
 
579
  memp_free(MEMP_NETCONN, conn);
580
}
581
 
582
#if LWIP_TCP
583
/**
584
 * Internal helper function to close a TCP netconn: since this sometimes
585
 * doesn't work at the first attempt, this function is called from multiple
586
 * places.
587
 *
588
 * @param conn the TCP netconn to close
589
 */
590
static void
591
do_close_internal(struct netconn *conn)
592
{
593
  err_t err;
594
 
595
  LWIP_ASSERT("invalid conn", (conn != NULL));
596
  LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
597
  LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
598
  LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
599
 
600
  /* Set back some callback pointers */
601
  if (conn->pcb.tcp->state == LISTEN) {
602
    tcp_arg(conn->pcb.tcp, NULL);
603
    tcp_accept(conn->pcb.tcp, NULL);
604
  } else {
605
    tcp_recv(conn->pcb.tcp, NULL);
606
  }
607
  /* Try to close the connection */
608
  err = tcp_close(conn->pcb.tcp);
609
  if (err == ERR_OK) {
610
    /* Closing succeeded */
611
    conn->state = NETCONN_NONE;
612
    /* Set back some callback pointers as conn is going away */
613
    tcp_err(conn->pcb.tcp, NULL);
614
    tcp_poll(conn->pcb.tcp, NULL, 4);
615
    tcp_sent(conn->pcb.tcp, NULL);
616
    tcp_recv(conn->pcb.tcp, NULL);
617
    tcp_arg(conn->pcb.tcp, NULL);
618
    conn->pcb.tcp = NULL;
619
    conn->err = ERR_OK;
620
    /* Trigger select() in socket layer. This send should something else so the
621
       errorfd is set, not the read and write fd! */
622
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
623
    API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
624
    /* wake up the application task */
625
    sys_sem_signal(conn->op_completed);
626
  }
627
  /* If closing didn't succeed, we get called again either
628
     from poll_tcp or from sent_tcp */
629
}
630
#endif /* LWIP_TCP */
631
 
632
/**
633
 * Delete the pcb inside a netconn.
634
 * Called from netconn_delete.
635
 *
636
 * @param msg the api_msg_msg pointing to the connection
637
 */
638
void
639
do_delconn(struct api_msg_msg *msg)
640
{
641
  if (msg->conn->pcb.tcp != NULL) {
642
    switch (NETCONNTYPE_GROUP(msg->conn->type)) {
643
#if LWIP_RAW
644
    case NETCONN_RAW:
645
      raw_remove(msg->conn->pcb.raw);
646
      break;
647
#endif /* LWIP_RAW */
648
#if LWIP_UDP
649
    case NETCONN_UDP:
650
      msg->conn->pcb.udp->recv_arg = NULL;
651
      udp_remove(msg->conn->pcb.udp);
652
      break;
653
#endif /* LWIP_UDP */
654
#if LWIP_TCP
655
    case NETCONN_TCP:
656
      msg->conn->state = NETCONN_CLOSE;
657
      do_close_internal(msg->conn);
658
      /* API_EVENT is called inside do_close_internal, before releasing
659
         the application thread, so we can return at this point! */
660
      return;
661
#endif /* LWIP_TCP */
662
    default:
663
      break;
664
    }
665
  }
666
  /* tcp netconns don't come here! */
667
 
668
  /* Trigger select() in socket layer. This send should something else so the
669
     errorfd is set, not the read and write fd! */
670
  API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
671
  API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
672
 
673
  if (msg->conn->op_completed != SYS_SEM_NULL) {
674
    sys_sem_signal(msg->conn->op_completed);
675
  }
676
}
677
 
678
/**
679
 * Bind a pcb contained in a netconn
680
 * Called from netconn_bind.
681
 *
682
 * @param msg the api_msg_msg pointing to the connection and containing
683
 *            the IP address and port to bind to
684
 */
685
void
686
do_bind(struct api_msg_msg *msg)
687
{
688
  if (!ERR_IS_FATAL(msg->conn->err)) {
689
    if (msg->conn->pcb.tcp != NULL) {
690
      switch (NETCONNTYPE_GROUP(msg->conn->type)) {
691
#if LWIP_RAW
692
      case NETCONN_RAW:
693
        msg->conn->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
694
        break;
695
#endif /* LWIP_RAW */
696
#if LWIP_UDP
697
      case NETCONN_UDP:
698
        msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
699
        break;
700
#endif /* LWIP_UDP */
701
#if LWIP_TCP
702
      case NETCONN_TCP:
703
        msg->conn->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
704
        break;
705
#endif /* LWIP_TCP */
706
      default:
707
        break;
708
      }
709
    } else {
710
      /* msg->conn->pcb is NULL */
711
      msg->conn->err = ERR_VAL;
712
    }
713
  }
714
  TCPIP_APIMSG_ACK(msg);
715
}
716
 
717
#if LWIP_TCP
718
/**
719
 * TCP callback function if a connection (opened by tcp_connect/do_connect) has
720
 * been established (or reset by the remote host).
721
 *
722
 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
723
 */
724
static err_t
725
do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
726
{
727
  struct netconn *conn;
728
 
729
  LWIP_UNUSED_ARG(pcb);
730
 
731
  conn = arg;
732
 
733
  if (conn == NULL) {
734
    return ERR_VAL;
735
  }
736
 
737
  conn->err = err;
738
  if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {
739
    setup_tcp(conn);
740
  }
741
  conn->state = NETCONN_NONE;
742
  sys_sem_signal(conn->op_completed);
743
  return ERR_OK;
744
}
745
#endif /* LWIP_TCP */
746
 
747
/**
748
 * Connect a pcb contained inside a netconn
749
 * Called from netconn_connect.
750
 *
751
 * @param msg the api_msg_msg pointing to the connection and containing
752
 *            the IP address and port to connect to
753
 */
754
void
755
do_connect(struct api_msg_msg *msg)
756
{
757
  if (msg->conn->pcb.tcp == NULL) {
758
    sys_sem_signal(msg->conn->op_completed);
759
    return;
760
  }
761
 
762
  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
763
#if LWIP_RAW
764
  case NETCONN_RAW:
765
    msg->conn->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
766
    sys_sem_signal(msg->conn->op_completed);
767
    break;
768
#endif /* LWIP_RAW */
769
#if LWIP_UDP
770
  case NETCONN_UDP:
771
    msg->conn->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
772
    sys_sem_signal(msg->conn->op_completed);
773
    break;
774
#endif /* LWIP_UDP */
775
#if LWIP_TCP
776
  case NETCONN_TCP:
777
    msg->conn->state = NETCONN_CONNECT;
778
    setup_tcp(msg->conn);
779
    msg->conn->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,
780
                                 do_connected);
781
    /* sys_sem_signal() is called from do_connected (or err_tcp()),
782
     * when the connection is established! */
783
    break;
784
#endif /* LWIP_TCP */
785
  default:
786
    break;
787
  }
788
}
789
 
790
/**
791
 * Connect a pcb contained inside a netconn
792
 * Only used for UDP netconns.
793
 * Called from netconn_disconnect.
794
 *
795
 * @param msg the api_msg_msg pointing to the connection to disconnect
796
 */
797
void
798
do_disconnect(struct api_msg_msg *msg)
799
{
800
#if LWIP_UDP
801
  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
802
    udp_disconnect(msg->conn->pcb.udp);
803
  }
804
#endif /* LWIP_UDP */
805
  TCPIP_APIMSG_ACK(msg);
806
}
807
 
808
/**
809
 * Set a TCP pcb contained in a netconn into listen mode
810
 * Called from netconn_listen.
811
 *
812
 * @param msg the api_msg_msg pointing to the connection
813
 */
814
void
815
do_listen(struct api_msg_msg *msg)
816
{
817
#if LWIP_TCP
818
  if (!ERR_IS_FATAL(msg->conn->err)) {
819
    if (msg->conn->pcb.tcp != NULL) {
820
      if (msg->conn->type == NETCONN_TCP) {
821
        if (msg->conn->pcb.tcp->state == CLOSED) {
822
#if TCP_LISTEN_BACKLOG
823
          struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
824
#else  /* TCP_LISTEN_BACKLOG */
825
          struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);
826
#endif /* TCP_LISTEN_BACKLOG */
827
          if (lpcb == NULL) {
828
            msg->conn->err = ERR_MEM;
829
          } else {
830
            /* delete the recvmbox and allocate the acceptmbox */
831
            if (msg->conn->recvmbox != SYS_MBOX_NULL) {
832
              /** @todo: should we drain the recvmbox here? */
833
              sys_mbox_free(msg->conn->recvmbox);
834
              msg->conn->recvmbox = SYS_MBOX_NULL;
835
            }
836
            if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
837
              if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) {
838
                msg->conn->err = ERR_MEM;
839
              }
840
            }
841
            if (msg->conn->err == ERR_OK) {
842
              msg->conn->state = NETCONN_LISTEN;
843
              msg->conn->pcb.tcp = lpcb;
844
              tcp_arg(msg->conn->pcb.tcp, msg->conn);
845
              tcp_accept(msg->conn->pcb.tcp, accept_function);
846
            }
847
          }
848
        } else {
849
          msg->conn->err = ERR_CONN;
850
        }
851
      }
852
    }
853
  }
854
#endif /* LWIP_TCP */
855
  TCPIP_APIMSG_ACK(msg);
856
}
857
 
858
/**
859
 * Send some data on a RAW or UDP pcb contained in a netconn
860
 * Called from netconn_send
861
 *
862
 * @param msg the api_msg_msg pointing to the connection
863
 */
864
void
865
do_send(struct api_msg_msg *msg)
866
{
867
  if (!ERR_IS_FATAL(msg->conn->err)) {
868
    if (msg->conn->pcb.tcp != NULL) {
869
      switch (NETCONNTYPE_GROUP(msg->conn->type)) {
870
#if LWIP_RAW
871
      case NETCONN_RAW:
872
        if (msg->msg.b->addr == NULL) {
873
          msg->conn->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
874
        } else {
875
          msg->conn->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr);
876
        }
877
        break;
878
#endif
879
#if LWIP_UDP
880
      case NETCONN_UDP:
881
        if (msg->msg.b->addr == NULL) {
882
          msg->conn->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
883
        } else {
884
          msg->conn->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port);
885
        }
886
        break;
887
#endif /* LWIP_UDP */
888
      default:
889
        break;
890
      }
891
    }
892
  }
893
  TCPIP_APIMSG_ACK(msg);
894
}
895
 
896
/**
897
 * Recv some data from a RAW or UDP pcb contained in a netconn
898
 * Called from netconn_recv
899
 *
900
 * @param msg the api_msg_msg pointing to the connection
901
 */
902
void
903
do_recv(struct api_msg_msg *msg)
904
{
905
#if LWIP_TCP
906
  if (!ERR_IS_FATAL(msg->conn->err)) {
907
    if (msg->conn->pcb.tcp != NULL) {
908
      if (msg->conn->type == NETCONN_TCP) {
909
#if TCP_LISTEN_BACKLOG
910
        if (msg->conn->pcb.tcp->state == LISTEN) {
911
          tcp_accepted(msg->conn->pcb.tcp);
912
        } else
913
#endif /* TCP_LISTEN_BACKLOG */
914
        {
915
          tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len);
916
        }
917
      }
918
    }
919
  }
920
#endif /* LWIP_TCP */
921
  TCPIP_APIMSG_ACK(msg);
922
}
923
 
924
#if LWIP_TCP
925
/**
926
 * See if more data needs to be written from a previous call to netconn_write.
927
 * Called initially from do_write. If the first call can't send all data
928
 * (because of low memory or empty send-buffer), this function is called again
929
 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
930
 * blocking application thread (waiting in netconn_write) is released.
931
 *
932
 * @param conn netconn (that is currently in state NETCONN_WRITE) to process
933
 * @return ERR_OK
934
 *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
935
 */
936
static err_t
937
do_writemore(struct netconn *conn)
938
{
939
  err_t err;
940
  void *dataptr;
941
  u16_t len, available;
942
  u8_t write_finished = 0;
943
 
944
  LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
945
 
946
  dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset;
947
  if ((conn->write_msg->msg.w.len - conn->write_offset > 0xffff)) { /* max_u16_t */
948
    len = 0xffff;
949
#if LWIP_TCPIP_CORE_LOCKING
950
    conn->write_delayed = 1;
951
#endif
952
  } else {
953
    len = conn->write_msg->msg.w.len - conn->write_offset;
954
  }
955
  available = tcp_sndbuf(conn->pcb.tcp);
956
  if (available < len) {
957
    /* don't try to write more than sendbuf */
958
    len = available;
959
#if LWIP_TCPIP_CORE_LOCKING
960
    conn->write_delayed = 1;
961
#endif
962
  }
963
 
964
  err = tcp_write(conn->pcb.tcp, dataptr, len, conn->write_msg->msg.w.apiflags);
965
  LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->write_msg->msg.w.len));
966
  if (err == ERR_OK) {
967
    conn->write_offset += len;
968
    if (conn->write_offset == conn->write_msg->msg.w.len) {
969
      /* everything was written */
970
      write_finished = 1;
971
      conn->write_msg = NULL;
972
      conn->write_offset = 0;
973
    }
974
    err = tcp_output_nagle(conn->pcb.tcp);
975
    conn->err = err;
976
    if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) {
977
      API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
978
    }
979
  } else if (err == ERR_MEM) {
980
    /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
981
       we do NOT return to the application thread, since ERR_MEM is
982
       only a temporary error! */
983
 
984
    /* tcp_enqueue returned ERR_MEM, try tcp_output anyway */
985
    err = tcp_output(conn->pcb.tcp);
986
 
987
#if LWIP_TCPIP_CORE_LOCKING
988
    conn->write_delayed = 1;
989
#endif
990
  } else {
991
    /* On errors != ERR_MEM, we don't try writing any more but return
992
       the error to the application thread. */
993
    conn->err = err;
994
    write_finished = 1;
995
  }
996
 
997
  if (write_finished) {
998
    /* everything was written: set back connection state
999
       and back to application task */
1000
    conn->state = NETCONN_NONE;
1001
#if LWIP_TCPIP_CORE_LOCKING
1002
    if (conn->write_delayed != 0)
1003
#endif
1004
    {
1005
      sys_sem_signal(conn->op_completed);
1006
    }
1007
  }
1008
#if LWIP_TCPIP_CORE_LOCKING
1009
  else
1010
    return ERR_MEM;
1011
#endif
1012
  return ERR_OK;
1013
}
1014
#endif /* LWIP_TCP */
1015
 
1016
/**
1017
 * Send some data on a TCP pcb contained in a netconn
1018
 * Called from netconn_write
1019
 *
1020
 * @param msg the api_msg_msg pointing to the connection
1021
 */
1022
void
1023
do_write(struct api_msg_msg *msg)
1024
{
1025
  if (!ERR_IS_FATAL(msg->conn->err)) {
1026
    if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
1027
#if LWIP_TCP
1028
      msg->conn->state = NETCONN_WRITE;
1029
      /* set all the variables used by do_writemore */
1030
      msg->conn->write_msg = msg;
1031
      msg->conn->write_offset = 0;
1032
#if LWIP_TCPIP_CORE_LOCKING
1033
      msg->conn->write_delayed = 0;
1034
      if (do_writemore(msg->conn) != ERR_OK) {
1035
        LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
1036
        UNLOCK_TCPIP_CORE();
1037
        sys_arch_sem_wait(msg->conn->op_completed, 0);
1038
        LOCK_TCPIP_CORE();
1039
        LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1040
      }
1041
#else
1042
      do_writemore(msg->conn);
1043
#endif
1044
      /* for both cases: if do_writemore was called, don't ACK the APIMSG! */
1045
      return;
1046
#endif /* LWIP_TCP */
1047
#if (LWIP_UDP || LWIP_RAW)
1048
    } else {
1049
      msg->conn->err = ERR_VAL;
1050
#endif /* (LWIP_UDP || LWIP_RAW) */
1051
    }
1052
  }
1053
  TCPIP_APIMSG_ACK(msg);
1054
}
1055
 
1056
/**
1057
 * Return a connection's local or remote address
1058
 * Called from netconn_getaddr
1059
 *
1060
 * @param msg the api_msg_msg pointing to the connection
1061
 */
1062
void
1063
do_getaddr(struct api_msg_msg *msg)
1064
{
1065
  if (msg->conn->pcb.ip != NULL) {
1066
    *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip);
1067
 
1068
    switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1069
#if LWIP_RAW
1070
    case NETCONN_RAW:
1071
      if (msg->msg.ad.local) {
1072
        *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
1073
      } else {
1074
        /* return an error as connecting is only a helper for upper layers */
1075
        msg->conn->err = ERR_CONN;
1076
      }
1077
      break;
1078
#endif /* LWIP_RAW */
1079
#if LWIP_UDP
1080
    case NETCONN_UDP:
1081
      if (msg->msg.ad.local) {
1082
        *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
1083
      } else {
1084
        if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
1085
          msg->conn->err = ERR_CONN;
1086
        } else {
1087
          *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
1088
        }
1089
      }
1090
      break;
1091
#endif /* LWIP_UDP */
1092
#if LWIP_TCP
1093
    case NETCONN_TCP:
1094
      *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);
1095
      break;
1096
#endif /* LWIP_TCP */
1097
    }
1098
  } else {
1099
    msg->conn->err = ERR_CONN;
1100
  }
1101
  TCPIP_APIMSG_ACK(msg);
1102
}
1103
 
1104
/**
1105
 * Close a TCP pcb contained in a netconn
1106
 * Called from netconn_close
1107
 *
1108
 * @param msg the api_msg_msg pointing to the connection
1109
 */
1110
void
1111
do_close(struct api_msg_msg *msg)
1112
{
1113
#if LWIP_TCP
1114
  if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
1115
      msg->conn->state = NETCONN_CLOSE;
1116
      do_close_internal(msg->conn);
1117
      /* for tcp netconns, do_close_internal ACKs the message */
1118
  } else
1119
#endif /* LWIP_TCP */
1120
  {
1121
    msg->conn->err = ERR_VAL;
1122
    TCPIP_APIMSG_ACK(msg);
1123
  }
1124
}
1125
 
1126
#if LWIP_IGMP
1127
/**
1128
 * Join multicast groups for UDP netconns.
1129
 * Called from netconn_join_leave_group
1130
 *
1131
 * @param msg the api_msg_msg pointing to the connection
1132
 */
1133
void
1134
do_join_leave_group(struct api_msg_msg *msg)
1135
{
1136
  if (!ERR_IS_FATAL(msg->conn->err)) {
1137
    if (msg->conn->pcb.tcp != NULL) {
1138
      if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1139
#if LWIP_UDP
1140
        if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
1141
          msg->conn->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);
1142
        } else {
1143
          msg->conn->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);
1144
        }
1145
#endif /* LWIP_UDP */
1146
#if (LWIP_TCP || LWIP_RAW)
1147
      } else {
1148
        msg->conn->err = ERR_VAL;
1149
#endif /* (LWIP_TCP || LWIP_RAW) */
1150
      }
1151
    }
1152
  }
1153
  TCPIP_APIMSG_ACK(msg);
1154
}
1155
#endif /* LWIP_IGMP */
1156
 
1157
#if LWIP_DNS
1158
/**
1159
 * Callback function that is called when DNS name is resolved
1160
 * (or on timeout). A waiting application thread is waked up by
1161
 * signaling the semaphore.
1162
 */
1163
static void
1164
do_dns_found(const char *name, struct ip_addr *ipaddr, void *arg)
1165
{
1166
  struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1167
 
1168
  LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0);
1169
 
1170
  if (ipaddr == NULL) {
1171
    /* timeout or memory error */
1172
    *msg->err = ERR_VAL;
1173
  } else {
1174
    /* address was resolved */
1175
    *msg->err = ERR_OK;
1176
    *msg->addr = *ipaddr;
1177
  }
1178
  /* wake up the application task waiting in netconn_gethostbyname */
1179
  sys_sem_signal(msg->sem);
1180
}
1181
 
1182
/**
1183
 * Execute a DNS query
1184
 * Called from netconn_gethostbyname
1185
 *
1186
 * @param arg the dns_api_msg pointing to the query
1187
 */
1188
void
1189
do_gethostbyname(void *arg)
1190
{
1191
  struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1192
 
1193
  *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);
1194
  if (*msg->err != ERR_INPROGRESS) {
1195
    /* on error or immediate success, wake up the application
1196
     * task waiting in netconn_gethostbyname */
1197
    sys_sem_signal(msg->sem);
1198
  }
1199
}
1200
#endif /* LWIP_DNS */
1201
 
1202
#endif /* LWIP_NETCONN */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.