I use following code:

/* Send Announce Packet */
int zc_freebsd_sendannounce(int fd, unsigned char *mac, int zc_addr) {
        unsigned char *announce = NULL;

        int i = 0;
        unsigned int packet_len = 0;
        
        struct ether_header *eth_hdr = NULL;
        struct ether_arp *eth_arp = NULL;

        if (mac == NULL || zc_addr == 0 || zc_addr == -1)
                return -1;

        packet_len = sizeof(struct ether_header) + (sizeof(struct ether_arp)
>= ETHER_PAYLOAD ?
                                                                                
sizeof(struct ether_arp) : ETHER_PAYLOAD);
        
        /* Allocate announce packet */
        if ((announce = malloc(packet_len)) == NULL)
                return -1;

        memset(announce, 0, packet_len);

        /* Populate Announce Packet
         *
         * eth_hdr
         * saddr - iface mac
         * daddr - ff:ff:ff:ff:ff:ff
         * type = ETHERTYPE_ARP
         *
         * eth_arp - ARP REQUEST
         * sender hw addr - iface mac
         * sender ip addr - zc_addr
         * target hw addr - 00:00:00:00:00:00
         * target ip addr - zc_addr
         */

        eth_hdr = (struct ether_header *)announce;
        eth_arp = (struct ether_arp *)((char *)eth_hdr + sizeof(struct 
ether_header));

        memcpy(eth_hdr->ether_dhost, eth_bcast_addr, ETHER_ADDR_LEN);
        memcpy(eth_hdr->ether_shost, mac, ETHER_ADDR_LEN);
        eth_hdr->ether_type = htons(ETHERTYPE_ARP);

        eth_arp->arp_hrd = htons(ARPHRD_ETHER);
        eth_arp->arp_pro = htons(ETHERTYPE_IP);
        eth_arp->arp_hln = ETHER_ADDR_LEN;
        eth_arp->arp_pln = IP_ADDR_LEN;
        eth_arp->arp_op = htons(ARPOP_REQUEST);
        
        memcpy(eth_arp->arp_sha, mac, ETHER_ADDR_LEN);
        memcpy(eth_arp->arp_spa, &zc_addr, IP_ADDR_LEN);
        memcpy(eth_arp->arp_tha, eth_null_addr, ETHER_ADDR_LEN);
        memcpy(eth_arp->arp_tpa, &zc_addr, IP_ADDR_LEN);

        /* Send packet over the wire */
        if ((i = write(fd, announce, packet_len)) < 0) {
                free(announce);
                return -1;
        }

        free(announce);
        return 0;
}

and later in my code i call this function in a loop:

                        for (i = 0; i < ANNOUNCE_NUM; i++) {
                                printf("ANNOUNCE ...\n"); fflush(stdout);

                                /* Get initial time */
                                if (clock_gettime(CLOCK_REALTIME, &ts0) < 0) {
                                        perror("clock_gettime");
                                        return -1;
                                }

                                /* Send Announce Packet */
                                if (zc_freebsd_sendannounce(bpf_fd, mac, 
zc_addr) < 0) {
                                        printf("zc_freebsd_sendannounce(): 
error\n");
                                        return -1;
                                }

                                /* Possibly check for conflicts here */

                                /* Get time after select() */
                                if (clock_gettime(CLOCK_REALTIME, &ts1) < 0) {
                                        perror("clock_gettime");
                                        return -1;
                                }

                                printf("ts0.sec |%ld|, ts0.nsec |%ld|\n", 
ts0.tv_sec,
ts0.tv_nsec); fflush(stdout);
                                printf("ts1.sec |%ld|, ts1.nsec |%ld|\n", 
ts1.tv_sec,
ts1.tv_nsec); fflush(stdout);

                                /* wait ANNOUNCE_INTERVAL or the rest of it */
                                ts0.tv_sec = ANNOUNCE_INTERVAL - (ts1.tv_sec - 
ts0.tv_sec) >= 0 ?
                                        ANNOUNCE_INTERVAL - (ts1.tv_sec - 
ts0.tv_sec) : 0;
                                ts0.tv_nsec = ((ANNOUNCE_INTERVAL - ts0.tv_sec) 
* 1000000000) -
(ts1.tv_nsec - ts0.tv_nsec) >= 0 ?
                                        ((ANNOUNCE_INTERVAL - ts0.tv_sec) * 
1000000000) - (ts1.tv_nsec -
ts0.tv_nsec) : 0;
                                nanosleep(&ts0, NULL);
                        } /* ANNOUNCE_NUM for() */

>From the two printf()'s above i see the nanosleep() is effective.
However, when I check the packet flow with Wireshark (on the same host
where this code is running) I see the announce packets timed only
miliseconds away from one another. Could this be an issue with
Wireshark ?! Right now I have only one computer to work on, but i'll
test the timing from another computer asap.

P.S. I'm implementing part of RFC3927 (ZeroConf) as part of a bigger project


On Thu, Nov 6, 2008 at 7:06 PM, Robert Watson <[EMAIL PROTECTED]> wrote:
>
> On Thu, 6 Nov 2008, Ivo Vachkov wrote:
>
>> I am using simple write() calls to send packets over BPF file descriptor.
>> The BPF file descriptor is in buffered read mode (I assume this is the
>> default and I do not set it explicitly). From what I see my write() calls
>> are somewhat buffered. Since timing is relatively important for my project
>> I'd like to ask if there is a way "flush" the write buffer. Setting O_DIRECT
>> flag on the file descriptor doesn't seem to have any effect.
>
> The write(2) system call does no buffering in userspace (unlike, say,
> fwrite(3)), and when you write to a BPF device it essentially goes straight
> into the network interface output queue, so there should be no need for a
> flush mechanism.  Could you describe the buffering effect you're seeing a
> bit more?
>
> Robert N M Watson
> Computer Laboratory
> University of Cambridge
>
_______________________________________________
freebsd-net@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to