static int ssdp_ip6_msearch(interface *i,const uint128_t saddr) { const unsigned char hw[ETH_ALEN] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0xc }; uint128_t net = { htonl(0xff020000ul), htonl(0x0ul), htonl(0x0ul), htonl(0xcul) }; struct tpacket_hdr *thdr; struct udphdr *udp; struct ip6_hdr *ip; size_t flen,tlen; void *frame; int r; if((frame = get_tx_frame(i,&flen)) == NULL) { return -1; } thdr = frame; tlen = thdr->tp_mac; if((r = prep_eth_header((char *)frame + tlen,flen - tlen,i, hw,ETH_P_IPV6)) < 0) { abort_tx_frame(i,frame); return -1; } tlen += r; ip = (struct ip6_hdr *)((char *)frame + tlen); if((r = prep_ipv6_header(ip,flen - tlen,saddr,net,IPPROTO_UDP)) < 0) { abort_tx_frame(i,frame); return -1; } tlen += r; if(flen - tlen < sizeof(*udp)) { abort_tx_frame(i,frame); return -1; } udp = (struct udphdr *)((char *)frame + tlen); udp->source = htons(SSDP_UDP_PORT); udp->dest = htons(SSDP_UDP_PORT); tlen += sizeof(*udp); r = setup_ssdp_query((char *)frame + tlen,flen - tlen); if(r < 0) { abort_tx_frame(i,frame); return -1; } tlen += r; thdr->tp_len = tlen; ip->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(thdr->tp_len - ((const char *)udp - (const char *)frame)); udp->len = ip->ip6_ctlun.ip6_un1.ip6_un1_plen; udp->check = udp6_csum(ip); thdr->tp_len -= thdr->tp_mac; return send_tx_frame(i,frame); }
static int ssdp_ip4_msearch(interface *i,const uint32_t *saddr) { const unsigned char hw[ETH_ALEN] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xc }; uint32_t net = htonl(SSDP_NET4); struct tpacket_hdr *thdr; struct udphdr *udp; struct iphdr *ip; size_t flen,tlen; void *frame; int r; if((frame = get_tx_frame(i,&flen)) == NULL) { return -1; } thdr = frame; tlen = thdr->tp_mac; if((r = prep_eth_header((char *)frame + tlen,flen - tlen,i, hw,ETH_P_IP)) < 0) { abort_tx_frame(i,frame); return -1; } tlen += r; ip = (struct iphdr *)((char *)frame + tlen); if((r = prep_ipv4_header(ip,flen - tlen,*saddr,net,IPPROTO_UDP)) < 0) { abort_tx_frame(i,frame); return -1; } tlen += r; if(flen - tlen < sizeof(*udp)) { abort_tx_frame(i,frame); return -1; } udp = (struct udphdr *)((char *)frame + tlen); udp->source = htons(SSDP_UDP_PORT); udp->dest = htons(SSDP_UDP_PORT); tlen += sizeof(*udp); r = setup_ssdp_query((char *)frame + tlen,flen - tlen); if(r < 0) { abort_tx_frame(i,frame); return -1; } tlen += r; ip->tot_len = htons(tlen - ((const char *)ip - (const char *)frame)); ip->check = ipv4_csum(ip); udp->len = htons(ntohs(ip->tot_len) - ip->ihl * 4u); udp->check = udp4_csum(ip); thdr->tp_len = tlen - thdr->tp_mac; return send_tx_frame(i,frame); }
// Always goes to ff02::2 (ALL-HOSTS), from each source address. int tx_ipv6_bcast_pings(interface *i,const uint128_t saddr){ const unsigned char hw[ETH_ALEN] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 }; uint128_t net = { htonl(0xff020000ul), htonl(0x0ul), htonl(0x0ul), htonl(0x1ul) }; struct tpacket_hdr *thdr; struct icmp6_hdr *icmp; struct ip6_hdr *ip; size_t flen,tlen; void *frame; int r; if((frame = get_tx_frame(i,&flen)) == NULL){ return -1; } thdr = frame; tlen = thdr->tp_mac; if((r = prep_eth_header((char *)frame + tlen,flen - tlen,i, hw,ETH_P_IPV6)) < 0){ abort_tx_frame(i,frame); return -1; } tlen += r; ip = (struct ip6_hdr *)((char *)frame + tlen); if((r = prep_ipv6_header(ip,flen - tlen,saddr,net,IPPROTO_ICMP6)) < 0){ abort_tx_frame(i,frame); return -1; } tlen += r; if(flen - tlen < sizeof(*icmp)){ abort_tx_frame(i,frame); return -1; } icmp = (struct icmp6_hdr *)((char *)frame + tlen); icmp->icmp6_type = ICMP6_ECHO_REQUEST; icmp->icmp6_code = 0; tlen += sizeof(*icmp); thdr->tp_len = tlen; ip->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(thdr->tp_len - ((const char *)icmp - (const char *)frame)); icmp->icmp6_cksum = icmp6_csum(ip); return send_tx_frame(i,frame); }