// remove MTD_FLASHMEM to speedup routing err_t MTD_FLASHMEM Router::netif_input(pbuf *p, netif *inp) { eth_hdr* ethdr = (eth_hdr*)p->payload; if (ntohs(ethdr->type) == ETHTYPE_IP) { // move buffer pointer to start of IP header pbuf_header(p, -sizeof(eth_hdr)); ip_hdr* iphdr = (ip_hdr*)(p->payload); // needs to route? // 1. check match of source interface IP/netmask and destination IP bool route = ((iphdr->dest.addr & inp->netmask.addr) != (inp->ip_addr.addr & inp->netmask.addr)); // 2. check if not multicast or broadcast (>=224.0.0.0 up to 255.255.255.255) route = route && ((iphdr->dest.addr & 0xE0) != 0xE0); if (route) { /* debug("netif_input intf=%d len=%d id=%d prot=%d src=%s dst=%s route?=%c\r\n", inp->num, p->tot_len, IPH_ID(iphdr), IPH_PROTO(iphdr), (char const*)IPAddress(iphdr->src.addr).get_str(), (char const*)IPAddress(iphdr->dest.addr).get_str(), route?'Y':'N'); */ // find destination interface ip_addr_t ipdest; ipdest.addr = iphdr->dest.addr; netif* destIntf = ip_route(&ipdest); // decrement TTL IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); if (IPH_TTL(iphdr) > 0) { // update IP checksum if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1); else IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100)); // send the packet ip_output_if(p, NULL, IP_HDRINCL, 0, 0, 0, destIntf); } pbuf_free(p); return ERR_OK; } // restore buffer pointer to start of Ethernet header pbuf_header(p, +sizeof(eth_hdr)); } return (Router::s_prevInput[inp->num])(p, inp); }
bool IPAddress::fromString6(const char *address) { // TODO: test test test uint32_t acc = 0; // Accumulator int dots = 0, doubledots = -1; while (*address) { char c = tolower(*address++); if (isalnum(c)) { if (c >= 'a') c -= 'a' - '0' - 10; acc = acc * 16 + (c - '0'); if (acc > 0xffff) // Value out of range return false; } else if (c == ':') { if (*address == ':') { if (doubledots >= 0) // :: allowed once return false; // remember location doubledots = dots + !!acc; address++; } if (dots == 7) // too many separators return false; raw6()[dots++] = PP_HTONS(acc); acc = 0; } else // Invalid char return false; } if (doubledots == -1 && dots != 7) // Too few separators return false; raw6()[dots++] = PP_HTONS(acc); if (doubledots != -1) { for (int i = dots - doubledots - 1; i >= 0; i--) raw6()[8 - dots + doubledots + i] = raw6()[doubledots + i]; for (int i = doubledots; i < 8 - dots + doubledots; i++) raw6()[i] = 0; } setV6(); return true; }
/** * Passes a pbuf to the lwIP stack for further processing. * The packet type is determined and checked before passing. * Note: When lwIP is built with threading, this pbuf will * be enqueued to lwIP's mailbox until it gets processed * by the tcpip thread. * * @param p * the pointer to received packet data * @param netif * the lwip network interface structure for this netfrontif */ static inline void netfrontif_input(struct pbuf *p, struct netif *netif) { struct eth_hdr *ethhdr; err_t err; LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_input: %c%c: " "Received %u bytes\n", netif->name[0], netif->name[1], p->tot_len)); ethhdr = p->payload; switch (ethhdr->type) { /* IP or ARP packet? */ case PP_HTONS(ETHTYPE_IP): #if IPV6_SUPPORT case PP_HTONS(ETHTYPE_IPV6): #endif case PP_HTONS(ETHTYPE_ARP): #if PPPOE_SUPPORT case PP_HTONS(ETHTYPE_PPPOEDISC): case PP_HTONS(ETHTYPE_PPPOE): #endif /* packet will be sent to lwIP stack for processing */ /* Note: On threaded configuration packet buffer will be enqueued on * a mailbox. The lwIP thread will do the packet processing when it gets * scheduled. */ err = netif->input(p, netif); if (unlikely(err != ERR_OK)) { #ifndef CONFIG_LWIP_NOTHREADS if (err == ERR_MEM) LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_input: %c%c: ERROR %d: " "Could not post packet to lwIP thread. Packet dropped\n", netif->name[0], netif->name[1], err)); else #endif /* CONFIG_LWIP_NOTHREADS */ LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_input: %c%c: ERROR %d: " "Packet dropped\n", netif->name[0], netif->name[1], err)); pbuf_free(p); } break; default: LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_input: %c%c: ERROR: " "Dropped packet with unknown type 0x%04x\n", netif->name[0], netif->name[1], htons(ethhdr->type))); pbuf_free(p); break; } }
PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) /** * Send an IPv6 packet on the network using netif->linkoutput * The ethernet header is filled in before sending. * * @params netif the lwIP network interface on which to send the packet * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header * @params src the source MAC address to be copied into the ethernet header * @params dst the destination MAC address to be copied into the ethernet header * @return ERR_OK if the packet was sent, any other err_t on failure */ static err_t ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) { struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; LWIP_ASSERT("netif->hwaddr_len must be 6 for ethip6!", (netif->hwaddr_len == 6)); SMEMCPY(ðhdr->dest, dst, 6); SMEMCPY(ðhdr->src, src, 6); ethhdr->type = PP_HTONS(ETHTYPE_IPV6); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethip6_send: sending packet %p\n", (void *)p)); /* send the packet */ return netif->linkoutput(netif, p); }
static void ChapMS_NT( char *rchallenge, int rchallenge_len, char *secret, int secret_len, MS_ChapResponse *response) { int i; MDstruct md4Context; u_char unicodePassword[MAX_NT_PASSWORD * 2]; static int low_byte_first = -1; LWIP_UNUSED_ARG(rchallenge_len); /* Initialize the Unicode version of the secret (== password). */ /* This implicitly supports 8-bit ISO8859/1 characters. */ BZERO(unicodePassword, sizeof(unicodePassword)); for (i = 0; i < secret_len; i++) { unicodePassword[i * 2] = (u_char)secret[i]; } MDbegin(&md4Context); MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */ if (low_byte_first == -1) { low_byte_first = (PP_HTONS((unsigned short int)1) != 1); } if (low_byte_first == 0) { /* @todo: arg type - u_long* or u_int* ? */ MDreverse((unsigned int*)&md4Context); /* sfb 961105 */ } MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */ ChallengeResponse((u_char*)rchallenge, (u_char*)md4Context.buffer, response->NTResp); }
/** * Send a TCP RESET packet (empty segment with RST flag set) either to * abort a connection or to show that there is no matching local connection * for a received segment. * * Called by tcp_abort() (to abort a local connection), tcp_input() (if no * matching local pcb was found), tcp_listen_input() (if incoming segment * has ACK flag set) and tcp_process() (received segment in the wrong state) * * Since a RST segment is in most cases not sent for an active connection, * tcp_rst() has a number of arguments that are taken from a tcp_pcb for * most other segment output functions. * * The pcb is given only when its valid and from an output context. * It is used with the external_ip_output function. * * @param seqno the sequence number to use for the outgoing segment * @param ackno the acknowledge number to use for the outgoing segment * @param local_ip the local IP address to send the segment from * @param remote_ip the remote IP address to send the segment to * @param local_port the local TCP port to send the segment from * @param remote_port the remote TCP port to send the segment to */ void tcp_rst(u32_t seqno, u32_t ackno, u16_t local_port, u16_t remote_port, struct tcp_pcb *pcb) { struct pbuf *p; struct tcp_hdr *tcphdr; #if LWIP_3RD_PARTY_BUFS if (!pcb) return; #endif p = tcp_tx_pbuf_alloc(pcb, 0, PBUF_RAM); if (p == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); return; } pbuf_header(p, TCP_HLEN); LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", (p->len >= sizeof(struct tcp_hdr))); tcphdr = (struct tcp_hdr *)p->payload; tcphdr->src = htons(local_port); tcphdr->dest = htons(remote_port); tcphdr->seqno = htonl(seqno); tcphdr->ackno = htonl(ackno); TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK); tcphdr->wnd = PP_HTONS(( TCP_WND & 0xFFFF )); tcphdr->chksum = 0; tcphdr->urgp = 0; TCP_STATS_INC(tcp.xmit); /* Send output with hardcoded TTL since we have no access to the pcb */ if(pcb) pcb->ip_output(p, pcb, 0); /* external_ip_output(p, NULL, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP) */; tcp_tx_pbuf_free(pcb, p); LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); }
static void send_data(void) { u16_t *payload; int ret; if(tftp_state.last_data != NULL) { pbuf_free(tftp_state.last_data); } tftp_state.last_data = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH + TFTP_MAX_PAYLOAD_SIZE, PBUF_RAM); if(tftp_state.last_data == NULL) { return; } payload = (u16_t *) tftp_state.last_data->payload; payload[0] = PP_HTONS(TFTP_DATA); payload[1] = lwip_htons(tftp_state.blknum); ret = tftp_state.ctx->read(tftp_state.handle, &payload[2], TFTP_MAX_PAYLOAD_SIZE); if (ret < 0) { send_error(&tftp_state.addr, tftp_state.port, TFTP_ERROR_ACCESS_VIOLATION, "Error occured while reading the file."); close_handle(); return; } pbuf_realloc(tftp_state.last_data, (u16_t)(TFTP_HEADER_LENGTH + ret)); resend_data(); }
/** * RTP send thread */ static void rtp_send_thread(void *arg) { int sock; struct sockaddr_in local; struct sockaddr_in to; u32_t rtp_stream_address; 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(INADDR_ANY); local.sin_addr.s_addr = PP_HTONL(INADDR_ANY); /* bind to local address */ if (bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) { /* prepare RTP stream address */ memset(&to, 0, sizeof(to)); to.sin_family = AF_INET; to.sin_port = PP_HTONS(RTP_STREAM_PORT); to.sin_addr.s_addr = rtp_stream_address; /* send RTP packets */ memset(rtp_send_packet, 0, sizeof(rtp_send_packet)); while (1) { rtp_send_packets( sock, &to); sys_msleep(RTP_SEND_DELAY); } } /* close the socket */ closesocket(sock); } } }
static struct pbuf* init_packet(u16_t opcode, u16_t extra, size_t size) { struct pbuf* p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + size), PBUF_RAM); u16_t* payload; if (p != NULL) { payload = (u16_t*) p->payload; payload[0] = PP_HTONS(opcode); payload[1] = lwip_htons(extra); } return p; }
/** * Send an IP packet on the network using netif->linkoutput * The ethernet header is filled in before sending. * * @params netif the lwIP network interface on which to send the packet * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header * @params src the source MAC address to be copied into the ethernet header * @params dst the destination MAC address to be copied into the ethernet header * @return ERR_OK if the packet was sent, any other err_t on failure */ static err_t etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) { struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", (netif->hwaddr_len == ETHARP_HWADDR_LEN)); ETHADDR32_COPY(ðhdr->dest, dst); ETHADDR16_COPY(ðhdr->src, src); ethhdr->type = PP_HTONS(ETHTYPE_IP); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p)); /* send the packet */ return netif->linkoutput(netif, p); }
BST_IP_ERR_T BST_IP_BsdBind( BST_FD_T fd, BST_UINT16 usPort ) { struct sockaddr_in stLocalAddr; if( !BST_IP_IsBsdFdValid(fd) ) { return BST_IP_ERR_MEM; } stLocalAddr.sin_len = BST_OS_SIZEOF(stLocalAddr); stLocalAddr.sin_family = AF_INET; stLocalAddr.sin_port = PP_HTONS( usPort ); stLocalAddr.sin_addr.s_addr = BST_IP_ADDRESS_ANY; return (BST_IP_ERR_T)lwip_bind( fd.lFd, ( struct sockaddr *)&stLocalAddr, BST_OS_SIZEOF(stLocalAddr) ); }
static void send_ack(u16_t blknum) { struct pbuf* p; u16_t* payload; p = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH, PBUF_RAM); if(p == NULL) { return; } payload = (u16_t*) p->payload; payload[0] = PP_HTONS(TFTP_ACK); payload[1] = lwip_htons(blknum); udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port); pbuf_free(p); }
static rt_err_t _low_level_dhcp_send(struct netif *netif, const void *buffer, rt_size_t size) { struct pbuf *p; struct eth_hdr *ethhdr; struct ip_hdr *iphdr; struct udp_hdr *udphdr; p = pbuf_alloc(PBUF_LINK, SIZEOF_ETH_HDR + sizeof(struct ip_hdr) + sizeof(struct udp_hdr) + size, PBUF_RAM); if (p == RT_NULL) return -RT_ENOMEM; ethhdr = (struct eth_hdr *)p->payload; iphdr = (struct ip_hdr *)((char *)ethhdr + SIZEOF_ETH_HDR); udphdr = (struct udp_hdr *)((char *)iphdr + sizeof(struct ip_hdr)); ETHADDR32_COPY(ðhdr->dest, (struct eth_addr *)ðbroadcast); ETHADDR16_COPY(ðhdr->src, netif->hwaddr); ethhdr->type = PP_HTONS(ETHTYPE_IP); iphdr->src.addr = 0x00000000; /* src: 0.0.0.0 */ iphdr->dest.addr = 0xFFFFFFFF; /* src: 255.255.255.255 */ IPH_VHL_SET(iphdr, 4, IP_HLEN / 4); IPH_TOS_SET(iphdr, 0x00); IPH_LEN_SET(iphdr, htons(IP_HLEN + sizeof(struct udp_hdr) + size)); IPH_ID_SET(iphdr, htons(2)); IPH_OFFSET_SET(iphdr, 0); IPH_TTL_SET(iphdr, 255); IPH_PROTO_SET(iphdr, IP_PROTO_UDP); IPH_CHKSUM_SET(iphdr, 0); IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); udphdr->src = htons(DHCP_SERVER_PORT); udphdr->dest = htons(DHCP_CLIENT_PORT); udphdr->len = htons(sizeof(struct udp_hdr) + size); udphdr->chksum = 0; memcpy((char *)udphdr + sizeof(struct udp_hdr), buffer, size); return netif->linkoutput(netif, p); }
void buttonConnectPressed(void* source) { struct sockaddr_in addr; int ret; ((button_t*)source)->hasBeenAcknowledged = 1; setStatus(CONNECTING); if (!isConnected) { memset(&addr, 0, sizeof(addr)); addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = PP_HTONS(SOCK_TARGET_PORT); addr.sin_addr.s_addr = inet_addr(SOCK_TARGET_HOST); socket_in = lwip_socket(AF_INET, SOCK_STREAM, 0); if ((ret = lwip_connect(socket_in, (struct sockaddr*)&addr, sizeof(addr))) == 0) { isConnected = 1; executeCommand(IDENT); executeCommand(END_IDENT); setStatus(CONNECTED); } else { isConnected = 0; setStatus(DISCONNECTED); } } else { if ((ret = lwip_close(socket_in)) == 0) { setStatus(DISCONNECTED); isConnected = 0; resetBoards(); setVersion(NULL); } } refreshBoards(); }
/* ------------------------------------------------------------------------------------------------------ * sockex_nonblocking_connect() * * Description : Handing socket receive data. * * Argument(s) : none. * */ void sockex_testrecv(void *arg) { // int ret; struct sockaddr_in servaddr, cliaddr; // struct timeval tv; unsigned long cliaddr_len; LWIP_UNUSED_ARG(arg); memset(&servaddr, 0, sizeof(servaddr)); /* set up address to connect to */ servaddr.sin_len = sizeof(servaddr); servaddr.sin_family = AF_INET; servaddr.sin_port = PP_HTONS(SOCK_HOSR_PORT); servaddr.sin_addr.s_addr = lwIPLocalIPAddrGet(); /* Set local IP address.*/ listenfd = lwip_socket(AF_INET, SOCK_STREAM, 0); lwip_bind(listenfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)); lwip_listen(listenfd, SOCK_HOSR_PORT); RS232printf("Accepting connections ...\n"); cliaddr_len = sizeof(cliaddr); for(;;) { connfd = lwip_accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); if(connfd <= 0) { OSTimeDly(2); continue; } else { connfd = connfd; RS232printf("cli is ok!"); } // lwip_select(); OSTimeDly(2); } }
static void send_error(const ip_addr_t *addr, u16_t port, enum tftp_error code, const char *str) { int str_length = strlen(str); struct pbuf* p; u16_t* payload; p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + str_length + 1), PBUF_RAM); if(p == NULL) { return; } payload = (u16_t*) p->payload; payload[0] = PP_HTONS(TFTP_ERROR); payload[1] = lwip_htons(code); MEMCPY(&payload[2], str, str_length + 1); udp_sendto(tftp_state.upcb, p, addr, port); pbuf_free(p); }
/** * 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 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); }
/** * This function is called by the network interface device driver when * an IPv6 packet is received. The function does the basic checks of the * IP header such as packet size being at least larger than the header * size etc. If the packet was not destined for us, the packet is * forwarded (using ip6_forward). * * Finally, the packet is sent to the upper layer protocol input function. * * @param p the received IPv6 packet (p->payload points to IPv6 header) * @param inp the netif on which this packet was received * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't * processed, but currently always returns ERR_OK) */ err_t ip6_input(struct pbuf *p, struct netif *inp) { struct ip6_hdr *ip6hdr; struct netif *netif; u8_t nexth; u16_t hlen; /* the current header length */ u8_t i; #if 0 /*IP_ACCEPT_LINK_LAYER_ADDRESSING*/ @todo int check_ip_src=1; #endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ IP6_STATS_INC(ip6.recv); /* identify the IP header */ ip6hdr = (struct ip6_hdr *)p->payload; if (IP6H_V(ip6hdr) != 6) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IPv6 packet dropped due to bad version number %"U32_F"\n", IP6H_V(ip6hdr))); pbuf_free(p); IP6_STATS_INC(ip6.err); IP6_STATS_INC(ip6.drop); return ERR_OK; } #ifdef LWIP_HOOK_IP6_INPUT if (LWIP_HOOK_IP6_INPUT(p, inp)) { /* the packet has been eaten */ return ERR_OK; } #endif /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ if ((IP6_HLEN > p->len) || ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len)) { if (IP6_HLEN > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", IP6_HLEN, p->len)); } if ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 (plen %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", IP6H_PLEN(ip6hdr) + IP6_HLEN, p->tot_len)); } /* free (drop) packet pbufs */ pbuf_free(p); IP6_STATS_INC(ip6.lenerr); IP6_STATS_INC(ip6.drop); return ERR_OK; } /* Trim pbuf. This should have been done at the netif layer, * but we'll do it anyway just to be sure that its done. */ pbuf_realloc(p, IP6_HLEN + IP6H_PLEN(ip6hdr)); /* copy IP addresses to aligned ip6_addr_t */ ip_addr_copy_from_ip6(ip_data.current_iphdr_dest, ip6hdr->dest); ip_addr_copy_from_ip6(ip_data.current_iphdr_src, ip6hdr->src); /* current header pointer. */ ip_data.current_ip6_header = ip6hdr; /* In netif, used in case we need to send ICMPv6 packets back. */ ip_data.current_netif = inp; ip_data.current_input_netif = inp; /* match packet against an interface, i.e. is this packet for us? */ if (ip6_addr_ismulticast(ip6_current_dest_addr())) { /* Always joined to multicast if-local and link-local all-nodes group. */ if (ip6_addr_isallnodes_iflocal(ip6_current_dest_addr()) || ip6_addr_isallnodes_linklocal(ip6_current_dest_addr())) { netif = inp; } #if LWIP_IPV6_MLD else if (mld6_lookfor_group(inp, ip6_current_dest_addr())) { netif = inp; } #else /* LWIP_IPV6_MLD */ else if (ip6_addr_issolicitednode(ip6_current_dest_addr())) { /* Filter solicited node packets when MLD is not enabled * (for Neighbor discovery). */ netif = NULL; for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) && ip6_addr_cmp_solicitednode(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { netif = inp; LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: solicited node packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); break; } } } #endif /* LWIP_IPV6_MLD */ else { netif = NULL; } } else { /* start trying with inp. if that's not acceptable, start walking the list of configured netifs. 'first' is used as a boolean to mark whether we started walking the list */ int first = 1; netif = inp; do { /* interface is up? */ if (netif_is_up(netif)) { /* unicast to this interface address? address configured? */ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(netif, i))) { /* exit outer loop */ goto netif_found; } } } if (ip6_addr_islinklocal(ip6_current_dest_addr())) { /* Do not match link-local addresses to other netifs. */ netif = NULL; break; } if (first) { first = 0; netif = netif_list; } else { netif = netif->next; } if (netif == inp) { netif = netif->next; } } while (netif != NULL); netif_found: LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet accepted on interface %c%c\n", netif ? netif->name[0] : 'X', netif? netif->name[1] : 'X')); } /* "::" packet source address? (used in duplicate address detection) */ if (ip6_addr_isany(ip6_current_src_addr()) && (!ip6_addr_issolicitednode(ip6_current_dest_addr()))) { /* packet source is not valid */ /* free (drop) packet pbufs */ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with src ANY_ADDRESS dropped\n")); pbuf_free(p); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; } /* packet not for us? */ if (netif == NULL) { /* packet not for us, route or discard */ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_TRACE, ("ip6_input: packet not for us.\n")); #if LWIP_IPV6_FORWARD /* non-multicast packet? */ if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { /* try to forward IP packet on (other) interfaces */ ip6_forward(p, ip6hdr, inp); } #endif /* LWIP_IPV6_FORWARD */ pbuf_free(p); goto ip6_input_cleanup; } /* current netif pointer. */ ip_data.current_netif = netif; /* Save next header type. */ nexth = IP6H_NEXTH(ip6hdr); /* Init header length. */ hlen = ip_data.current_ip_header_tot_len = IP6_HLEN; /* Move to payload. */ pbuf_header(p, -IP6_HLEN); /* Process known option extension headers, if present. */ while (nexth != IP6_NEXTH_NONE) { switch (nexth) { case IP6_NEXTH_HOPBYHOP: LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header\n")); /* Get next header type. */ nexth = *((u8_t *)p->payload); /* Get the header length. */ hlen = 8 * (1 + *((u8_t *)p->payload + 1)); ip_data.current_ip_header_tot_len += hlen; /* Skip over this header. */ if (hlen > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", hlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP6_STATS_INC(ip6.lenerr); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; } pbuf_header(p, -(s16_t)hlen); break; case IP6_NEXTH_DESTOPTS: LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Destination options header\n")); /* Get next header type. */ nexth = *((u8_t *)p->payload); /* Get the header length. */ hlen = 8 * (1 + *((u8_t *)p->payload + 1)); ip_data.current_ip_header_tot_len += hlen; /* Skip over this header. */ if (hlen > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", hlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP6_STATS_INC(ip6.lenerr); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; } pbuf_header(p, -(s16_t)hlen); break; case IP6_NEXTH_ROUTING: LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Routing header\n")); /* Get next header type. */ nexth = *((u8_t *)p->payload); /* Get the header length. */ hlen = 8 * (1 + *((u8_t *)p->payload + 1)); ip_data.current_ip_header_tot_len += hlen; /* Skip over this header. */ if (hlen > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", hlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP6_STATS_INC(ip6.lenerr); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; } pbuf_header(p, -(s16_t)hlen); break; case IP6_NEXTH_FRAGMENT: { struct ip6_frag_hdr * frag_hdr; LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header\n")); frag_hdr = (struct ip6_frag_hdr *)p->payload; /* Get next header type. */ nexth = frag_hdr->_nexth; /* Fragment Header length. */ hlen = 8; ip_data.current_ip_header_tot_len += hlen; /* Make sure this header fits in current pbuf. */ if (hlen > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", hlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP6_FRAG_STATS_INC(ip6_frag.lenerr); IP6_FRAG_STATS_INC(ip6_frag.drop); goto ip6_input_cleanup; } /* Offset == 0 and more_fragments == 0? */ if ((frag_hdr->_fragment_offset & PP_HTONS(IP6_FRAG_OFFSET_MASK | IP6_FRAG_MORE_FLAG)) == 0) { /* This is a 1-fragment packet, usually a packet that we have * already reassembled. Skip this header anc continue. */ pbuf_header(p, -(s16_t)hlen); } else { #if LWIP_IPV6_REASS /* reassemble the packet */ p = ip6_reass(p); /* packet not fully reassembled yet? */ if (p == NULL) { goto ip6_input_cleanup; } /* Returned p point to IPv6 header. * Update all our variables and pointers and continue. */ ip6hdr = (struct ip6_hdr *)p->payload; nexth = IP6H_NEXTH(ip6hdr); hlen = ip_data.current_ip_header_tot_len = IP6_HLEN; pbuf_header(p, -IP6_HLEN); #else /* LWIP_IPV6_REASS */ /* free (drop) packet pbufs */ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header dropped (with LWIP_IPV6_REASS==0)\n")); pbuf_free(p); IP6_STATS_INC(ip6.opterr); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; #endif /* LWIP_IPV6_REASS */ } break; } default: goto options_done; break; } } options_done: /* p points to IPv6 header again. */ pbuf_header_force(p, ip_data.current_ip_header_tot_len); /* send to upper layers */ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n")); ip6_debug_print(p); LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); #if LWIP_RAW /* raw input did not eat the packet? */ if (raw_input(p, inp) == 0) #endif /* LWIP_RAW */ { switch (nexth) { case IP6_NEXTH_NONE: pbuf_free(p); break; #if LWIP_UDP case IP6_NEXTH_UDP: #if LWIP_UDPLITE case IP6_NEXTH_UDPLITE: #endif /* LWIP_UDPLITE */ /* Point to payload. */ pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len); udp_input(p, inp); break; #endif /* LWIP_UDP */ #if LWIP_TCP case IP6_NEXTH_TCP: /* Point to payload. */ pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len); tcp_input(p, inp); break; #endif /* LWIP_TCP */ #if LWIP_ICMP6 case IP6_NEXTH_ICMP6: /* Point to payload. */ pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len); icmp6_input(p, inp); break; #endif /* LWIP_ICMP */ default: #if LWIP_ICMP6 /* send ICMP parameter problem unless it was a multicast or ICMPv6 */ if ((!ip6_addr_ismulticast(ip6_current_dest_addr())) && (IP6H_NEXTH(ip6hdr) != IP6_NEXTH_ICMP6)) { icmp6_param_problem(p, ICMP6_PP_HEADER, ip_data.current_ip_header_tot_len - hlen); } #endif /* LWIP_ICMP */ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: Unsupported transport protocol %"U16_F"\n", IP6H_NEXTH(ip6hdr))); pbuf_free(p); IP6_STATS_INC(ip6.proterr); IP6_STATS_INC(ip6.drop); break; } } ip6_input_cleanup: ip_data.current_netif = NULL; ip_data.current_input_netif = NULL; ip_data.current_ip6_header = NULL; ip_data.current_ip_header_tot_len = 0; ip6_addr_set_zero(ip6_current_src_addr()); ip6_addr_set_zero(ip6_current_dest_addr()); return ERR_OK; }
/** * @ingroup lwip_nosys * Process received ethernet frames. Using this function instead of directly * calling ip_input and passing ARP frames through etharp in ethernetif_input, * the ARP cache is protected from concurrent access.\n * Don't call directly, pass to netif_add() and call netif->input(). * * @param p the received packet, p->payload pointing to the ethernet header * @param netif the network interface on which the packet was received * * @see LWIP_HOOK_UNKNOWN_ETH_PROTOCOL * @see ETHARP_SUPPORT_VLAN * @see LWIP_HOOK_VLAN_CHECK */ err_t ethernet_input(struct pbuf *p, struct netif *netif) { struct eth_hdr* ethhdr; u16_t type; #if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6 s16_t ip_hdr_offset = SIZEOF_ETH_HDR; #endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */ if (p->len <= SIZEOF_ETH_HDR) { /* a packet with only an ethernet header (or less) is not valid for us */ ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); MIB2_STATS_NETIF_INC(netif, ifinerrors); goto free_and_return; } /* points to packet payload, which starts with an Ethernet header */ ethhdr = (struct eth_hdr *)p->payload; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n", (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], lwip_htons(ethhdr->type))); type = ethhdr->type; #if ETHARP_SUPPORT_VLAN if (type == PP_HTONS(ETHTYPE_VLAN)) { struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR); if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) { /* a packet with only an ethernet/vlan header (or less) is not valid for us */ ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); MIB2_STATS_NETIF_INC(netif, ifinerrors); goto free_and_return; } #if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */ #ifdef LWIP_HOOK_VLAN_CHECK if (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan)) { #elif defined(ETHARP_VLAN_CHECK_FN) if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) { #elif defined(ETHARP_VLAN_CHECK) if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { #endif /* silently ignore this packet: not for our VLAN */ pbuf_free(p); return ERR_OK; } #endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */ type = vlan->tpid; ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; } #endif /* ETHARP_SUPPORT_VLAN */ #if LWIP_ARP_FILTER_NETIF netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type)); #endif /* LWIP_ARP_FILTER_NETIF*/ if (ethhdr->dest.addr[0] & 1) { /* this might be a multicast or broadcast packet */ if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) { #if LWIP_IPV4 if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) && (ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) { /* mark the pbuf as link-layer multicast */ p->flags |= PBUF_FLAG_LLMCAST; } #endif /* LWIP_IPV4 */ } #if LWIP_IPV6 else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) && (ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) { /* mark the pbuf as link-layer multicast */ p->flags |= PBUF_FLAG_LLMCAST; } #endif /* LWIP_IPV6 */ else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) { /* mark the pbuf as link-layer broadcast */ p->flags |= PBUF_FLAG_LLBCAST; } } switch (type) { #if LWIP_IPV4 && LWIP_ARP /* IP packet? */ case PP_HTONS(ETHTYPE_IP): if (!(netif->flags & NETIF_FLAG_ETHARP)) { goto free_and_return; } /* skip Ethernet header */ if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ethernet_input: IPv4 packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, ip_hdr_offset)); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); goto free_and_return; } else { /* pass to IP layer */ ip4_input(p, netif); } break; case PP_HTONS(ETHTYPE_ARP): if (!(netif->flags & NETIF_FLAG_ETHARP)) { goto free_and_return; } /* skip Ethernet header */ if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ethernet_input: ARP response packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, ip_hdr_offset)); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); ETHARP_STATS_INC(etharp.lenerr); ETHARP_STATS_INC(etharp.drop); goto free_and_return; } else { /* pass p to ARP module */ etharp_input(p, netif); } break; #endif /* LWIP_IPV4 && LWIP_ARP */ #if PPPOE_SUPPORT case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */ pppoe_disc_input(netif, p); break; case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */ pppoe_data_input(netif, p); break; #endif /* PPPOE_SUPPORT */ #if LWIP_IPV6 case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */ /* skip Ethernet header */ if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ethernet_input: IPv6 packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, ip_hdr_offset)); goto free_and_return; } else { /* pass to IPv6 layer */ ip6_input(p, netif); } break; #endif /* LWIP_IPV6 */ default: #ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL if(LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK) { break; } #endif ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); MIB2_STATS_NETIF_INC(netif, ifinunknownprotos); goto free_and_return; } /* This means the pbuf is freed or consumed, so the caller doesn't have to free it again */ return ERR_OK; free_and_return: pbuf_free(p); return ERR_OK; } /** * @ingroup ethernet * Send an ethernet packet on the network using netif->linkoutput(). * The ethernet header is filled in before sending. * * @see LWIP_HOOK_VLAN_SET * * @param netif the lwIP network interface on which to send the packet * @param p the packet to send. pbuf layer must be @ref PBUF_LINK. * @param src the source MAC address to be copied into the ethernet header * @param dst the destination MAC address to be copied into the ethernet header * @param eth_type ethernet type (@ref eth_type) * @return ERR_OK if the packet was sent, any other err_t on failure */ err_t ethernet_output(struct netif* netif, struct pbuf* p, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type) { struct eth_hdr* ethhdr; u16_t eth_type_be = lwip_htons(eth_type); #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) s32_t vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type); if (vlan_prio_vid >= 0) { struct eth_vlan_hdr* vlanhdr; LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF); if (pbuf_header(p, SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) != 0) { goto pbuf_header_failed; } vlanhdr = (struct eth_vlan_hdr*)(((u8_t*)p->payload) + SIZEOF_ETH_HDR); vlanhdr->tpid = eth_type_be; vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid); eth_type_be = PP_HTONS(ETHTYPE_VLAN); } else #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ { if (pbuf_header(p, SIZEOF_ETH_HDR) != 0) { goto pbuf_header_failed; } } ethhdr = (struct eth_hdr*)p->payload; ethhdr->type = eth_type_be; ETHADDR32_COPY(ðhdr->dest, dst); ETHADDR16_COPY(ðhdr->src, src); LWIP_ASSERT("netif->hwaddr_len must be 6 for ethernet_output!", (netif->hwaddr_len == ETH_HWADDR_LEN)); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethernet_output: sending packet %p\n", (void *)p)); /* send the packet */ return netif->linkoutput(netif, p); pbuf_header_failed: LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("ethernet_output: could not allocate room for header.\n")); LINK_STATS_INC(link.lenerr); return ERR_BUF; }
/** * ICMP Echo Request in pbuf "p" is to be proxied. */ static void pxping_recv4(void *arg, struct pbuf *p) { struct pxping *pxping = (struct pxping *)arg; const struct ip_hdr *iph; const struct icmp_echo_hdr *icmph; u16_t iphlen; size_t bufsize; struct pong4 *pong; IPAddr dst; int mapped; int ttl; IP_OPTION_INFORMATION opts; void *reqdata; size_t reqsize; int status; pong = NULL; iphlen = ip_current_header_tot_len(); if (RT_UNLIKELY(iphlen != IP_HLEN)) { /* we don't do options */ goto out; } iph = (const struct ip_hdr *)ip_current_header(); icmph = (const struct icmp_echo_hdr *)p->payload; mapped = pxremap_outbound_ip4((ip_addr_t *)&dst, (ip_addr_t *)&iph->dest); if (RT_UNLIKELY(mapped == PXREMAP_FAILED)) { goto out; } ttl = IPH_TTL(iph); if (mapped == PXREMAP_ASIS) { if (RT_UNLIKELY(ttl == 1)) { status = pbuf_header(p, iphlen); /* back to IP header */ if (RT_LIKELY(status == 0)) { icmp_time_exceeded(p, ICMP_TE_TTL); } goto out; } --ttl; } status = pbuf_header(p, -(u16_t)sizeof(*icmph)); /* to ping payload */ if (RT_UNLIKELY(status != 0)) { goto out; } bufsize = sizeof(ICMP_ECHO_REPLY) + p->tot_len; pong = (struct pong4 *)malloc(sizeof(*pong) - sizeof(pong->buf) + bufsize); if (RT_UNLIKELY(pong == NULL)) { goto out; } pong->bufsize = bufsize; pong->netif = pxping->netif; memcpy(&pong->reqiph, iph, sizeof(*iph)); memcpy(&pong->reqicmph, icmph, sizeof(*icmph)); reqsize = p->tot_len; if (p->next == NULL) { /* single pbuf can be directly used as request data source */ reqdata = p->payload; } else { /* data from pbuf chain must be concatenated */ pbuf_copy_partial(p, pong->buf, p->tot_len, 0); reqdata = pong->buf; } opts.Ttl = ttl; opts.Tos = IPH_TOS(iph); /* affected by DisableUserTOSSetting key */ opts.Flags = (IPH_OFFSET(iph) & PP_HTONS(IP_DF)) != 0 ? IP_FLAG_DF : 0; opts.OptionsSize = 0; opts.OptionsData = 0; status = IcmpSendEcho2(pxping->hdl4, NULL, pxping->callback4, pong, dst, reqdata, (WORD)reqsize, &opts, pong->buf, (DWORD)pong->bufsize, 5 * 1000 /* ms */); if (RT_UNLIKELY(status != 0)) { DPRINTF(("IcmpSendEcho2: unexpected status %d\n", status)); goto out; } else if ((status = GetLastError()) != ERROR_IO_PENDING) { int code; DPRINTF(("IcmpSendEcho2: error %d\n", status)); switch (status) { case ERROR_NETWORK_UNREACHABLE: code = ICMP_DUR_NET; break; case ERROR_HOST_UNREACHABLE: code = ICMP_DUR_HOST; break; default: code = -1; break; } if (code != -1) { /* move payload back to IP header */ status = pbuf_header(p, (u16_t)(sizeof(*icmph) + iphlen)); if (RT_LIKELY(status == 0)) { icmp_dest_unreach(p, code); } } goto out; } pong = NULL; /* callback owns it now */ out: if (pong != NULL) { free(pong); } pbuf_free(p); }
/** * According to a pbuf which include a ieee 802.15.4 frame, * Abstract the ethernet frame header. * The ip packet in the frame is compressed. So we can analyse the ip type. * The ip type can be ipv4_ip¡¢ipv4_arp or ipv6. * * @param p The ieee 802.15.4 frame buffer. * @param ethhdr The convert result of the ethernet header. * @param isbc is a boardcast packet ? * @return The length of the ieee 802.15.4 frame header before abstracting. */ u8_t ieee802154_to_eth (struct pbuf *p, struct eth_hdr *ethhdr, u8_t *isbc) { u8_t *head; u8_t type; ieee802154_frame_fcf_t fcf; head = (u8_t *)p->payload; /* decode the FCF */ fcf.frame_type = head[0] & 7; fcf.security_enabled = (head[0] >> 3) & 1; fcf.frame_pending = (head[0] >> 4) & 1; fcf.ack_required = (head[0] >> 5) & 1; fcf.panid_compression = (head[0] >> 6) & 1; fcf.dest_addr_mode = (head[1] >> 2) & 3; fcf.frame_version = (head[1] >> 4) & 3; fcf.src_addr_mode = (head[1] >> 6) & 3; /* The index is point to the dest address, bypass the Sequence number and PAN ID. */ head += 5; if (isbc) { *isbc = 0; } /* 802.15.4 raw address must swp */ if (fcf.dest_addr_mode == IEEE802154_LONGADDRMODE) { long_addr_to_eth_addr(head, ethhdr->dest.addr, 1); head += 8; } else { short_addr_to_eth_addr(head, ethhdr->dest.addr, 1); if (isbc && (head[0] == 0xff) && (head[1] == 0xff)) { *isbc = 1; } head += 2; } if (fcf.panid_compression == 0) { head += 2; } if (fcf.src_addr_mode == IEEE802154_LONGADDRMODE) { long_addr_to_eth_addr(head, ethhdr->src.addr, 1); head += 8; } else { short_addr_to_eth_addr(head, ethhdr->src.addr, 1); head += 2; } /* Pad the ethernet type */ type = *head; /* If the type is IPv6 */ if (type & 0xc0) { ethhdr->type = PP_HTONS(ETHTYPE_IPV6); } else { if(LOWPAN_DISPATCH_IPV4 == type) { /* If he packet is IPv4*/ ethhdr->type = PP_HTONS(ETHTYPE_IP); } else if (LOWPAN_DISPATCH_ARP == type) { /* If the Packet is arp*/ ethhdr->type = PP_HTONS(ETHTYPE_ARP); } else { ethhdr->type = PP_HTONS(ETHTYPE_IP); /* ? */ } } return (head - (u8_t *)p->payload); }
static void dhcp6ds_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip6_addr_t *addr, u16_t port) { u8_t msg_header[4]; unsigned int msg_type, msg_tid; int copied; size_t roff; struct pbuf *q; err_t error; LWIP_UNUSED_ARG(arg); LWIP_ASSERT1(p != NULL); copied = pbuf_copy_partial(p, msg_header, sizeof(msg_header), 0); if (copied != sizeof(msg_header)) { DPRINTF(("%s: message header truncated\n", __func__)); pbuf_free(p); return; } pbuf_header(p, -(s16_t)sizeof(msg_header)); msg_type = msg_header[0]; msg_tid = (msg_header[1] << 16) | (msg_header[2] << 8) | msg_header[3]; DPRINTF(("%s: type %u, tid 0x%6x\n", __func__, msg_type, msg_tid)); if (msg_type != DHCP6_INFORMATION_REQUEST) { /* TODO:? RELAY_FORW */ pbuf_free(p); return; } roff = 0; msg_header[0] = DHCP6_REPLY; memcpy(dhcp6ds_reply_buf + roff, msg_header, sizeof(msg_header)); roff += sizeof(msg_header); /* loop over options */ while (p->tot_len > 0) { u16_t opt, optlen; /* fetch option code */ copied = pbuf_copy_partial(p, &opt, sizeof(opt), 0); if (copied != sizeof(opt)) { DPRINTF(("%s: option header truncated\n", __func__)); pbuf_free(p); return; } pbuf_header(p, -(s16_t)sizeof(opt)); opt = ntohs(opt); /* fetch option length */ copied = pbuf_copy_partial(p, &optlen, sizeof(optlen), 0); if (copied != sizeof(optlen)) { DPRINTF(("%s: option %u length truncated\n", __func__, opt)); pbuf_free(p); return; } pbuf_header(p, -(s16_t)sizeof(optlen)); optlen = ntohs(optlen); /* enough data? */ if (optlen > p->tot_len) { DPRINTF(("%s: option %u truncated: expect %u, got %u\n", __func__, opt, optlen, p->tot_len)); pbuf_free(p); return; } DPRINTF2(("%s: option %u length %u\n", __func__, opt, optlen)); if (opt == DHCP6_OPTION_CLIENTID) { u16_t s; /* "A DUID can be no more than 128 octets long (not including the type code)." */ if (optlen > 130) { DPRINTF(("%s: client DUID too long: %u\n", __func__, optlen)); pbuf_free(p); return; } s = PP_HTONS(DHCP6_OPTION_CLIENTID); memcpy(dhcp6ds_reply_buf + roff, &s, sizeof(s)); roff += sizeof(s); s = ntohs(optlen); memcpy(dhcp6ds_reply_buf + roff, &s, sizeof(s)); roff += sizeof(s); pbuf_copy_partial(p, dhcp6ds_reply_buf + roff, optlen, 0); roff += optlen; } else if (opt == DHCP6_OPTION_ORO) { u16_t *opts; int i, nopts; if (optlen % 2 != 0) { DPRINTF2(("%s: Option Request of odd length\n", __func__)); goto bad_oro; } nopts = optlen / 2; opts = (u16_t *)malloc(optlen); if (opts == NULL) { DPRINTF2(("%s: failed to allocate space for Option Request\n", __func__)); goto bad_oro; } pbuf_copy_partial(p, opts, optlen, 0); for (i = 0; i < nopts; ++i) { opt = ntohs(opts[i]); DPRINTF2(("> request option %u\n", opt)); }; free(opts); bad_oro: /* empty */; } pbuf_header(p, -optlen); /* go to next option */ } pbuf_free(p); /* done */ memcpy(dhcp6ds_reply_buf + roff, dhcp6ds_serverid, sizeof(dhcp6ds_serverid)); roff += sizeof(dhcp6ds_serverid); memcpy(dhcp6ds_reply_buf + roff, dhcp6ds_dns, sizeof(dhcp6ds_dns)); roff += sizeof(dhcp6ds_dns); q = pbuf_alloc(PBUF_RAW, roff, PBUF_RAM); if (q == NULL) { DPRINTF(("%s: pbuf_alloc(%d) failed\n", __func__, (int)roff)); return; } error = pbuf_take(q, dhcp6ds_reply_buf, roff); if (error != ERR_OK) { DPRINTF(("%s: pbuf_take(%d) failed: %s\n", __func__, (int)roff, proxy_lwip_strerr(error))); pbuf_free(q); return; } error = udp_sendto_ip6(pcb, q, addr, port); if (error != ERR_OK) { DPRINTF(("%s: udp_sendto failed: %s\n", __func__, proxy_lwip_strerr(error))); } pbuf_free(q); }
/** This is an example function that tests more than one thread being active in select. */ static void sockex_testtwoselects(void *arg) { int s1; int s2; int ret; struct sockaddr_in addr; size_t len; err_t lwiperr; struct sockex_select_helper h1, h2, h3, h4; LWIP_UNUSED_ARG(arg); /* set up address to connect to */ memset(&addr, 0, sizeof(addr)); addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = PP_HTONS(SOCK_TARGET_PORT); addr.sin_addr.s_addr = inet_addr(SOCK_TARGET_HOST); /* create the sockets */ s1 = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s1 >= 0", s1 >= 0); s2 = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s2 >= 0", s2 >= 0); /* connect, should succeed */ ret = lwip_connect(s1, (struct sockaddr*)&addr, sizeof(addr)); LWIP_ASSERT("ret == 0", ret == 0); ret = lwip_connect(s2, (struct sockaddr*)&addr, sizeof(addr)); LWIP_ASSERT("ret == 0", ret == 0); /* write the start of a GET request */ #define SNDSTR1 "G" len = strlen(SNDSTR1); ret = lwip_write(s1, SNDSTR1, len); LWIP_ASSERT("ret == len", ret == (int)len); ret = lwip_write(s2, SNDSTR1, len); LWIP_ASSERT("ret == len", ret == (int)len); h1.wait_read = 1; h1.wait_write = 1; h1.wait_err = 1; h1.expect_read = 0; h1.expect_write = 0; h1.expect_err = 0; lwiperr = sys_sem_new(&h1.sem, 0); LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK); h1.socket = s1; h1.wait_ms = 500; h2 = h1; lwiperr = sys_sem_new(&h2.sem, 0); LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK); h2.socket = s2; h2.wait_ms = 1000; h3 = h1; lwiperr = sys_sem_new(&h3.sem, 0); LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK); h3.socket = s2; h3.wait_ms = 1500; h4 = h1; lwiperr = sys_sem_new(&h4.sem, 0); LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK); h4.socket = s2; h4.wait_ms = 2000; /* select: all sockets should time out if the other side is a good HTTP server */ sys_thread_new("sockex_select_waiter1", sockex_select_waiter, &h2, 0, 0); sys_msleep(100); sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h1, 0, 0); sys_msleep(100); sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h4, 0, 0); sys_msleep(100); sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h3, 0, 0); sys_sem_wait(&h1.sem); sys_sem_wait(&h2.sem); sys_sem_wait(&h3.sem); sys_sem_wait(&h4.sem); /* close */ ret = lwip_close(s1); LWIP_ASSERT("ret == 0", ret == 0); ret = lwip_close(s2); LWIP_ASSERT("ret == 0", ret == 0); printf("sockex_testtwoselects finished successfully\n"); }
/** This is an example function that tests blocking- and nonblocking connect. */ static void sockex_nonblocking_connect(void *arg) { int s; int ret; u32_t opt; struct sockaddr_in addr; fd_set readset; fd_set writeset; fd_set errset; struct timeval tv; u32_t ticks_a, ticks_b; int err; LWIP_UNUSED_ARG(arg); /* set up address to connect to */ memset(&addr, 0, sizeof(addr)); addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = PP_HTONS(SOCK_TARGET_PORT); addr.sin_addr.s_addr = inet_addr(SOCK_TARGET_HOST); /* first try blocking: */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should succeed */ LWIP_ASSERT("ret == 0", ret == 0); /* write something */ ret = lwip_write(s, "test", 4); LWIP_ASSERT("ret == 4", ret == 4); /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); /* now try nonblocking and close before being connected */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* nonblocking */ opt = lwip_fcntl(s, F_GETFL, 0); LWIP_ASSERT("ret != -1", ret != -1); opt |= O_NONBLOCK; ret = lwip_fcntl(s, F_SETFL, opt); LWIP_ASSERT("ret != -1", ret != -1); /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should have an error: "inprogress" */ LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); /* try to close again, should fail with EBADF */ ret = lwip_close(s); LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EBADF", err == EBADF); printf("closing socket in nonblocking connect succeeded\n"); /* now try nonblocking, connect should succeed: this test only works if it is fast enough, i.e. no breakpoints, please! */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* nonblocking */ opt = 1; ret = lwip_ioctl(s, FIONBIO, &opt); LWIP_ASSERT("ret == 0", ret == 0); /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should have an error: "inprogress" */ LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); /* write should fail, too */ ret = lwip_write(s, "test", 4); LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); FD_ZERO(&readset); FD_SET(s, &readset); FD_ZERO(&writeset); FD_SET(s, &writeset); FD_ZERO(&errset); FD_SET(s, &errset); tv.tv_sec = 0; tv.tv_usec = 0; /* select without waiting should fail */ ret = lwip_select(s + 1, &readset, &writeset, &errset, &tv); LWIP_ASSERT("ret == 0", ret == 0); LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &writeset)); LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &readset)); LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &errset)); FD_ZERO(&readset); FD_SET(s, &readset); FD_ZERO(&writeset); FD_SET(s, &writeset); FD_ZERO(&errset); FD_SET(s, &errset); ticks_a = sys_now(); /* select with waiting should succeed */ ret = lwip_select(s + 1, &readset, &writeset, &errset, NULL); ticks_b = sys_now(); LWIP_ASSERT("ret == 1", ret == 1); LWIP_ASSERT("FD_ISSET(s, &writeset)", FD_ISSET(s, &writeset)); LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &readset)); LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &errset)); /* now write should succeed */ ret = lwip_write(s, "test", 4); LWIP_ASSERT("ret == 4", ret == 4); /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); printf("select() needed %d ticks to return writable\n", ticks_b - ticks_a); /* now try nonblocking to invalid address: this test only works if it is fast enough, i.e. no breakpoints, please! */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* nonblocking */ opt = 1; ret = lwip_ioctl(s, FIONBIO, &opt); LWIP_ASSERT("ret == 0", ret == 0); addr.sin_addr.s_addr++; /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should have an error: "inprogress" */ LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); /* write should fail, too */ ret = lwip_write(s, "test", 4); LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); FD_ZERO(&readset); FD_SET(s, &readset); FD_ZERO(&writeset); FD_SET(s, &writeset); FD_ZERO(&errset); FD_SET(s, &errset); tv.tv_sec = 0; tv.tv_usec = 0; /* select without waiting should fail */ ret = lwip_select(s + 1, &readset, &writeset, &errset, &tv); LWIP_ASSERT("ret == 0", ret == 0); FD_ZERO(&readset); FD_SET(s, &readset); FD_ZERO(&writeset); FD_SET(s, &writeset); FD_ZERO(&errset); FD_SET(s, &errset); ticks_a = sys_now(); /* select with waiting should eventually succeed and return errset! */ ret = lwip_select(s + 1, &readset, &writeset, &errset, NULL); ticks_b = sys_now(); LWIP_ASSERT("ret > 0", ret > 0); LWIP_ASSERT("FD_ISSET(s, &errset)", FD_ISSET(s, &errset)); LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &readset)); LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &writeset)); /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); printf("select() needed %d ticks to return error\n", ticks_b - ticks_a); printf("all tests done, thread ending\n"); }
/** * Convert an u16_t from host- to network byte order. * * @param n u16_t in host byte order * @return n in network byte order */ u16_t lwip_htons(u16_t n) { return (u16_t)PP_HTONS(n); }
/** * Processes ICMP input packets, called from ip_input(). * * Currently only processes icmp echo requests and sends * out the echo response. * * @param p the icmp echo request packet, p->payload pointing to the icmp header * @param inp the netif on which this packet was received */ void icmp_input(struct pbuf *p, struct netif *inp) { u8_t type; #ifdef LWIP_DEBUG u8_t code; #endif /* LWIP_DEBUG */ struct icmp_echo_hdr *iecho; struct ip_hdr *iphdr; s16_t hlen; ICMP_STATS_INC(icmp.recv); snmp_inc_icmpinmsgs(); iphdr = (struct ip_hdr *)ip_current_header(); hlen = IPH_HL(iphdr) * 4; if (p->len < sizeof(u16_t)*2) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); goto lenerr; } type = *((u8_t *)p->payload); #ifdef LWIP_DEBUG code = *(((u8_t *)p->payload)+1); #endif /* LWIP_DEBUG */ switch (type) { case ICMP_ER: /* This is OK, echo reply might have been parsed by a raw PCB (as obviously, an echo request has been sent, too). */ break; case ICMP_ECHO: #if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING { int accepted = 1; #if !LWIP_MULTICAST_PING /* multicast destination address? */ if (ip_addr_ismulticast(ip_current_dest_addr())) { accepted = 0; } #endif /* LWIP_MULTICAST_PING */ #if !LWIP_BROADCAST_PING /* broadcast destination address? */ if (ip_addr_isbroadcast(ip_current_dest_addr(), inp)) { accepted = 0; } #endif /* LWIP_BROADCAST_PING */ /* broadcast or multicast destination address not acceptd? */ if (!accepted) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n")); ICMP_STATS_INC(icmp.err); pbuf_free(p); return; } } #endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); if (p->tot_len < sizeof(struct icmp_echo_hdr)) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); goto lenerr; } #if CHECKSUM_CHECK_ICMP if (inet_chksum_pbuf(p) != 0) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); pbuf_free(p); ICMP_STATS_INC(icmp.chkerr); snmp_inc_icmpinerrors(); return; } #endif #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) { /* p is not big enough to contain link headers * allocate a new one and copy p into it */ struct pbuf *r; /* switch p->payload to ip header */ if (pbuf_header(p, hlen)) { LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0); goto memerr; } /* allocate new packet buffer with space for link headers */ r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); if (r == NULL) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); goto memerr; } LWIP_ASSERT("check that first pbuf can hold struct the ICMP header", (r->len >= hlen + sizeof(struct icmp_echo_hdr))); /* copy the whole packet including ip header */ if (pbuf_copy(r, p) != ERR_OK) { LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0); goto memerr; } iphdr = (struct ip_hdr *)r->payload; /* switch r->payload back to icmp header */ if (pbuf_header(r, -hlen)) { LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); goto memerr; } /* free the original p */ pbuf_free(p); /* we now have an identical copy of p that has room for link headers */ p = r; } else { /* restore p->payload to point to icmp header */ if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) { LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); goto memerr; } } #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ /* At this point, all checks are OK. */ /* We generate an answer by switching the dest and src ip addresses, * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ iecho = (struct icmp_echo_hdr *)p->payload; ip_addr_copy(iphdr->src, *ip_current_dest_addr()); ip_addr_copy(iphdr->dest, *ip_current_src_addr()); ICMPH_TYPE_SET(iecho, ICMP_ER); #if CHECKSUM_GEN_ICMP /* adjust the checksum */ if (iecho->chksum > PP_HTONS(0xffffU - (ICMP_ECHO << 8))) { iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1; } else { iecho->chksum += PP_HTONS(ICMP_ECHO << 8); } #else /* CHECKSUM_GEN_ICMP */ iecho->chksum = 0; #endif /* CHECKSUM_GEN_ICMP */ /* Set the correct TTL and recalculate the header checksum. */ IPH_TTL_SET(iphdr, ICMP_TTL); IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); #endif /* CHECKSUM_GEN_IP */ ICMP_STATS_INC(icmp.xmit); /* increase number of messages attempted to send */ snmp_inc_icmpoutmsgs(); /* increase number of echo replies attempted to send */ snmp_inc_icmpoutechoreps(); if(pbuf_header(p, hlen)) { LWIP_ASSERT("Can't move over header in packet", 0); } else { err_t ret; /* send an ICMP packet, src addr is the dest addr of the curren packet */ ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL, ICMP_TTL, 0, IP_PROTO_ICMP, inp); if (ret != ERR_OK) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret)); } } break; default: LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", (s16_t)type, (s16_t)code)); ICMP_STATS_INC(icmp.proterr); ICMP_STATS_INC(icmp.drop); } pbuf_free(p); return; lenerr: pbuf_free(p); ICMP_STATS_INC(icmp.lenerr); snmp_inc_icmpinerrors(); return; #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN memerr: pbuf_free(p); ICMP_STATS_INC(icmp.err); snmp_inc_icmpinerrors(); return; #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ }
/* ------------------------------------------------------------------------------------------------------ * sockex_nonblocking_connect() * * Description : tests socket blocking and nonblocking connect. * * Argument(s) : none. * */ void sockex_nonblocking_connect(void *arg) { int ret; struct sockaddr_in addr; fd_set readset; fd_set writeset; fd_set errset; struct timeval tv; LWIP_UNUSED_ARG(arg); memset(&addr, 0, sizeof(addr)); /* set up address to connect to */ addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = PP_HTONS(SOCK_TARGET_PORT); addr.sin_addr.s_addr = inet_addr(SOCK_TARGET_HOST); socket_state = SOCKET_NEW; for(;;) { if(g_bNetStatus == NETS_LOCIP) /* IP is setted.*/ { switch(socket_state) { case SOCKET_NEW: { s = lwip_socket(AF_INET, SOCK_STREAM, 0); socket_state = SOCKET_CON; break; } case SOCKET_CON: { unsigned int ip; ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); LWIP_ASSERT("ret == 0", ret == 0); if(ret < 0) { lwip_close(s); socket_state = SOCKET_NEW; OSTimeDly(2); RS232printf("socket connect failed.\n"); break; } ip = lwIPLocalIPAddrGet(); NetDisplayIPAddress(ip); /* Socket updata IP address.*/ socket_state = SOCKET_IDIE; } case SOCKET_IDIE: { INT8U *msg; INT8U err; msg = (INT8U *)OSMboxPend(NET_RfMbox, 0, &err); /* Waiting socket writing data.*/ if(err != OS_ERR_NONE) break; ret = lwip_write(s, msg, 6); if(ret < 0) { lwip_close(s); socket_state = SOCKET_CON; } } break; case SOCKET_CHECK: // TODO: Check socket connecting. FD_ZERO(&readset); FD_SET(s, &readset); FD_ZERO(&writeset); FD_SET(s, &writeset); FD_ZERO(&errset); FD_SET(s, &errset); tv.tv_sec = 3; tv.tv_usec = 0; /* Set time out 3s, 函数立即返回*/ ret = lwip_select(s+1, &readset, &writeset, &errset, &tv); if(ret == 0) { RS232printf("socket check timeout.\n"); lwip_close(s); socket_state = SOCKET_CON; /* Reconnect socket.*/ } if(FD_ISSET(s, &writeset) == 0) /* If socket couldn't write.*/ { RS232printf("socket write test error.\n"); lwip_close(s); socket_state = SOCKET_CON; /* Reconnect socket.*/ } ret = lwip_write(s, "test", 6); if(ret < 0) { lwip_close(s); socket_state = SOCKET_CON; } OSTimeDly(2000); break; default: break; } } OSTimeDly(2); } }
/** This is an example function that tests the recv function (timeout etc.). */ static void sockex_testrecv(void *arg) { int s; int ret; int err; int opt; struct sockaddr_in addr; size_t len; char rxbuf[1024]; fd_set readset; fd_set errset; struct timeval tv; LWIP_UNUSED_ARG(arg); /* set up address to connect to */ memset(&addr, 0, sizeof(addr)); addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = PP_HTONS(SOCK_TARGET_PORT); addr.sin_addr.s_addr = inet_addr(SOCK_TARGET_HOST); /* first try blocking: */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should succeed */ LWIP_ASSERT("ret == 0", ret == 0); /* set recv timeout (100 ms) */ opt = 100; ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt, sizeof(int)); LWIP_ASSERT("ret == 0", ret == 0); /* write the start of a GET request */ #define SNDSTR1 "G" len = strlen(SNDSTR1); ret = lwip_write(s, SNDSTR1, len); LWIP_ASSERT("ret == len", ret == (int)len); /* should time out if the other side is a good HTTP server */ ret = lwip_read(s, rxbuf, 1); LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EAGAIN", err == EAGAIN); /* write the rest of a GET request */ #define SNDSTR2 "ET / HTTP_1.1\r\n\r\n" len = strlen(SNDSTR2); ret = lwip_write(s, SNDSTR2, len); LWIP_ASSERT("ret == len", ret == (int)len); /* wait a while: should be enough for the server to send a response */ sys_msleep(1000); /* should not time out but receive a response */ ret = lwip_read(s, rxbuf, 1024); LWIP_ASSERT("ret > 0", ret > 0); /* now select should directly return because the socket is readable */ FD_ZERO(&readset); FD_ZERO(&errset); FD_SET(s, &readset); FD_SET(s, &errset); tv.tv_sec = 10; tv.tv_usec = 0; ret = lwip_select(s + 1, &readset, NULL, &errset, &tv); LWIP_ASSERT("ret == 1", ret == 1); LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &errset)); LWIP_ASSERT("FD_ISSET(s, &readset)", FD_ISSET(s, &readset)); /* should not time out but receive a response */ ret = lwip_read(s, rxbuf, 1024); /* might receive a second packet for HTTP/1.1 servers */ if (ret > 0) { /* should return 0: closed */ ret = lwip_read(s, rxbuf, 1024); LWIP_ASSERT("ret == 0", ret == 0); } /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); printf("sockex_testrecv finished successfully\n"); }
/** * This function does the actual transmission of a packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * can be chained. * * @param netif * the lwip network interface structure for this netfrontif * @param p * the packet to send (e.g. IP packet including MAC addresses and type) * @return * ERR_OK when the packet could be enqueued for sending; an err_t value otherwise */ static inline err_t netfrontif_transmit(struct netif *netif, struct pbuf *p) { struct netfrontif *nfi = netif->state; #if LWIP_CHECKSUM_PARTIAL || defined CONFIG_LWIP_BATCHTX s16_t ip_hdr_offset; const struct eth_hdr *ethhdr; const struct ip_hdr *iphdr; #endif /* LWIP_CHECKSUM_PARTIAL || defined CONFIG_LWIP_BATCHTX */ #ifdef CONFIG_LWIP_BATCHTX const struct tcp_hdr *tcphdr; #endif /* CONFIG_LWIP_BATCHTX */ int tso = 0; int push = 1; err_t err; LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_transmit: %c%c: " "Transmitting %u bytes\n", netif->name[0], netif->name[1], p->tot_len)); #if LWIP_CHECKSUM_PARTIAL || defined CONFIG_LWIP_BATCHTX /* detect if payload contains a TCP packet */ /* NOTE: We assume here that all protocol headers are in the first pbuf of a pbuf chain! */ ip_hdr_offset = SIZEOF_ETH_HDR; ethhdr = (struct eth_hdr *) p->payload; #if ETHARP_SUPPORT_VLAN if (type == PP_HTONS(ETHTYPE_VLAN)) { type = ((struct eth_vlan_hdr*)(((uintptr_t)ethhdr) + SIZEOF_ETH_HDR))->tpid; ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; } #endif /* ETHARP_SUPPORT_VLAN */ /* TODO: PPP support? */ switch (ethhdr->type) { case PP_HTONS(ETHTYPE_IP): iphdr = (struct ip_hdr *)((uintptr_t) p->payload + ip_hdr_offset); if (IPH_PROTO(iphdr) != IP_PROTO_TCP) { goto xmit; /* IPv4 but not TCP */ } #if LWIP_CHECKSUM_PARTIAL tso = XEN_NETIF_GSO_TYPE_TCPV4; /* TCPv4 segmentation and checksum offloading */ #endif /* LWIP_CHECKSUM_PARTIAL */ #ifdef CONFIG_LWIP_BATCHTX /* push only when FIN, RST, PSH, or URG flag is set */ tcphdr = (struct tcp_hdr *)((uintptr_t) p->payload + ip_hdr_offset + (IPH_HL(iphdr) * 4)); push = (TCPH_FLAGS(tcphdr) & (TCP_FIN | TCP_RST | TCP_PSH | TCP_URG)); #endif /* CONFIG_LWIP_BATCHTX */ break; #if IPV6_SUPPORT case PP_HTONS(ETHTYPE_IPV6): if (IP6H_NEXTH((struct ip6_hdr *)((uintptr_t) p->payload + ip_hdr_offset)) != IP6_NEXTH_TCP) goto xmit; /* IPv6 but not TCP */ #if LWIP_CHECKSUM_PARTIAL tso = XEN_NETIF_GSO_TYPE_TCPV6; /* TCPv6 segmentation and checksum offloading */ #endif /* LWIP_CHECKSUM_PARTIAL */ #ifdef CONFIG_LWIP_BATCHTX /* push only when FIN, RST, PSH, or URG flag is set */ #error "TSOv6 is not yet supported. Please add it" tcphdr = NULL; push = (TCPH_FLAGS(tcphdr) & (TCP_FIN | TCP_RST | TCP_PSH | TCP_URG)); #endif /* CONFIG_LWIP_BATCHTX */ break; #endif /* IPV6_SUPPORT */ default: break; /* non-IP packet */ } #endif /* LWIP_CHECKSUM_PARTIAL || defined CONFIG_LWIP_BATCHTX */ xmit: #if ETH_PAD_SIZE pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif err = netfront_xmit_pbuf(nfi->dev, p, tso, push); if (likely(err == ERR_OK)) { LINK_STATS_INC(link.xmit); } else { LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_transmit: transmission failed, dropping packet: %d\n", err)); LINK_STATS_INC(link.drop); } #if ETH_PAD_SIZE pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif return err; }