* Unreliable IPv4 transmission of an mbuf chain to the debugnet server * Note: can't handle fragmentation; fails if the packet is larger than * ifp->if_mtu after adding the UDP/IP headers * * Parameters: * pcb The debugnet context block * m mbuf chain * * Returns: * int see errno.h, 0 for success */
| 442 | * int see errno.h, 0 for success |
| 443 | */ |
| 444 | int |
| 445 | debugnet_ip_output(struct debugnet_pcb *pcb, struct mbuf *m) |
| 446 | { |
| 447 | struct udphdr *udp; |
| 448 | struct ifnet *ifp; |
| 449 | struct ip *ip; |
| 450 | |
| 451 | MPASS(pcb->dp_state >= DN_STATE_HAVE_GW_MAC); |
| 452 | |
| 453 | ifp = pcb->dp_ifp; |
| 454 | |
| 455 | M_PREPEND(m, sizeof(*ip), M_NOWAIT); |
| 456 | if (m == NULL) { |
| 457 | printf("%s: out of mbufs\n", __func__); |
| 458 | return (ENOBUFS); |
| 459 | } |
| 460 | |
| 461 | if (m->m_pkthdr.len > ifp->if_mtu) { |
| 462 | printf("%s: Packet is too big: %d > MTU %u\n", __func__, |
| 463 | m->m_pkthdr.len, ifp->if_mtu); |
| 464 | m_freem(m); |
| 465 | return (ENOBUFS); |
| 466 | } |
| 467 | |
| 468 | ip = mtod(m, void *); |
| 469 | udp = (void *)(ip + 1); |
| 470 | |
| 471 | memset(ip, 0, offsetof(struct ip, ip_p)); |
| 472 | ip->ip_p = IPPROTO_UDP; |
| 473 | ip->ip_sum = udp->uh_ulen; |
| 474 | ip->ip_src = (struct in_addr) { pcb->dp_client }; |
| 475 | ip->ip_dst = (struct in_addr) { pcb->dp_server }; |
| 476 | |
| 477 | /* Compute UDP-IPv4 checksum. */ |
| 478 | udp->uh_sum = in_cksum(m, m->m_pkthdr.len); |
| 479 | if (udp->uh_sum == 0) |
| 480 | udp->uh_sum = 0xffff; |
| 481 | |
| 482 | ip->ip_v = IPVERSION; |
| 483 | ip->ip_hl = sizeof(*ip) >> 2; |
| 484 | ip->ip_tos = 0; |
| 485 | ip->ip_len = htons(m->m_pkthdr.len); |
| 486 | ip->ip_id = 0; |
| 487 | ip->ip_off = htons(IP_DF); |
| 488 | ip->ip_ttl = 255; |
| 489 | ip->ip_sum = 0; |
| 490 | ip->ip_sum = in_cksum(m, sizeof(struct ip)); |
| 491 | |
| 492 | return (debugnet_ether_output(m, ifp, pcb->dp_gw_mac, ETHERTYPE_IP)); |
| 493 | } |
no test coverage detected