Andreas Wrede <andreas%wrede.ca@localhost> writes: > Except for the length and seq, this is the same when doing an arp -s > 10.99.3.16 0.d.88.6f.2d.37 > > got message of size 154 on Thu Apr 2 11:46:57 2009 > RTM_ADD: Add Route: len 154, pid 16031, seq 1, errno 22, flags: > <HOST,STATIC,PROTO2> > locks: inits: <expire> > sockaddrs: <DST,GATEWAY> > 10.99.3.16 0.d.88.6f.2d.37 > > I compared the actual data written by arp and by pppd to the routing > socket. The differences: > > 1. pppd's request has the interface name in the sockaddr_dl structure, > arp does not > 2. arp's sdl_len is padded by 6 bytes, pppd's is not > 3. arp's rtm_msglen is padded by 4 byes, pppd's is not > > Changing pppd's arpmsg packet accordingly makes the proxy arp request > in pppd work! very interesting. Would you be able to back out the changes one by one to find the one that matters, or the minimal set needed. I am guessing that for rtm_msglen, the message was not a multiple of 8, and that there is some ROUND macro that can be used so that it gets rounded to sizeof(void *). > The diff below illustrates the changes: > > --- sys-bsd.c 25 Oct 2008 22:12:20 -0000 1.58 > +++ sys-bsd.c 2 Apr 2009 17:25:32 -0000 > @@ -1598,6 +1598,13 @@ > return 0; > } > > + /* remove the intrafce name from the sdl struct */ > + memcpy((char *)&arpmsg.hwa.sdl_data, (char *)&arpmsg.hwa.sdl_data > +arpmsg.hwa.sdl_nlen, arpmsg.hwa.sdl_alen); > + arpmsg.hwa.sdl_len-=arpmsg.hwa.sdl_nlen; > + arpmsg.hwa.sdl_nlen=0; > + /* pad the packet */ > + arpmsg.hwa.sdl_len+=6; > + This is the first one I would back out to try. > if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) { > error("Couldn't add proxy arp entry: socket: %m"); > return 0; > @@ -1615,7 +1622,7 @@ > arpmsg.dst.sin_other = SIN_PROXY; > > arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg > - + arpmsg.hwa.sdl_len; > + + arpmsg.hwa.sdl_len + 4; > if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { > error("Couldn't add proxy arp entry: %m"); > close(routes); > > I don't understand why the padding is needed, maybe i386 vs. amd64? In some user/kernel communications, the real rules (the code in the kernel) expects padding to sizeof(long) or sizeof(void *) between structures, or alternatively that structures are lined up on 4/8 boundaries with the padding internal to them. It maybe that the kernel is rounding to find the start of next structure, and it ends up in the wrong place. But we can't add 4 - we have to do some sort of rounding. If you are in the mood this can probably be figured out by reading kernel source code. Look for structs that have long or * in them that when compiled on amd64 won't endup on 8 byte boundaries, and see if the kernel code handles finding the next structure differently.
Attachment:
pgpenhjJcETnz.pgp
Description: PGP signature