/* Standalone single-RA injection test - check if RA arrives in icmp6 */
#include <sys/fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <net/ethernet.h>
struct pi { uint8_t t,l,pl,fl; uint32_t v,p,r; struct in6_addr prefix; };
static uint16_t cksum6(const struct in6_addr*s,const struct in6_addr*d,const void*p,size_t l){
  uint32_t sum=0; const uint16_t*q=p; size_t i;
  for(i=0;i+1<l;i+=2) sum+=ntohs(q[i]);
  if(i<l) sum+=((uint16_t)((const uint8_t*)p)[i])<<8;
  for(i=0;i<8;i++){sum+=ntohs(s->__u6_addr.__u6_addr16[i]);sum+=ntohs(d->__u6_addr.__u6_addr16[i]);}
  sum+=l; sum+=IPPROTO_ICMPV6;
  while(sum>>16) sum=(sum&0xffff)+(sum>>16);
  return htons(~sum&0xffff);
}
int main(int argc,char**argv){
  const char*path=argc>1?argv[1]:"/dev/tap0";
  int fd=open(path,O_RDWR);
  if(fd<0){perror("open");return 1;}
  unsigned char pkt[256]; size_t off=0;
  struct ether_header*eh=(void*)pkt;
  eh->ether_dhost[0]=0x33;eh->ether_dhost[1]=0x33;eh->ether_dhost[2]=0;eh->ether_dhost[3]=0;eh->ether_dhost[4]=0;eh->ether_dhost[5]=1;
  eh->ether_shost[0]=0x02;eh->ether_shost[1]=0xaa;eh->ether_shost[2]=0xbb;eh->ether_shost[3]=0;eh->ether_shost[4]=0;eh->ether_shost[5]=0xcc;
  eh->ether_type=htons(ETHERTYPE_IPV6);
  off+=sizeof(*eh);
  struct ip6_hdr*ip6=(void*)(pkt+off);
  ip6->ip6_flow=0;            /* 4-byte union with vfc — set FIRST */
  ip6->ip6_vfc=0x60;          /* then version=6, traffic class=0 */
  ip6->ip6_plen=htons(sizeof(struct nd_router_advert)+sizeof(struct pi));
  ip6->ip6_nxt=IPPROTO_ICMPV6;ip6->ip6_hlim=255;
  inet_pton(AF_INET6,"ff02::1",&ip6->ip6_dst);
  inet_pton(AF_INET6,"fe80::1",&ip6->ip6_src);
  off+=sizeof(*ip6);
  struct nd_router_advert*ra=(void*)(pkt+off);
  ra->nd_ra_type=ND_ROUTER_ADVERT;ra->nd_ra_code=0;ra->nd_ra_cksum=0;
  ra->nd_ra_curhoplimit=64;ra->nd_ra_flags_reserved=0;
  ra->nd_ra_router_lifetime=htons(1800);ra->nd_ra_reachable=0;ra->nd_ra_retransmit=0;
  off+=sizeof(*ra);
  struct pi*pi=(void*)(pkt+off);
  pi->t=3;pi->l=4;pi->pl=64;pi->fl=0xc0;
  pi->v=htonl(1800);pi->p=htonl(1800);pi->r=0;
  inet_pton(AF_INET6,"2001:db8:1::",&pi->prefix);
  off+=sizeof(*pi);
  ra->nd_ra_cksum=cksum6(&ip6->ip6_src,&ip6->ip6_dst,ra,sizeof(*ra)+sizeof(*pi));
  ssize_t w=write(fd,pkt,off);
  printf("w=%zd len=%zu cksum=%04x\n",w,off,ntohs(ra->nd_ra_cksum));
  sleep(1);
  close(fd);
  return 0;
}
