1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
| /** * Same as ip_output_if() but 'src' address is not replaced by netif address * when it is 'any'. */ err_t ip4_output_if_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif) { #if IP_OPTIONS_SEND return ip4_output_if_opt_src(p, src, dest, ttl, tos, proto, netif, NULL, 0); }
/** * Same as ip_output_if_opt() but 'src' address is not replaced by netif address * when it is 'any'. */ err_t ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, u16_t optlen) { #endif /* IP_OPTIONS_SEND */ struct ip_hdr *iphdr; ip4_addr_t dest_addr; #if CHECKSUM_GEN_IP_INLINE u32_t chk_sum = 0; #endif /* CHECKSUM_GEN_IP_INLINE */
LWIP_ASSERT_CORE_LOCKED(); LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
MIB2_STATS_INC(mib2.ipoutrequests);
/* Should the IP header be generated or is it already included in p? */ if (dest != LWIP_IP_HDRINCL) { u16_t ip_hlen = IP_HLEN; #if IP_OPTIONS_SEND u16_t optlen_aligned = 0; if (optlen != 0) { #if CHECKSUM_GEN_IP_INLINE int i; #endif /* CHECKSUM_GEN_IP_INLINE */ if (optlen > (IP_HLEN_MAX - IP_HLEN)) { /* optlen too long */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output_if_opt: optlen too long\n")); IP_STATS_INC(ip.err); MIB2_STATS_INC(mib2.ipoutdiscards); return ERR_VAL; } /* round up to a multiple of 4 */ optlen_aligned = (u16_t)((optlen + 3) & ~3); ip_hlen = (u16_t)(ip_hlen + optlen_aligned); /* First write in the IP options */ if (pbuf_add_header(p, optlen_aligned)) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output_if_opt: not enough room for IP options in pbuf\n")); IP_STATS_INC(ip.err); MIB2_STATS_INC(mib2.ipoutdiscards); return ERR_BUF; } MEMCPY(p->payload, ip_options, optlen); if (optlen < optlen_aligned) { /* zero the remaining bytes */ memset(((char *)p->payload) + optlen, 0, (size_t)(optlen_aligned - optlen)); } #if CHECKSUM_GEN_IP_INLINE for (i = 0; i < optlen_aligned / 2; i++) { chk_sum += ((u16_t *)p->payload)[i]; } #endif /* CHECKSUM_GEN_IP_INLINE */ } #endif /* IP_OPTIONS_SEND */ /* generate IP header */ if (pbuf_add_header(p, IP_HLEN)) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output: not enough room for IP header in pbuf\n"));
IP_STATS_INC(ip.err); MIB2_STATS_INC(mib2.ipoutdiscards); return ERR_BUF; }
iphdr = (struct ip_hdr *)p->payload; LWIP_ASSERT("check that first pbuf can hold struct ip_hdr", (p->len >= sizeof(struct ip_hdr)));
IPH_TTL_SET(iphdr, ttl); IPH_PROTO_SET(iphdr, proto); #if CHECKSUM_GEN_IP_INLINE chk_sum += PP_NTOHS(proto | (ttl << 8)); #endif /* CHECKSUM_GEN_IP_INLINE */
/* dest cannot be NULL here */ ip4_addr_copy(iphdr->dest, *dest); #if CHECKSUM_GEN_IP_INLINE chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF; chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16; #endif /* CHECKSUM_GEN_IP_INLINE */
IPH_VHL_SET(iphdr, 4, ip_hlen / 4); IPH_TOS_SET(iphdr, tos); #if CHECKSUM_GEN_IP_INLINE chk_sum += PP_NTOHS(tos | (iphdr->_v_hl << 8)); #endif /* CHECKSUM_GEN_IP_INLINE */ IPH_LEN_SET(iphdr, lwip_htons(p->tot_len)); #if CHECKSUM_GEN_IP_INLINE chk_sum += iphdr->_len; #endif /* CHECKSUM_GEN_IP_INLINE */ IPH_OFFSET_SET(iphdr, 0); IPH_ID_SET(iphdr, lwip_htons(ip_id)); #if CHECKSUM_GEN_IP_INLINE chk_sum += iphdr->_id; #endif /* CHECKSUM_GEN_IP_INLINE */ ++ip_id;
if (src == NULL) { ip4_addr_copy(iphdr->src, *IP4_ADDR_ANY4); } else { /* src cannot be NULL here */ ip4_addr_copy(iphdr->src, *src); }
#if CHECKSUM_GEN_IP_INLINE chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF; chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16; chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF); chk_sum = (chk_sum >> 16) + chk_sum; chk_sum = ~chk_sum; IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { iphdr->_chksum = (u16_t)chk_sum; /* network order */ } #if LWIP_CHECKSUM_CTRL_PER_NETIF else { IPH_CHKSUM_SET(iphdr, 0); } #endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/ #else /* CHECKSUM_GEN_IP_INLINE */ IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); } #endif /* CHECKSUM_GEN_IP */ #endif /* CHECKSUM_GEN_IP_INLINE */ } else { /* IP header already included in p */ if (p->len < IP_HLEN) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output: LWIP_IP_HDRINCL but pbuf is too short\n")); IP_STATS_INC(ip.err); MIB2_STATS_INC(mib2.ipoutdiscards); return ERR_BUF; } iphdr = (struct ip_hdr *)p->payload; ip4_addr_copy(dest_addr, iphdr->dest); dest = &dest_addr; }
IP_STATS_INC(ip.xmit);
LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], (u16_t)netif->num)); ip4_debug_print(p);
#if ENABLE_LOOPBACK if (ip4_addr_eq(dest, netif_ip4_addr(netif)) #if !LWIP_HAVE_LOOPIF || ip4_addr_isloopback(dest) #endif /* !LWIP_HAVE_LOOPIF */ ) { /* Packet to self, enqueue it for loopback */ LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()\n")); return netif_loop_output(netif, p); } #if LWIP_MULTICAST_TX_OPTIONS if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { netif_loop_output(netif, p); } #endif /* LWIP_MULTICAST_TX_OPTIONS */ #endif /* ENABLE_LOOPBACK */ #if IP_FRAG /* don't fragment if interface has mtu set to 0 [loopif] */ if (netif->mtu && (p->tot_len > netif->mtu)) { return ip4_frag(p, netif, dest); } #endif /* IP_FRAG */
LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: call netif->output()\n")); return netif->output(netif, p, dest); }
|