📄 vapornet.c
字号:
ctl->remote_exists = 1; } } closedir(dd); ctl->bcast_mtime = st.st_mtime; ctl->nbcasts = n; } else { n = ctl->nbcasts; } for (i = 0; i < n; i++) idx[i] = i; if (n) { while (n > 0) { i = random() % n; vp_unicast(ctl, p, ctl->bcasts[idx[i]]); idx[i] = idx[--n]; } } else { /* We might have an unnumbered link to send to */ if (ctl->remote_exists) vp_link_send(ctl, p); }}/* * Process an outgoing Attache IP packet. Since we just drop packets * that we can't send right away, we may as well do this directly * from the driver rather than maintaining an output queue. * * Except that sometimes it's weirder when we're simulating a bad link. */static void vp_ip_send_handler(struct timer *tm, void *cookie){ packet *p = cookie, **pp; struct net *net = p->pkt_n; struct bsdif *bif = net->specific; struct vp_ctl *ctl = bif->private; struct vp_lnh *lh = (struct vp_lnh *) (p->pkt_buffer); inaddr_t host = lh->host; int drop = 0; if (ctl) { /* * Packet dropping to simulate bad networks. * Yes, thank you, I am making this up as I go along. */ ctl->drop_count++; switch (ctl->drop_p1) { case 1: /* * Drop nth packet. p2 specifies n, p2 specifies whether * we're dropping every-nth or just first-nth. */ if (ctl->drop_count % ctl->drop_p2 == 0) { drop = 1; if (!ctl->drop_p3) ctl->drop_p1 = 0; } break; case 2: /* * Drop p2/p3 of the packets, pseudo-randomly. */ if (random() % ctl->drop_p3 < ctl->drop_p2) drop = 1; break; } /* * Send the packet in the right way, unless we're dropping it. */ if (!drop) { if (ctl->pktlog) vp_log_packet(ctl->pktlog, p); if ((p->pkt_flags & (PF_TX_BROADCAST | PF_TX_MULTICAST)) != 0) vp_broadcast(ctl, p); else if (ctl->remote_exists && ctl->local_exists) vp_link_send(ctl, p); else vp_unicast(ctl, p, host); }#if 0 else { printf("[Dropping packet #%lu (%s)]\n", ctl->drop_count, net->s_name); }#endif /* * Unlink packet from the gc chain. */ for (pp = &ctl->opkts; *pp; pp = &(*pp)->pkt_link) { if (*pp == p) { *pp = p->pkt_link; break; } } } /* * Free the packet no matter what else we do. */ pkt_free(p);}static void vp_ip_send(struct net *net, packet *p, inaddr_t host){ struct bsdif *bif = net->specific; struct vp_ctl *ctl = bif->private; struct vp_lnh *lh = (struct vp_lnh *) (p->pkt_buffer); if (!ctl) { pkt_free(p); return; } etc_tm_init(&lh->tm); lh->tm.handler = vp_ip_send_handler; lh->tm.cookie = p; lh->host = host; p->pkt_n = net; p->pkt_link = ctl->opkts; ctl->opkts = p; if (ctl->jitter) etc_tm_set(&lh->tm, ctl->delay + random() % ctl->jitter); else if (ctl->delay) etc_tm_set(&lh->tm, ctl->delay); else lh->tm.handler(&lh->tm, lh->tm.cookie);}/* * The parameters set in this function all degrade the virtual network * simulated by this code in various ways that may be useful when * testing/debugging. Leaving all of these parameters in their default * (zero) state yields the best network we can simulate (no delays, * packets dropped only when the underlying IPC decides to drop them). */static void vp_ip_send_config (struct vp_ctl *ctl, struct ini_handle *ini_handle){ char *s, varname[20]; /* * Delay each outbound packet by a fixed number of milliseconds. * This and "jitter" are additive. */ sprintf(varname, "%s-delay", ctl->net->s_name); if ((s = ini_lookup(ini_handle, attache_section, varname)) != 0) sscanf(s, "%lu", &ctl->delay); /* * Delay each outbound packet by a pseudorandom number of milliseconds * in the range from zero to (n - 1). This and "delay" are additive. */ sprintf(varname, "%s-jitter", ctl->net->s_name); if ((s = ini_lookup(ini_handle, attache_section, varname)) != 0) sscanf(s, "%lu", &ctl->jitter); /* * Drop packets according to one of the algorithms in vp_ip_send_handler(). * See that function for details. */ sprintf(varname, "%s-drop", ctl->net->s_name); if ((s = ini_lookup(ini_handle, attache_section, varname)) != 0) sscanf(s, "%lu %lu %lu", &ctl->drop_p1, &ctl->drop_p2, &ctl->drop_p3);}static void vp_link_config(struct vp_ctl *ctl, struct ini_handle *ini_handle){ char *s; char *av[20]; int ac, i = 0; for (s = ini_iter_start(ini_handle, attache_section, "unnumbered-link"); s; s = ini_iter_next(ini_handle)) { ac = parse_line(s, av, sizeof(av)/sizeof(*av)); if (ac < 3) continue; if (STRCMP(av[i++], ctl->net->s_name) != 0) continue; if (STRLEN(av[i]) > VP_MAX_TAG) av[i][VP_MAX_TAG+1] = '\0'; STRCPY(ctl->local_tag, av[i++]); if (STRLEN(av[i]) > VP_MAX_TAG) av[i][VP_MAX_TAG+1] = '\0'; STRCPY(ctl->remote_tag, av[i]); printf(" -- Configuring %s with local tag %s, remote link to tag %s\n", ctl->net->s_name, ctl->local_tag, ctl->remote_tag); return; }} /* * Process whatever incoming packets we can without blocking. * Passes zero or more Attache packets to ip_rcv(). */static void vp_rcv(struct net *net){ struct bsdif *bif = net->specific; struct vp_ctl *ctl = bif->private; packet *p = ctl->ipkt; size_t len = net->driver->maxlen + MaxLnh; int n; for (;;) { if (p == 0) { if ((p = pkt_alloc(len)) == 0) break; p->pkt_data += MaxLnh; p->pkt_datalen -= MaxLnh; } do { n = recv(bif->fd, p->pkt_data, p->pkt_datalen, 0); } while (n < 0 && errno == EINTR); if (n <= 0) { if (errno != EWOULDBLOCK) bif->flags &= ~BSDIF_READ; break; } p->pkt_datalen = n; p->pkt_n = net; ip_rcv(p); p = 0; } ctl->ipkt = p;}/* * Handle events detected by generic BSD I/O loop. * This particular driver should never get anything but read events. */static void vp_handler(int fd, void *net, unsigned flags){ assert((flags & ~BSDIF_READ) == 0); vp_rcv(net);}/* * Media control routine. In this particular driver, this takes * the place of the driver init and close routines as well, since * there's no real need to separate out those functions. */static int vp_media_ctl(struct net *net, int code, void *cookie){ char sockname[sizeof(vp_socket_dir) + 16]; struct bsdif *bif = net->specific; struct sockaddr_un sa; struct vp_ctl *ctl; sprintf(sa.sun_path, "%s/i%d-%s", vp_socket_dir, (int) getpid(), net->s_name); sa.sun_family = AF_UNIX; switch (code) { case MEDIA_CTL_INIT: net->flags |= NF_DRIVER_DOWN; if ((bif->private = ctl = GLUE_ALLOC(sizeof(*ctl))) == 0) { fprintf(stderr, "couldn't allocate vp control structure\n"); return MEDIA_CTL_ERROR; } MEMSET(ctl, 0, sizeof(*ctl)); etc_tm_init(&ctl->pktlog_sync); ctl->net = net; if ((bif->fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { perror("couldn't create vp socket"); } else if (mkdir(vp_socket_dir, 0777) < 0 && errno != EEXIST) { perror("couldn't create vp socket inode directory"); } else if (unlink(sa.sun_path) < 0 && errno != ENOENT) { perror("couldn't unlink old vp socket inode"); } else if (bind(bif->fd, (struct sockaddr *) &sa, (sizeof(sa) - sizeof(sa.sun_path) + STRLEN(sa.sun_path))) < 0) { perror("couldn't bind vp socket address"); } else if (fcntl(bif->fd, F_SETFL, FNDELAY) < 0) { perror("couldn't set vp socket non-blocking"); } else { struct ini_handle *ini_handle = ini_open(256); vp_open_log(ctl, ini_handle); vp_ip_send_config(ctl, ini_handle); /* This is where we configure point-to-point names */ vp_link_config(ctl, ini_handle); ini_close(ini_handle); bif->handler = vp_handler; bif->flags |= BSDIF_READ; net->flags &= ~NF_DRIVER_DOWN; return MEDIA_CTL_GOOD; } /* aieeeee.... */ case MEDIA_CTL_CLOSE: ctl = bif->private; net->flags |= NF_DRIVER_DOWN; bif->flags &= ~(BSDIF_READ | BSDIF_WRITE); unlink(sa.sun_path); if (bif->fd >= 0) { close(bif->fd); bif->fd = -1; } if (ctl) { if (ctl->ipkt) pkt_free(ctl->ipkt); while (ctl->opkts) { packet *p = ctl->opkts; struct vp_lnh *lh = (struct vp_lnh *) (p->pkt_buffer); etc_tm_cancel(&lh->tm); ctl->opkts = p->pkt_link; pkt_free(p); } if (ctl->pktlog) vp_close_log(ctl); GLUE_FREE(ctl); bif->private = 0; } return code == MEDIA_CTL_CLOSE ? MEDIA_CTL_GOOD : MEDIA_CTL_ERROR; case MEDIA_CTL_IP_UP: ctl = bif->private; net->flags &= ~NF_DOWN; net->status_tstamp = GLUE_NOW();#if INSTALL_ATTACHE_MIB net->ifLastChange = centiseconds_since_attache_boot();#endif if (!route_address_count(net, 0) && (ctl->local_tag[0])) { sprintf(sockname, "%s/%s", vp_socket_dir, ctl->local_tag); if (unlink(sockname) < 0 && errno != ENOENT) perror("couldn't unlink vp unnumbered link"); else if (link(sa.sun_path, sockname) < 0) perror("couldn't link vp unnumbered link"); else { ctl->local_exists = 1; ip_advise_if_up(net); return MEDIA_CTL_GOOD; } return MEDIA_CTL_ERROR; } ip_advise_if_up(net); return MEDIA_CTL_GOOD; case MEDIA_CTL_IP_DOWN: ctl = bif->private; net->flags |= NF_DOWN; net->status_tstamp = GLUE_NOW();#if INSTALL_ATTACHE_MIB net->ifLastChange = centiseconds_since_attache_boot();#endif ip_advise_if_down(net); if (STRLEN(ctl->local_tag)) { sprintf(sockname, "%s/%s", vp_socket_dir, ctl->local_tag); unlink(sockname); ctl->local_exists = 0; } return MEDIA_CTL_GOOD; case MEDIA_CTL_ADD_ADDRESS: ctl = bif->private; sprintf(sockname, "%s/%s", vp_socket_dir, inettoa(* (inaddr_t *) cookie)); if (unlink(sockname) < 0 && errno != ENOENT) perror("couldn't unlink vp IP address"); else if (link(sa.sun_path, sockname) < 0) perror("couldn't link secondary vp IP address"); else { if (ctl->local_exists) { sprintf(sockname, "%s/%s", vp_socket_dir, ctl->local_tag); unlink(sockname); ctl->local_exists = 0; } return MEDIA_CTL_GOOD; } return MEDIA_CTL_ERROR; case MEDIA_CTL_DELETE_ADDRESS: sprintf(sockname, "%s/%s", vp_socket_dir, inettoa(* (inaddr_t *) cookie)); unlink(sockname); return MEDIA_CTL_ERROR; default: return MEDIA_CTL_UNKNOWN_CODE; }}static struct driver vp_driver = { 0, /* Init routine */ 0, /* Raw send routine */ vp_ip_send, /* IP packet send routine */ 0, /* ARP routine */ 0, /* Device control routine */ 0, /* Close routine */ "vp", /* Driver name prefix */ "BSD Socket VaporNet", /* Driver name */ sizeof(struct vp_lnh), /* Net header length */ 0, /* Net trailer length */ VP_MTU, /* Max packet size */ IF_ETHER_3MB, /* MIB interface type (fake broadcast) */ 0, /* ARP hardware type (none) */ vp_media_ctl /* Media layer control routine */};static struct driver ws_driver = { 0, /* Init routine */ 0, /* Raw send routine */ vp_ip_send, /* IP packet send routine */ 0, /* ARP routine */ 0, /* Device control routine */ 0, /* Close routine */ "ws", /* Driver name prefix */ "BSD Socket WetStringNet", /* Driver name */ sizeof(struct vp_lnh), /* Net header length */ 0, /* Net trailer length */ VP_MTU, /* Max packet size */ IF_PROP_SERIAL, /* MIB interface type (fake point-to-point) */ 0, /* ARP hardware type (none) */ vp_media_ctl, /* Media layer control routine */ 0, /* IPv6 send */ 0 /* IPv4 send */};/* * Standard snark interface find routine. * Since there's no real device in back of a vapornet interface, * we just generate a specified number of interface names, then exit. */void vp_driver_find (void (*config)(char *, struct driver *, int, bits16_t, unsigned, bits32_t)){ char name[10]; int instance; for (instance = 0; instance < VP_MAX_INTERFACES; instance++) { sprintf(name, "%d", instance); config(name, &vp_driver, instance, 0, vp_driver.maxlen - vp_driver.lnh - vp_driver.lnt, VP_SPEED); } for (instance = 0; instance < WS_MAX_INTERFACES; instance++) { sprintf(name, "%d", instance); config(name, &ws_driver, instance, 0, ws_driver.maxlen - ws_driver.lnh - ws_driver.lnt, WS_SPEED); }}#endif /* INSTALL_SNARK_BSD_VAPORNET */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -