/** * Send a MLD message (report or done). * * An IPv6 hop-by-hop options header with a router alert option * is prepended. * * @param group the group to report or quit * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done) */ static void mld6_send(struct mld_group *group, u8_t type) { struct mld_header * mld_hdr; struct pbuf * p; ip6_addr_t * src_addr; /* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */ p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr), PBUF_RAM); if ((p == NULL) || (p->len < (sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr)))) { /* We couldn't allocate a suitable pbuf. drop it. */ if (p != NULL) { pbuf_free(p); } MLD6_STATS_INC(mld6.memerr); return; } /* Move to make room for Hop-by-hop options header. */ if (pbuf_header(p, -IP6_HBH_HLEN)) { pbuf_free(p); MLD6_STATS_INC(mld6.lenerr); return; } /* Select our source address. */ if (!ip6_addr_isvalid(netif_ip6_addr_state(group->netif, 0))) { /* This is a special case, when we are performing duplicate address detection. * We must join the multicast group, but we don't have a valid address yet. */ src_addr = IP6_ADDR_ANY; } else { /* Use link-local address as source address. */ src_addr = netif_ip6_addr(group->netif, 0); } /* MLD message header pointer. */ mld_hdr = (struct mld_header *)p->payload; /* Set fields. */ mld_hdr->type = type; mld_hdr->code = 0; mld_hdr->chksum = 0; mld_hdr->max_resp_delay = 0; mld_hdr->reserved = 0; ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address)); #if CHECKSUM_GEN_ICMP6 mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, &(group->group_address)); #endif /* CHECKSUM_GEN_ICMP6 */ /* Add hop-by-hop headers options: router alert with MLD value. */ ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD); /* Send the packet out. */ MLD6_STATS_INC(mld6.xmit); ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address), MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, group->netif); pbuf_free(p); }
static void pxping_icmp6_callback(struct pong6 *pong) { DWORD nreplies; ICMPV6_ECHO_REPLY *reply; struct pbuf *p; struct icmp6_echo_hdr *icmph; size_t icmplen; ip6_addr_t src; int mapped; nreplies = Icmp6ParseReplies(pong->buf, (DWORD)pong->bufsize); if (nreplies == 0) { DWORD error = GetLastError(); if (error == IP_REQ_TIMED_OUT) { DPRINTF2(("pong6: %p timed out\n", (void *)pong)); } else { DPRINTF(("pong6: %p: Icmp6ParseReplies: error %d\n", (void *)pong, error)); } return; } reply = (ICMPV6_ECHO_REPLY *)pong->buf; mapped = pxremap_inbound_ip6(&src, (ip6_addr_t *)reply->Address.sin6_addr); if (mapped == PXREMAP_FAILED) { return; } /* * Reply data follows ICMPV6_ECHO_REPLY structure in memory, but * it doesn't tell us its size. Assume it's equal the size of the * request. */ icmplen = sizeof(*icmph) + pong->reqsize; p = pbuf_alloc(PBUF_IP, (u16_t)icmplen, PBUF_RAM); if (RT_UNLIKELY(p == NULL)) { return; } icmph = (struct icmp6_echo_hdr *)p->payload; icmph->type = ICMP6_TYPE_EREP; icmph->code = 0; icmph->chksum = 0; icmph->id = pong->reqicmph.id; icmph->seqno = pong->reqicmph.seqno; memcpy((u8_t *)p->payload + sizeof(*icmph), pong->buf + sizeof(*reply), pong->reqsize); icmph->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, &src, &pong->reqsrc); ip6_output_if(p, /* :src */ &src, /* :dst */ &pong->reqsrc, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, pong->netif); pbuf_free(p); }
void icmp6_proxy_input(struct pbuf *p, struct netif *inp) { struct icmp6_hdr *icmp6hdr; ICMP6_STATS_INC(icmp6.recv); /* Check that ICMPv6 header fits in payload */ if (p->len < sizeof(struct icmp6_hdr)) { /* drop short packets */ pbuf_free(p); ICMP6_STATS_INC(icmp6.lenerr); ICMP6_STATS_INC(icmp6.drop); return; } icmp6hdr = (struct icmp6_hdr *)p->payload; if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(), ip6_current_dest_addr()) != 0) { /* Checksum failed */ pbuf_free(p); ICMP6_STATS_INC(icmp6.chkerr); ICMP6_STATS_INC(icmp6.drop); return; } switch (icmp6hdr->type) { case ICMP6_TYPE_EREQ: if (ping6_proxy_accept_callback != NULL) { (*ping6_proxy_accept_callback)(ping6_proxy_accept_arg, p); return; } ICMP6_STATS_INC(icmp6.drop); break; case ICMP6_TYPE_EREP: /* ignore silently */ ICMP6_STATS_INC(icmp6.drop); break; default: ICMP6_STATS_INC(icmp6.drop); break; } pbuf_free(p); }
/** * Send the raw IP packet to the given address. Note that actually you cannot * modify the IP headers (this is inconsistent with the receive callback where * you actually get the IP headers), you can only specify the IP payload here. * It requires some more changes in lwIP. (there will be a raw_send() function * then.) * * @param pcb the raw pcb which to send * @param p the IP payload to send * @param ipaddr the destination address of the IP packet * */ err_t raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) { err_t err; struct netif *netif; ipX_addr_t *src_ip; struct pbuf *q; /* q will be sent down the stack */ s16_t header_size; const ipX_addr_t *dst_ip = ip_2_ipX(ipaddr); LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); header_size = ( #if LWIP_IPV6 PCB_ISIPV6(pcb) ? IP6_HLEN : #endif /* LWIP_IPV6 */ IP_HLEN); /* not enough space to add an IP header to first pbuf in given p chain? */ if (pbuf_header(p, header_size)) { /* allocate header in new pbuf */ q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); /* new header pbuf could not be allocated? */ if (q == NULL) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); return ERR_MEM; } if (p->tot_len != 0) { /* chain header q in front of given pbuf p */ pbuf_chain(q, p); } /* { first pbuf q points to header pbuf } */ LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); } else { /* first pbuf q equals given pbuf */ q = p; if(pbuf_header(q, -header_size)) { LWIP_ASSERT("Can't restore header we just removed!", 0); return ERR_MEM; } } netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip); if (netif == NULL) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); ipX_addr_debug_print(PCB_ISIPV6(pcb), RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip); /* free any temporary header pbuf allocated by pbuf_header() */ if (q != p) { pbuf_free(q); } return ERR_RTE; } #if IP_SOF_BROADCAST #if LWIP_IPV6 if (!PCB_ISIPV6(pcb)) #endif /* LWIP_IPV6 */ { /* broadcast filter? */ if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); /* free any temporary header pbuf allocated by pbuf_header() */ if (q != p) { pbuf_free(q); } return ERR_VAL; } } #endif /* IP_SOF_BROADCAST */ if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { /* use outgoing network interface IP address as source address */ src_ip = ipX_netif_get_local_ipX(PCB_ISIPV6(pcb), netif, dst_ip); #if LWIP_IPV6 if (src_ip == NULL) { if (q != p) { pbuf_free(q); } return ERR_RTE; } #endif /* LWIP_IPV6 */ } else { /* use RAW PCB local IP address as source address */ src_ip = &pcb->local_ip; } #if LWIP_IPV6 /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542, compute the checksum and update the checksum in the payload. */ if (PCB_ISIPV6(pcb) && pcb->chksum_reqd) { u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ipX_2_ip6(src_ip), ipX_2_ip6(dst_ip)); LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2)); SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t)); } #endif NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); err = ipX_output_if(PCB_ISIPV6(pcb), q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif); NETIF_SET_HWADDRHINT(netif, NULL); /* did we chain a header earlier? */ if (q != p) { /* free the header */ pbuf_free(q); } return err; }
/** * Process an input ICMPv6 message. Called by ip6_input. * * Will generate a reply for echo requests. Other messages are forwarded * to nd6_input, or mld6_input. * * @param p the mld packet, p->payload pointing to the icmpv6 header * @param inp the netif on which this packet was received */ void icmp6_input(struct pbuf *p, struct interface *inp) { struct icmp6_hdr *icmp6hdr; struct pbuf * r; ip6_addr_t * reply_src; ICMP6_STATS_INC(icmp6.recv); /* Check that ICMPv6 header fits in payload */ if (p->len < sizeof(struct icmp6_hdr)) { /* drop short packets */ pbuf_free(p); ICMP6_STATS_INC(icmp6.lenerr); ICMP6_STATS_INC(icmp6.drop); return; } icmp6hdr = (struct icmp6_hdr *)p->payload; #if LWIP_ICMP6_CHECKSUM_CHECK if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(), ip6_current_dest_addr()) != 0) { /* Checksum failed */ pbuf_free(p); ICMP6_STATS_INC(icmp6.chkerr); ICMP6_STATS_INC(icmp6.drop); return; } #endif /* LWIP_ICMP6_CHECKSUM_CHECK */ switch (icmp6hdr->type) { case ICMP6_TYPE_NA: /* Neighbor advertisement */ case ICMP6_TYPE_NS: /* Neighbor solicitation */ case ICMP6_TYPE_RA: /* Router advertisement */ case ICMP6_TYPE_RD: /* Redirect */ case ICMP6_TYPE_PTB: /* Packet too big */ nd6_input(p, inp); return; break; case ICMP6_TYPE_RS: #if LWIP_IPV6_FORWARD /* TODO implement router functionality */ #endif break; #if LWIP_IPV6_MLD case ICMP6_TYPE_MLQ: case ICMP6_TYPE_MLR: case ICMP6_TYPE_MLD: mld6_input(p, inp); return; break; #endif case ICMP6_TYPE_EREQ: #if !LWIP_MULTICAST_PING /* multicast destination address? */ if (ip6_addr_ismulticast(ip6_current_dest_addr())) { /* drop */ pbuf_free(p); ICMP6_STATS_INC(icmp6.drop); return; } #endif /* LWIP_MULTICAST_PING */ /* Allocate reply. */ r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM); if (r == NULL) { /* drop */ pbuf_free(p); ICMP6_STATS_INC(icmp6.memerr); return; } /* Copy echo request. */ if (pbuf_copy(r, p) != ERR_OK) { /* drop */ pbuf_free(p); pbuf_free(r); ICMP6_STATS_INC(icmp6.err); return; } /* Determine reply source IPv6 address. */ #if LWIP_MULTICAST_PING if (ip6_addr_ismulticast(ip6_current_dest_addr())) { reply_src = ip6_select_source_address(inp, ip6_current_src_addr()); if (reply_src == NULL) { /* drop */ pbuf_free(p); pbuf_free(r); ICMP6_STATS_INC(icmp6.rterr); return; } } else #endif /* LWIP_MULTICAST_PING */ { reply_src = ip6_current_dest_addr(); } /* Set fields in reply. */ ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP; ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0; ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr()); /* Send reply. */ ICMP6_STATS_INC(icmp6.xmit); ip6_output_if(r, reply_src, ip6_current_src_addr(), LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp); pbuf_free(r); break; default: ICMP6_STATS_INC(icmp6.proterr); ICMP6_STATS_INC(icmp6.drop); break; } pbuf_free(p); }
/** * Send an ICMPv6 packet in response to an incoming packet. * * @param p the input packet for which the response should be sent, * p->payload pointing to the IPv6 header * @param code Code of the ICMPv6 header * @param data Additional 32-bit parameter in the ICMPv6 header * @param type Type of the ICMPv6 header */ static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) { struct pbuf *q; struct icmp6_hdr *icmp6hdr; ip6_addr_t *reply_src, *reply_dest; ip6_addr_t reply_src_local, reply_dest_local; struct ip6_hdr *ip6hdr; struct interface *netif; /* ICMPv6 header + IPv6 header + data */ q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE, PBUF_RAM); if (q == NULL) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n")); ICMP6_STATS_INC(icmp6.memerr); return; } LWIP_ASSERT("check that first pbuf can hold icmp 6message", (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE))); icmp6hdr = (struct icmp6_hdr *)q->payload; icmp6hdr->type = type; icmp6hdr->code = code; icmp6hdr->data = data; /* copy fields from original packet */ SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload, IP6_HLEN + LWIP_ICMP6_DATASIZE); /* Get the destination address and netif for this ICMP message. */ if ((ip_current_netif() == NULL) || ((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) { /* Special case, as ip6_current_xxx is either NULL, or points * to a different packet than the one that expired. * We must use the addresses that are stored in the expired packet. */ ip6hdr = (struct ip6_hdr *)p->payload; /* copy from packed address to aligned address */ ip6_addr_copy(reply_dest_local, ip6hdr->src); ip6_addr_copy(reply_src_local, ip6hdr->dest); reply_dest = &reply_dest_local; reply_src = &reply_src_local; netif = ip6_route(reply_src, reply_dest); if (netif == NULL) { /* drop */ pbuf_free(q); ICMP6_STATS_INC(icmp6.rterr); return; } } else { netif = ip_current_netif(); reply_dest = ip6_current_src_addr(); /* Select an address to use as source. */ reply_src = ip6_select_source_address(netif, reply_dest); if (reply_src == NULL) { /* drop */ pbuf_free(q); ICMP6_STATS_INC(icmp6.rterr); return; } } /* calculate checksum */ icmp6hdr->chksum = 0; icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, reply_src, reply_dest); ICMP6_STATS_INC(icmp6.xmit); ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); pbuf_free(q); }
/********************************************************************************************************* ** 函数名称: __inetPing6Prepare ** 功能描述: 构造 ping 包 ** 输 入 : icmp6hdrEcho 数据 ** pip6addrDest 目标 IP ** iDataSize 数据大小 ** pcNetif 网络接口名 (NULL 表示自动确定接口) ** pusSeqRecv 需要判断的 seq ** 输 出 : ERROR ** 全局变量: ** 调用模块: *********************************************************************************************************/ static INT __inetPing6Prepare (struct icmp6_echo_hdr *icmp6hdrEcho, struct ip6_addr *pip6addrDest, INT iDataSize, CPCHAR pcNetif, UINT16 *pusSeqRecv) { static u16_t usSeqNum = 1; REGISTER INT i; #if CHECKSUM_GEN_ICMP6 INT iError; struct ip6_addr ip6addrSrc; struct pbuf pbuf; struct netif *netif; #endif /* CHECKSUM_GEN_ICMP6 */ SYS_ARCH_DECL_PROTECT(x); icmp6hdrEcho->type = ICMP6_TYPE_EREQ; icmp6hdrEcho->code = 0; *pusSeqRecv = usSeqNum; icmp6hdrEcho->chksum = 0; icmp6hdrEcho->id = 0xAFAF; /* ID */ icmp6hdrEcho->seqno = htons(usSeqNum); /* * 填充数据 */ for(i = 0; i < iDataSize; i++) { ((PCHAR)icmp6hdrEcho)[sizeof(struct icmp6_echo_hdr) + i] = (CHAR)(i % 256); } #if CHECKSUM_GEN_ICMP6 LOCK_TCPIP_CORE(); if (pcNetif) { netif = netif_find((PCHAR)pcNetif); if (netif == LW_NULL) { UNLOCK_TCPIP_CORE(); fprintf(stderr, "Invalid interface.\n"); return (PX_ERROR); } } else { netif = LW_NULL; } iError = __inetPing6FindSrc(netif, pip6addrDest, &ip6addrSrc); UNLOCK_TCPIP_CORE(); if (iError == -1) { fprintf(stderr, "You must determine net interface.\n"); return (PX_ERROR); } else if (iError == -2) { fprintf(stderr, "Unreachable destination.\n"); return (PX_ERROR); } pbuf.next = LW_NULL; pbuf.payload = (void *)icmp6hdrEcho; pbuf.tot_len = (u16_t)(iDataSize + sizeof(struct icmp6_echo_hdr)); pbuf.len = pbuf.tot_len; pbuf.type = PBUF_ROM; pbuf.flags = 0; pbuf.ref = 1; icmp6hdrEcho->chksum = ip6_chksum_pseudo(&pbuf, IP6_NEXTH_ICMP6, pbuf.tot_len, &ip6addrSrc, pip6addrDest); #endif /* CHECKSUM_GEN_ICMP6 */ SYS_ARCH_PROTECT(x); usSeqNum++; SYS_ARCH_UNPROTECT(x); return (ERROR_NONE); }