static err_t test_tcp_netif_output(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) { struct test_tcp_txcounters *txcounters = (struct test_tcp_txcounters*)netif->state; LWIP_UNUSED_ARG(ipaddr); if (txcounters != NULL) { txcounters->num_tx_calls++; txcounters->num_tx_bytes += p->tot_len; if (txcounters->copy_tx_packets) { struct pbuf *p_copy = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); err_t err; EXPECT(p_copy != NULL); err = pbuf_copy(p_copy, p); EXPECT(err == ERR_OK); if (txcounters->tx_packets == NULL) { txcounters->tx_packets = p_copy; } else { pbuf_cat(txcounters->tx_packets, p_copy); } } } return ERR_OK; }
/* * We have failed to authenticate ourselves to the peer using `protocol'. */ void auth_withpeer_fail(int unit, u16_t protocol) { int errCode = PPPERR_AUTHFAIL; LWIP_UNUSED_ARG(protocol); AUTHDEBUG((LOG_INFO, "auth_withpeer_fail: %d proto=%X\n", unit, protocol)); if (passwd_from_file) { BZERO(ppp_settings.passwd, MAXSECRETLEN); } /* * XXX Warning: the unit number indicates the interface which is * not necessarily the PPP connection. It works here as long * as we are only supporting PPP interfaces. */ pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode); /* * We've failed to authenticate ourselves to our peer. * He'll probably take the link down, and there's not much * we can do except wait for that. */ }
/** * Set the state of the connection to be LISTEN, which means that it * is able to accept incoming connections. The protocol control block * is reallocated in order to consume less memory. Setting the * connection to LISTEN is an irreversible process. * * @param pcb the original tcp_pcb * @param backlog the incoming connections queue limit * @return tcp_pcb used for listening, consumes less memory. * * @note The original tcp_pcb is freed. This function therefore has to be * called like this: * tpcb = tcp_listen(tpcb); */ struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) { struct tcp_pcb_listen *lpcb; LWIP_UNUSED_ARG(backlog); LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL); /* already listening? */ if (pcb->state == LISTEN) { return pcb; } lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN); if (lpcb == NULL) { return NULL; } lpcb->callback_arg = pcb->callback_arg; lpcb->local_port = pcb->local_port; lpcb->state = LISTEN; lpcb->so_options = pcb->so_options; lpcb->so_options |= SOF_ACCEPTCONN; lpcb->ttl = pcb->ttl; lpcb->tos = pcb->tos; ip_addr_set(&lpcb->local_ip, &pcb->local_ip); TCP_RMV(&tcp_bound_pcbs, pcb); memp_free(MEMP_TCP_PCB, pcb); #if LWIP_CALLBACK_API lpcb->accept = tcp_accept_null; #endif /* LWIP_CALLBACK_API */ #if TCP_LISTEN_BACKLOG lpcb->accepts_pending = 0; lpcb->backlog = (backlog ? backlog : 1); #endif /* TCP_LISTEN_BACKLOG */ TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb); return (struct tcp_pcb *)lpcb; }
static void sensorentry_get_object_def_a(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od) { LWIP_UNUSED_ARG(rid); /* return to object name, adding index depth (1) */ ident_len += 1; ident -= 1; if (ident_len == 2) { od->id_inst_len = ident_len; od->id_inst_ptr = ident; od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("sensorentry_get_object_def_a: no scalar\n")); od->instance = MIB_OBJECT_NONE; } }
/** * Retry: send a new request (and increase retry timeout). * * @param arg is unused (only necessary to conform to sys_timeout) */ static void sntp_retry(void* arg) { LWIP_UNUSED_ARG(arg); LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n", sntp_retry_timeout)); /* set up a timer to send a retry and increase the retry delay */ sys_timeout(sntp_retry_timeout, sntp_request, NULL); #if SNTP_RETRY_TIMEOUT_EXP { u32_t new_retry_timeout; /* increase the timeout for next retry */ new_retry_timeout = sntp_retry_timeout << 1; /* limit to maximum timeout and prevent overflow */ if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) && (new_retry_timeout > sntp_retry_timeout)) { sntp_retry_timeout = new_retry_timeout; } } #endif /* SNTP_RETRY_TIMEOUT_EXP */ }
/** * Finds (stable) ethernet/IP address pair from ARP table * using interface and IP address index. * @note the addresses in the ARP table are in network order! * * @param netif points to interface index * @param ipaddr points to the (network order) IP address index * @param eth_ret points to return pointer * @param ip_ret points to return pointer * @return table index if found, -1 otherwise */ s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr **eth_ret, ip_addr_t **ip_ret) { s8_t i; LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL", eth_ret != NULL && ip_ret != NULL); LWIP_UNUSED_ARG(netif); ARP_LOCK(); i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) { *eth_ret = &arp_table[i].ethaddr; *ip_ret = &arp_table[i].ipaddr; ARP_UNLOCK(); return i; } ARP_UNLOCK(); return -1; }
static void tftp_tmr(void* arg) { LWIP_UNUSED_ARG(arg); tftp_state.timer++; if (tftp_state.handle == NULL) { return; } sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL); if ((tftp_state.timer - tftp_state.last_pkt) > (TFTP_TIMEOUT_MSECS / TFTP_TIMER_MSECS)) { if ((tftp_state.last_data != NULL) && (tftp_state.retries < TFTP_MAX_RETRIES)) { LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout, retrying\n")); resend_data(); tftp_state.retries++; } else { LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout\n")); close_handle(); } } }
/* This function initializes this lwIP test. When NO_SYS=1, this is done in * the main_loop context (there is no other one), when NO_SYS=0, this is done * in the tcpip_thread context */ static void test_init(void * arg) { /* remove compiler warning */ #if NO_SYS LWIP_UNUSED_ARG(arg); #else /* NO_SYS */ sys_sem_t *init_sem; LWIP_ASSERT("arg != NULL", arg != NULL); init_sem = (sys_sem_t*)arg; #endif /* NO_SYS */ /* init randomizer again (seed per thread) */ srand((unsigned int)time(0)); /* init network interfaces */ msvc_netif_init(); /* init apps */ apps_init(); #if !NO_SYS sys_sem_signal(init_sem); #endif /* !NO_SYS */ }
END_TEST START_TEST(test_sockets_select) { #if LWIP_SOCKET_SELECT int s; int ret; fd_set readset; fd_set writeset; fd_set errset; struct timeval tv; fail_unless(test_sockets_get_used_count() == 0); s = lwip_socket(AF_INET, SOCK_STREAM, 0); fail_unless(s >= 0); fail_unless(test_sockets_get_used_count() == 0); FD_ZERO(&readset); FD_SET(s, &readset); FD_ZERO(&writeset); FD_SET(s, &writeset); FD_ZERO(&errset); FD_SET(s, &errset); tv.tv_sec = tv.tv_usec = 0; ret = lwip_select(s + 1, &readset, &writeset, &errset, &tv); fail_unless(ret == 0); fail_unless(test_sockets_get_used_count() == 0); ret = lwip_close(s); fail_unless(ret == 0); #endif LWIP_UNUSED_ARG(_i); }
/* lwIP UDP receive callback function */ static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { struct snmp_msg_pstat *msg_ps; u8_t req_idx; err_t err_ret; u16_t payload_len = p->tot_len; u16_t payload_ofs = 0; u16_t varbind_ofs = 0; /* suppress unused argument warning */ LWIP_UNUSED_ARG(arg); /* traverse input message process list, look for SNMP_MSG_EMPTY */ msg_ps = &msg_input_list[0]; req_idx = 0; while ((req_idx < SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY)) { req_idx++; msg_ps++; } if (req_idx == SNMP_CONCURRENT_REQUESTS) { /* exceeding number of concurrent requests */ pbuf_free(p); return; } /* accepting request */ snmp_inc_snmpinpkts(); /* record used 'protocol control block' */ msg_ps->pcb = pcb; /* source address (network order) */ msg_ps->sip = *addr; /* source port (host order (lwIP oddity)) */ msg_ps->sp = port; /* check total length, version, community, pdu type */ err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps); /* Only accept requests and requests without error (be robust) */ /* Reject response and trap headers or error requests as input! */ if ((err_ret != ERR_OK) || ((msg_ps->rt != SNMP_ASN1_PDU_GET_REQ) && (msg_ps->rt != SNMP_ASN1_PDU_GET_NEXT_REQ) && (msg_ps->rt != SNMP_ASN1_PDU_SET_REQ)) || ((msg_ps->error_status != SNMP_ES_NOERROR) || (msg_ps->error_index != 0)) ) { /* header check failed drop request silently, do not return error! */ pbuf_free(p); LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n")); return; } LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community)); /* Builds a list of variable bindings. Copy the varbinds from the pbuf chain to glue them when these are divided over two or more pbuf's. */ err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps); /* we've decoded the incoming message, release input msg now */ pbuf_free(p); if ((err_ret != ERR_OK) || (msg_ps->invb.count == 0)) { /* varbind-list decode failed, or varbind list empty. drop request silently, do not return error! (errors are only returned for a specific varbind failure) */ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n")); return; } msg_ps->error_status = SNMP_ES_NOERROR; msg_ps->error_index = 0; /* find object for each variable binding */ msg_ps->state = SNMP_MSG_SEARCH_OBJ; /* first variable binding from list to inspect */ msg_ps->vb_idx = 0; LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count)); /* handle input event and as much objects as possible in one go */ snmp_msg_event(req_idx); }
/** * Search the ARP table for a matching or new entry. * * If an IP address is given, return a pending or stable ARP entry that matches * the address. If no match is found, create a new entry with this address set, * but in state ETHARP_EMPTY. The caller must check and possibly change the * state of the returned entry. * * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY. * * In all cases, attempt to create new entries from an empty entry. If no * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle * old entries. Heuristic choose the least important entry for recycling. * * @param ipaddr IP address to find in ARP cache, or to add if not found. * @param flags See @ref etharp_state * @param netif netif related to this address (used for NETIF_HWADDRHINT) * * @return The ARP entry index that matched or is created, ERR_MEM if no * entry is found or could be recycled. */ static s8_t etharp_find_entry(const ip4_addr_t *ipaddr, u8_t flags, struct netif* netif) { s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; s8_t empty = ARP_TABLE_SIZE; u8_t i = 0; /* oldest entry with packets on queue */ s8_t old_queue = ARP_TABLE_SIZE; /* its age */ u16_t age_queue = 0, age_pending = 0, age_stable = 0; LWIP_UNUSED_ARG(netif); /** * a) do a search through the cache, remember candidates * b) select candidate entry * c) create new entry */ /* a) in a single search sweep, do all of this * 1) remember the first empty entry (if any) * 2) remember the oldest stable entry (if any) * 3) remember the oldest pending entry without queued packets (if any) * 4) remember the oldest pending entry with queued packets (if any) * 5) search for a matching IP entry, either pending or stable * until 5 matches, or all entries are searched for. */ for (i = 0; i < ARP_TABLE_SIZE; ++i) { u8_t state = arp_table[i].state; /* no empty entry found yet and now we do find one? */ if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) { LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_find_entry: found empty entry %"U16_F"\n", (u16_t)i)); /* remember first empty entry */ empty = i; } else if (state != ETHARP_STATE_EMPTY) { LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE", state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE); /* if given, does IP address match IP address in ARP entry? */ if (ipaddr && ip4_addr_cmp(ipaddr, &arp_table[i].ipaddr) #if ETHARP_TABLE_MATCH_NETIF && ((netif == NULL) || (netif == arp_table[i].netif)) #endif /* ETHARP_TABLE_MATCH_NETIF */ ) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %"U16_F"\n", (u16_t)i)); /* found exact IP address match, simply bail out */ return i; } /* pending entry? */ if (state == ETHARP_STATE_PENDING) { /* pending with queued packets? */ if (arp_table[i].q != NULL) { if (arp_table[i].ctime >= age_queue) { old_queue = i; age_queue = arp_table[i].ctime; } } else /* pending without queued packets? */ { if (arp_table[i].ctime >= age_pending) { old_pending = i; age_pending = arp_table[i].ctime; } } /* stable entry? */ } else if (state >= ETHARP_STATE_STABLE) { #if ETHARP_SUPPORT_STATIC_ENTRIES /* don't record old_stable for static entries since they never expire */ if (state < ETHARP_STATE_STATIC) #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ { /* remember entry with oldest stable entry in oldest, its age in maxtime */ if (arp_table[i].ctime >= age_stable) { old_stable = i; age_stable = arp_table[i].ctime; } } } } } /* { we have no match } => try to create a new entry */ /* don't create new entry, only search? */ if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) || /* or no empty entry found and not allowed to recycle? */ ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty entry found and not allowed to recycle\n")); return (s8_t)ERR_MEM; } /* b) choose the least destructive entry to recycle: * 1) empty entry * 2) oldest stable entry * 3) oldest pending entry without queued packets * 4) oldest pending entry with queued packets * * { ETHARP_FLAG_TRY_HARD is set at this point } */ /* 1) empty entry available? */ if (empty < ARP_TABLE_SIZE) { i = empty; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); } else { /* 2) found recyclable stable entry? */ if (old_stable < ARP_TABLE_SIZE) { /* recycle oldest stable*/ i = old_stable; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); /* no queued packets should exist on stable entries */ LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); /* 3) found recyclable pending entry without queued packets? */ } else if (old_pending < ARP_TABLE_SIZE) { /* recycle oldest pending */ i = old_pending; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); /* 4) found recyclable pending entry with queued packets? */ } else if (old_queue < ARP_TABLE_SIZE) { /* recycle oldest pending (queued packets are free in etharp_free_entry) */ i = old_queue; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); /* no empty or recyclable entries found */ } else { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n")); return (s8_t)ERR_MEM; } /* { empty or recyclable entry found } */ LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); etharp_free_entry(i); } LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY", arp_table[i].state == ETHARP_STATE_EMPTY); /* IP address given? */ if (ipaddr != NULL) { /* set IP address */ ip4_addr_copy(arp_table[i].ipaddr, *ipaddr); } arp_table[i].ctime = 0; #if ETHARP_TABLE_MATCH_NETIF arp_table[i].netif = netif; #endif /* ETHARP_TABLE_MATCH_NETIF*/ return (err_t)i; }
/****************************************************************************** * FunctionName : espconn_tcp_accept * Description : A new incoming connection has been accepted. * Parameters : arg -- Additional argument to pass to the callback function * pcb -- The connection pcb which is accepted * err -- An unused error code, always ERR_OK currently * Returns : acception result *******************************************************************************/ static err_t ICACHE_FLASH_ATTR espconn_tcp_accept(void *arg, struct tcp_pcb *pcb, err_t err) { struct espconn *espconn = arg; espconn_msg *paccept = NULL; remot_info *pinfo = NULL; LWIP_UNUSED_ARG(err); if (!espconn || !espconn->proto.tcp) { return ERR_ARG; } tcp_arg(pcb, paccept); tcp_err(pcb, esponn_server_err); /*Ensure the active connection is less than the count of active connections on the server*/ espconn_get_connection_info(espconn, &pinfo , 0); espconn_printf("espconn_tcp_accept link_cnt: %d\n", espconn->link_cnt); if (espconn->link_cnt == espconn_tcp_get_max_con_allow(espconn)) return ERR_ISCONN; /*Creates a new active connect control message*/ paccept = (espconn_msg *)malloc(sizeof(espconn_msg)); memset(paccept, 0, sizeof(espconn_msg)); tcp_arg(pcb, paccept); if (paccept == NULL) return ERR_MEM; /*Insert the node to the active connection list*/ espconn_list_creat(&plink_active, paccept); paccept->preverse = espconn; paccept->pespconn = (struct espconn *)malloc(sizeof(struct espconn)); if (paccept->pespconn == NULL) return ERR_MEM; paccept->pespconn->proto.tcp = (esp_tcp *)malloc(sizeof(esp_tcp)); if (paccept->pespconn->proto.tcp == NULL) return ERR_MEM; /*Reserve the remote information for current active connection*/ paccept->pcommon.pcb = pcb; paccept->pcommon.remote_port = pcb->remote_port; paccept->pcommon.remote_ip[0] = ip4_addr1_16(&pcb->remote_ip.u_addr.ip4); paccept->pcommon.remote_ip[1] = ip4_addr2_16(&pcb->remote_ip.u_addr.ip4); paccept->pcommon.remote_ip[2] = ip4_addr3_16(&pcb->remote_ip.u_addr.ip4); paccept->pcommon.remote_ip[3] = ip4_addr4_16(&pcb->remote_ip.u_addr.ip4); paccept->pcommon.write_flag = true; memcpy(espconn->proto.tcp->remote_ip, paccept->pcommon.remote_ip, 4); espconn->proto.tcp->remote_port = pcb->remote_port; espconn->state = ESPCONN_CONNECT; espconn_copy_partial(paccept->pespconn, espconn); /*Set the specify function that should be called * when TCP data has been successfully delivered, * when active connection receives data, * or periodically from active connection*/ tcp_sent(pcb, espconn_server_sent); tcp_recv(pcb, espconn_server_recv); tcp_poll(pcb, espconn_server_poll, 8); /* every 1 seconds */ /*Disable Nagle algorithm default*/ tcp_nagle_disable(pcb); /*Default set the total number of espconn_buf on the unsent lists for one*/ espconn_tcp_set_buf_count(paccept->pespconn, 1); if (paccept->pespconn->proto.tcp->connect_callback != NULL) { paccept->pespconn->proto.tcp->connect_callback(paccept->pespconn); } /*Enable keep alive option*/ if (espconn_keepalive_disabled(paccept)) espconn_keepalive_enable(pcb); return ERR_OK; }
enum pcapifh_link_event pcapifh_linkstate_get(struct pcapifh_linkstate* state) { LWIP_UNUSED_ARG(state); LWIP_ASSERT("not implemented", 0); return LINKEVENT_UNKNOWN; }
/** * RTP recv thread */ static void rtp_recv_thread(void *arg) { int sock; struct sockaddr_in local; struct sockaddr_in from; int fromlen; struct ip_mreq ipmreq; struct rtp_hdr* rtphdr; u32_t rtp_stream_address; int timeout; size_t result; int recvrtppackets = 0; int lostrtppackets = 0; u16_t lastrtpseq = 0; LWIP_UNUSED_ARG(arg); /* initialize RTP stream address */ rtp_stream_address = RTP_STREAM_ADDRESS; /* if we got a valid RTP stream address... */ if (rtp_stream_address != 0) { /* create new socket */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock >= 0) { /* prepare local address */ memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_port = PP_HTONS(RTP_STREAM_PORT); local.sin_addr.s_addr = PP_HTONL(INADDR_ANY); /* bind to local address */ if (bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) { /* set recv timeout */ timeout = RTP_RECV_TIMEOUT; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); /* prepare multicast "ip_mreq" struct */ ipmreq.imr_multiaddr.s_addr = rtp_stream_address; ipmreq.imr_interface.s_addr = PP_HTONL(INADDR_ANY); /* join multicast group */ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipmreq, sizeof(ipmreq)) == 0) { /* receive RTP packets */ while(1) { fromlen = sizeof(from); result = recvfrom(sock, rtp_recv_packet, sizeof(rtp_recv_packet), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen); if (result >= sizeof(struct rtp_hdr)) { rtphdr = (struct rtp_hdr *)rtp_recv_packet; recvrtppackets++; if ((lastrtpseq == 0) || ((lastrtpseq + 1) == lwip_ntohs(rtphdr->seqNum))) { RTP_RECV_PROCESSING((rtp_recv_packet + sizeof(rtp_hdr)),(result-sizeof(rtp_hdr))); } else { lostrtppackets++; } lastrtpseq = lwip_ntohs(rtphdr->seqNum); if ((recvrtppackets % RTP_RECV_STATS) == 0) { LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: recv %6i packet(s) / lost %4i packet(s) (%.4f%%)...\n", recvrtppackets, lostrtppackets, (lostrtppackets*100.0)/recvrtppackets)); } } else { LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: recv timeout...\n")); } } /* leave multicast group */ setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &ipmreq, sizeof(ipmreq)); } } /* close the socket */ closesocket(sock); } } }
static int pxudp_pmgr_pump(struct pollmgr_handler *handler, SOCKET fd, int revents) { struct pxudp *pxudp; struct pbuf *p; ssize_t nread; err_t error; pxudp = (struct pxudp *)handler->data; LWIP_ASSERT1(handler == &pxudp->pmhdl); LWIP_ASSERT1(fd == pxudp->sock); LWIP_UNUSED_ARG(fd); if (revents & ~(POLLIN|POLLERR)) { DPRINTF(("%s: unexpected revents 0x%x\n", __func__, revents)); return pxudp_schedule_delete(pxudp); } /* * XXX: AFAICS, there's no way to match the error with the * outgoing datagram that triggered it, since we do non-blocking * sends from lwip thread. */ if (revents & POLLERR) { int sockerr = -1; socklen_t optlen = (socklen_t)sizeof(sockerr); int status; status = getsockopt(pxudp->sock, SOL_SOCKET, SO_ERROR, (char *)&sockerr, &optlen); if (status < 0) { DPRINTF(("%s: sock %d: SO_ERROR failed:%R[sockerr]\n", __func__, pxudp->sock, SOCKERRNO())); } else { DPRINTF(("%s: sock %d: %R[sockerr]\n", __func__, pxudp->sock, sockerr)); } } if ((revents & POLLIN) == 0) { return POLLIN; } nread = recv(pxudp->sock, pollmgr_udpbuf, sizeof(pollmgr_udpbuf), 0); if (nread == SOCKET_ERROR) { DPRINTF(("%s: %R[sockerr]\n", __func__, SOCKERRNO())); return POLLIN; } p = pbuf_alloc(PBUF_RAW, (u16_t)nread, PBUF_RAM); if (p == NULL) { DPRINTF(("%s: pbuf_alloc(%d) failed\n", __func__, (int)nread)); return POLLIN; } error = pbuf_take(p, pollmgr_udpbuf, (u16_t)nread); if (error != ERR_OK) { DPRINTF(("%s: pbuf_take(%d) failed\n", __func__, (int)nread)); pbuf_free(p); return POLLIN; } error = sys_mbox_trypost(&pxudp->inmbox, p); if (error != ERR_OK) { pbuf_free(p); return POLLIN; } proxy_lwip_post(&pxudp->msg_inbound); return POLLIN; }
/** * 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); }
static void pxudp_pcb_forward_outbound(struct pxudp *pxudp, struct pbuf *p, ip_addr_t *addr, u16_t port) { int status; LWIP_UNUSED_ARG(addr); LWIP_UNUSED_ARG(port); if (!pxudp->is_mapped && pxudp_ttl_expired(p)) { return; } if (!ip_current_is_v6()) { /* IPv4 */ const struct ip_hdr *iph = ip_current_header(); int ttl, tos, df; /* * Different OSes have different socket options for DF. * Unlike pxping.c, we can't use IP_HDRINCL here as it's only * valid for SOCK_RAW. */ # define USE_DF_OPTION(_Optname) \ const int dfopt = _Optname; \ const char * const dfoptname = #_Optname; #if defined(IP_MTU_DISCOVER) /* Linux */ USE_DF_OPTION(IP_MTU_DISCOVER); #elif defined(IP_DONTFRAG) /* Solaris 11+, FreeBSD */ USE_DF_OPTION(IP_DONTFRAG); #elif defined(IP_DONTFRAGMENT) /* Windows */ USE_DF_OPTION(IP_DONTFRAGMENT); #else USE_DF_OPTION(0); #endif ttl = IPH_TTL(iph); if (!pxudp->is_mapped) { LWIP_ASSERT1(ttl > 1); --ttl; } if (ttl != pxudp->ttl) { status = setsockopt(pxudp->sock, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl)); if (RT_LIKELY(status == 0)) { pxudp->ttl = ttl; } else { DPRINTF(("IP_TTL: %R[sockerr]\n", SOCKERRNO())); } } tos = IPH_TOS(iph); if (tos != pxudp->tos) { status = setsockopt(pxudp->sock, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(tos)); if (RT_LIKELY(status == 0)) { pxudp->tos = tos; } else { DPRINTF(("IP_TOS: %R[sockerr]\n", SOCKERRNO())); } } if (dfopt) { df = (IPH_OFFSET(iph) & PP_HTONS(IP_DF)) != 0; #if defined(IP_MTU_DISCOVER) df = df ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; #endif if (df != pxudp->df) { status = setsockopt(pxudp->sock, IPPROTO_IP, dfopt, (char *)&df, sizeof(df)); if (RT_LIKELY(status == 0)) { pxudp->df = df; } else { DPRINTF(("%s: %R[sockerr]\n", dfoptname, SOCKERRNO())); } } } } else { /* IPv6 */ const struct ip6_hdr *iph = ip6_current_header(); int ttl; ttl = IP6H_HOPLIM(iph); if (!pxudp->is_mapped) { LWIP_ASSERT1(ttl > 1); --ttl; } if (ttl != pxudp->ttl) { status = setsockopt(pxudp->sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *)&ttl, sizeof(ttl)); if (RT_LIKELY(status == 0)) { pxudp->ttl = ttl; } else { DPRINTF(("IPV6_UNICAST_HOPS: %R[sockerr]\n", SOCKERRNO())); } } } if (pxudp->pcb->local_port == 53) { ++pxudp->count; } proxy_sendto(pxudp->sock, p, NULL, 0); pbuf_free(p); }
/** * Process an incoming UDP datagram. * * Given an incoming UDP datagram (as a chain of pbufs) this function * finds a corresponding UDP PCB and hands over the pbuf to the pcbs * recv function. If no pcb is found or the datagram is incorrect, the * pbuf is freed. * * @param p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header) * @param inp network interface on which the datagram was received. * */ void udp_input(struct pbuf *p, struct netif *inp) { struct udp_hdr *udphdr; struct udp_pcb *pcb, *prev; struct udp_pcb *uncon_pcb; u16_t src, dest; u8_t broadcast; u8_t for_us = 0; LWIP_UNUSED_ARG(inp); PERF_START; UDP_STATS_INC(udp.recv); /* Check minimum length (UDP header) */ if (p->len < UDP_HLEN) { /* drop short packets */ LWIP_DEBUGF(UDP_DEBUG, ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); UDP_STATS_INC(udp.lenerr); UDP_STATS_INC(udp.drop); MIB2_STATS_INC(mib2.udpinerrors); pbuf_free(p); goto end; } udphdr = (struct udp_hdr *)p->payload; /* is broadcast packet ? */ broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); /* convert src and dest ports to host byte order */ src = lwip_ntohs(udphdr->src); dest = lwip_ntohs(udphdr->dest); udp_debug_print(udphdr); /* print the UDP source and destination */ LWIP_DEBUGF(UDP_DEBUG, ("udp (")); ip_addr_debug_print(UDP_DEBUG, ip_current_dest_addr()); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", lwip_ntohs(udphdr->dest))); ip_addr_debug_print(UDP_DEBUG, ip_current_src_addr()); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", lwip_ntohs(udphdr->src))); pcb = NULL; prev = NULL; uncon_pcb = NULL; /* Iterate through the UDP pcb list for a matching pcb. * 'Perfect match' pcbs (connected to the remote port & ip address) are * preferred. If no perfect match is found, the first unconnected pcb that * matches the local port and ip address gets the datagram. */ for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { /* print the PCB local and remote address */ LWIP_DEBUGF(UDP_DEBUG, ("pcb (")); ip_addr_debug_print(UDP_DEBUG, &pcb->local_ip); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port)); ip_addr_debug_print(UDP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ if ((pcb->local_port == dest) && (udp_input_local_match(pcb, inp, broadcast) != 0)) { if (((pcb->flags & UDP_FLAGS_CONNECTED) == 0) && ((uncon_pcb == NULL) #if SO_REUSE /* prefer specific IPs over cath-all */ || !ip_addr_isany(&pcb->local_ip) #endif /* SO_REUSE */ )) { /* the first unconnected matching PCB */ uncon_pcb = pcb; } /* compare PCB remote addr+port to UDP source addr+port */ if ((pcb->remote_port == src) && (ip_addr_isany_val(pcb->remote_ip) || ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { /* the first fully matching PCB */ if (prev != NULL) { /* move the pcb to the front of udp_pcbs so that is found faster next time */ prev->next = pcb->next; pcb->next = udp_pcbs; udp_pcbs = pcb; } else { UDP_STATS_INC(udp.cachehit); } break; } } prev = pcb; } /* no fully matching pcb found? then look for an unconnected pcb */ if (pcb == NULL) { pcb = uncon_pcb; } /* Check checksum if this is a match or if it was directed at us. */ if (pcb != NULL) { for_us = 1; } else { #if LWIP_IPV6 if (ip_current_is_v6()) { for_us = netif_get_ip6_addr_match(inp, ip6_current_dest_addr()) >= 0; } #endif /* LWIP_IPV6 */ #if LWIP_IPV4 if (!ip_current_is_v6()) { for_us = ip4_addr_cmp(netif_ip4_addr(inp), ip4_current_dest_addr()); } #endif /* LWIP_IPV4 */ } if (for_us) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); #if CHECKSUM_CHECK_UDP IF__NETIF_CHECKSUM_ENABLED(inp, CHECKSUM_CHECK_UDP) { #if LWIP_UDPLITE if (ip_current_header_proto() == IP_PROTO_UDPLITE) { /* Do the UDP Lite checksum */ u16_t chklen = lwip_ntohs(udphdr->len); if (chklen < sizeof(struct udp_hdr)) { if (chklen == 0) { /* For UDP-Lite, checksum length of 0 means checksum over the complete packet (See RFC 3828 chap. 3.1) */ chklen = p->tot_len; } else { /* At least the UDP-Lite header must be covered by the checksum! (Again, see RFC 3828 chap. 3.1) */ goto chkerr; } } if (ip_chksum_pseudo_partial(p, IP_PROTO_UDPLITE, p->tot_len, chklen, ip_current_src_addr(), ip_current_dest_addr()) != 0) { goto chkerr; } } else #endif /* LWIP_UDPLITE */ { if (udphdr->chksum != 0) { if (ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, ip_current_src_addr(), ip_current_dest_addr()) != 0) { goto chkerr; } } } } #endif /* CHECKSUM_CHECK_UDP */ if (pbuf_header(p, -UDP_HLEN)) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); UDP_STATS_INC(udp.drop); MIB2_STATS_INC(mib2.udpinerrors); pbuf_free(p); goto end; } if (pcb != NULL) { MIB2_STATS_INC(mib2.udpindatagrams); #if SO_REUSE && SO_REUSE_RXTOALL if (ip_get_option(pcb, SOF_REUSEADDR) && (broadcast || ip_addr_ismulticast(ip_current_dest_addr()))) { /* pass broadcast- or multicast packets to all multicast pcbs if SOF_REUSEADDR is set on the first match */ struct udp_pcb *mpcb; u8_t p_header_changed = 0; s16_t hdrs_len = (s16_t)(ip_current_header_tot_len() + UDP_HLEN); for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { if (mpcb != pcb) { /* compare PCB local addr+port to UDP destination addr+port */ if ((mpcb->local_port == dest) && (udp_input_local_match(mpcb, inp, broadcast) != 0)) { /* pass a copy of the packet to all local matches */ if (mpcb->recv != NULL) { struct pbuf *q; /* for that, move payload to IP header again */ if (p_header_changed == 0) { pbuf_header_force(p, hdrs_len); p_header_changed = 1; } q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if (q != NULL) { err_t err = pbuf_copy(q, p); if (err == ERR_OK) { /* move payload to UDP data */ pbuf_header(q, -hdrs_len); mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); } } } } } } if (p_header_changed) { /* and move payload to UDP data again */ pbuf_header(p, -hdrs_len); } } #endif /* SO_REUSE && SO_REUSE_RXTOALL */ /* callback */ if (pcb->recv != NULL) { /* now the recv function is responsible for freeing p */ pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); } else { /* no recv function registered? then we have to free the pbuf! */ pbuf_free(p); goto end; } } else { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); #if LWIP_ICMP || LWIP_ICMP6 /* No match was found, send ICMP destination port unreachable unless destination address was broadcast/multicast. */ if (!broadcast && !ip_addr_ismulticast(ip_current_dest_addr())) { /* move payload pointer back to ip header */ pbuf_header_force(p, ip_current_header_tot_len() + UDP_HLEN); icmp_port_unreach(ip_current_is_v6(), p); } #endif /* LWIP_ICMP || LWIP_ICMP6 */ UDP_STATS_INC(udp.proterr); UDP_STATS_INC(udp.drop); MIB2_STATS_INC(mib2.udpnoports); pbuf_free(p); } } else {
/** * Send an IP packet to be received on the same netif (loopif-like). * The pbuf is simply copied and handed back to netif->input. * In multithreaded mode, this is done directly since netif->input must put * the packet on a queue. * In callback mode, the packet is put on an internal queue and is fed to * netif->input by netif_poll(). * * @param netif the lwip network interface structure * @param p the (IP) packet to 'send' * @param ipaddr the ip address to send the packet to (not used) * @return ERR_OK if the packet has been sent * ERR_MEM if the pbuf used to copy the packet couldn't be allocated */ err_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) { struct pbuf *r; err_t err; struct pbuf *last; #if LWIP_LOOPBACK_MAX_PBUFS u8_t clen = 0; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ /* If we have a loopif, SNMP counters are adjusted for it, * if not they are adjusted for 'netif'. */ #if LWIP_SNMP #if LWIP_HAVE_LOOPIF struct netif *stats_if = &loop_netif; #else /* LWIP_HAVE_LOOPIF */ struct netif *stats_if = netif; #endif /* LWIP_HAVE_LOOPIF */ #endif /* LWIP_SNMP */ SYS_ARCH_DECL_PROTECT(lev); LWIP_UNUSED_ARG(ipaddr); /* Allocate a new pbuf */ r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); if (r == NULL) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(stats_if); return ERR_MEM; } #if LWIP_LOOPBACK_MAX_PBUFS clen = pbuf_clen(r); /* check for overflow or too many pbuf on queue */ if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { pbuf_free(r); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(stats_if); return ERR_MEM; } netif->loop_cnt_current += clen; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ /* Copy the whole pbuf queue p into the single pbuf r */ if ((err = pbuf_copy(r, p)) != ERR_OK) { pbuf_free(r); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(stats_if); return err; } /* Put the packet on a linked list which gets emptied through calling netif_poll(). */ /* let last point to the last pbuf in chain r */ for (last = r; last->next != NULL; last = last->next); SYS_ARCH_PROTECT(lev); if(netif->loop_first != NULL) { LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); netif->loop_last->next = r; netif->loop_last = last; } else { netif->loop_first = r; netif->loop_last = last; } SYS_ARCH_UNPROTECT(lev); LINK_STATS_INC(link.xmit); snmp_add_ifoutoctets(stats_if, p->tot_len); snmp_inc_ifoutucastpkts(stats_if); #if LWIP_NETIF_LOOPBACK_MULTITHREADING /* For multithreading environment, schedule a call to netif_poll */ tcpip_callback((tcpip_callback_fn)netif_poll, netif); #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ return ERR_OK; }
/** * The main lwIP thread. This thread has exclusive access to lwIP core functions * (unless access to them is not locked). Other threads communicate with this * thread using message boxes. * * It also starts all the timers to make sure they are running in the right * thread context. * * @param arg unused argument */ static void tcpip_thread(void *arg) { struct tcpip_msg *msg; LWIP_UNUSED_ARG(arg); #if IP_REASSEMBLY sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); #endif /* IP_REASSEMBLY */ #if LWIP_ARP sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); #endif /* LWIP_ARP */ #if LWIP_DHCP sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); #endif /* LWIP_DHCP */ #if LWIP_AUTOIP sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); #endif /* LWIP_AUTOIP */ #if LWIP_IGMP sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); #endif /* LWIP_IGMP */ #if LWIP_DNS sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); #endif /* LWIP_DNS */ if (tcpip_init_done != NULL) { tcpip_init_done(tcpip_init_done_arg); } LOCK_TCPIP_CORE(); while (1) { /* MAIN Loop */ sys_mbox_fetch(mbox, (void *)&msg); switch (msg->type) { #if LWIP_NETCONN case TCPIP_MSG_API: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); msg->msg.apimsg->function(&(msg->msg.apimsg->msg)); break; #endif /* LWIP_NETCONN */ case TCPIP_MSG_INPKT: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); #if LWIP_ARP if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) { ethernet_input(msg->msg.inp.p, msg->msg.inp.netif); } else #endif /* LWIP_ARP */ { ip_input(msg->msg.inp.p, msg->msg.inp.netif); } memp_free(MEMP_TCPIP_MSG_INPKT, msg); break; #if LWIP_NETIF_API case TCPIP_MSG_NETIFAPI: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg)); msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg)); break; #endif /* LWIP_NETIF_API */ case TCPIP_MSG_CALLBACK: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); msg->msg.cb.f(msg->msg.cb.ctx); memp_free(MEMP_TCPIP_MSG_API, msg); break; case TCPIP_MSG_TIMEOUT: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); memp_free(MEMP_TCPIP_MSG_API, msg); break; case TCPIP_MSG_UNTIMEOUT: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); memp_free(MEMP_TCPIP_MSG_API, msg); break; default: break; } } }
struct pcapifh_linkstate* pcapifh_linkstate_init(const char *adapter_name) { LWIP_UNUSED_ARG(adapter_name); return NULL; }
/** * Determine if in incoming IP packet is covered by a RAW PCB * and if so, pass it to a user-provided receive callback function. * * Given an incoming IP datagram (as a chain of pbufs) this function * finds a corresponding RAW PCB and calls the corresponding receive * callback function. * * @param p pbuf to be demultiplexed to a RAW PCB. * @param inp network interface on which the datagram was received. * @return - 1 if the packet has been eaten by a RAW PCB receive * callback function. The caller MAY NOT not reference the * packet any longer, and MAY NOT call pbuf_free(). * @return - 0 if packet is not eaten (pbuf is still referenced by the * caller). * */ u8_t ICACHE_FLASH_ATTR raw_input(struct pbuf *p, struct netif *inp) { struct raw_pcb *pcb, *prev; struct ip_hdr *iphdr; s16_t proto; u8_t eaten = 0; #if LWIP_IPV6 struct ip6_hdr *ip6hdr; #endif /* LWIP_IPV6 */ LWIP_UNUSED_ARG(inp); iphdr = (struct ip_hdr *)p->payload; #if LWIP_IPV6 if (IPH_V(iphdr) == 6) { ip6hdr = (struct ip6_hdr *)p->payload; proto = IP6H_NEXTH(ip6hdr); } else #endif /* LWIP_IPV6 */ { proto = IPH_PROTO(iphdr); } prev = NULL; pcb = raw_pcbs; /* loop through all raw pcbs until the packet is eaten by one */ /* this allows multiple pcbs to match against the packet by design */ while ((eaten == 0) && (pcb != NULL)) { if ((pcb->protocol == proto) && IP_PCB_IPVER_INPUT_MATCH(pcb) && (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip) || ipX_addr_cmp(PCB_ISIPV6(pcb), &(pcb->local_ip), ipX_current_dest_addr()))) { #if IP_SOF_BROADCAST_RECV /* broadcast filter? */ if ((ip_get_option(pcb, SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp)) #if LWIP_IPV6 && !PCB_ISIPV6(pcb) #endif /* LWIP_IPV6 */ ) #endif /* IP_SOF_BROADCAST_RECV */ { /* receive callback function available? */ if (pcb->recv.ip4 != NULL) { #ifndef LWIP_NOASSERT void* old_payload = p->payload; #endif /* the receive callback function did not eat the packet? */ eaten = pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr()); if (eaten != 0) { /* receive function ate the packet */ p = NULL; eaten = 1; if (prev != NULL) { /* move the pcb to the front of raw_pcbs so that is found faster next time */ prev->next = pcb->next; pcb->next = raw_pcbs; raw_pcbs = pcb; } } else { /* sanity-check that the receive callback did not alter the pbuf */ LWIP_ASSERT("raw pcb recv callback altered pbuf payload pointer without eating packet", p->payload == old_payload); } } /* no receive callback function was set for this raw PCB */ } /* drop the packet */ } prev = pcb; pcb = pcb->next; } return eaten; }
void pcapifh_linkstate_close(struct pcapifh_linkstate* state) { LWIP_UNUSED_ARG(state); LWIP_ASSERT("not implemented", 0); }
static err_t netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, ip6_addr_t* addr) { LWIP_UNUSED_ARG(addr); return netif_loop_output(netif, p); }
/** * Just a callback function for tcpip_callback() that calls pbuf_free_ooseq(). */ static void pbuf_free_ooseq_callback(void *arg) { LWIP_UNUSED_ARG(arg); pbuf_free_ooseq(); }
/** * Send an IP packet to be received on the same netif (loopif-like). * The pbuf is simply copied and handed back to netif->input. * In multithreaded mode, this is done directly since netif->input must put * the packet on a queue. * In callback mode, the packet is put on an internal queue and is fed to * netif->input by netif_poll(). * * @param netif the lwip network interface structure * @param p the (IP) packet to 'send' * @param ipaddr the ip address to send the packet to (not used) * @return ERR_OK if the packet has been sent * ERR_MEM if the pbuf used to copy the packet couldn't be allocated */ err_t netif_loop_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) { struct pbuf *r; err_t err; struct pbuf *last; #if LWIP_LOOPBACK_MAX_PBUFS u8_t clen = 0; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ SYS_ARCH_DECL_PROTECT(lev); LWIP_UNUSED_ARG(ipaddr); /* Allocate a new pbuf */ r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); if (r == NULL) { return ERR_MEM; } #if LWIP_LOOPBACK_MAX_PBUFS clen = pbuf_clen(r); /* check for overflow or too many pbuf on queue */ if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { pbuf_free(r); r = NULL; return ERR_MEM; } netif->loop_cnt_current += clen; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ /* Copy the whole pbuf queue p into the single pbuf r */ if ((err = pbuf_copy(r, p)) != ERR_OK) { pbuf_free(r); r = NULL; return err; } /* Put the packet on a linked list which gets emptied through calling netif_poll(). */ /* let last point to the last pbuf in chain r */ for (last = r; last->next != NULL; last = last->next); SYS_ARCH_PROTECT(lev); if(netif->loop_first != NULL) { LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); netif->loop_last->next = r; netif->loop_last = last; } else { netif->loop_first = r; netif->loop_last = last; } SYS_ARCH_UNPROTECT(lev); #if LWIP_NETIF_LOOPBACK_MULTITHREADING /* For multithreading environment, schedule a call to netif_poll */ tcpip_callback((void (*)(void *))(netif_poll), netif); #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ return ERR_OK; }
/* Ping using the raw ip */ static u8_t ICACHE_FLASH_ATTR ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) { struct icmp_echo_hdr *iecho = NULL; static u16_t seqno = 0; // struct ping_msg *pingmsg = (struct ping_msg*)arg; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(addr); LWIP_ASSERT("p != NULL", p != NULL); if (pbuf_header( p, -PBUF_IP_HLEN)==0) { iecho = (struct icmp_echo_hdr *)p->payload; if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)) && iecho->type == ICMP_ER) { LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); ip_addr_debug_print(PING_DEBUG, addr); LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now()-ping_time))); if (iecho->seqno != seqno){ /* do some ping result processing */ { struct ip_hdr *iphdr = NULL; char ipaddrstr[16]; ip_addr_t source_ip; sys_untimeout(ping_timeout, pingmsg); os_bzero(&source_ip, sizeof(ip_addr_t)); os_bzero(ipaddrstr, sizeof(ipaddrstr)); uint32 delay = system_relative_time(pingmsg->ping_sent); delay /= PING_COARSE; iphdr = (struct ip_hdr*)((u8*)iecho - PBUF_IP_HLEN); source_ip.addr = iphdr->src.addr; ipaddr_ntoa_r(&source_ip,ipaddrstr, sizeof(ipaddrstr)); if (pingmsg->ping_opt->recv_function == NULL){ os_printf("recv %s: byte = %d, time = %d ms, seq = %d\n",ipaddrstr, PING_DATA_SIZE, delay, ntohs(iecho->seqno)); } else { struct ping_resp pingresp; os_bzero(&pingresp, sizeof(struct ping_resp)); pingresp.bytes = PING_DATA_SIZE; pingresp.resp_time = delay; pingresp.seqno = ntohs(iecho->seqno); pingresp.ping_err = 0; pingmsg->ping_opt->recv_function(pingmsg->ping_opt,(void*) &pingresp); } } seqno = iecho->seqno; } PING_RESULT(1); pbuf_free(p); return 1; /* eat the packet */ } // } else if(iecho->type == ICMP_ECHO){ // struct pbuf *q = NULL; // os_printf("receive ping request:seq=%d\n", ntohs(iecho->seqno)); // q = pbuf_alloc(PBUF_IP, (u16_t)p->tot_len, PBUF_RAM); // if (q!=NULL) { // pbuf_copy(q, p); // iecho = (struct icmp_echo_hdr *)q->payload; // ping_prepare_er(iecho, q->tot_len); // raw_sendto(pcb, q, addr); // pbuf_free(q); // } // pbuf_free(p); // return 1; // } } return 0; /* don't eat the packet */ }
/* * check_passwd - Check the user name and passwd against the PAP secrets * file. If requested, also check against the system password database, * and login the user if OK. * * returns: * UPAP_AUTHNAK: Authentication failed. * UPAP_AUTHACK: Authentication succeeded. * In either case, msg points to an appropriate message. */ int check_passwd( int unit, char *auser, int userlen, char *apasswd, int passwdlen, char **msg, int *msglen) { #if 1 LWIP_UNUSED_ARG(unit); LWIP_UNUSED_ARG(auser); LWIP_UNUSED_ARG(userlen); LWIP_UNUSED_ARG(apasswd); LWIP_UNUSED_ARG(passwdlen); LWIP_UNUSED_ARG(msglen); *msg = (char *) 0; return UPAP_AUTHACK; /* XXX Assume all entries OK. */ #else int ret = 0; struct wordlist *addrs = NULL; char passwd[256], user[256]; char secret[MAXWORDLEN]; static u_short attempts = 0; /* * Make copies of apasswd and auser, then null-terminate them. */ BCOPY(apasswd, passwd, passwdlen); passwd[passwdlen] = '\0'; BCOPY(auser, user, userlen); user[userlen] = '\0'; *msg = (char *) 0; /* XXX Validate user name and password. */ ret = UPAP_AUTHACK; /* XXX Assume all entries OK. */ if (ret == UPAP_AUTHNAK) { if (*msg == (char *) 0) { *msg = "Login incorrect"; } *msglen = strlen(*msg); /* * Frustrate passwd stealer programs. * Allow 10 tries, but start backing off after 3 (stolen from login). * On 10'th, drop the connection. */ if (attempts++ >= 10) { AUTHDEBUG((LOG_WARNING, "%d LOGIN FAILURES BY %s\n", attempts, user)); /*ppp_panic("Excess Bad Logins");*/ } if (attempts > 3) { sys_msleep((attempts - 3) * 5); } if (addrs != NULL) { free_wordlist(addrs); } } else { attempts = 0; /* Reset count */ if (*msg == (char *) 0) { *msg = "Login ok"; } *msglen = strlen(*msg); set_allowed_addrs(unit, addrs); } BZERO(passwd, sizeof(passwd)); BZERO(secret, sizeof(secret)); return ret; #endif }
/** * 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; } }
/** * Create a non-blocking socket. Disable SIGPIPE for TCP sockets if * possible. On Linux it's not possible and should be disabled for * each send(2) individually. */ static SOCKET proxy_create_socket(int sdom, int stype) { SOCKET s; int stype_and_flags; int status; LWIP_UNUSED_ARG(status); /* depends on ifdefs */ stype_and_flags = stype; #if defined(SOCK_NONBLOCK) stype_and_flags |= SOCK_NONBLOCK; #endif /* * Disable SIGPIPE on disconnected socket. It might be easier to * forgo it and just use MSG_NOSIGNAL on each send*(2), since we * have to do it for Linux anyway, but Darwin does NOT have that * flag (but has SO_NOSIGPIPE socket option). */ #if !defined(SOCK_NOSIGPIPE) && !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) #if 0 /* XXX: Solaris has neither, the program should ignore SIGPIPE globally */ #error Need a way to disable SIGPIPE on connection oriented sockets! #endif #endif #if defined(SOCK_NOSIGPIPE) if (stype == SOCK_STREAM) { stype_and_flags |= SOCK_NOSIGPIPE; } #endif s = socket(sdom, stype_and_flags, 0); if (s == INVALID_SOCKET) { DPRINTF(("socket: %R[sockerr]\n", SOCKERRNO())); return INVALID_SOCKET; } #if defined(RT_OS_WINDOWS) { u_long mode = 1; status = ioctlsocket(s, FIONBIO, &mode); if (status == SOCKET_ERROR) { DPRINTF(("FIONBIO: %R[sockerr]\n", SOCKERRNO())); closesocket(s); return INVALID_SOCKET; } } #elif !defined(SOCK_NONBLOCK) { int sflags; sflags = fcntl(s, F_GETFL, 0); if (sflags < 0) { DPRINTF(("F_GETFL: %R[sockerr]\n", SOCKERRNO())); closesocket(s); return INVALID_SOCKET; } status = fcntl(s, F_SETFL, sflags | O_NONBLOCK); if (status < 0) { DPRINTF(("O_NONBLOCK: %R[sockerr]\n", SOCKERRNO())); closesocket(s); return INVALID_SOCKET; } } #endif #if !defined(SOCK_NOSIGPIPE) && defined(SO_NOSIGPIPE) if (stype == SOCK_STREAM) { int on = 1; const socklen_t onlen = sizeof(on); status = setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &on, onlen); if (status < 0) { DPRINTF(("SO_NOSIGPIPE: %R[sockerr]\n", SOCKERRNO())); closesocket(s); return INVALID_SOCKET; } } #endif #if defined(RT_OS_WINDOWS) /* * lwIP only holds one packet of "refused data" for us. Proxy * relies on OS socket send buffer and doesn't do its own * buffering. Unfortunately on Windows send buffer is very small * (8K by default) and is not dynamically adpated by the OS it * seems. So a single large write will fill it up and that will * make lwIP drop segments, causing guest TCP into pathologic * resend patterns. As a quick and dirty fix just bump it up. */ if (stype == SOCK_STREAM) { int sndbuf; socklen_t optlen = sizeof(sndbuf); status = getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf, &optlen); if (status == 0) { if (sndbuf < 64 * 1024) { sndbuf = 64 * 1024; status = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf, optlen); if (status != 0) { DPRINTF(("SO_SNDBUF: setsockopt: %R[sockerr]\n", SOCKERRNO())); } } } else { DPRINTF(("SO_SNDBUF: getsockopt: %R[sockerr]\n", SOCKERRNO())); } } #endif return s; }