int icmp_send(struct iphdr * __ip, struct icmp * __icp, int __len) { struct route * rt; uint32_t saddr; uint32_t daddr; int ret; ICMP_PROTO_STAT_ADD(tx_ok, 1); __len += ICMP_MINLEN; saddr = __ip->daddr; daddr = __ip->saddr; /* build the ip header (swap addresses) */ iph_template(__ip, IPPROTO_ICMP, ip_defttl, ip_deftos); mk_iphdr(__ip, saddr, daddr, __len); __icp->icmp_chksum = 0; __icp->icmp_chksum = ~in_chksum(0, (uint8_t *)__icp, __len); DCC_LOG3(LOG_INFO, "ICMP %I > %I (%d)", __ip->saddr, __ip->daddr, __len); if ((rt = __route_lookup(daddr)) == NULL) { ICMP_PROTO_STAT_ADD(tx_drop, 1); DCC_LOG1(LOG_WARNING, "no route to host: %I", daddr); return -1; } if ((ret = ip_output(rt->rt_ifn, rt, __ip)) < 0) { DCC_LOG(LOG_ERROR, "ip_output() fail!"); /* XXX: */ ICMP_PROTO_STAT_ADD(tx_drop, 1); if (ret == -EAGAIN) { /* FIXME: non ethernet type interfaces */ etharp_query_pending(); } return -1; } return 0; }
int raw_sendto(struct raw_pcb * __raw, void * __buf, int __len, const struct sockaddr_in * __sin) { struct iphdr * ip; in_addr_t daddr; in_addr_t saddr; struct route * rt; uint8_t * ptr; int mtu; struct ifnet * ifn; DCC_LOG2(LOG_TRACE, "<%05x> len=%d", (int)__raw, __len); tcpip_net_lock(); DCC_LOG2(LOG_INFO, "<%05x> lock [%d]", (int)__raw, net_mutex); if (__raw == NULL) { DCC_LOG(LOG_WARNING, "invalid pcb"); tcpip_net_unlock(); return -EFAULT; } if (__buf == NULL) { DCC_LOG(LOG_WARNING, "invalid buffer"); tcpip_net_unlock(); return -EFAULT; } daddr = __sin->sin_addr.s_addr; if ((rt = __route_lookup(daddr)) == NULL) { DCC_LOG1(LOG_WARNING, "no route to host: %I", daddr); tcpip_net_unlock(); return -1; } ifn = (struct ifnet *)rt->rt_ifn; mtu = ifn->if_mtu - sizeof(struct iphdr); if ((__len <= 0) || (__len > mtu)) { DCC_LOG3(LOG_WARNING, "<%05x> invalid length %d (max: %d)", (int)__raw, __len, __raw->r_mtu); tcpip_net_unlock(); return 0; } /* get the source address */ if ((saddr = __raw->r_laddr) == INADDR_ANY) { saddr = ifn->if_ipv4_addr; } ip = (struct iphdr *)ifn_mmap(ifn, sizeof(struct iphdr) + __len); iph_template(ip, __raw->r_protocol, ip_defttl, __raw->r_tos); ptr = (uint8_t *)ip->opt; /* build the ip header */ mk_iphdr(ip, saddr, daddr, __len); memcpy(ptr, __buf, __len); DCC_LOG3(LOG_TRACE, "IP %I > %I (%d)", ip->saddr, ip->daddr, __len); if (ip_output(rt, ip) < 0) { DCC_LOG1(LOG_ERROR, "<%05x> ip_output() fail!", (int)__raw); /* if the reason to fail was an arp failure try query an address pending for resolution ... */ etharp_query_pending(); tcpip_net_unlock(); return -1; } tcpip_net_unlock(); return __len; }
int udp_sendto(struct udp_pcb * __up, void * __buf, int __len, const struct sockaddr_in * __sin) { struct iphdr * ip; struct udphdr * uh; in_addr_t daddr; int dport; in_addr_t saddr; struct route * rt; #if (ENABLE_NET_UDP_CHECKSUM) unsigned int sum; #endif uint8_t * ptr; int mtu; struct ifnet * ifn; int ret; int retry = 0; DCC_LOG2(LOG_INFO, "<%05x> len=%d", (int)__up, __len); if (__up == NULL) { DCC_LOG1(LOG_WARNING, "<%05x> invalid pcb", (int)__up); return -EFAULT; } if (__buf == NULL) { DCC_LOG1(LOG_WARNING, "<%05x> invalid buffer", (int)__up); return -EFAULT; } tcpip_net_lock(); #if (ENABLE_NET_SANITY_CHECK) if (pcb_find((struct pcb *)__up, &__udp__.pcb) < 0) { DCC_LOG1(LOG_ERROR, "<%05x> pcb_find()", (int)__up); tcpip_net_unlock(); /* TODO: errno */ return -1; } #endif if ((__up->u_lport) == 0) { DCC_LOG1(LOG_WARNING, "<%05x> not bound", (int)__up); tcpip_net_unlock(); /* TODO: errno */ return -3; } if (__sin == NULL) { if ((dport = __up->u_fport) == 0) { DCC_LOG1(LOG_WARNING, "<%05x> connection refused", (int)__up); tcpip_net_unlock(); return -ECONNREFUSED; } if ((daddr = __up->u_faddr) == INADDR_ANY) { DCC_LOG1(LOG_WARNING, "<%05x> not connected", (int)__up); tcpip_net_unlock(); return -ENOTCONN; } } else { if ((dport = __sin->sin_port) == 0) { DCC_LOG1(LOG_WARNING, "<%05x> invalid port", (int)__up); tcpip_net_unlock(); return -ECONNREFUSED; } if ((daddr = __sin->sin_addr.s_addr) == INADDR_ANY) { DCC_LOG1(LOG_WARNING, "<%05x> invalid address", (int)__up); tcpip_net_unlock(); return -EDESTADDRREQ; } } if ((rt = __route_lookup(daddr)) == NULL) { DCC_LOG2(LOG_WARNING, "<%05x> no route to host: %I", (int)__up, daddr); tcpip_net_unlock(); UDP_PROTO_STAT_ADD(tx_drop, 1); UDP_PROTO_STAT_ADD(tx_err, 1); return -EHOSTUNREACH; } ifn = (struct ifnet *)rt->rt_ifn; mtu = ifn->if_mtu - sizeof(struct iphdr); if ((__len <= 0) || (__len > mtu)) { DCC_LOG3(LOG_WARNING, "<%04x> invalid length %d (max: %d)", (int)__up, __len, mtu); tcpip_net_unlock(); /* TODO: errno */ return -7; } /* get the source address */ if ((saddr = __up->u_laddr) == INADDR_ANY) { saddr = ifn->if_ipv4_addr; } again: ip = (struct iphdr *)ifn_mmap(ifn, sizeof(struct iphdr) + sizeof(struct udphdr) + __len); if (ip == NULL) { DCC_LOG1(LOG_WARNING, "<%04x> ifn_mmap() fail", (int)__up); tcpip_net_unlock(); /* TODO: errno */ return -1; } DCC_LOG2(LOG_TRACE, "<%05x> ip=%p", (int)__up, ip); iph_template(ip, IPPROTO_UDP, udp_def_ttl, udp_def_tos); uh = (struct udphdr *)ip->opt; /* build the ip header */ ip = mk_iphdr(ip, saddr, daddr, sizeof(struct udphdr) + __len); /* fill the udp header fields */ uh = (struct udphdr *)ip->opt; uh->dport = dport; uh->sport = __up->u_lport; uh->len = htons(__len + sizeof(struct udphdr)); #if (ENABLE_NET_UDP_CHECKSUM) /* initialize the udp checksum */ sum = uh->len << 1; sum += uh->dport; sum += uh->sport; sum += (IPPROTO_UDP << 8); sum += ((uint16_t *)(void *)&(ip->saddr))[0] + ((uint16_t *)(void *)&(ip->saddr))[1]; sum += ((uint16_t *)(void *)&(ip->daddr))[0] + ((uint16_t *)(void *)&(ip->daddr))[1]; #endif ptr = (uint8_t *)uh + sizeof(struct udphdr); memcpy(ptr, __buf, __len); #if (ENABLE_NET_UDP_CHECKSUM) if (__len) { sum = in_chksum(sum, ptr, __len); } uh->chksum = ~sum; #else uh->chksum = 0; #endif #if 0 DCC_LOG(LOG_INFO, "IP %d.%d.%d.%d:%d > %d.%d.%d.%d:%d: %d", IP4_ADDR1(ip->saddr), IP4_ADDR2(ip->saddr), IP4_ADDR3(ip->saddr), IP4_ADDR4(ip->saddr), ntohs(uh->sport), IP4_ADDR1(ip->daddr), IP4_ADDR2(ip->daddr), IP4_ADDR3(ip->daddr), IP4_ADDR4(ip->daddr), ntohs(uh->dport), ntohs(uh->len)); #endif if ((ret = ip_output(ifn, rt, ip)) < 0) { ifn_munmap(ifn, ip); /* if the reason to fail was an arp failure try query an address pending for resolution ... */ if ((ret == -EAGAIN) && (retry < 10)) { etharp_query_pending(); tcpip_net_unlock(); DCC_LOG2(LOG_WARNING, "<%05x> again, retry=%d!", (int)__up, retry); thinkos_sleep(10 + retry * 10); retry++; tcpip_net_lock(); goto again; } DCC_LOG1(LOG_ERROR, "<%05x> ip_output() fail!", (int)__up); UDP_PROTO_STAT_ADD(tx_drop, 1); } else { UDP_PROTO_STAT_ADD(tx_ok, 1); DCC_LOG5(LOG_INFO, "IP %I:%d > %I:%d: %d", ip->saddr, ntohs(uh->sport), ip->daddr, ntohs(uh->dport), ntohs(uh->len)); #if (LOG_LEVEL < LOG_INFO) DCC_LOG(LOG_INFO, "sent."); #endif ret = __len; } tcpip_net_unlock(); return ret; }