예제 #1
0
파일: ard_tcp.c 프로젝트: 4bcat/Arduino
/**
 * Start UDP transfer.
 */
static int udp_start(struct ttcp* ttcp) {
	ttcp->udp_end_marker_left = 5;
	ttcp->upcb = udp_new();
	if (ttcp->upcb == NULL) {
		printk("TTCP [%p]: could not allocate pcb\n", ttcp);
		return -1;
	}

	if (ttcp->mode == TTCP_MODE_TRANSMIT) {
		if (udp_connect(ttcp->upcb, &ttcp->addr, ttcp->port) != ERR_OK) {
			printk("TTCP [%p]: udp connect failed\n", ttcp);
			return -1;
		}
		udp_send_data(ttcp);
	} else {
		udp_recv(ttcp->upcb, udp_recv_cb, ttcp);
	}

	return 0;
}
예제 #2
0
/**
  * @brief  Processes TFTP write request
  * @param  to: pointer on the receive IP address
  * @param  to_port: receive port number
  * @retval none
  */
static int IAP_tftp_process_write(struct udp_pcb *upcb, struct ip_addr *to, int to_port)
{
  tftp_connection_args *args = NULL;
  /* This function is called from a callback,
  * therefore interrupts are disabled,
  * therefore we can use regular malloc   */
  args = mem_malloc(sizeof *args);
  if (!args)
  {
    IAP_tftp_cleanup_wr(upcb, args);
    return 0;
  }

  args->op = TFTP_WRQ;
  args->to_ip.addr = to->addr;
  args->to_port = to_port;
  /* the block # used as a positive response to a WRQ is _always_ 0!!! (see RFC1350)  */
  args->block = 0;
  args->tot_bytes = 0;

  /* set callback for receives on this UDP PCB (Protocol Control Block) */
  udp_recv(upcb, IAP_wrq_recv_callback, args);
  
  total_count =0;

  /* init flash */
  FLASH_If_Init();
  
  /* erase user flash area */
  FLASH_If_Erase(USER_FLASH_FIRST_PAGE_ADDRESS);
 
  Flash_Write_Address = USER_FLASH_FIRST_PAGE_ADDRESS;    
  /* initiate the write transaction by sending the first ack */
  IAP_tftp_send_ack_packet(upcb, to, to_port, args->block);
  
#ifdef USE_LCD
  LCD_DisplayStringLine(Line9, (char*)"State: Programming.."); 
#endif
  
  return 0;
}
/*..........................................................................*/
QState LwIPMgr_initial(LwIPMgr *me, QEvt const *e) {
    uint8_t  macaddr[NETIF_MAX_HWADDR_LEN];

    (void)e;        /* suppress the compiler warning about unused parameter */

    /* Configure the hardware MAC address for the Ethernet Controller */
    macaddr[0] = MAC_ADDR0;
    macaddr[1] = MAC_ADDR1;
    macaddr[2] = MAC_ADDR2;
    macaddr[3] = MAC_ADDR3;
    macaddr[4] = MAC_ADDR4;
    macaddr[5] = MAC_ADDR5;

                                          /* initialize the Ethernet Driver */
    me->netif = eth_driver_init((QActive *)me, macaddr);

    me->ip_addr = 0x00000000U;            /* initialize to impossible value */

                                     /* initialize the lwIP applications... */
    httpd_init();         /* initialize the simple HTTP-Deamon (web server) */
    http_set_ssi_handler(&ssi_handler, ssi_tags, Q_DIM(ssi_tags));
    http_set_cgi_handlers(cgi_handlers, Q_DIM(cgi_handlers));

    me->upcb = udp_new();
    udp_bind(me->upcb, IP_ADDR_ANY, 777U);          /* use port 777 for UDP */
    udp_recv(me->upcb, &udp_rx_handler, me);

    QS_OBJ_DICTIONARY(&l_lwIPMgr);
    QS_OBJ_DICTIONARY(&l_lwIPMgr.te_LWIP_SLOW_TICK);
    QS_FUN_DICTIONARY(&QHsm_top);
    QS_FUN_DICTIONARY(&LwIPMgr_initial);
    QS_FUN_DICTIONARY(&LwIPMgr_running);

    QS_SIG_DICTIONARY(SEND_UDP_SIG,       (QActive *)me);
    QS_SIG_DICTIONARY(LWIP_SLOW_TICK_SIG, (QActive *)me);
    QS_SIG_DICTIONARY(LWIP_RX_READY_SIG,  (QActive *)me);
    QS_SIG_DICTIONARY(LWIP_TX_READY_SIG,  (QActive *)me);
    QS_SIG_DICTIONARY(LWIP_RX_OVERRUN_SIG,(QActive *)me);

    return Q_TRAN(&LwIPMgr_connecting);
}
예제 #4
0
/**
  * @brief  Creates and initializes a UDP PCB for TFTP receive operation  
  * @param  none  
  * @retval none
  */
void IAP_tftpd_init(void)
{
  err_t err;
  unsigned port = 69; /* 69 is the port used for TFTP protocol initial transaction */

  /* create a new UDP PCB structure  */
  UDPpcb = udp_new();
  if (!UDPpcb)
  {
    /* Error creating PCB. Out of Memory  */
    return ;
  }

  /* Bind this PCB to port 69  */
  err = udp_bind(UDPpcb, IP_ADDR_ANY, port);
  if (err == ERR_OK)
  {
    /* Initialize receive callback function  */
    udp_recv(UDPpcb, IAP_tftp_recv_callback, NULL);
  } 
}
예제 #5
0
파일: sntp.c 프로젝트: TomerCo/ESP8266-AT
/**
 * Initialize this module.
 * Send out request instantly or after SNTP_STARTUP_DELAY.
 */
void
sntp_init(int tz)
{
  LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE,"Sntp initializing TZ: GMT%s%02d...\n",tz > 0 ? "+" : "",tz);
  ets_uart_printf("Sntp initializing...\n");
  sntp_tz = tz;
  if (sntp_pcb == NULL) {
    os_timer_setfn(&ntp_timer,ntp_time_update,NULL);
    SNTP_RESET_RETRY_TIMEOUT();
    sntp_pcb = udp_new();
    LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
    if (sntp_pcb != NULL) {
      udp_recv(sntp_pcb, sntp_recv, NULL);
#if SNTP_STARTUP_DELAY
      sys_timeout((u32_t)SNTP_STARTUP_DELAY, sntp_request, NULL);
#else
      sntp_request(NULL);
#endif
    }
  }
}
예제 #6
0
/**
  * @brief  Initialize the server application.
  * @param  None
  * @retval None
  */
void udp_echoserver_init(void)
{
   struct udp_pcb *upcb;
   err_t err;
   
   /* Create a new UDP control block  */
   upcb = udp_new();
   
   if (upcb)
   {
     /* Bind the upcb to the UDP_PORT port */
     /* Using IP_ADDR_ANY allow the upcb to be used by any local interface */
      err = udp_bind(upcb, IP_ADDR_ANY, UDP_SERVER_PORT);
      
      if(err == ERR_OK)
      {
        /* Set a receive callback for the upcb */
        udp_recv(upcb, udp_echoserver_receive_callback, NULL);
      }
   }
}
static socket_error_t lwipv4_socket_create(struct socket *sock, const socket_address_family_t af, const socket_proto_family_t pf, socket_api_handler_t const handler)
{
    switch (af) {
        case SOCKET_AF_INET4:
            break;
        default:
            return SOCKET_ERROR_BAD_FAMILY;
    }
    if (sock == NULL || handler == NULL)
        return SOCKET_ERROR_NULL_PTR;
    switch (pf) {
    case SOCKET_DGRAM:
    {
        struct udp_pcb *udp = udp_new();
        if (udp == NULL)
            return SOCKET_ERROR_BAD_ALLOC;
        sock->stack = SOCKET_STACK_LWIP_IPV4;
        sock->impl = (void *)udp;
        udp_recv((struct udp_pcb *)sock->impl, irqUDPRecv, (void *)sock);
        break;
    }
    case SOCKET_STREAM:
    {
      struct tcp_pcb *tcp = tcp_new();
      if (tcp == NULL)
        return SOCKET_ERROR_BAD_ALLOC;
      sock->impl = (void *)tcp;
      sock->stack = SOCKET_STACK_LWIP_IPV4;
      tcp_arg(tcp, (void*) sock);
      tcp_err(tcp, tcp_error_handler);
      break;
    }
    default:
        return SOCKET_ERROR_BAD_FAMILY;
    }
    sock->family = pf;
    sock->handler = (void*)handler;
    sock->rxBufChain = NULL;
    return SOCKET_ERROR_NONE;
}
예제 #8
0
파일: udp_demo.c 프로젝트: jeenter/CH-K-Lib
void udp_echo_init(void)
{
    struct udp_pcb * pcb;

    // get new pcb
    pcb = udp_new();
    if (pcb == NULL) {
        LWIP_DEBUGF(UDP_DEBUG, ("udp_new failed!\n"));
        return;
    }

    // bind to any IP address on port 7
    if (udp_bind(pcb, IP_ADDR_ANY, 7) != ERR_OK) {
        LWIP_DEBUGF(UDP_DEBUG, ("udp_bind failed!\n"));
        return;
    }
    printf("UDP bind to PORT:7 OK!\r\n");

    // set udp_echo_recv() as callback function
    // for received packets
    udp_recv(pcb, udp_echo_recv, NULL);
}
예제 #9
0
파일: tftpserver.c 프로젝트: jdaheron/GHB
/**
  * @brief  processes tftp write operation
  * @param  upcb: pointer on upd pcb 
  * @param  to: pointer on remote IP address
  * @param  to_port: pointer on remote udp port
  * @param  FileName: pointer on filename to be written 
  * @retval error code
  */
int tftp_process_write(struct udp_pcb *upcb, struct ip_addr *to, int to_port, char *FileName)
{
  tftp_connection_args *args = NULL;

  /* Can not create file */
  if (f_open(&file_CR, (const TCHAR*)FileName, FA_CREATE_ALWAYS|FA_WRITE) != FR_OK)
  {
    tftp_send_error_message(upcb, to, to_port, TFTP_ERR_NOTDEFINED);

    tftp_cleanup_wr(upcb, args);

    return 0;
  }

  args = mem_malloc(sizeof *args);
  if (!args)
  {
    tftp_send_error_message(upcb, to, to_port, TFTP_ERR_NOTDEFINED);

    tftp_cleanup_wr(upcb, args);

    return 0;
  }

  args->op = TFTP_WRQ;
  args->to_ip.addr = to->addr;
  args->to_port = to_port;
  /* the block # used as a positive response to a WRQ is _always_ 0!!! (see RFC1350)  */
  args->block = 0;
  args->tot_bytes = 0;

  /* set callback for receives on this UDP PCB  */
  udp_recv(upcb, wrq_recv_callback, args);

  /* initiate the write transaction by sending the first ack */
  tftp_send_ack_packet(upcb, to, to_port, args->block);

  return 0;
}
예제 #10
0
/**
  * @brief  Creates and initializes a UDP PCB for TFTP receive operation  
  * @param  none  
  * @retval none
  */
void IAP_tftpd_init(void)
{
  err_t err;
  unsigned port = 69; /* 69 is the port used for TFTP protocol initial transaction */

  /* create a new UDP PCB structure  */
  UDPpcb = udp_new();
  if (!UDPpcb)
  {
	udp_lcd_y += UPDATE_WORD_SIZE + UPDATE_ROW_DISTANCE;
	lcd_font24(udp_lcd_x,udp_lcd_y,COLOR_POINT,COLOR_BACK,"> ÒÔÌ«ÍøÉý¼¶³ö´íÁË¡£´íÎó´úÂ룺9",UPDATE_FONT); 
	UDP_AddUpdateError();
	  
    /* Error creating PCB. Out of Memory  */
// #ifdef USE_LCD
//     LCD_SetTextColor(Red);
//     LCD_DisplayStringLine(Line9, (uint8_t*)"Can not create pcb");
// #endif
    return ;
  }

  /* Bind this PCB to port 69  */
  err = udp_bind(UDPpcb, IP_ADDR_ANY, port);
  if (err == ERR_OK)
  {
    /* Initialize receive callback function  */
    udp_recv(UDPpcb, IAP_tftp_recv_callback, NULL);
  } 
  else
  {
	  udp_lcd_y += UPDATE_WORD_SIZE + UPDATE_ROW_DISTANCE;
	  lcd_font24(udp_lcd_x,udp_lcd_y,COLOR_POINT,COLOR_BACK,"> ÒÔÌ«ÍøÉý¼¶³ö´íÁË¡£´íÎó´úÂ룺10",UPDATE_FONT); 
	  UDP_AddUpdateError();
// #ifdef USE_LCD
//     LCD_SetTextColor(Red);
//     LCD_DisplayStringLine(Line9, (uint8_t*)"Can not bind pcb");
// #endif
  }
}
예제 #11
0
파일: rpc.c 프로젝트: gapry/AOS
struct udp_pcb* 
rpc_new_udp(const struct ip_addr *server, int remote_port, 
            enum port_type local_port)
{
    struct udp_pcb* ret;
    static int root_port = -1;
    struct ip_addr s = *server;
    ret = udp_new();
    assert(ret);
    udp_recv(ret, my_recv, NULL);
    if(local_port == PORT_ROOT){
        if(root_port >= ROOT_PORT_MAX || root_port < ROOT_PORT_MIN){
            root_port = ROOT_PORT_MIN;
            debug("Recycling ports\n");
        }
        udp_bind(ret, IP_ADDR_ANY, root_port++);
    }else{
        /* let lwip decide for itself */
    }
    udp_connect(ret, &s, remote_port);
    return ret;
}
예제 #12
0
/**
 * Function: buildNTPUDPConnection
 * Description: 向远程的主机建立UDP连接
 * @param ipaddr 远程主机的IP地址
 * @return 创建连接的返回的状态信息
**/
static err_t buildNTPUDPConnection(ip_addr_t* ipaddr){
	err_t err_status;
	ntp_udp_client = udp_new();
		if( !ntp_udp_client){
			printf("create udp pcb failed\n\r");
			return ERR_VAL;
		}
		/* 先绑定udp链接 */
		err_status = udp_bind(ntp_udp_client,IP_ADDR_ANY,1233);    //绑定任意地址和1233端口
		if(err_status != ERR_OK){  //绑定失败
			printf("ntp udp bind failed\n\r");
			return ERR_VAL;
		}
		err_status = udp_connect(ntp_udp_client,ipaddr,123);   //与远程NTP服务器建立连接
		if(err_status != ERR_OK){  //创建连接失败
			printf("ntp udp create connect failed\n\r");
			return ERR_VAL;
		}
		//UDP PCB收到数据时的回调函数
		udp_recv(ntp_udp_client,get_ntp_time,NULL);
		return ERR_OK;
}
예제 #13
0
void tftpd_init(void)
{
  err_t err;
  unsigned port = 69;

  /* create a new UDP PCB structure  */
  UDPpcb = udp_new();
  if (!UDPpcb)
  {  /* Error creating PCB. Out of Memory  */
    return;
  }

  /* Bind this PCB to port 69  */
  err = udp_bind(UDPpcb, IP_ADDR_ANY, port);
  if (err != ERR_OK)
  {    /* Unable to bind to port  */
    return;
  }

  /* TFTP server start  */
  udp_recv(UDPpcb, recv_callback_tftp, NULL);
}
예제 #14
0
파일: sntp.c 프로젝트: NBitWonder/VoIP32
static void send_ntp_req(void)
{

	struct pbuf * p;

	//Once here, we should have the NTP server's IP address in memory already
	err_t result = dns_gethostbyname(dns_hostname, &ntp_server_ip, send_ntp_req, NULL);
	if (result != ERR_OK) return;

	//Allocate a pbuf for this packet... use PBUF_ROM since payload is permanently stored in ROM
	p=pbuf_alloc(PBUF_TRANSPORT, 60, PBUF_ROM);

	//Only continue if the allocation actually "took"
	if (p != NULL) {
		
		//We should have the server's IP now.
		//Create a UDP PCB for handling this connection.
		ntp_pcb = udp_new();
		if (ntp_pcb == NULL) {
			pbuf_free(p);
			return;
		}

		//Register a callback for this pcb - just make it our NTP receive function.
		udp_recv(ntp_pcb, recv_ntp_resp, NULL);

		//Populate the NTP request.
		p->payload = (void*)ntp_request_payload;
		p->len = 60;
		p->tot_len = 60;	

		//Send the request.
		udp_sendto(ntp_pcb, p, &ntp_server_ip, 123);

		//We no longer need the pbuf
		pbuf_free(p);
	}
}
예제 #15
0
void udp_echo_init(void)
{
    struct udp_pcb *pcb;

    /* get new pcb */
    pcb = udp_new();
    if (pcb == NULL)
    {
        LWIP_DEBUGF(UDP_DEBUG, ("udp_new failed!\r\n"));
        return;
    }

    /* bind to any IP address on port 7 */
    if (udp_bind(pcb, IP_ADDR_ANY, 7) != ERR_OK)
    {
        LWIP_DEBUGF(UDP_DEBUG, ("udp_bind failed!\r\n"));
        return;
    }

    /* set udp_echo_recv() as callback function */
    /* for received packets */
    udp_recv(pcb, udp_echo_recv, NULL);
}
예제 #16
0
/**
  * @brief  Connect to UDP echo server
  * @param  None
  * @retval None
  */
void udp_echoclient_connect(void)
{
  struct ip_addr DestIPaddr;
  err_t err;
  
  /* Create a new UDP control block  */
  upcb = udp_new();
  
  if (upcb!=NULL)
  {
    /*assign destination IP address */
    IP4_ADDR( &DestIPaddr, DEST_IP_ADDR0, DEST_IP_ADDR1, DEST_IP_ADDR2, DEST_IP_ADDR3 );
    
    /* configure destination IP address and port */
    err= udp_connect(upcb, &DestIPaddr, UDP_SERVER_PORT);
    
    if (err == ERR_OK)
    {
      /* Set a receive callback for the upcb */
      udp_recv(upcb, udp_receive_callback, NULL);  
    }
  }
}
예제 #17
0
파일: msg_in.c 프로젝트: peterliu2/FreeRTOS
/**
 * Starts SNMP Agent.
 * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.
 */
void
snmp_init(void)
{
    struct snmp_msg_pstat *msg_ps;
    u8_t i;

    snmp1_pcb = udp_new();
    if (snmp1_pcb != NULL) {
        udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT);
        udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT);
    }
    msg_ps = &msg_input_list[0];
    for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++) {
        msg_ps->state = SNMP_MSG_EMPTY;
        msg_ps->error_index = 0;
        msg_ps->error_status = SNMP_ES_NOERROR;
        msg_ps++;
    }
    trap_msg.pcb = snmp1_pcb;
    /* The coldstart trap will only be output
       if our outgoing interface is up & configured  */
    snmp_coldstart_trap();
}
예제 #18
0
void ICACHE_FLASH_ATTR dhcps_start(struct ip_info *info)
{
	os_memset(&msg_dhcps, 0, sizeof(dhcps_msg));
	pcb_dhcps = udp_new();
	if (pcb_dhcps == NULL || info ==NULL) {
#if DEBUGSOO > 0
		os_printf("dhcps_start(): could not obtain pcb\n");
#endif
	}

	IP4_ADDR(&broadcast_dhcps, 255, 255, 255, 255);

	server_address = info->ip;
	wifi_softap_init_dhcps_lease(server_address.addr);
	client_address_plus.addr = dhcps_lease.start_ip.addr;

	udp_bind(pcb_dhcps, IP_ADDR_ANY, DHCPS_SERVER_PORT);
	udp_recv(pcb_dhcps, handle_dhcp, NULL);
#if DHCPS_DEBUG
	os_printf("dhcps:dhcps_start->udp_recv function Set a receive callback handle_dhcp for UDP_PCB pcb_dhcps\n");
#endif

}
예제 #19
0
void
udpecho_raw_init(void)
{
  udpecho_raw_pcb = udp_new();
  if (udpecho_raw_pcb != NULL)
  {
    err_t err;

    err = udp_bind(udpecho_raw_pcb, IP_ADDR_ANY, 7);
    if (err == ERR_OK)
    {
      udp_recv(udpecho_raw_pcb, udpecho_raw_recv, NULL);
    }
    else
    {
      /* abort? output diagnostic? */
    }
  }
  else
  {
    /* abort? output diagnostic? */
  }
}
예제 #20
0
/*..........................................................................*/
struct udp_pcb *server_init(u16_t port)
{
    struct udp_pcb *pcb;
    err_t err;

    pcb = udp_new();
    if (!pcb)
    {
//    	iprintf("Error creating PCB. Out of Memory\n\r");
        return NULL;
    }

    err = udp_bind(pcb, IP_ADDR_ANY, port);
    if (err != ERR_OK)
    {
//        iprintf("Unable to bind to port %d: err = %d\n\r", port, err);
        return NULL;
    }

    udp_recv(pcb, server_recv_callback, NULL);

    return pcb;
}
예제 #21
0
static void
udp_receiver(struct udp_pcb *upcb, struct ip_addr *listen_ip,
        uint16_t listen_port)
{
    printf("U: Going in UDP_RECEIVER mode\n");
    // Bind to specified port
    errval_t r = udp_bind(upcb, listen_ip, listen_port);
    if (err_is_fail(r)) {
        DEBUG_ERR(r, "udp_bind:");
    }

    lwip_benchmark_control(connection_type, BMS_START_REQUEST,
            iterations, rdtsc());
    udp_recv(upcb, udp_recv_handler, 0 /*client data, arg in callback*/);

    while (true) {
        r = event_dispatch(ws);
        if (err_is_fail(r)) {
            DEBUG_ERR(r, "in event_dispatch");
            break;
        }
    }
} // end function: udp_receiver
예제 #22
0
파일: lwip_dhcp6.c 프로젝트: 0xc0170/mbed
/** Ensure DHCP PCB is allocated and bound */
static err_t
dhcp6_inc_pcb_refcount(void)
{
  if (dhcp6_pcb_refcount == 0) {
    LWIP_ASSERT("dhcp6_inc_pcb_refcount(): memory leak", dhcp6_pcb == NULL);

    /* allocate UDP PCB */
    dhcp6_pcb = udp_new_ip6();

    if (dhcp6_pcb == NULL) {
      return ERR_MEM;
    }

    ip_set_option(dhcp6_pcb, SOF_BROADCAST);

    /* set up local and remote port for the pcb -> listen on all interfaces on all src/dest IPs */
    udp_bind(dhcp6_pcb, IP6_ADDR_ANY, DHCP6_CLIENT_PORT);
    udp_recv(dhcp6_pcb, dhcp6_recv, NULL);
  }

  dhcp6_pcb_refcount++;

  return ERR_OK;
}
예제 #23
0
파일: api_msg.c 프로젝트: comrid1987/jb3500
/**
 * Receive callback function for UDP netconns.
 * Posts the packet to conn->recvmbox or deletes it on memory error.
 *
 * @see udp.h (struct udp_pcb.recv) for parameters
 */
static void
recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
         ip_addr_t *addr, u16_t port)
{
    struct netbuf *buf;
    struct netconn *conn;
    u16_t len;
#if LWIP_SO_RCVBUF
    int recv_avail;
#endif /* LWIP_SO_RCVBUF */

    LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
    LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
    LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
    conn = (struct netconn *)arg;
    LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);

#if LWIP_SO_RCVBUF
    SYS_ARCH_GET(conn->recv_avail, recv_avail);
    if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||
            ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
#else  /* LWIP_SO_RCVBUF */
    if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {
#endif /* LWIP_SO_RCVBUF */
        pbuf_free(p);
        return;
    }

    buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
    if (buf == NULL) {
        pbuf_free(p);
        return;
    } else {
        buf->p = p;
        buf->ptr = p;
        ip_addr_set(&buf->addr, addr);
        buf->port = port;
#if LWIP_NETBUF_RECVINFO
        {
            const struct ip_hdr* iphdr = ip_current_header();
            /* get the UDP header - always in the first pbuf, ensured by udp_input */
            const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
#if LWIP_CHECKSUM_ON_COPY
            buf->flags = NETBUF_FLAG_DESTADDR;
#endif /* LWIP_CHECKSUM_ON_COPY */
            ip_addr_set(&buf->toaddr, ip_current_dest_addr());
            buf->toport_chksum = udphdr->dest;
        }
#endif /* LWIP_NETBUF_RECVINFO */
    }

    len = p->tot_len;
    if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
        netbuf_delete(buf);
        return;
    } else {
#if LWIP_SO_RCVBUF
        SYS_ARCH_INC(conn->recv_avail, len);
#endif /* LWIP_SO_RCVBUF */
        /* Register event with callback */
        API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
    }
}
#endif /* LWIP_UDP */

#if LWIP_TCP
/**
 * Receive callback function for TCP netconns.
 * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
 *
 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
 */
static err_t
recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
    struct netconn *conn;
    u16_t len;

    LWIP_UNUSED_ARG(pcb);
    LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
    LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
    conn = (struct netconn *)arg;
    LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);

    if (conn == NULL) {
        return ERR_VAL;
    }
    if (!sys_mbox_valid(&conn->recvmbox)) {
        /* recvmbox already deleted */
        if (p != NULL) {
            tcp_recved(pcb, p->tot_len);
            pbuf_free(p);
        }
        return ERR_OK;
    }
    /* Unlike for UDP or RAW pcbs, don't check for available space
       using recv_avail since that could break the connection
       (data is already ACKed) */

    /* don't overwrite fatal errors! */
    NETCONN_SET_SAFE_ERR(conn, err);

    if (p != NULL) {
        len = p->tot_len;
    } else {
        len = 0;
    }

    if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
        /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
        return ERR_MEM;
    } else {
#if LWIP_SO_RCVBUF
        SYS_ARCH_INC(conn->recv_avail, len);
#endif /* LWIP_SO_RCVBUF */
        /* Register event with callback */
        API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
    }

    return ERR_OK;
}

/**
 * Poll callback function for TCP netconns.
 * Wakes up an application thread that waits for a connection to close
 * or data to be sent. The application thread then takes the
 * appropriate action to go on.
 *
 * Signals the conn->sem.
 * netconn_close waits for conn->sem if closing failed.
 *
 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
 */
static err_t
poll_tcp(void *arg, struct tcp_pcb *pcb)
{
    struct netconn *conn = (struct netconn *)arg;

    LWIP_UNUSED_ARG(pcb);
    LWIP_ASSERT("conn != NULL", (conn != NULL));

    if (conn->state == NETCONN_WRITE) {
        do_writemore(conn);
    } else if (conn->state == NETCONN_CLOSE) {
        do_close_internal(conn);
    }
    /* @todo: implement connect timeout here? */

    /* Did a nonblocking write fail before? Then check available write-space. */
    if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
        /* If the queued byte- or pbuf-count drops below the configured low-water limit,
           let select mark this pcb as writable again. */
        if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
                (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
            conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
            API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
        }
    }

    return ERR_OK;
}

/**
 * Sent callback function for TCP netconns.
 * Signals the conn->sem and calls API_EVENT.
 * netconn_write waits for conn->sem if send buffer is low.
 *
 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
 */
static err_t
sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
{
    struct netconn *conn = (struct netconn *)arg;

    LWIP_UNUSED_ARG(pcb);
    LWIP_ASSERT("conn != NULL", (conn != NULL));

    if (conn->state == NETCONN_WRITE) {
        do_writemore(conn);
    } else if (conn->state == NETCONN_CLOSE) {
        do_close_internal(conn);
    }

    if (conn) {
        /* If the queued byte- or pbuf-count drops below the configured low-water limit,
           let select mark this pcb as writable again. */
        if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
                (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
            conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
            API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
        }
    }

    return ERR_OK;
}

/**
 * Error callback function for TCP netconns.
 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
 * The application thread has then to decide what to do.
 *
 * @see tcp.h (struct tcp_pcb.err) for parameters
 */
static void
err_tcp(void *arg, err_t err)
{
    struct netconn *conn;
    enum netconn_state old_state;
    SYS_ARCH_DECL_PROTECT(lev);

    conn = (struct netconn *)arg;
    LWIP_ASSERT("conn != NULL", (conn != NULL));

    conn->pcb.tcp = NULL;

    /* no check since this is always fatal! */
    SYS_ARCH_PROTECT(lev);
    conn->last_err = err;
    SYS_ARCH_UNPROTECT(lev);

    /* reset conn->state now before waking up other threads */
    old_state = conn->state;
    conn->state = NETCONN_NONE;

    /* Notify the user layer about a connection error. Used to signal
       select. */
    API_EVENT(conn, NETCONN_EVT_ERROR, 0);
    /* Try to release selects pending on 'read' or 'write', too.
       They will get an error if they actually try to read or write. */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
    API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);

    /* pass NULL-message to recvmbox to wake up pending recv */
    if (sys_mbox_valid(&conn->recvmbox)) {
        /* use trypost to prevent deadlock */
        sys_mbox_trypost(&conn->recvmbox, NULL);
    }
    /* pass NULL-message to acceptmbox to wake up pending accept */
    if (sys_mbox_valid(&conn->acceptmbox)) {
        /* use trypost to preven deadlock */
        sys_mbox_trypost(&conn->acceptmbox, NULL);
    }

    if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
            (old_state == NETCONN_CONNECT)) {
        /* calling do_writemore/do_close_internal is not necessary
           since the pcb has already been deleted! */
        int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
        SET_NONBLOCKING_CONNECT(conn, 0);

        if (!was_nonblocking_connect) {
            /* set error return code */
            LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
            conn->current_msg->err = err;
            conn->current_msg = NULL;
            /* wake up the waiting task */
            sys_sem_signal(&conn->op_completed);
        }
    } else {
        LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
    }
}

/**
 * Setup a tcp_pcb with the correct callback function pointers
 * and their arguments.
 *
 * @param conn the TCP netconn to setup
 */
static void
setup_tcp(struct netconn *conn)
{
    struct tcp_pcb *pcb;

    pcb = conn->pcb.tcp;
    tcp_arg(pcb, conn);
    tcp_recv(pcb, recv_tcp);
    tcp_sent(pcb, sent_tcp);
    tcp_poll(pcb, poll_tcp, 4);
    tcp_err(pcb, err_tcp);
}

/**
 * Accept callback function for TCP netconns.
 * Allocates a new netconn and posts that to conn->acceptmbox.
 *
 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
 */
static err_t
accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
{
    struct netconn *newconn;
    struct netconn *conn = (struct netconn *)arg;

    LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));

    if (!sys_mbox_valid(&conn->acceptmbox)) {
        LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
        return ERR_VAL;
    }

    /* We have to set the callback here even though
     * the new socket is unknown. conn->socket is marked as -1. */
    newconn = netconn_alloc(conn->type, conn->callback);
    if (newconn == NULL) {
        return ERR_MEM;
    }
    newconn->pcb.tcp = newpcb;
    setup_tcp(newconn);
    /* no protection: when creating the pcb, the netconn is not yet known
       to the application thread */
    newconn->last_err = err;

    if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
        /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
           so do nothing here! */
        /* remove all references to this netconn from the pcb */
        struct tcp_pcb* pcb = newconn->pcb.tcp;
        tcp_arg(pcb, NULL);
        tcp_recv(pcb, NULL);
        tcp_sent(pcb, NULL);
        tcp_poll(pcb, NULL, 4);
        tcp_err(pcb, NULL);
        /* remove reference from to the pcb from this netconn */
        newconn->pcb.tcp = NULL;
        /* no need to drain since we know the recvmbox is empty. */
        sys_mbox_free(&newconn->recvmbox);
        sys_mbox_set_invalid(&newconn->recvmbox);
        netconn_free(newconn);
        return ERR_MEM;
    } else {
        /* Register event with callback */
        API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
    }

    return ERR_OK;
}
#endif /* LWIP_TCP */

/**
 * Create a new pcb of a specific type.
 * Called from do_newconn().
 *
 * @param msg the api_msg_msg describing the connection type
 * @return msg->conn->err, but the return value is currently ignored
 */
static void
pcb_new(struct api_msg_msg *msg)
{
    LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);

    /* Allocate a PCB for this connection */
    switch(NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
    case NETCONN_RAW:
        msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
        if(msg->conn->pcb.raw == NULL) {
            msg->err = ERR_MEM;
            break;
        }
        raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
        break;
#endif /* LWIP_RAW */
#if LWIP_UDP
    case NETCONN_UDP:
        msg->conn->pcb.udp = udp_new();
        if(msg->conn->pcb.udp == NULL) {
            msg->err = ERR_MEM;
            break;
        }
#if LWIP_UDPLITE
        if (msg->conn->type==NETCONN_UDPLITE) {
            udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
        }
#endif /* LWIP_UDPLITE */
        if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
            udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
        }
        udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
        break;
#endif /* LWIP_UDP */
#if LWIP_TCP
    case NETCONN_TCP:
        msg->conn->pcb.tcp = tcp_new();
        if(msg->conn->pcb.tcp == NULL) {
            msg->err = ERR_MEM;
            break;
        }
        setup_tcp(msg->conn);
        break;
#endif /* LWIP_TCP */
    default:
        /* Unsupported netconn type, e.g. protocol disabled */
        msg->err = ERR_VAL;
        break;
    }
}
예제 #24
0
/*-------------------------------------------------------------------------
	Description:	
		This function is used to start DHCP Server for a network interface.
	Arguments:
		Netif: Pointer to the Lwip network interface.
		
	Return Value:
		The DHCP Server error code:
			DHCPS_ERR_SUCCESS - No error
			DHCPS_ERR_MEM - Out of memory
			DHCPS_ERR_LINKDOWN - The NI is inactive
	Note:	
		The dhcp server must be started after the network interface was actived.
-------------------------------------------------------------------------*/
INT32 DHCPS_Start(struct netif *Netif)
{
	INT32U Val, Mask, tmp, i;
	PDHCP_CLIENT pClient;

	/* Check the network interface is active now. */
	if(netif_is_up(Netif) == 0)
	{
		return DHCPS_ERR_LINKDOWN;
	}
	
	memset(&DhcpServer, 0, sizeof(DhcpServer));

	/* Calculate the start ip address of the server's ip pool. */
	Val = ntohl(Netif->ip_addr.addr);
	Mask = ntohl(Netif->netmask.addr);
	tmp = (Val & (~Mask));
	tmp = ((tmp + 1) % (~Mask)) ? ((tmp + 1) % (~Mask)) : 1;
	Val = htonl((Val & Mask) | tmp);

	/* Configure the DHCP Server. */
	ip_addr_set(&DhcpServer.ServerIpAddr, &Netif->ip_addr);
	ip_addr_set(&DhcpServer.StartIpAddr, (struct ip_addr *)&Val);
	ip_addr_set(&DhcpServer.SubnetMask, &Netif->netmask);
	ip_addr_set(&DhcpServer.GateWay, &Netif->ip_addr);
	ip_addr_set(&DhcpServer.Dns1, &Netif->ip_addr);
	ip_addr_set(&DhcpServer.Dns1, &Netif->ip_addr);

	/* Set the default lease time - 2 hours. */
	DhcpServer.LeaseTime = DHCP_DEFAULT_LEASE_TIME;

	/* Initialize the free DHCP clients. */
	for(i = 0; i < DHCPS_HISTORY_CLIENT_NUM; i++)
	{
		pClient = &DhcpServer.Clients[i];

		/* Set the initial client state is "IDLE". */
		pClient->State = DHCP_CLIENT_STATE_IDLE;

		/* Set the ip address to the client. */
		Val = ntohl(DhcpServer.StartIpAddr.addr);
		tmp = (Val & (~Mask));
		tmp = ((tmp + i) % (~Mask)) ? ((tmp + i) % (~Mask)) : 1;
		Val = htonl((Val & Mask) | tmp);
		ip_addr_set(&pClient->IpAddr, (struct ip_addr *)&Val);

		/* Set the default lease time. */
		pClient->Lease = DHCP_DEFAULT_LEASE_TIME;
	}

	/* Allocate a UDP PCB. */
	DhcpServer.Socket = udp_new();
	if(DhcpServer.Socket == NULL)
	{
		return DHCPS_ERR_MEM;
	}

	/* Set up local and remote port for the pcb. */
	udp_bind(DhcpServer.Socket, IP_ADDR_ANY, DHCP_SERVER_UDP_PORT);
	
	/* Set up the recv callback and argument. */
	udp_recv(DhcpServer.Socket, DHCPS_RecvCb, Netif);

	/* Start the DHCP Server tick timer. */
	sys_timeout(DHCP_TICK_TIME, _DhcpTickHandle, NULL);

	/* Enable the DHCP Server. */
	DhcpServer.Enable = 1;

	return DHCPS_ERR_SUCCESS;
}
예제 #25
0
/**
 * New proxied UDP conversation created.
 * Global callback for udp_proxy_accept().
 */
static void
pxudp_pcb_accept(void *arg, struct udp_pcb *newpcb, struct pbuf *p,
                 ip_addr_t *addr, u16_t port)
{
    struct pxudp *pxudp;
    ipX_addr_t dst_addr;
    int mapping;
    int sdom;
    SOCKET sock;

    LWIP_ASSERT1(newpcb != NULL);
    LWIP_ASSERT1(p != NULL);
    LWIP_UNUSED_ARG(arg);

    mapping = pxremap_outbound_ipX(PCB_ISIPV6(newpcb), &dst_addr, &newpcb->local_ip);
    if (mapping != PXREMAP_MAPPED && pxudp_ttl_expired(p)) {
        udp_remove(newpcb);
        return;
    }

    pxudp = pxudp_allocate();
    if (pxudp == NULL) {
        DPRINTF(("pxudp_allocate: failed\n"));
        udp_remove(newpcb);
        pbuf_free(p);
        return;
    }

    sdom = PCB_ISIPV6(newpcb) ? PF_INET6 : PF_INET;
    pxudp->is_mapped = (mapping == PXREMAP_MAPPED);

#if 0 /* XXX: DNS IPv6->IPv4 remapping hack */
    if (pxudp->is_mapped
        && newpcb->local_port == 53
        && PCB_ISIPV6(newpcb))
    {
        /*
         * "Remap" DNS over IPv6 to IPv4 since Ubuntu dnsmasq does not
         * listen on IPv6.
         */
        sdom = PF_INET;
        ipX_addr_set_loopback(0, &dst_addr);
    }
#endif  /* DNS IPv6->IPv4 remapping hack */

    sock = proxy_connected_socket(sdom, SOCK_DGRAM,
                                  &dst_addr, newpcb->local_port);
    if (sock == INVALID_SOCKET) {
        udp_remove(newpcb);
        pbuf_free(p);
        return;
    }

    pxudp->sock = sock;
    pxudp->pcb = newpcb;
    udp_recv(newpcb, pxudp_pcb_recv, pxudp);

    pxudp->pmhdl.callback = pxudp_pmgr_pump;
    pxudp_chan_send(POLLMGR_CHAN_PXUDP_ADD, pxudp);

    /* dispatch directly instead of calling pxudp_pcb_recv() */
    pxudp_pcb_forward_outbound(pxudp, p, addr, port);
}
예제 #26
0
int test_net_udp(void)
{
        struct timeval timeout;
        socket_udp *s1, *s2;
        char buf1[BUFSIZE], buf2[BUFSIZE];
        const char *hname;
        int rc, i;

#ifndef WIN32

        /* "BSD" bug test that appears in this function uses fork and
         * exec, that are not present on WIN32.  Since the original
         * bug has not been seen on Win32 it's probably not worth
         * converting to use CreateProcess() */

        int status_parent, status_child;

#endif                          /* WIN32 */

        srand48(time(NULL));

        /**********************************************************************/
        /* The first test is to loopback a packet to ourselves...             */
        printf
            ("Testing UDP/IP networking (IPv4 loopback) ................................ ");
        fflush(stdout);
        s1 = udp_init("127.0.0.1", 5004, 5004, 1);
        if (s1 == NULL) {
                printf("FAIL\n");
                printf("  Cannot initialize socket\n");
                return 1;
        }
        randomize(buf1, BUFSIZE);
        randomize(buf2, BUFSIZE);
        if (udp_send(s1, buf1, BUFSIZE) < 0) {
                printf("FAIL\n");
                perror("  Cannot send packet");
                goto abort_loopback;
        }
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        udp_fd_zero();
        udp_fd_set(s1);
        rc = udp_select(&timeout);
        if (rc < 0) {
                printf("FAIL\n");
                perror("  Select failed");
                goto abort_loopback;
        }
        if (rc == 0) {
                printf("FAIL\n");
                printf("  No data waiting\n");
                goto abort_loopback;
        }
        if (!udp_fd_isset(s1)) {
                printf("FAIL\n");
                printf("  No data on file descriptor\n");
                goto abort_loopback;
        }
        if (udp_recv(s1, buf2, BUFSIZE) < 0) {
                printf("FAIL\n");
                perror("  Receive failed");
                goto abort_loopback;
        }
        if (memcmp(buf1, buf2, BUFSIZE) != 0) {
                printf("FAIL\n");
                printf("  Buffer corrupt\n");
                goto abort_loopback;
        }
        printf("Ok\n");
 abort_loopback:
        hname = udp_host_addr(s1);      /* we need this for the unicast test... */
        udp_exit(s1);

        /**********************************************************************/
        /* Now we send a packet to ourselves via our real network address...  */
        printf
            ("Testing UDP/IP networking (IPv4 unicast) ................................. ");
        fflush(stdout);
        s1 = udp_init(hname, 5004, 5005, 1);
        if (s1 == NULL) {
                printf("FAIL\n");
                printf("  Cannot initialize socket\n");
                return 1;
        }

        s2 = udp_init(hname, 5005, 5004, 1);
        if (s2 == NULL) {
                printf("FAIL\n");
                printf("  Cannot initialize socket\n");
                return 1;
        }

        randomize(buf1, BUFSIZE);
        randomize(buf2, BUFSIZE);
        if (udp_send(s1, buf1, BUFSIZE) < 0) {
                printf("FAIL\n");
                perror("  Cannot send");
                goto abort_unicast;
        }
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        udp_fd_zero();
        udp_fd_set(s1);
        udp_fd_set(s2);
        rc = udp_select(&timeout);
        if (rc < 0) {
                printf("FAIL\n");
                perror("  Select failed");
                goto abort_unicast;
        }
        if (rc == 0) {
                printf("FAIL\n");
                printf("  No data waiting (no route to %s?)\n", hname);
                goto abort_unicast;
        }
        if (!udp_fd_isset(s2)) {
                printf("FAIL\n");
                printf("  No data on file descriptor\n");
                goto abort_unicast;
        }
        if (udp_recv(s2, buf2, BUFSIZE) < 0) {
                printf("FAIL\n");
                perror("  Cannot receive");
                goto abort_unicast;
        }
        if (memcmp(buf1, buf2, BUFSIZE) != 0) {
                printf("FAIL\n");
                printf("  Buffer corrupt\n");
                goto abort_unicast;
        }
        printf("Ok\n");
 abort_unicast:
        udp_exit(s1);
        udp_exit(s2);

        /**********************************************************************/
        /* Loopback a packet to ourselves via multicast...                    */
        printf
            ("Testing UDP/IP networking (IPv4 multicast) ............................... ");
        fflush(stdout);
        s1 = udp_init("224.2.0.1", 5004, 5004, 1);
        if (s1 == NULL) {
                printf("FAIL\n");
                printf("  Cannot initialize socket\n");
                return 1;
        }
        randomize(buf1, BUFSIZE);
        randomize(buf2, BUFSIZE);
        if (udp_send(s1, buf1, BUFSIZE) < 0) {
                printf("FAIL\n");
                perror("  Cannot send");
                goto abort_multicast;
        }
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        udp_fd_zero();
        udp_fd_set(s1);
        rc = udp_select(&timeout);
        if (rc < 0) {
                printf("FAIL\n");
                perror("  Select failed");
                goto abort_multicast;
        }
        if (rc == 0) {
                printf("FAIL\n");
                printf("  No data waiting (no multicast loopback route?)\n");
                goto abort_multicast;
        }
        if (!udp_fd_isset(s1)) {
                printf("FAIL\n");
                printf("  No data on file descriptor\n");
                goto abort_multicast;
        }
        if (udp_recv(s1, buf2, BUFSIZE) < 0) {
                printf("FAIL\n");
                perror("  Cannot receive");
                goto abort_multicast;
        }
        if (memcmp(buf1, buf2, BUFSIZE) != 0) {
                printf("FAIL\n");
                printf("  Buffer corrupt\n");
                goto abort_multicast;
        }
        printf("Ok\n");
 abort_multicast:
        udp_exit(s1);

        /**********************************************************************/
        /* Loopback a packet to ourselves via multicast, checking lengths...  */
        printf
            ("Testing UDP/IP networking (IPv4 length check) ............................ ");
        fflush(stdout);
        s1 = udp_init("224.2.0.1", 5004, 5004, 1);
        if (s1 == NULL) {
                printf("FAIL\n");
                printf("  Cannot initialize socket\n");
                return 1;
        }
        for (i = 1; i < BUFSIZE; i++) {
                randomize(buf1, i);
                randomize(buf2, i);
                if (udp_send(s1, buf1, i) < 0) {
                        printf("FAIL\n");
                        perror("  Cannot send");
                        goto abort_length;
                }
                timeout.tv_sec = 1;
                timeout.tv_usec = 0;
                udp_fd_zero();
                udp_fd_set(s1);
                rc = udp_select(&timeout);
                if (rc < 0) {
                        printf("FAIL\n");
                        perror("  Select failed");
                        goto abort_length;
                }
                if (rc == 0) {
                        printf("FAIL\n");
                        printf
                            ("  No data waiting (no multicast loopback route?)\n");
                        goto abort_length;
                }
                if (!udp_fd_isset(s1)) {
                        printf("FAIL\n");
                        printf("  No data on file descriptor\n");
                        goto abort_length;
                }
                if (udp_recv(s1, buf2, BUFSIZE) != i) {
                        printf("FAIL\n");
                        perror("  Cannot receive");
                        goto abort_length;
                }
                if (memcmp(buf1, buf2, i) != 0) {
                        printf("FAIL\n");
                        printf("  Buffer corrupt\n");
                        goto abort_length;
                }
        }
        printf("Ok\n");
 abort_length:
        udp_exit(s1);

#ifdef HAVE_IPv6
        /**********************************************************************/
        /* The first test is to loopback a packet to ourselves...             */
        printf
            ("Testing UDP/IP networking (IPv6 loopback) ................................ ");
        fflush(stdout);
        s1 = udp_init("::1", 5004, 5004, 1);
        if (s1 == NULL) {
                printf("FAIL\n");
                printf("  Cannot initialize socket\n");
                return 1;
        }
        randomize(buf1, BUFSIZE);
        randomize(buf2, BUFSIZE);
        if (udp_send(s1, buf1, BUFSIZE) < 0) {
                printf("FAIL\n");
                perror("  Cannot send");
                goto abort_loopback_ipv6;
        }
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        udp_fd_zero();
        udp_fd_set(s1);
        rc = udp_select(&timeout);
        if (rc < 0) {
                printf("FAIL\n");
                perror("  Select failed");
                goto abort_loopback_ipv6;
        }
        if (rc == 0) {
                printf("FAIL\n");
                printf("  No data waiting\n");
                goto abort_loopback_ipv6;
        }
        if (!udp_fd_isset(s1)) {
                printf("FAIL\n");
                printf("  No data on file descriptor\n");
                goto abort_loopback_ipv6;
        }
        if (udp_recv(s1, buf2, BUFSIZE) < 0) {
                printf("FAIL\n");
                perror("  Cannot receive");
                goto abort_loopback_ipv6;
        }
        if (memcmp(buf1, buf2, BUFSIZE) != 0) {
                printf("FAIL\n");
                printf("  Buffer corrupt\n");
                goto abort_loopback_ipv6;
        }
        printf("Ok\n");
 abort_loopback_ipv6:
        udp_exit(s1);

        /**********************************************************************/
        /* Loopback a packet to ourselves via multicast. The address is the   */
        /* SAP address, but we use a different port.                          */
        printf
            ("Testing UDP/IP networking (IPv6 multicast) ............................... ");
        fflush(stdout);
        s1 = udp_init("ff01::2:7ffe", 5004, 5004, 1);
        if (s1 == NULL) {
                printf("FAIL\n");
                printf("  Cannot initialize socket\n");
                return 1;
        }
        randomize(buf1, BUFSIZE);
        randomize(buf2, BUFSIZE);
        if (udp_send(s1, buf1, BUFSIZE) < 0) {
                printf("FAIL\n");
                perror("  Cannot send");
                goto abort_multicast_ipv6;
        }
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        udp_fd_zero();
        udp_fd_set(s1);
        rc = udp_select(&timeout);
        if (rc < 0) {
                printf("FAIL\n");
                perror("  Select failed");
                goto abort_multicast_ipv6;
        }
        if (rc == 0) {
                printf("FAIL\n");
                printf("  No data waiting (no multicast loopback route?)\n");
                goto abort_multicast_ipv6;
        }
        if (!udp_fd_isset(s1)) {
                printf("FAIL\n");
                printf("  No data on file descriptor\n");
                goto abort_multicast_ipv6;
        }
        if (udp_recv(s1, buf2, BUFSIZE) < 0) {
                printf("FAIL\n");
                perror("  Cannot receive");
                goto abort_multicast_ipv6;
        }
        if (memcmp(buf1, buf2, BUFSIZE) != 0) {
                printf("FAIL\n");
                printf("  Buffer corrupt\n");
                goto abort_multicast_ipv6;
        }
        hname = udp_host_addr(s1);      /* we need this for the unicast test... */
        printf("Ok\n");
 abort_multicast_ipv6:
        udp_exit(s1);
#else
        printf
            ("Testing UDP/IP networking (IPv6 loopback) ................................ --\n");
        printf
            ("Testing UDP/IP networking (IPv6 unicast) ................................. --\n");
        printf
            ("Testing UDP/IP networking (IPv6 multicast) ............................... --\n");
#endif

        /**********************************************************************/

#ifdef WIN32
        printf
            ("Testing UDP/IP networking (FreeBSD bug) .................................. --\n");
#else
        printf
            ("Testing UDP/IP networking (FreeBSD bug) .................................. ");
        fflush(stdout);
        status_parent = 0;
        randomize(buf1, 64);
        s1 = udp_init("224.2.0.1", 5004, 5004, 1);
        if (s1 == NULL) {
                printf("fail (parent): cannot initialize socket\n");
                return 1;
        }
        rc = fork();
        if (rc == -1) {
                printf("fail: cannot fork\n");
                goto abort_bsd;
        } else if (rc == 0) {
                /* child */
                s2 = udp_init("224.2.0.1", 5004, 5004, 1);
                if (s2 == NULL) {
                        printf("FAIL\n");
                        printf("  Child cannot initialize socket\n");
                        exit(0);
                }
                if (udp_send(s2, buf1, 64) < 0) {
                        printf("FAIL\n");
                        perror("  Child cannot send");
                        exit(0);
                }
                timeout.tv_sec = 10;
                timeout.tv_usec = 0;
                udp_fd_zero();
                udp_fd_set(s2);
                rc = udp_select(&timeout);
                if (rc < 0) {
                        printf("FAIL\n");
                        perror("  Child select");
                        exit(0);
                }
                if (rc == 0) {
                        printf("FAIL\n");
                        printf
                            ("  Child: no data waiting (no multicast loopback route?)\n");
                        exit(0);
                }
                if (!udp_fd_isset(s2)) {
                        printf("FAIL\n");
                        printf("  Child: no data on file descriptor\n");
                        exit(0);
                }
                rc = udp_recv(s2, buf2, BUFSIZE);
                if (rc < 0) {
                        printf("FAIL\n");
                        perror("  Child cannot receive");
                        exit(0);
                }
                if (rc != 64) {
                        printf("FAIL\n");
                        printf("  Child: read size incorrect (%d != %d)\n", rc,
                               64);
                        exit(0);
                }
                if (memcmp(buf1, buf2, 64) != 0) {
                        printf("FAIL\n");
                        printf("  Child: buffer corrupt\n");
                        exit(0);
                }
                udp_exit(s2);
                exit(1);
        } else {
                /* parent */
                timeout.tv_sec = 10;
                timeout.tv_usec = 0;
                udp_fd_zero();
                udp_fd_set(s1);
                rc = udp_select(&timeout);
                if (rc < 0) {
                        printf("FAIL\n");
                        perror("  Parent select");
                        goto abort_bsd;
                }
                if (rc == 0) {
                        printf("FAIL\n");
                        printf
                            ("  Parent: no data waiting (no multicast loopback route?)\n");
                        goto abort_bsd;
                }
                if (!udp_fd_isset(s1)) {
                        printf("FAIL\n");
                        printf("  Parent: no data on file descriptor\n");
                        goto abort_bsd;
                }
                rc = udp_recv(s1, buf2, BUFSIZE);
                if (rc < 0) {
                        printf("FAIL\n");
                        perror("  Parent cannot receive");
                        goto abort_bsd;
                }
                if (rc != 64) {
                        printf("FAIL\n");
                        printf("  Parent: read size incorrect (%d != %d)\n", rc,
                               64);
                        goto abort_bsd;
                }
                if (memcmp(buf1, buf2, 64) != 0) {
                        printf("FAIL\n");
                        printf("  Parent: buffer corrupt\n");
                        goto abort_bsd;
                }
                status_parent = 1;
        }
 abort_bsd:
        wait(&status_child);
        if (status_parent && status_child) {
                printf("Ok\n");
        }
        udp_exit(s1);
#endif                          /* WIN32 */

        return 0;
}
static void
do_connect(struct api_msg_msg *msg)
{
  if (msg->conn->pcb.tcp == NULL) {
    switch (msg->conn->type) {
#if LWIP_RAW
    case NETCONN_RAW:
      msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */
      raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
      break;
#endif
#if LWIP_UDP
    case NETCONN_UDPLITE:
      msg->conn->pcb.udp = udp_new();
      if (msg->conn->pcb.udp == NULL) {
  msg->conn->err = ERR_MEM;
  sys_mbox_post(msg->conn->mbox, NULL);
  return;
      }
      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
      break;
    case NETCONN_UDPNOCHKSUM:
      msg->conn->pcb.udp = udp_new();
      if (msg->conn->pcb.udp == NULL) {
  msg->conn->err = ERR_MEM;
  sys_mbox_post(msg->conn->mbox, NULL);
  return;
      }
      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
      break;
    case NETCONN_UDP:
      msg->conn->pcb.udp = udp_new();
      if (msg->conn->pcb.udp == NULL) {
  msg->conn->err = ERR_MEM;
  sys_mbox_post(msg->conn->mbox, NULL);
  return;
      }
      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
      break;
#endif /* LWIP_UDP */
#if LWIP_TCP      
    case NETCONN_TCP:
      msg->conn->pcb.tcp = tcp_new();      
      if (msg->conn->pcb.tcp == NULL) {
  msg->conn->err = ERR_MEM;
  sys_mbox_post(msg->conn->mbox, NULL);
  return;
      }
#endif
    default:
      break;
    }
  }
  switch (msg->conn->type) {
#if LWIP_RAW
  case NETCONN_RAW:
    raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
    sys_mbox_post(msg->conn->mbox, NULL);
    break;
#endif
#if LWIP_UDP
  case NETCONN_UDPLITE:
    /* FALLTHROUGH */
  case NETCONN_UDPNOCHKSUM:
    /* FALLTHROUGH */
  case NETCONN_UDP:
    udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
    sys_mbox_post(msg->conn->mbox, NULL);
    break;
#endif 
#if LWIP_TCP      
  case NETCONN_TCP:
    /*    tcp_arg(msg->conn->pcb.tcp, msg->conn);*/
    setup_tcp(msg->conn);
    tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,
    do_connected);
    /*tcp_output(msg->conn->pcb.tcp);*/
#endif

  default:
    break;
  }
}
static void
do_bind(struct api_msg_msg *msg)
{
  if (msg->conn->pcb.tcp == NULL) {
    switch (msg->conn->type) {
#if LWIP_RAW
    case NETCONN_RAW:
      msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */
      raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
      break;
#endif
#if LWIP_UDP
    case NETCONN_UDPLITE:
      msg->conn->pcb.udp = udp_new();
      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
      break;
    case NETCONN_UDPNOCHKSUM:
      msg->conn->pcb.udp = udp_new();
      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
      break;
    case NETCONN_UDP:
      msg->conn->pcb.udp = udp_new();
      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
      break;
#endif /* LWIP_UDP */
#if LWIP_TCP      
    case NETCONN_TCP:
      msg->conn->pcb.tcp = tcp_new();
      setup_tcp(msg->conn);
#endif /* LWIP_TCP */
    default:  
    break;
    }
  }
  switch (msg->conn->type) {
#if LWIP_RAW
  case NETCONN_RAW:
    msg->conn->err = raw_bind(msg->conn->pcb.raw,msg->msg.bc.ipaddr);
    break;
#endif
#if LWIP_UDP
  case NETCONN_UDPLITE:
    /* FALLTHROUGH */
  case NETCONN_UDPNOCHKSUM:
    /* FALLTHROUGH */
  case NETCONN_UDP:
    msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
    break;
#endif /* LWIP_UDP */
#if LWIP_TCP
  case NETCONN_TCP:
    msg->conn->err = tcp_bind(msg->conn->pcb.tcp,
            msg->msg.bc.ipaddr, msg->msg.bc.port);
#endif /* LWIP_TCP */
  default:
    break;
  }
  sys_mbox_post(msg->conn->mbox, NULL);
}
static void
do_newconn(struct api_msg_msg *msg)
{
   if(msg->conn->pcb.tcp != NULL) {
   /* This "new" connection already has a PCB allocated. */
   /* Is this an error condition? Should it be deleted? 
      We currently just are happy and return. */
     sys_mbox_post(msg->conn->mbox, NULL);
     return;
   }

   msg->conn->err = ERR_OK;

   /* Allocate a PCB for this connection */
   switch(msg->conn->type) {
#if LWIP_RAW
   case NETCONN_RAW:
      msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field */
      raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
     break;
#endif
#if LWIP_UDP
   case NETCONN_UDPLITE:
      msg->conn->pcb.udp = udp_new();
      if(msg->conn->pcb.udp == NULL) {
         msg->conn->err = ERR_MEM;
         break;
      }
      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
      break;
   case NETCONN_UDPNOCHKSUM:
      msg->conn->pcb.udp = udp_new();
      if(msg->conn->pcb.udp == NULL) {
         msg->conn->err = ERR_MEM;
         break;
      }
      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
      break;
   case NETCONN_UDP:
      msg->conn->pcb.udp = udp_new();
      if(msg->conn->pcb.udp == NULL) {
         msg->conn->err = ERR_MEM;
         break;
      }
      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
      break;
#endif /* LWIP_UDP */
#if LWIP_TCP
   case NETCONN_TCP:
      msg->conn->pcb.tcp = tcp_new();
      if(msg->conn->pcb.tcp == NULL) {
         msg->conn->err = ERR_MEM;
         break;
      }
      setup_tcp(msg->conn);
      break;
#endif
   }
   
  
  sys_mbox_post(msg->conn->mbox, NULL);
}
예제 #30
-1
/**
 * Receive callback function for RAW netconns.
 * Doesn't 'eat' the packet, only references it and sends it to
 * conn->recvmbox
 *
 * @see raw.h (struct raw_pcb.recv) for parameters and return value
 */
static u8_t
recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
    struct ip_addr *addr)
{
  struct pbuf *q;
  struct netbuf *buf;
  struct netconn *conn;
#if LWIP_SO_RCVBUF
  int recv_avail;
#endif /* LWIP_SO_RCVBUF */

  LWIP_UNUSED_ARG(addr);
  conn = arg;

#if LWIP_SO_RCVBUF
  SYS_ARCH_GET(conn->recv_avail, recv_avail);
  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) &&
      ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) {
#else  /* LWIP_SO_RCVBUF */
  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) {
#endif /* LWIP_SO_RCVBUF */
    /* copy the whole packet into new pbufs */
    q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
    if(q != NULL) {
      if (pbuf_copy(q, p) != ERR_OK) {
        pbuf_free(q);
        q = NULL;
      }
    }

    if(q != NULL) {
      buf = memp_malloc(MEMP_NETBUF);
      if (buf == NULL) {
        pbuf_free(q);
        return 0;
      }

      buf->p = q;
      buf->ptr = q;
      buf->addr = &(((struct ip_hdr*)(q->payload))->src);
      buf->port = pcb->protocol;

      if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
        netbuf_delete(buf);
        return 0;
      } else {
        SYS_ARCH_INC(conn->recv_avail, q->tot_len);
        /* Register event with callback */
        API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);
      }
    }
  }

  return 0; /* do not eat the packet */
}
#endif /* LWIP_RAW*/

#if LWIP_UDP
/**
 * Receive callback function for UDP netconns.
 * Posts the packet to conn->recvmbox or deletes it on memory error.
 *
 * @see udp.h (struct udp_pcb.recv) for parameters
 */
static void
recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
   struct ip_addr *addr, u16_t port)
{
  struct netbuf *buf;
  struct netconn *conn;
#if LWIP_SO_RCVBUF
  int recv_avail;
#endif /* LWIP_SO_RCVBUF */

  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
  LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
  LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
  conn = arg;
  LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);

#if LWIP_SO_RCVBUF
  SYS_ARCH_GET(conn->recv_avail, recv_avail);
  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) ||
      ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
#else  /* LWIP_SO_RCVBUF */
  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
#endif /* LWIP_SO_RCVBUF */
    pbuf_free(p);
    return;
  }

  buf = memp_malloc(MEMP_NETBUF);
  if (buf == NULL) {
    pbuf_free(p);
    return;
  } else {
    buf->p = p;
    buf->ptr = p;
    buf->addr = addr;
    buf->port = port;
#if LWIP_NETBUF_RECVINFO
    {
      const struct ip_hdr* iphdr = ip_current_header();
      /* get the UDP header - always in the first pbuf, ensured by udp_input */
      const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
      buf->toaddr = (struct ip_addr*)&iphdr->dest;
      buf->toport = udphdr->dest;
    }
#endif /* LWIP_NETBUF_RECVINFO */
  }

  if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
    netbuf_delete(buf);
    return;
  } else {
    SYS_ARCH_INC(conn->recv_avail, p->tot_len);
    /* Register event with callback */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
  }
}
#endif /* LWIP_UDP */

#if LWIP_TCP
/**
 * Receive callback function for TCP netconns.
 * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
 *
 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
 */
static err_t
recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
  struct netconn *conn;
  u16_t len;

  LWIP_UNUSED_ARG(pcb);
  LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
  LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
  conn = arg;
  LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);

  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
    return ERR_VAL;
  }

  conn->err = err;
  if (p != NULL) {
    len = p->tot_len;
    SYS_ARCH_INC(conn->recv_avail, len);
  } else {
    len = 0;
  }

  if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {
    return ERR_MEM;
  } else {
    /* Register event with callback */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
  }

  return ERR_OK;
}

/**
 * Poll callback function for TCP netconns.
 * Wakes up an application thread that waits for a connection to close
 * or data to be sent. The application thread then takes the
 * appropriate action to go on.
 *
 * Signals the conn->sem.
 * netconn_close waits for conn->sem if closing failed.
 *
 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
 */
static err_t
poll_tcp(void *arg, struct tcp_pcb *pcb)
{
  struct netconn *conn = arg;

  LWIP_UNUSED_ARG(pcb);
  LWIP_ASSERT("conn != NULL", (conn != NULL));

  if (conn->state == NETCONN_WRITE) {
    do_writemore(conn);
  } else if (conn->state == NETCONN_CLOSE) {
    do_close_internal(conn);
  }

  return ERR_OK;
}

/**
 * Sent callback function for TCP netconns.
 * Signals the conn->sem and calls API_EVENT.
 * netconn_write waits for conn->sem if send buffer is low.
 *
 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
 */
static err_t
sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
{
  struct netconn *conn = arg;

  LWIP_UNUSED_ARG(pcb);
  LWIP_ASSERT("conn != NULL", (conn != NULL));

  if (conn->state == NETCONN_WRITE) {
    LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
    do_writemore(conn);
  } else if (conn->state == NETCONN_CLOSE) {
    do_close_internal(conn);
  }

  if (conn) {
    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) {
      API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
    }
  }
  
  return ERR_OK;
}

/**
 * Error callback function for TCP netconns.
 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
 * The application thread has then to decide what to do.
 *
 * @see tcp.h (struct tcp_pcb.err) for parameters
 */
static void
err_tcp(void *arg, err_t err)
{
  struct netconn *conn;

  conn = arg;
  LWIP_ASSERT("conn != NULL", (conn != NULL));

  conn->pcb.tcp = NULL;

  conn->err = err;
  if (conn->recvmbox != SYS_MBOX_NULL) {
    /* Register event with callback */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
    sys_mbox_post(conn->recvmbox, NULL);
  }
  if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) {
    conn->state = NETCONN_NONE;
    sys_sem_signal(conn->op_completed);
  }
  if (conn->acceptmbox != SYS_MBOX_NULL) {
    /* Register event with callback */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
    sys_mbox_post(conn->acceptmbox, NULL);
  }
  if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {
    /* calling do_writemore/do_close_internal is not necessary
       since the pcb has already been deleted! */
    conn->state = NETCONN_NONE;
    /* wake up the waiting task */
    sys_sem_signal(conn->op_completed);
  }
}

/**
 * Setup a tcp_pcb with the correct callback function pointers
 * and their arguments.
 *
 * @param conn the TCP netconn to setup
 */
static void
setup_tcp(struct netconn *conn)
{
  struct tcp_pcb *pcb;

  pcb = conn->pcb.tcp;
  tcp_arg(pcb, conn);
  tcp_recv(pcb, recv_tcp);
  tcp_sent(pcb, sent_tcp);
  tcp_poll(pcb, poll_tcp, 4);
  tcp_err(pcb, err_tcp);
}

/**
 * Accept callback function for TCP netconns.
 * Allocates a new netconn and posts that to conn->acceptmbox.
 *
 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
 */
static err_t
accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
{
  struct netconn *newconn;
  struct netconn *conn;

#if API_MSG_DEBUG
#if TCP_DEBUG
  tcp_debug_print_state(newpcb->state);
#endif /* TCP_DEBUG */
#endif /* API_MSG_DEBUG */
  conn = (struct netconn *)arg;

  LWIP_ERROR("accept_function: invalid conn->acceptmbox",
             conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;);

  /* We have to set the callback here even though
   * the new socket is unknown. conn->socket is marked as -1. */
  newconn = netconn_alloc(conn->type, conn->callback);
  if (newconn == NULL) {
    return ERR_MEM;
  }
  newconn->pcb.tcp = newpcb;
  setup_tcp(newconn);
  newconn->err = err;

  if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
    /* When returning != ERR_OK, the connection is aborted in tcp_process(),
       so do nothing here! */
    newconn->pcb.tcp = NULL;
    netconn_free(newconn);
    return ERR_MEM;
  } else {
    /* Register event with callback */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
  }

  return ERR_OK;
}
#endif /* LWIP_TCP */

/**
 * Create a new pcb of a specific type.
 * Called from do_newconn().
 *
 * @param msg the api_msg_msg describing the connection type
 * @return msg->conn->err, but the return value is currently ignored
 */
static err_t
pcb_new(struct api_msg_msg *msg)
{
   msg->conn->err = ERR_OK;

   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);

   /* Allocate a PCB for this connection */
   switch(NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
   case NETCONN_RAW:
     msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
     if(msg->conn->pcb.raw == NULL) {
       msg->conn->err = ERR_MEM;
       break;
     }
     raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
     break;
#endif /* LWIP_RAW */
#if LWIP_UDP
   case NETCONN_UDP:
     msg->conn->pcb.udp = udp_new();
     if(msg->conn->pcb.udp == NULL) {
       msg->conn->err = ERR_MEM;
       break;
     }
#if LWIP_UDPLITE
     if (msg->conn->type==NETCONN_UDPLITE) {
       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
     }
#endif /* LWIP_UDPLITE */
     if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
     }
     udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
     break;
#endif /* LWIP_UDP */
#if LWIP_TCP
   case NETCONN_TCP:
     msg->conn->pcb.tcp = tcp_new();
     if(msg->conn->pcb.tcp == NULL) {
       msg->conn->err = ERR_MEM;
       break;
     }
     setup_tcp(msg->conn);
     break;
#endif /* LWIP_TCP */
   default:
     /* Unsupported netconn type, e.g. protocol disabled */
     msg->conn->err = ERR_VAL;
     break;
   }

  return msg->conn->err;
}