// public function definitions void *arpd(void *threadarg) { assert(threadarg); struct thread_context *context; struct thread_context *contexts; struct arpd_data *data; struct in_addr *my_addr; int rv; struct transaction *transaction = NULL; struct ethernet_pkt *etherpkt; struct arp_pkt *arp; struct netmap_ring *rxring; void *ring_idx; uint32_t dispatcher_idx; struct msg_hdr *msg_hdr; context = (struct thread_context *)threadarg; contexts = context->shared->contexts; data = context->data; rxring = data->rxring; dispatcher_idx = context->shared->dispatcher_idx; my_addr = &context->shared->inet_info->addr; rv = arpd_init(context); if (!rv) { pthread_exit(NULL); } printf("arpd[%d]: initialized\n", context->thread_id); // signal to main() that we are initialized atomic_store_explicit(&context->initialized, 1, memory_order_release); // main event loop for (;;) { // read all the incoming packets while (tqueue_remove(context->pkt_recv_q, &transaction, &ring_idx) > 0) { etherpkt = (struct ethernet_pkt *) NETMAP_BUF(rxring, rxring->slot[(uint32_t)ring_idx].buf_idx); arp = (struct arp_pkt*) etherpkt->data; if (!arp_is_valid(arp)) { send_msg_transaction_update_single(&contexts[dispatcher_idx], (uint32_t)ring_idx); continue; } if (arp->arp_h.ar_op == ARP_OP_REQUEST) { if (arp->tpa.s_addr != my_addr->s_addr) { send_msg_transaction_update_single(&contexts[dispatcher_idx], (uint32_t) ring_idx); continue; } printf("R)"); arp_print_line(arp); // send_pkt_arp_reply could fail when xmit queue is full, // however, the sender should just resend a request send_pkt_arp_reply(context->pkt_xmit_q, &arp->spa, &arp->sha); } else { // ARP_OP_REPLY if (!arp_reply_filter(arp, my_addr)) { send_msg_transaction_update_single(&contexts[dispatcher_idx], (uint32_t) ring_idx); continue; } printf("R)"); arp_print_line(arp); // TODO: also check against a list of my outstanding arp requests // prior to insertion in the arp cache recv_pkt_arp_reply(arp, data->arp_cache, contexts); } send_msg_transaction_update_single(&contexts[dispatcher_idx], (uint32_t) ring_idx); } // while (packets) // resend outstanding requests and refresh expiring entries update_arp_cache(data->arp_cache, contexts, context->pkt_xmit_q); // TODO: read all the messages rv = squeue_enter(context->msg_q, 1); if (!rv) continue; while ((msg_hdr = squeue_get_next_pop_slot(context->msg_q)) != NULL) { switch (msg_hdr->msg_type) { case MSG_ARPD_GET_MAC: recv_msg_get_mac((void *)msg_hdr, data->arp_cache, contexts, context->pkt_xmit_q); break; default: printf("arpd: unknown message %hu\n", msg_hdr->msg_type); } } squeue_exit(context->msg_q); usleep(ARP_CACHE_RETRY_INTERVAL); } // for (;;) pthread_exit(NULL); }
int main(int argc, char *argv[]) { struct event recv_ev; char *dev; int c, debug; FILE *fp; dev = NULL; debug = 0; while ((c = getopt(argc, argv, "di:h?")) != -1) { switch (c) { case 'd': debug = 1; break; case 'i': dev = optarg; break; default: usage(); break; } } argc -= optind; argv += optind; if (argc == 0) arpd_init(dev, 0, NULL); else arpd_init(dev, argc, argv); if ((fp = fopen(PIDFILE, "w")) == NULL) err(1, "fopen"); if (!debug) { setlogmask(LOG_UPTO(LOG_INFO)); if (daemon(1, 0) < 0) { unlink(PIDFILE); err(1, "daemon"); } } fprintf(fp, "%d\n", getpid()); fclose(fp); chmod(PIDFILE, 0644); event_init(); event_set(&recv_ev, pcap_fileno(arpd_pcap), EV_READ, arpd_recv, &recv_ev); event_add(&recv_ev, NULL); /* Setup signal handler */ if (signal(SIGINT, terminate_handler) == SIG_ERR) { perror("signal"); return (-1); } if (signal(SIGTERM, terminate_handler) == SIG_ERR) { perror("signal"); return (-1); } event_dispatch(); return (0); }