--- /home/orly/src/sys/netinet/ip_dummynet.c Mon Feb 9 12:48:06 2004 +++ ip_dummynet.c Thu Mar 11 16:13:25 2004 @@ -70,10 +70,13 @@ #include #include #include +#include #include #include #include +#include #include +#include #include #include #include @@ -132,6 +135,18 @@ static struct callout_handle dn_timeout; +/* + * Statics for Dummynet Discard Interface + */ +static void ddattach __P((void)); +static void dddetach __P((void)); +static struct ifnet ddif; +static int ddoutput(struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *); +static void ddrtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info); +static int ddioctl(struct ifnet *, u_long, caddr_t); +#define DDMTU 65536 + #ifdef SYSCTL_NODE SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, "Dummynet"); @@ -1194,16 +1209,16 @@ q->tot_bytes += len ; q->tot_pkts++ ; if ( fs->plr && random() < fs->plr ) - goto dropit ; /* random pkt drop */ + goto bpf_dropit ; /* random pkt drop */ if ( fs->flags_fs & DN_QSIZE_IS_BYTES) { if (q->len_bytes > fs->qsize) - goto dropit ; /* queue size overflow */ + goto bpf_dropit ; /* queue size overflow */ } else { if (q->len >= fs->qsize) - goto dropit ; /* queue count overflow */ + goto bpf_dropit ; /* queue count overflow */ } if ( fs->flags_fs & DN_IS_RED && red_drops(fs, q, len) ) - goto dropit ; + goto bpf_dropit ; /* XXX expensive to zero, see if we can remove it*/ pkt = (struct dn_pkt *)malloc(sizeof (*pkt), M_DUMMYNET, M_NOWAIT|M_ZERO); @@ -1328,6 +1343,55 @@ splx(s); return 0; +bpf_dropit: + if(ddif.if_bpf != NULL) { + /* + * We need to prepend the address family as + * a four byte field. Cons up a dummy header + * to pacify bpf. This is safe because bpf + * will only read from the mbuf (i.e., it won't + * try to free it or keep a pointer a to it). + */ + struct mbuf m0; + struct ip *ip; + struct ether_header *eh; + u_int af; + + switch (dir) { + case DN_TO_IP_OUT: + case DN_TO_IP_IN: + af = AF_INET; + ip = mtod(m, struct ip *); + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); + break; + case DN_TO_BDG_FWD: + case DN_TO_ETH_DEMUX: + case DN_TO_ETH_OUT: + eh = mtod(m, struct ether_header *); + switch (ntohs(eh->ether_type)) { + case ETHERTYPE_IP: + af = AF_INET; + break; + case ETHERTYPE_IPV6: + af = AF_INET6; + break; + } + m->m_data += sizeof(struct ether_header); + m->m_len -= sizeof(struct ether_header); + m->m_pkthdr.len -= sizeof(struct ether_header); + break; + default: + goto dropit; + } + + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + + bpf_mtap(&ddif, &m0); + } + dropit: splx(s); if (q) @@ -1343,7 +1407,6 @@ #define DN_FREE_PKT(pkt) { \ struct dn_pkt *n = pkt ; \ rt_unref ( n->ip6opt.ro_or.ro_rt ); /* XXX */ \ - rt_unref ( n->ro.ro_rt ) ; \ m_freem(n->dn_m); \ pkt = DN_NEXT(n) ; \ free(n, M_DUMMYNET) ; } @@ -2036,6 +2099,7 @@ return EEXIST ; } ip_dn_init(); + ddattach(); /* load dd module */ splx(s); break; @@ -2050,6 +2114,7 @@ ip_dn_ctl_ptr = NULL; ip_dn_io_ptr = NULL; ip_dn_ruledel_ptr = NULL; + dddetach(); /* unload dd interface */ splx(s); #endif break ; @@ -2067,3 +2132,111 @@ DECLARE_MODULE(dummynet, dummynet_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); MODULE_DEPEND(dummynet, ipfw, 1, 1, 1); MODULE_VERSION(dummynet, 1); + +/* Attach the "Dummynet Discard" Interface */ +static void +ddattach() +{ + register struct ifnet *ifp = &ddif; + + ifp->if_name = "dd"; + ifp->if_mtu = DDMTU; + ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; + ifp->if_ioctl = ddioctl; + ifp->if_output = ddoutput; + ifp->if_type = IFT_LOOP; + ifp->if_hdrlen = 0; + ifp->if_addrlen = 0; + ifp->if_snd.ifq_maxlen = 20; + if_attach(ifp); + bpfattach(ifp, DLT_NULL, sizeof(u_int)); +} + +/* Detach the "Dummynet Discard" Interface */ +static void +dddetach() +{ + register struct ifnet *ifp = &ddif; + + bpfdetach(ifp); + if_detach(ifp); +} + +static int +ddoutput(ifp, m, dst, rt) + struct ifnet *ifp; + register struct mbuf *m; + struct sockaddr *dst; + register struct rtentry *rt; + +{ + m_freem(m); + return 0; + +} + +static void +ddrtrequest(cmd, rt, info) + int cmd; + struct rtentry *rt; + struct rt_addrinfo *info; +{ + if (rt) + rt->rt_rmx.rmx_mtu = DDMTU; +} + + +static int +ddioctl(ifp, cmd, data) + register struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + register struct ifaddr *ifa; + register struct ifreq *ifr = (struct ifreq *)data; + register int error = 0; + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + ifa = (struct ifaddr *)data; + if (ifa != 0) + ifa->ifa_rtrequest = ddrtrequest; + /* + * Everything else is done at a higher level. + */ + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifr == 0) { + error = EAFNOSUPPORT; /* XXX */ + break; + } + switch (ifr->ifr_addr.sa_family) { + +#ifdef INET + case AF_INET: + break; +#endif +#ifdef INET6 + case AF_INET6: + break; +#endif + + default: + error = EAFNOSUPPORT; + break; + } + break; + + case SIOCSIFMTU: + ifp->if_mtu = ifr->ifr_mtu; + break; + + default: + error = EINVAL; + } + return (error); +}