Index: src/sbin/ipfw/ipfw.c =================================================================== RCS file: /home/ncvs/src/sbin/ipfw/ipfw.c,v retrieving revision 1.60 diff -u -r1.60 ipfw.c --- ipfw.c 1998/09/28 22:56:37 1.60 +++ ipfw.c 1998/10/15 13:59:49 @@ -45,17 +45,22 @@ #include #include #include +#include /* def. of struct route */ +#include +#include +#include #include #include int lineno = -1; int s; /* main RAW socket */ -int do_resolv=0; /* Would try to resolv all */ +int do_resolv=0; /* Would try to resolve all */ int do_acct=0; /* Show packet/byte count */ int do_time=0; /* Show time stamps */ int do_quiet=0; /* Be quiet in add and flush */ int do_force=0; /* Don't ask for confirmation */ +int do_pipe=0; /* this cmd refers to a pipe */ struct icmpcode { int code; @@ -216,6 +221,9 @@ case IP_FW_F_SKIPTO: printf("skipto %u", chain->fw_skipto_rule); break; + case IP_FW_F_PIPE: + printf("pipe %u", chain->fw_skipto_rule); + break ; case IP_FW_F_REJECT: if (chain->fw_reject_code == IP_FW_REJECT_RST) printf("reset"); @@ -411,12 +419,64 @@ { struct ip_fw *r; struct ip_fw rules[1024]; + struct dn_pipe *p; + struct dn_pipe pipes[1024]; int l,i,bytes; unsigned long rulenum; int pcwidth = 0; int bcwidth = 0; /* extract rules from kernel */ + if (do_pipe) { + memset(rules,0,sizeof pipes); + bytes = sizeof pipes; + i = getsockopt(s, IPPROTO_IP, IP_DUMMYNET_GET, pipes, &bytes); + if (i < 0) + err(2,"getsockopt(IP_DUMMYNET_GET)"); + /* display requested pipes */ + if (ac > 0) + rulenum = strtoul(*av++, NULL, 10); + else + rulenum = 0 ; + for (p = pipes, l = bytes; l >= sizeof pipes[0]; + p++, l-=sizeof pipes[0]) { + if (rulenum == 0 || rulenum == p->pipe_nr) { + double b = p->bandwidth ; + int l ; + char buf[30] ; + char qs[30] ; + char plr[30] ; + + if (b == 0) + sprintf(buf, "unlimited"); + else if (b >= 1000000) + sprintf(buf, "%7.3f Mbit/s", b/1000000 ); + else if (b >= 1000) + sprintf(buf, "%7.3f Kbit/s", b/1000 ); + else + sprintf(buf, "%7.3f bit/s ", b ); + + if ( (l = p->queue_size_bytes) ) { + if (l >= 8192) + sprintf(qs,"%d KB", l / 1024); + else + sprintf(qs,"%d B", l); + } else + sprintf(qs,"%3d sl.", p->queue_size); + if (p->plr) + sprintf(plr,"plr %f", 1.0*p->plr/(double)(0x7fffffff)); + else + plr[0]='\0'; + + printf("%05d: %s %4d ms %s %s -- %d pkts (%d B) %d drops\n", + p->pipe_nr, buf, p->delay, qs, plr, + p->r_len, p->r_len_bytes, p->r_drops); + } + } + + return ; + } + memset(rules,0,sizeof rules); bytes = sizeof rules; i = getsockopt(s, IPPROTO_IP, IP_FW_GET, rules, &bytes); @@ -778,21 +838,33 @@ char **av; { struct ip_fw rule; + struct dn_pipe pipe; int i; int exitval = EX_OK; memset(&rule, 0, sizeof rule); + memset(&pipe, 0, sizeof pipe); av++; ac--; /* Rule number */ while (ac && isdigit(**av)) { + if (do_pipe) { + pipe.pipe_nr = atoi(*av); av++; ac--; + i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_DEL, + &pipe, sizeof pipe); + if (i) { + exitval = 1; + warn("rule %u: setsockopt(%s)", pipe.pipe_nr, "IP_DUMMYNET_DEL"); + } + } else { rule.fw_number = atoi(*av); av++; ac--; i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule); if (i) { exitval = EX_UNAVAILABLE; warn("rule %u: setsockopt(%s)", rule.fw_number, "IP_FW_DEL"); } + } } if (exitval != EX_OK) exit(exitval); @@ -844,6 +916,69 @@ } static void +config_pipe(int ac, char **av) +{ + struct dn_pipe pipe; + int i ; + char *end ; + + memset(&pipe, 0, sizeof pipe); + + av++; ac--; + /* Pipe number */ + if (ac && isdigit(**av)) { + pipe.pipe_nr = atoi(*av); av++; ac--; + } + while (ac > 1) { + if (!strncmp(*av,"bw",strlen(*av)) || + ! strncmp(*av,"bandwidth",strlen(*av))) { + pipe.bandwidth = strtoul(av[1], &end, 0); + if (*end == 'K') + end++, pipe.bandwidth *= 1000 ; + else if (*end == 'M') + end++, pipe.bandwidth *= 1000000 ; + if (*end == 'B') + pipe.bandwidth *= 8 ; + av+=2; ac-=2; + } else if (!strncmp(*av,"delay",strlen(*av)) ) { + pipe.delay = strtoul(av[1], NULL, 0); + av+=2; ac-=2; + } else if (!strncmp(*av,"plr",strlen(*av)) ) { + + double d = strtod(av[1], NULL); + pipe.plr = (int)(d*0x7fffffff) ; + av+=2; ac-=2; + } else if (!strncmp(*av,"queue",strlen(*av)) ) { + end = NULL ; + pipe.queue_size = strtoul(av[1], &end, 0); + if (*end == 'K') { + pipe.queue_size_bytes = pipe.queue_size*1024 ; + pipe.queue_size = 0 ; + } else if (*end == 'B') { + pipe.queue_size_bytes = pipe.queue_size ; + pipe.queue_size = 0 ; + } + av+=2; ac-=2; + } else + show_usage("unrecognised option ``%s''", *av); + } + if (pipe.pipe_nr == 0 ) + show_usage("pipe_nr %d be > 0", pipe.pipe_nr); + if (pipe.queue_size > 100 ) + show_usage("queue size %d must be 2 <= x <= 100", pipe.queue_size); + if (pipe.delay > 10000 ) + show_usage("delay %d must be < 10000", pipe.delay); +#if 0 + printf("configuring pipe %d bw %d delay %d size %d\n", + pipe.pipe_nr, pipe.bandwidth, pipe.delay, pipe.queue_size); +#endif + i = setsockopt(s,IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &pipe,sizeof pipe); + if (i) + err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); + +} + +static void add(ac,av) int ac; char **av; @@ -873,6 +1008,11 @@ rule.fw_flg |= IP_FW_F_ACCEPT; av++; ac--; } else if (!strncmp(*av,"count",strlen(*av))) { rule.fw_flg |= IP_FW_F_COUNT; av++; ac--; + } else if (!strncmp(*av,"pipe",strlen(*av))) { + rule.fw_flg |= IP_FW_F_PIPE; av++; ac--; + if (!ac) + show_usage("missing pipe number"); + rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--; } else if (!strncmp(*av,"divert",strlen(*av))) { rule.fw_flg |= IP_FW_F_DIVERT; av++; ac--; if (!ac) @@ -1235,8 +1375,21 @@ show_usage("Bad arguments"); } + if (!strncmp(*av, "pipe", strlen(*av))) { + do_pipe = 1 ; + ac-- ; + av++ ; + } + /* allow argument swapping */ + if (ac > 1 && *av[0]>='0' && *av[0]<='9') { + char *p = av[0] ; + av[0] = av[1] ; + av[1] = p ; + } if (!strncmp(*av, "add", strlen(*av))) { add(ac,av); + } else if (do_pipe && !strncmp(*av, "config", strlen(*av))) { + config_pipe(ac,av); } else if (!strncmp(*av, "delete", strlen(*av))) { delete(ac,av); } else if (!strncmp(*av, "flush", strlen(*av))) { Index: src/sys/i386/isa/if_ed.c =================================================================== RCS file: /home/ncvs/src/sys/i386/isa/if_ed.c,v retrieving revision 1.145 diff -u -r1.145 if_ed.c --- if_ed.c 1998/09/13 22:15:44 1.145 +++ if_ed.c 1998/10/14 14:59:33 @@ -40,6 +40,7 @@ #include "ed.h" #include "bpfilter.h" #include "pnp.h" +#include "opt_bdg.h" #ifndef EXTRA_ED # if NPNP > 0 @@ -68,6 +69,9 @@ #if NBPFILTER > 0 #include #endif +#ifdef BRIDGE +#include +#endif #include #include @@ -2738,6 +2742,43 @@ m->m_data += 2; eh = mtod(m, struct ether_header *); +#ifdef BRIDGE + /* + * Get link layer header, invoke brige_in, then + * depending on the outcome of the test fetch the rest of the + * packet and either pass up or call bdg_forward. + */ + if (do_bridge) { + struct ifnet *ifp ; + int need_more = 1 ; /* in case not bpf */ + +#if NBPFILTER > 0 + if (sc->arpcom.ac_if.if_bpf) { + need_more = 0 ; + ed_ring_copy(sc, buf, (char *)eh, len); + bpf_mtap(&sc->arpcom.ac_if, m); + } else +#endif + ed_ring_copy(sc, buf, (char *)eh, 14); + ifp = bridge_in(m); + if (ifp == BDG_DROP) { + m_freem(m); + return ; + } + /* else fetch rest of pkt and continue */ + if (need_more) + ed_ring_copy(sc, buf+14, (char *)(eh+1), len - 14); + if (ifp != BDG_LOCAL ) + bdg_forward(&m, ifp); /* not local, need forwarding */ + if (ifp == BDG_LOCAL || ifp == BDG_BCAST || ifp == BDG_MCAST) + goto getit ; + /* not local and not multicast, just drop it */ + if (m) + m_freem(m); + return ; + } +#endif + /* * Get packet, including link layer address, from interface. */ @@ -2749,23 +2790,21 @@ * Check if there's a BPF listener on this interface. If so, hand off * the raw packet to bpf. */ - if (sc->arpcom.ac_if.if_bpf) { + if (sc->arpcom.ac_if.if_bpf) bpf_mtap(&sc->arpcom.ac_if, m); - - /* - * Note that the interface cannot be in promiscuous mode if - * there are no BPF listeners. And if we are in promiscuous - * mode, we have to check if this packet is really ours. - */ - if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) && - bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, - sizeof(eh->ether_dhost)) != 0 && multicast == 0) { - m_freem(m); - return; - } - } #endif + /* + * If we are in promiscuous mode, we have to check if + * this packet is really ours. + */ + if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) && + bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, + sizeof(eh->ether_dhost)) != 0 && multicast == 0) { + m_freem(m); + return; + } +getit: /* * Remove link layer address. */ Index: src/sys/i386/isa/if_ep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/isa/if_ep.c,v retrieving revision 1.76 diff -u -r1.76 if_ep.c --- if_ep.c 1998/06/21 18:02:38 1.76 +++ if_ep.c 1998/10/15 13:29:36 @@ -62,6 +62,7 @@ #include "bpfilter.h" #include "opt_inet.h" #include "opt_ipx.h" +#include "opt_bdg.h" #include #if defined(__FreeBSD__) @@ -96,6 +97,9 @@ #if NBPFILTER > 0 #include #endif +#ifdef BRIDGE +#include +#endif #if defined(__FreeBSD__) #include @@ -1138,36 +1142,49 @@ top->m_pkthdr.len = sc->cur_len; #if NBPFILTER > 0 - if (ifp->if_bpf) { + if (ifp->if_bpf) bpf_mtap(ifp, top); - - /* - * Note that the interface cannot be in promiscuous mode if there are - * no BPF listeners. And if we are in promiscuous mode, we have to - * check if this packet is really ours. - */ - eh = mtod(top, struct ether_header *); - if ((ifp->if_flags & IFF_PROMISC) && - (eh->ether_dhost[0] & 1) == 0 && - bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, - sizeof(eh->ether_dhost)) != 0 && - bcmp(eh->ether_dhost, etherbroadcastaddr, - sizeof(eh->ether_dhost)) != 0) { +#endif +#ifdef BRIDGE + if (do_bridge) { + struct ifnet * bdg_ifp ; + + bdg_ifp = bridge_in(top); + if (bdg_ifp == BDG_DROP) + goto dropit ; + if (bdg_ifp != BDG_LOCAL) + bdg_forward(&(sc->top), bdg_ifp); + if (bdg_ifp !=BDG_LOCAL && bdg_ifp !=BDG_BCAST && bdg_ifp !=BDG_MCAST) + goto dropit ; + /* all others accepted locally */ + goto getit ; + } +#endif + /* + * If we are in promiscuous mode, we have to + * check if this packet is really ours. + */ + eh = mtod(top, struct ether_header *); + if ((ifp->if_flags & IFF_PROMISC) && + (eh->ether_dhost[0] & 1) == 0 && + bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, + sizeof(eh->ether_dhost)) != 0 && + bcmp(eh->ether_dhost, etherbroadcastaddr, + sizeof(eh->ether_dhost)) != 0) { +dropit: if (sc->top) { m_freem(sc->top); sc->top = 0; } - ep_fset(F_RX_FIRST); + ep_fset(F_RX_FIRST); #ifdef EP_LOCAL_STATS - sc->rx_bpf_disc++; + sc->rx_bpf_disc++; #endif - while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); - outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); - return; - } + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); + return; } -#endif - +getit: eh = mtod(top, struct ether_header *); m_adj(top, sizeof(struct ether_header)); ether_input(ifp, eh, top); Index: src/sys/net/bridge.c =================================================================== RCS file: /home/ncvs/src/sys/net/bridge.c,v retrieving revision 1.2 diff -u -r1.2 bridge.c --- bridge.c 1998/09/18 20:55:50 1.2 +++ bridge.c 1998/10/13 16:44:54 @@ -77,6 +77,7 @@ #include #include +#include #include #include /* for net/if.h */ #include @@ -89,9 +90,11 @@ #include /* for struct arpcom */ #include "opt_ipfw.h" +#include "opt_ipdn.h" #if defined(IPFIREWALL) && defined(DUMMYNET) #include +#include #include #endif @@ -236,7 +239,7 @@ if (--slowtimer <= 0 ) { slowtimer = 5 ; - for (ifp = ifnet; ifp; ifp = ifp->if_next) { + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { if (ifp->if_type != IFT_ETHER) continue ; if ( 0 == ( ifp->if_flags & IFF_UP) ) { @@ -299,8 +302,9 @@ bdg_ports = 0 ; eth_addr = bdg_addresses ; - printf("BRIDGE 980911, have %d interfaces\n", if_index); - for (i = 0 , ifp = ifnet ; i < if_index ; i++, ifp = ifp->if_next) + printf("BRIDGE 981002, have %d interfaces\n", if_index); + for (i = 0 , ifp = ifnet.tqh_first ; i < if_index ; + i++, ifp = ifp->if_link.tqe_next) if (ifp->if_type == IFT_ETHER) { /* ethernet ? */ ac = (struct arpcom *)ifp; sprintf(bdg_stats.s[ifp->if_index].name, @@ -464,7 +468,7 @@ return 0; } if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_UNKNOWN) { - ifp = ifnet ; + ifp = ifnet.tqh_first ; once = 0 ; if (dst != BDG_UNKNOWN) canfree = 0 ; @@ -515,7 +519,7 @@ } dummy = 0 ; - off=(*ip_fw_chk_ptr)(NULL, 0, src, &dummy, &m, &rule) ; + off= (*ip_fw_chk_ptr)(NULL, 0, src, &dummy, &m, &rule, NULL /*next hop */ ) ; if (m == NULL) { /* pkt discarded by firewall */ printf("-- bdg: firewall discarded pkt\n"); if (canfree) @@ -556,12 +560,12 @@ else m = NULL ; - for ( ; ifp ; ifp = ifp->if_next ) { + for ( ; ifp ; ifp = ifp->if_link.tqe_next ) { if (ifp != src && ifp->if_type == IFT_ETHER && (ifp->if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING) && SAMEGROUP(ifp, src) && !MUTED(ifp) ) { if (m == NULL) { /* do i need to make a copy ? */ - if (canfree && ifp->if_next == NULL) /* last one! */ + if (canfree && ifp->if_link.tqe_next == NULL) /* last one! */ m = *m0 ; else /* on a P5-90, m_packetcopy takes 540 ticks */ m = m_copypacket(*m0, M_DONTWAIT); Index: src/sys/net/bridge.h =================================================================== RCS file: /home/ncvs/src/sys/net/bridge.h,v retrieving revision 1.1 diff -u -r1.1 bridge.h --- bridge.h 1998/09/12 22:07:47 1.1 +++ bridge.h 1998/10/13 16:44:54 @@ -108,7 +108,7 @@ * BDG_DROP must be dropped * other ifp of the dest. interface (incl.self) */ -static inline +static __inline struct ifnet * bridge_dst_lookup(struct mbuf *m) { Index: src/sys/net/if_ethersubr.c =================================================================== RCS file: /home/ncvs/src/sys/net/if_ethersubr.c,v retrieving revision 1.52 diff -u -r1.52 if_ethersubr.c --- if_ethersubr.c 1998/08/04 23:17:05 1.52 +++ if_ethersubr.c 1998/10/13 16:44:54 @@ -37,6 +37,7 @@ #include "opt_atalk.h" #include "opt_inet.h" #include "opt_ipx.h" +#include "opt_bdg.h" #include #include @@ -101,6 +102,10 @@ extern u_char aarp_org_code[3]; #endif /* NETATALK */ +#ifdef BRIDGE +#include +#endif + #include "vlan.h" #if NVLAN > 0 #include @@ -372,7 +377,19 @@ return(0); /* XXX */ } } - +#ifdef BRIDGE + if (do_bridge) { + struct ifnet *old_ifp = ifp ; + struct mbuf *m0 = m ; + if (m->m_pkthdr.rcvif ) + m->m_pkthdr.rcvif = NULL ; + ifp = bridge_dst_lookup(m); + bdg_forward(&m0, ifp); + if (m0) + m_freem(m0); + return 0 ; + } +#endif s = splimp(); /* * Queue message on interface, and start output if interface Index: src/sys/netinet/if_ether.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/if_ether.c,v retrieving revision 1.48 diff -u -r1.48 if_ether.c --- if_ether.c 1998/09/17 00:04:21 1.48 +++ if_ether.c 1998/10/13 16:44:54 @@ -41,6 +41,7 @@ */ #include "opt_inet.h" +#include "opt_bdg.h" #include #include @@ -461,7 +462,16 @@ (void)memcpy(&isaddr, ea->arp_spa, sizeof (isaddr)); (void)memcpy(&itaddr, ea->arp_tpa, sizeof (itaddr)); for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) +#ifdef BRIDGE + /* + * For a bridge, we want to check the address irrespective + * of the receive interface. (This will change slightly + * when we have clusters of interfaces). + */ + { +#else if (ia->ia_ifp == &ac->ac_if) { +#endif maybe_ia = ia; if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) || (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) Index: src/sys/netinet/in.h =================================================================== RCS file: /home/ncvs/src/sys/netinet/in.h,v retrieving revision 1.37 diff -u -r1.37 in.h --- in.h 1998/08/23 03:07:14 1.37 +++ in.h 1998/10/13 16:44:54 @@ -323,6 +323,11 @@ #define IP_FW_GET 54 /* get entire firewall rule chain */ #define IP_NAT 55 /* set/get NAT opts */ +#define IP_DUMMYNET_CONFIGURE 60 /* add/configure a dummynet pipe */ +#define IP_DUMMYNET_DEL 61 /* delete a dummynet pipe from chain */ +#define IP_DUMMYNET_FLUSH 62 /* flush dummynet */ +#define IP_DUMMYNET_GET 64 /* get entire dummynet pipes */ + /* * Defaults and limits for options */ Index: src/sys/netinet/ip_dummynet.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_dummynet.c,v retrieving revision 1.1 diff -u -r1.1 ip_dummynet.c --- ip_dummynet.c 1998/09/12 22:03:20 1.1 +++ ip_dummynet.c 1998/10/14 14:02:04 @@ -40,6 +40,7 @@ #include /* XXX */ #include #include +#include #include #include #include @@ -68,7 +69,7 @@ SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, idle, CTLFLAG_RD, &dn_idle, 0, ""); #endif -static int ip_dn_ctl(int optname, struct mbuf **mm); +static int ip_dn_ctl(struct sockopt *sopt); static void dummynet(void); static void dn_restart(void); @@ -116,7 +117,7 @@ */ if ( pipe->p.head == NULL && pipe->ticks_from_last_insert != pipe->delay) { - printf("Warning, empty pipe and delay %d (should be %a)d\n", + printf("Warning, empty pipe and delay %d (should be %d)\n", pipe->ticks_from_last_insert, pipe->delay); pipe->ticks_from_last_insert = pipe->delay; } @@ -402,16 +403,23 @@ { struct dn_pipe *q, *p = all_pipes ; - + int matches = 0 ; for ( p= all_pipes ; p ; p = p->next ) { struct dn_pkt *x ; for (x = p->r.head ; x ; x = (struct dn_pkt *)x->dn_next ) - if (x->hdr.mh_data == r) + if (x->hdr.mh_data == r) { + matches++ ; x->hdr.mh_data = (void *)ip_fw_default_rule ; + } for (x = p->p.head ; x ; x = (struct dn_pkt *)x->dn_next ) - if (x->hdr.mh_data == r) + if (x->hdr.mh_data == r) { + matches++ ; x->hdr.mh_data = (void *)ip_fw_default_rule ; + } } + printf("dn_rule_delete, r 0x%x, default 0x%x%s, %d matches\n", + r, ip_fw_default_rule, + r == ip_fw_default_rule ? " AARGH!":"", matches); } /* @@ -419,146 +427,151 @@ * (get, flush, config, del) */ static int -ip_dn_ctl(int optname, struct mbuf **mm) +ip_dn_ctl(struct sockopt *sopt) { - struct mbuf *m ; - if (optname == IP_DUMMYNET_GET) { - struct dn_pipe *p = all_pipes ; - *mm = m = m_get(M_WAIT, MT_SOOPTS); - m->m_len = 0 ; - m->m_next = NULL ; - for (; p ; p = p->next ) { - struct dn_pipe *q = mtod(m,struct dn_pipe *) ; - memcpy( m->m_data, p, sizeof(*p) ); - /* - * return bw and delay in bits/s and ms, respectively - */ - q->bandwidth *= (8*hz) ; - q->delay = (q->delay * 1000) / hz ; - - m->m_len = sizeof(*p) ; - m->m_next = m_get(M_WAIT, MT_SOOPTS); - m = m->m_next ; - m->m_len = 0 ; - } - return 0 ; - } - if (securelevel > 2) { /* like in the firewall code... */ - if (m) (void)m_free(m); - return (EPERM) ; - } - m = *mm ; - if (optname == IP_DUMMYNET_FLUSH) { - dummynet_flush() ; - if (m) (void)m_free(m); - return 0 ; + int error = 0 ; + size_t size ; + char *buf, *bp ; + struct dn_pipe *p, *q, tmp_pipe ; + + struct dn_pipe *x, *a, *b ; + + /* Disallow sets in really-really secure mode. */ + if (sopt->sopt_dir == SOPT_SET && securelevel >= 3) + return (EPERM); + + switch (sopt->sopt_name) { + default : + panic("ip_dn_ctl -- unknown option"); + + case IP_DUMMYNET_GET : + for (p = all_pipes, size = 0 ; p ; p = p->next ) + size += sizeof( *p ) ; + buf = malloc(size, M_TEMP, M_WAITOK); + if (buf == 0) { + error = ENOBUFS ; + break ; } - if (!m) /* need an argument for the following */ - return (EINVAL); - if (optname == IP_DUMMYNET_CONFIGURE) { - struct dn_pipe *p = mtod(m,struct dn_pipe *) ; - struct dn_pipe *x, *a, *b ; - if (m->m_len != sizeof (*p) ) { - printf("dn_pipe Invalid length, %d instead of %d\n", - m->m_len, sizeof(*p) ); - (void)m_free(m); - return (EINVAL); - } + for (p = all_pipes, bp = buf ; p ; p = p->next ) { + struct dn_pipe *q = (struct dn_pipe *)bp ; + + bcopy(p, bp, sizeof( *p ) ); /* - * The config program passes parameters as follows: - * bandwidth = bits/second (0 = no limits); - * must be translated in bytes/tick. - * delay = ms - * must be translated in ticks. - * queue_size = slots (0 = no limit) - * queue_size_bytes = bytes (0 = no limit) - * only one can be set, must be bound-checked + * return bw and delay in bits/s and ms, respectively */ - if ( p->bandwidth > 0 ) { - p->bandwidth = p->bandwidth / 8 / hz ; - if (p->bandwidth == 0) /* too little does not make sense! */ - p->bandwidth = 10 ; - } - p->delay = ( p->delay * hz ) / 1000 ; - if (p->queue_size == 0 && p->queue_size_bytes == 0) - p->queue_size = 100 ; - if (p->queue_size != 0 ) /* buffers are prevailing */ - p->queue_size_bytes = 0 ; - if (p->queue_size > 100) - p->queue_size = 100 ; - if (p->queue_size_bytes > 1024*1024) - p->queue_size_bytes = 1024*1024 ; + q->bandwidth *= (8*hz) ; + q->delay = (q->delay * 1000) / hz ; + bp += sizeof( *p ) ; + } + error = sooptcopyout(sopt, buf, size); + FREE(buf, M_TEMP); + break ; + case IP_DUMMYNET_FLUSH : + dummynet_flush() ; + break ; + case IP_DUMMYNET_CONFIGURE : + p = &tmp_pipe ; + error = sooptcopyin(sopt, p, sizeof *p, sizeof *p); + if (error) + break ; + /* + * The config program passes parameters as follows: + * bandwidth = bits/second (0 = no limits); + * must be translated in bytes/tick. + * delay = ms + * must be translated in ticks. + * queue_size = slots (0 = no limit) + * queue_size_bytes = bytes (0 = no limit) + * only one can be set, must be bound-checked + */ + if ( p->bandwidth > 0 ) { + p->bandwidth = p->bandwidth / 8 / hz ; + if (p->bandwidth == 0) /* too little does not make sense! */ + p->bandwidth = 10 ; + } + p->delay = ( p->delay * hz ) / 1000 ; + if (p->queue_size == 0 && p->queue_size_bytes == 0) + p->queue_size = 100 ; + if (p->queue_size != 0 ) /* buffers are prevailing */ + p->queue_size_bytes = 0 ; + if (p->queue_size > 100) + p->queue_size = 100 ; + if (p->queue_size_bytes > 1024*1024) + p->queue_size_bytes = 1024*1024 ; #if 0 - printf("ip_dn: config pipe %d %d bit/s %d ms %d bufs\n", - p->pipe_nr, - p->bandwidth * 8 * hz , - p->delay * 1000 / hz , p->queue_size); + printf("ip_dn: config pipe %d %d bit/s %d ms %d bufs\n", + p->pipe_nr, + p->bandwidth * 8 * hz , + p->delay * 1000 / hz , p->queue_size); #endif - for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ; - a = b , b = b->next) ; - if (b && b->pipe_nr == p->pipe_nr) { - /* XXX should spl and flush old pipe... */ - b->bandwidth = p->bandwidth ; - b->delay = p->delay ; - b->ticks_from_last_insert = p->delay ; - b->queue_size = p->queue_size ; - b->queue_size_bytes = p->queue_size_bytes ; - b->plr = p->plr ; - } else { - int s ; - x = malloc(sizeof(struct dn_pipe), M_IPFW, M_DONTWAIT) ; - if (x == NULL) { - printf("ip_dummynet.c: sorry no memory\n"); - return (ENOSPC) ; - } - bzero(x, sizeof(*x) ); - x->bandwidth = p->bandwidth ; - x->delay = p->delay ; - x->ticks_from_last_insert = p->delay ; - x->pipe_nr = p->pipe_nr ; - x->queue_size = p->queue_size ; - x->queue_size_bytes = p->queue_size_bytes ; - x->plr = p->plr ; - - s = splnet() ; - x->next = b ; - if (a == NULL) - all_pipes = x ; - else - a->next = x ; - splx(s); + for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ; + a = b , b = b->next) ; + if (b && b->pipe_nr == p->pipe_nr) { + /* XXX should spl and flush old pipe... */ + b->bandwidth = p->bandwidth ; + b->delay = p->delay ; + b->ticks_from_last_insert = p->delay ; + b->queue_size = p->queue_size ; + b->queue_size_bytes = p->queue_size_bytes ; + b->plr = p->plr ; + } else { + int s ; + x = malloc(sizeof(struct dn_pipe), M_IPFW, M_DONTWAIT) ; + if (x == NULL) { + printf("ip_dummynet.c: sorry no memory\n"); + error = ENOSPC ; + break ; } - (void)m_free(m); - return 0 ; + bzero(x, sizeof(*x) ); + x->bandwidth = p->bandwidth ; + x->delay = p->delay ; + x->ticks_from_last_insert = p->delay ; + x->pipe_nr = p->pipe_nr ; + x->queue_size = p->queue_size ; + x->queue_size_bytes = p->queue_size_bytes ; + x->plr = p->plr ; + + s = splnet() ; + x->next = b ; + if (a == NULL) + all_pipes = x ; + else + a->next = x ; + splx(s); } - if (optname == IP_DUMMYNET_DEL) { - struct dn_pipe *p = mtod(m,struct dn_pipe *) ; - struct dn_pipe *x, *a, *b ; - - for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ; - a = b , b = b->next) ; - if (b && b->pipe_nr == p->pipe_nr) { /* found pipe */ - int s = splnet() ; - struct ip_fw_chain *chain = ip_fw_chain.lh_first; - - if (a == NULL) - all_pipes = b->next ; - else - a->next = b->next ; - /* - * remove references to this pipe from the ip_fw rules. - */ - for (; chain; chain = chain->chain.le_next) { - register struct ip_fw *const f = chain->rule; - if (f->pipe_ptr == b) - f->pipe_ptr = NULL ; - } - splx(s); - purge_pipe(b); /* remove pkts from here */ - free(b, M_IPFW); + break ; + + case IP_DUMMYNET_DEL : + p = &tmp_pipe ; + error = sooptcopyin(sopt, p, sizeof *p, sizeof *p); + if (error) + break ; + + for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ; + a = b , b = b->next) ; + if (b && b->pipe_nr == p->pipe_nr) { /* found pipe */ + int s = splnet() ; + struct ip_fw_chain *chain = ip_fw_chain.lh_first; + + if (a == NULL) + all_pipes = b->next ; + else + a->next = b->next ; + /* + * remove references to this pipe from the ip_fw rules. + */ + for (; chain; chain = chain->chain.le_next) { + register struct ip_fw *const f = chain->rule; + if (f->pipe_ptr == b) + f->pipe_ptr = NULL ; } + splx(s); + purge_pipe(b); /* remove pkts from here */ + free(b, M_IPFW); } - return 0 ; + break ; + } + return error ; } void Index: src/sys/netinet/ip_dummynet.h =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_dummynet.h,v retrieving revision 1.1 diff -u -r1.1 ip_dummynet.h --- ip_dummynet.h 1998/09/12 22:03:20 1.1 +++ ip_dummynet.h 1998/10/13 16:44:55 @@ -10,12 +10,14 @@ * * This software is provided ``AS IS'' without any warranties of any kind. * - * $Id: ip_dummynet.h,v 1.1 1998/09/12 22:03:20 luigi Exp $ + * $Id: ip_dummynet.h,v 1.1 1998/05/10 01:30:23 luigi Exp $ */ #ifndef _IP_DUMMYNET_H #define _IP_DUMMYNET_H +typedef int ip_dn_ctl_t __P((struct sockopt *)) ; +extern ip_dn_ctl_t *ip_dn_ctl_ptr; /* * Definition of dummynet data structures. * Dummynet handles a list of pipes, each one identified by a unique @@ -85,12 +87,20 @@ }; /* + * The following is used to define a new mbuf type that is + * prepended to the packet when it comes out of a pipe. The definition + * ought to go in /sys/sys/mbuf.h but here it is less intrusive. + */ + +#define MT_DUMMYNET MT_CONTROL +/* * what to do of a packet when it comes out of a pipe */ #define DN_TO_IP_OUT 1 #define DN_TO_IP_IN 2 #define DN_TO_BDG_FWD 3 #ifdef KERNEL +MALLOC_DECLARE(M_IPFW); void ip_dn_init(void); /* called in ip_input.c */ void dn_rule_delete(void *r); /* used in ip_fw.c */ int dummynet_io(int pipe, int dir, Index: src/sys/netinet/ip_fw.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_fw.c,v retrieving revision 1.96 diff -u -r1.96 ip_fw.c --- ip_fw.c 1998/08/23 03:07:14 1.96 +++ ip_fw.c 1998/10/15 13:18:47 @@ -21,6 +21,7 @@ #ifndef IPFIREWALL_MODULE #include "opt_ipfw.h" +#include "opt_ipdn.h" #include "opt_ipdivert.h" #include "opt_inet.h" #ifndef INET @@ -43,18 +44,25 @@ #include #include #include +#ifdef DUMMYNET +#include +#include +#endif #include #include #include #include #include +#include /* XXX ethertype_ip */ + static int fw_debug = 1; #ifdef IPFIREWALL_VERBOSE static int fw_verbose = 1; #else static int fw_verbose = 0; #endif +static int fw_one_pass = 0; /* XXX */ #ifdef IPFIREWALL_VERBOSE_LIMIT static int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT; #else @@ -63,13 +71,14 @@ #define IPFW_DEFAULT_RULE ((u_int)(u_short)~0) -static LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain; +LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain; -static MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); +MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); #ifdef SYSCTL_NODE SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, ""); +SYSCTL_INT(_net_inet_ip_fw, OID_AUTO,one_pass,CTLFLAG_RW, &fw_one_pass, 0, ""); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, ""); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, ""); #endif @@ -100,6 +109,8 @@ static void ipfw_report __P((struct ip_fw *f, struct ip *ip, struct ifnet *rif, struct ifnet *oif)); +static void flush_rule_ptrs(void); + #ifdef IPFIREWALL_MODULE static ip_fw_chk_t *old_chk_ptr; static ip_fw_ctl_t *old_ctl_ptr; @@ -107,6 +118,7 @@ static int ip_fw_chk __P((struct ip **pip, int hlen, struct ifnet *oif, u_int16_t *cookie, struct mbuf **m, + struct ip_fw_chain **flow_id, struct sockaddr_in **next_hop)); static int ip_fw_ctl __P((struct sockopt *sopt)); @@ -284,6 +296,7 @@ ipfw_report(struct ip_fw *f, struct ip *ip, struct ifnet *rif, struct ifnet *oif) { + if (ip) { static u_int64_t counter; struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *) ip+ ip->ip_hl); struct udphdr *const udp = (struct udphdr *) ((u_int32_t *) ip+ ip->ip_hl); @@ -324,6 +337,11 @@ case IP_FW_F_SKIPTO: printf("SkipTo %d", f->fw_skipto_rule); break; +#ifdef DUMMYNET + case IP_FW_F_PIPE: + printf("Pipe %d", f->fw_skipto_rule); + break; +#endif #ifdef IPFIREWALL_FORWARD case IP_FW_F_FWD: printf("Forward to "); @@ -387,16 +405,46 @@ if (fw_verbose_limit != 0 && count == fw_verbose_limit) printf("ipfw: limit reached on rule #%d\n", f ? f->fw_number : -1); + } +} + +/* + * given an ip_fw_chain *, lookup_next_rule will return a pointer + * of the same type to the next one. This can be either the jump + * target (for skipto instructions) or the next one in the chain (in + * all other cases including a missing jump target). + * Backward jumps are not allowed, so start looking from the next + * rule... + */ +static struct ip_fw_chain * lookup_next_rule(struct ip_fw_chain *me); + +static struct ip_fw_chain * +lookup_next_rule(struct ip_fw_chain *me) +{ + struct ip_fw_chain *chain ; + int rule = me->rule->fw_skipto_rule ; /* guess... */ + + if ( (me->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_SKIPTO ) + for (chain = me->chain.le_next; chain ; chain = chain->chain.le_next ) + if (chain->rule->fw_number >= rule) + return chain ; + return me->chain.le_next ; /* failure or not a skipto */ } /* * Parameters: + * + * pip Pointer to packet header (struct ip **) + * XXX future extension: pip = NULL means a complete ethernet packet + * including ethernet header in the mbuf. Other fields + * are ignored/invalid. * - * ip Pointer to packet header (struct ip *) * hlen Packet header length * oif Outgoing interface, or NULL if packet is incoming * *cookie Skip up to the first rule past this rule number; * *m The packet; we set to NULL when/if we nuke it. + * *flow_id pointer to the last matching rule (in/out) + * *next_hop socket we are forwarding to (in/out). * * Return value: * @@ -409,32 +457,77 @@ static int ip_fw_chk(struct ip **pip, int hlen, struct ifnet *oif, u_int16_t *cookie, struct mbuf **m, + struct ip_fw_chain **flow_id, struct sockaddr_in **next_hop) { struct ip_fw_chain *chain; struct ip_fw *rule = NULL; - struct ip *ip = *pip; + struct ip *ip = NULL ; struct ifnet *const rif = (*m)->m_pkthdr.rcvif; - u_short offset = (ip->ip_off & IP_OFFMASK); + u_short offset ; u_short src_port, dst_port; u_int16_t skipto = *cookie; - *cookie = 0; - /* - * Go down the chain, looking for enlightment - * If we've been asked to start at a given rule immediatly, do so. - */ - chain = LIST_FIRST(&ip_fw_chain); - if ( skipto ) { + if (pip) { /* normal ip packet */ + ip = *pip; + offset = (ip->ip_off & IP_OFFMASK); + } else { /* bridged or non-ip packet */ + struct ether_header *eh = mtod(*m, struct ether_header *); + switch (ntohs(eh->ether_type)) { + case ETHERTYPE_IP : + if ((*m)->m_lenip_v != IPVERSION) + goto non_ip ; + hlen = ip->ip_hl << 2; + if (hlen < sizeof(struct ip)) /* minimum header length */ + goto non_ip ; + if ((*m)->m_len < 14 + hlen + 14) { + printf("-- m_len %d, need more...\n", (*m)->m_len); + goto non_ip ; + } + offset = (ip->ip_off & IP_OFFMASK); + break ; + default : +non_ip: ip = NULL ; + break ; + } + } + + if (*flow_id) { + if (fw_one_pass) + return 0 ; /* accept if passed first test */ + /* + * pkt has already been tagged. Look for the next rule + * to restart processing + */ + chain = LIST_NEXT( *flow_id, chain); + + if ( (chain = (*flow_id)->rule->next_rule_ptr) == NULL ) + chain = (*flow_id)->rule->next_rule_ptr = + lookup_next_rule(*flow_id) ; + if (! chain) goto dropit; + } else { + /* + * Go down the chain, looking for enlightment + * If we've been asked to start at a given rule immediatly, do so. + */ + chain = LIST_FIRST(&ip_fw_chain); + if ( skipto ) { if (skipto >= IPFW_DEFAULT_RULE) goto dropit; while (chain && (chain->rule->fw_number <= skipto)) { chain = LIST_NEXT(chain, chain); } if (! chain) goto dropit; + } } + *cookie = 0; for (; chain; chain = LIST_NEXT(chain, chain)) { - register struct ip_fw *const f = chain->rule; + register struct ip_fw * f ; +again: + f = chain->rule; if (oif) { /* Check direction outbound */ @@ -445,6 +538,40 @@ if (!(f->fw_flg & IP_FW_F_IN)) continue; } + if (ip == NULL ) { + /* + * do relevant checks for non-ip packets: + * after this, only goto got_match or continue + */ + struct ether_header *eh = mtod(*m, struct ether_header *); + + /* + * make default rule always match or we have a panic + */ + if (f->fw_number == IPFW_DEFAULT_RULE) + goto got_match ; + /* + * temporary hack: + * udp from 0.0.0.0 means this rule applies. + * 1 src port is match ether type + * 2 src ports (interval) is match ether type + * 3 src ports is match ether address + */ + if ( f->fw_src.s_addr != 0 || f->fw_prot != IPPROTO_UDP) + continue; + switch (IP_FW_GETNSRCP(f)) { + case 1: /* match one type */ + if ( /* ( (f->fw_flg & IP_FW_F_INVSRC) != 0) ^ */ + ( f->fw_uar.fw_pts[0] == ntohs(eh->ether_type) ) ) { + printf("match!\n"); + goto got_match ; + } + break ; + default: + break ; + } + continue ; + } /* Fragments */ if ((f->fw_flg & IP_FW_F_FRAG) && !(ip->ip_off & IP_OFFMASK)) @@ -494,12 +621,12 @@ continue; #define PULLUP_TO(len) do { \ - if ((*m)->m_len < (len) \ - && (*m = m_pullup(*m, (len))) == 0) { \ + if ((*m)->m_len < (len) ) { \ + if ( (*m = m_pullup(*m, (len))) == 0) \ goto bogusfrag; \ + *pip = ip = mtod(*m, struct ip *); \ + offset = (ip->ip_off & IP_OFFMASK); \ } \ - *pip = ip = mtod(*m, struct ip *); \ - offset = (ip->ip_off & IP_OFFMASK); \ } while (0) /* Protocol specific checks */ @@ -583,9 +710,19 @@ } got_match: + *flow_id = chain ; /* XXX set flow id */ /* Update statistics */ f->fw_pcnt += 1; - f->fw_bcnt += ip->ip_len; + /* + * note -- bridged-ip packets still have some fields + * in network order, including ip_len + */ + if (ip) { + if (pip) + f->fw_bcnt += ip->ip_len; + else + f->fw_bcnt += ntohs(ip->ip_len); + } f->timestamp = time_second; /* Log to console if desired */ @@ -598,9 +735,11 @@ return(0); case IP_FW_F_COUNT: continue; +#ifdef IPDIVERT case IP_FW_F_DIVERT: *cookie = f->fw_number; return(f->fw_divert_port); +#endif case IP_FW_F_TEE: /* * XXX someday tee packet here, but beware that you @@ -611,17 +750,17 @@ * to write custom routine. */ continue; - case IP_FW_F_SKIPTO: -#ifdef DIAGNOSTIC - while (LIST_NEXT(chain, chain) - && LIST_NEXT(chain, chain)->rule->fw_number - < f->fw_skipto_rule) -#else - while (LIST_NEXT(chain, chain)->rule->fw_number - < f->fw_skipto_rule) + case IP_FW_F_SKIPTO: /* XXX check */ + if ( f->next_rule_ptr ) + chain = f->next_rule_ptr ; + else + chain = lookup_next_rule(chain) ; + if (! chain) goto dropit; + goto again ; +#ifdef DUMMYNET + case IP_FW_F_PIPE: + return(f->fw_pipe_nr | 0x10000 ); #endif - chain = LIST_NEXT(chain, chain); - continue; #ifdef IPFIREWALL_FORWARD case IP_FW_F_FWD: /* Change the next-hop address for this packet. @@ -661,6 +800,7 @@ * - The packet is not a multicast or broadcast packet */ if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT + && ip && (ip->ip_p != IPPROTO_ICMP || is_icmp_query(ip)) && !((*m)->m_flags & (M_BCAST|M_MCAST)) && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { @@ -703,7 +843,7 @@ /* * Finally, drop the packet. */ - *cookie = 0; + /* *cookie = 0; */ /* XXX is this necessary ? */ if (*m) { m_freem(*m); *m = NULL; @@ -711,6 +851,22 @@ return(0); } +/* + * when a rule is added/deleted, zero the direct pointers within + * all firewall rules. These will be reconstructed on the fly + * as packets are matched. + * Must be called at splnet(). + */ +static void +flush_rule_ptrs() +{ + struct ip_fw_chain *fcp ; + + for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next) { + fcp->rule->next_rule_ptr = NULL ; + } +} + static int add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl) { @@ -732,6 +888,8 @@ ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0'; ftmp->fw_pcnt = 0L; ftmp->fw_bcnt = 0L; + ftmp->next_rule_ptr = NULL ; + ftmp->pipe_ptr = NULL ; fwc->rule = ftmp; s = splnet(); @@ -768,6 +926,7 @@ fcpl = fcp; } } + flush_rule_ptrs(); splx(s); return (0); @@ -791,6 +950,10 @@ next = LIST_NEXT(fcp, chain); LIST_REMOVE(fcp, chain); +#ifdef DUMMYNET + dn_rule_delete(fcp) ; +#endif + flush_rule_ptrs(); free(fcp->rule, M_IPFW); free(fcp, M_IPFW); fcp = next; @@ -946,6 +1109,7 @@ } break; case IP_FW_F_DIVERT: /* Diverting to port zero is invalid */ + case IP_FW_F_PIPE: /* piping through 0 is invalid */ case IP_FW_F_TEE: if (frwl->fw_divert_port == 0) { dprintf(("%s can't divert to port 0\n", err_prefix)); @@ -1054,12 +1218,15 @@ break; default: - panic("ip_fw_ctl"); + printf("ip_fw_ctl invalid option %d\n", sopt->sopt_name); + error = EINVAL ; } return (error); } +struct ip_fw_chain *ip_fw_default_rule ; + void ip_fw_init(void) { @@ -1082,6 +1249,7 @@ add_entry(&ip_fw_chain, &default_rule)) panic("ip_fw_init"); + ip_fw_default_rule = ip_fw_chain.lh_first ; printf("IP packet filtering initialized, " #ifdef IPDIVERT "divert enabled, "); Index: src/sys/netinet/ip_fw.h =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_fw.h,v retrieving revision 1.35 diff -u -r1.35 ip_fw.h --- ip_fw.h 1998/09/02 19:14:01 1.35 +++ ip_fw.h 1998/10/13 16:44:55 @@ -35,7 +35,7 @@ union ip_fw_if { struct in_addr fu_via_ip; /* Specified by IP address */ struct { /* Specified by interface name */ -#define FW_IFNLEN IFNAMSIZ +#define FW_IFNLEN 10 /* need room ! was IFNAMSIZ */ char name[FW_IFNLEN]; short unit; /* -1 means match any unit */ } fu_via_if; @@ -69,6 +69,7 @@ union ip_fw_if fw_in_if, fw_out_if; /* Incoming and outgoing interfaces */ union { u_short fu_divert_port; /* Divert/tee port (options IPDIVERT) */ + u_short fu_pipe_nr; /* pipe number (option DUMMYNET) */ u_short fu_skipto_rule; /* SKIPTO command rule number */ u_short fu_reject_code; /* REJECT response code */ struct sockaddr_in fu_fwd_ip; @@ -78,6 +79,8 @@ /* in ports array (dst ports follow */ /* src ports; max of 10 ports in all; */ /* count of 0 means match all ports) */ + void *pipe_ptr; /* Pipe ptr in case of dummynet pipe */ + void *next_rule_ptr ; /* next rule in case of match */ }; #define IP_FW_GETNSRCP(rule) ((rule)->fw_nports & 0x0f) @@ -94,6 +97,7 @@ #define fw_divert_port fw_un.fu_divert_port #define fw_skipto_rule fw_un.fu_skipto_rule #define fw_reject_code fw_un.fu_reject_code +#define fw_pipe_nr fw_un.fu_pipe_nr #define fw_fwd_ip fw_un.fu_fwd_ip struct ip_fw_chain { @@ -113,6 +117,7 @@ #define IP_FW_F_TEE 0x00000005 /* This is a tee rule */ #define IP_FW_F_SKIPTO 0x00000006 /* This is a skipto rule */ #define IP_FW_F_FWD 0x00000007 /* This is a "change forwarding address" rule */ +#define IP_FW_F_PIPE 0x00000008 /* This is a dummynet rule */ #define IP_FW_F_IN 0x00000100 /* Check inbound packets */ #define IP_FW_F_OUT 0x00000200 /* Check outbound packets */ @@ -188,7 +193,7 @@ struct ip; struct sockopt; typedef int ip_fw_chk_t __P((struct ip **, int, struct ifnet *, u_int16_t *, - struct mbuf **, struct sockaddr_in **)); + struct mbuf **, struct ip_fw_chain **, struct sockaddr_in **)); typedef int ip_fw_ctl_t __P((struct sockopt *)); extern ip_fw_chk_t *ip_fw_chk_ptr; extern ip_fw_ctl_t *ip_fw_ctl_ptr; Index: src/sys/netinet/ip_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v retrieving revision 1.101 diff -u -r1.101 ip_input.c --- ip_input.c 1998/09/10 08:56:40 1.101 +++ ip_input.c 1998/10/13 16:44:55 @@ -39,6 +39,7 @@ #include "opt_bootp.h" #include "opt_ipfw.h" +#include "opt_ipdn.h" #include "opt_ipdivert.h" #include "opt_ipfilter.h" @@ -47,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -76,6 +78,10 @@ #include #endif +#ifdef DUMMYNET +#include +#endif + int rsvp_on = 0; static int ip_rsvp_on; struct socket *ip_rsvpd; @@ -149,6 +155,10 @@ ip_fw_chk_t *ip_fw_chk_ptr; ip_fw_ctl_t *ip_fw_ctl_ptr; +#ifdef DUMMYNET +ip_dn_ctl_t *ip_dn_ctl_ptr; +#endif + /* IP Network Address Translation (NAT) hooks */ ip_nat_t *ip_nat_ptr; ip_nat_ctl_t *ip_nat_ctl_ptr; @@ -227,6 +237,9 @@ #ifdef IPFIREWALL ip_fw_init(); #endif +#ifdef DUMMYNET + ip_dn_init(); +#endif #ifdef IPNAT ip_nat_init(); #endif @@ -252,7 +265,31 @@ struct in_ifaddr *ia; int i, hlen, mff; u_short sum; +#ifndef IPDIVERT /* dummy variable for the firewall code to play with */ + u_short ip_divert_cookie = 0 ; +#endif +#ifdef COMPAT_IPFW + struct ip_fw_chain *rule = NULL ; +#endif +#if defined(IPFIREWALL) && defined(DUMMYNET) + /* + * dummynet packet are prepended a vestigial mbuf with + * m_type = MT_DUMMYNET and m_data pointing to the matching + * rule. + */ + if (m->m_type == MT_DUMMYNET) { + struct mbuf *m0 = m ; + rule = (struct ip_fw_chain *)(m->m_data) ; + m = m->m_next ; + free(m0, M_IPFW); + ip = mtod(m, struct ip *); + hlen = IP_VHL_HL(ip->ip_vhl) << 2; + goto iphack ; + } else + rule = NULL ; +#endif + #ifdef DIAGNOSTIC if (m == NULL || (m->m_flags & M_PKTHDR) == 0) panic("ip_input no HDR"); @@ -340,9 +377,12 @@ * deals with it. * - Firewall: deny/allow/divert * - Xlate: translate packet's addr/port (NAT). + * - Pipe: pass pkt through dummynet. * - Wrap: fake packet's addr/port * - Encapsulate: put it in another IP and send out. */ + +iphack: #if defined(IPFILTER) || defined(IPFILTER_LKM) /* * Check if we want to allow this packet to be processed. @@ -358,8 +398,6 @@ #endif #ifdef COMPAT_IPFW if (ip_fw_chk_ptr) { - u_int16_t port; - #ifdef IPFIREWALL_FORWARD /* * If we've been forwarded from the output side, then @@ -368,29 +406,41 @@ if (ip_fw_fwd_addr) goto ours; #endif /* IPFIREWALL_FORWARD */ + i = (*ip_fw_chk_ptr)(&ip, hlen, NULL, &ip_divert_cookie, + &m, &rule, &ip_fw_fwd_addr); + /* + * see the comment in ip_output for the return values + * produced by the firewall. + */ + if (!m) /* packet discarded by firewall */ + return ; + if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */ + goto pass ; +#ifdef DUMMYNET + if (i & 0x10000) { + /* send packet to the appropriate pipe */ + dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule); + return ; + } +#endif #ifdef IPDIVERT - port = (*ip_fw_chk_ptr)(&ip, hlen, NULL, &ip_divert_cookie, - &m, &ip_fw_fwd_addr); - if (port) { + if (i > 0 && i < 0x10000) { /* Divert packet */ - frag_divert_port = port; + frag_divert_port = i & 0xffff ; goto ours; } -#else /* !DIVERT */ +#endif +#ifdef IPFIREWALL_FORWARD + if (i == 0 && ip_fw_fwd_addr != NULL) + goto pass ; +#endif /* - * If ipfw says divert, we have to just drop packet - * Use port as a dummy argument. + * if we get here, the packet must be dropped */ - port = 0; - if ((*ip_fw_chk_ptr)(&ip, hlen, NULL, &port, - &m, &ip_fw_fwd_addr)) { - m_freem(m); - m = NULL; - } -#endif /* !DIVERT */ - if (!m) - return; + m_freem(m); + return; } +pass: if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, m->m_pkthdr.rcvif, IP_NAT_IN)) return; Index: src/sys/netinet/ip_output.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_output.c,v retrieving revision 1.82 diff -u -r1.82 ip_output.c --- ip_output.c 1998/09/02 15:11:14 1.82 +++ ip_output.c 1998/10/13 16:44:55 @@ -37,6 +37,7 @@ #define _IP_VHL #include "opt_ipfw.h" +#include "opt_ipdn.h" #include "opt_ipdivert.h" #include "opt_ipfilter.h" @@ -76,6 +77,10 @@ #include #endif +#ifdef DUMMYNET +#include +#endif + #ifdef IPFIREWALL_FORWARD_DEBUG #define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\ (ntohl(a.s_addr)>>16)&0xFF,\ @@ -130,6 +135,41 @@ int fwd_rewrite_src = 0; #endif +#ifndef IPDIVERT /* dummy variable for the firewall code to play with */ + u_short ip_divert_cookie = 0 ; +#endif +#ifdef COMPAT_IPFW + struct ip_fw_chain *rule = NULL ; +#endif + +#if defined(IPFIREWALL) && defined(DUMMYNET) + /* + * dummynet packet are prepended a vestigial mbuf with + * m_type = MT_DUMMYNET and m_data pointing to the matching + * rule. + */ + if (m->m_type == MT_DUMMYNET) { + struct mbuf *tmp_m = m ; + /* + * the packet was already tagged, so part of the + * processing was already done, and we need to go down. + * opt, flags and imo have already been used, and now + * they are used to hold ifp and hlen and NULL, respectively. + */ + rule = (struct ip_fw_chain *)(m->m_data) ; + m = m->m_next ; + free(tmp_m, M_IPFW); + ip = mtod(m, struct ip *); + dst = (struct sockaddr_in *)&ro->ro_dst; + ifp = (struct ifnet *)opt; + hlen = IP_VHL_HL(ip->ip_vhl) << 2 ; + opt = NULL ; + flags = 0 ; /* XXX is this correct ? */ + goto sendit; + } else + rule = NULL ; +#endif + #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("ip_output no HDR"); @@ -393,28 +433,52 @@ * Check with the firewall... */ if (ip_fw_chk_ptr) { -#ifdef IPFIREWALL_FORWARD struct sockaddr_in *old = dst; -#endif -#ifdef IPDIVERT - ip_divert_port = (*ip_fw_chk_ptr)(&ip, - hlen, ifp, &ip_divert_cookie, &m, &dst); - if (ip_divert_port) { /* Divert packet */ - (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0); - goto done; - } -#else /* !IPDIVERT */ - u_int16_t dummy = 0; - /* If ipfw says divert, we have to just drop packet */ - if ((*ip_fw_chk_ptr)(&ip, hlen, ifp, &dummy, &m, &dst)) { - m_freem(m); - goto done; - } -#endif /* !IPDIVERT */ - if (!m) { + + off = (*ip_fw_chk_ptr)(&ip, + hlen, ifp, &ip_divert_cookie, &m, &rule, &dst); + /* + * On return we must do the following: + * m == NULL -> drop the pkt + * 1<=off<= 0xffff -> DIVERT + * (off & 0x10000) -> send to a DUMMYNET pipe + * dst != old -> IPFIREWALL_FORWARD + * off==0, dst==old -> accept + * If some of the above modules is not compiled in, then + * we should't have to check the corresponding condition + * (because the ipfw control socket should not accept + * unsupported rules), but better play safe and drop + * packets in case of doubt. + */ + if (!m) { /* firewall said to reject */ error = EACCES; goto done; } + if (off == 0 && dst == old) /* common case */ + goto pass ; +#ifdef DUMMYNET + if (off & 0x10000) { + /* + * pass the pkt to dummynet. Need to include + * pipe number, m, ifp, ro, hlen because these are + * not recomputed in the next pass. + * All other parameters have been already used and + * so they are not needed anymore. + * XXX note: if the ifp or ro entry are deleted + * while a pkt is in dummynet, we are in trouble! + */ + dummynet_io(off & 0xffff, DN_TO_IP_OUT, m,ifp,ro,hlen,rule); + goto done ; + } +#endif +#ifdef IPDIVERT + if (off > 0 && off < 0x10000) { /* Divert packet */ + ip_divert_port = off & 0xffff ; + (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0); + goto done; + } +#endif + #ifdef IPFIREWALL_FORWARD /* Here we check dst to make sure it's directly reachable on the * interface we previously thought it was. @@ -425,7 +489,7 @@ * such control is nigh impossible. So we do it here. * And I'm babbling. */ - if (old != dst) { + if (off == 0 && old != dst) { struct in_ifaddr *ia; /* It's changed... */ @@ -514,12 +578,20 @@ */ if (fwd_rewrite_src) ip->ip_src = IA_SIN(ia)->sin_addr; + goto pass ; } #endif /* IPFIREWALL_FORWARD */ + /* + * if we get here, none of the above matches, and + * we have to drop the pkt + */ + m_freem(m); + error = EACCES; /* not sure this is the right error msg */ + goto done; } #endif /* COMPAT_IPFW */ - +pass: /* * If small enough for interface, can just send directly. */ Index: src/sys/netinet/raw_ip.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/raw_ip.c,v retrieving revision 1.55 diff -u -r1.55 raw_ip.c --- raw_ip.c 1998/08/23 03:07:14 1.55 +++ raw_ip.c 1998/10/13 16:44:55 @@ -61,6 +61,10 @@ #include +#include "opt_ipdn.h" +#ifdef DUMMYNET +#include +#endif #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 #undef COMPAT_IPFW #define COMPAT_IPFW 1 @@ -259,6 +263,14 @@ else error = ip_nat_ctl_ptr(sopt); break; +#ifdef DUMMYNET + case IP_DUMMYNET_GET: + if (ip_dn_ctl_ptr == NULL) + error = ENOPROTOOPT ; + else + error = ip_dn_ctl_ptr(sopt); + break ; +#endif /* DUMMYNET */ #endif /* COMPAT_IPFW */ case MRT_INIT: @@ -308,6 +320,16 @@ else error = ip_nat_ctl_ptr(sopt); break; +#ifdef DUMMYNET + case IP_DUMMYNET_CONFIGURE: + case IP_DUMMYNET_DEL: + case IP_DUMMYNET_FLUSH: + if (ip_dn_ctl_ptr == NULL) + error = ENOPROTOOPT ; + else + error = ip_dn_ctl_ptr(sopt); + break ; +#endif #endif /* COMPAT_IPFW */ case IP_RSVP_ON: Index: src/sys/netinet/tcp_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v retrieving revision 1.81 diff -u -r1.81 tcp_input.c --- tcp_input.c 1998/09/11 16:04:03 1.81 +++ tcp_input.c 1998/10/13 16:44:56 @@ -81,6 +81,9 @@ static int log_in_vain = 0; SYSCTL_INT(_net_inet_tcp, OID_AUTO, log_in_vain, CTLFLAG_RW, &log_in_vain, 0, ""); +static int no_local_slowstart = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, no_local_slowstart, CTLFLAG_RW, + &no_local_slowstart, 0, ""); int tcp_delack_enabled = 1; SYSCTL_INT(_net_inet_tcp, OID_AUTO, delayed_ack, CTLFLAG_RW, @@ -2192,8 +2195,9 @@ } /* * Don't force slow-start on local network. + * Make this depend on the sysctl variable below */ - if (!in_localaddr(inp->inp_faddr)) + if (!no_local_slowstart || !in_localaddr(inp->inp_faddr)) tp->snd_cwnd = mss; if (rt->rt_rmx.rmx_ssthresh) { Index: src/sys/pci/if_de.c =================================================================== RCS file: /home/ncvs/src/sys/pci/if_de.c,v retrieving revision 1.89 diff -u -r1.89 if_de.c --- if_de.c 1998/10/14 08:31:26 1.89 +++ if_de.c 1998/10/15 13:44:33 @@ -1,5 +1,5 @@ -/* $NetBSD: if_de.c,v 1.80 1998/09/25 18:06:53 matt Exp $ */ -/* $Id: if_de.c,v 1.89 1998/10/14 08:31:26 peter Exp $ */ +/* $NetBSD: if_de.c,v 1.72 1998/07/05 06:49:14 jonathan Exp $ */ +/* $Id: if_de.c,v 1.86 1998/09/24 13:31:01 peter Exp $ */ /*- * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) @@ -42,6 +42,7 @@ #ifdef __FreeBSD__ #include "opt_inet.h" #include "opt_ipx.h" +#include "opt_bdg.h" #endif #ifdef __NetBSD__ @@ -121,6 +122,10 @@ #define __FreeBSD_version 200000 #endif #endif + +#ifdef BRIDGE +#include +#endif #endif /* __FreeBSD__ */ #if defined(__bsdi__) @@ -2304,13 +2309,11 @@ switch (sc->tulip_chipid) { case TULIP_21140A: strcat(sc->tulip_boardid, "EN1207 "); - if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) - sc->tulip_boardsw = &tulip_21140_accton_boardsw; + sc->tulip_boardsw = &tulip_21140_accton_boardsw; break; case TULIP_21140: strcat(sc->tulip_boardid, "EN1207TX "); - if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) - sc->tulip_boardsw = &tulip_21140_eb_boardsw; + sc->tulip_boardsw = &tulip_21140_eb_boardsw; break; case TULIP_21040: strcat(sc->tulip_boardid, "EN1203 "); @@ -2508,7 +2511,7 @@ switch (type & 0x3f) { case 0: { /* 21140[A] GPR block */ tulip_media_t media; - srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); + srom_media = (tulip_srom_media_t) dp[0]; for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) break; @@ -2597,7 +2600,7 @@ } case 2: { /* 2114[23] SIA block */ tulip_media_t media; - srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); + srom_media = (tulip_srom_media_t) dp[0]; for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) break; @@ -2607,10 +2610,10 @@ break; mi->mi_type = TULIP_MEDIAINFO_SIA; sc->tulip_mediums[media] = mi; - if (dp[0] & 0x40) { - mi->mi_sia_connectivity = dp[1] + dp[2] * 256; - mi->mi_sia_tx_rx = dp[3] + dp[4] * 256; - mi->mi_sia_general = dp[5] + dp[6] * 256; + if (type & 0x40) { + mi->mi_sia_connectivity = dp[0] + dp[1] * 256; + mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; + mi->mi_sia_general = dp[4] + dp[5] * 256; dp += 6; } else { switch (media) { @@ -2637,8 +2640,8 @@ } } } - mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16; - mi->mi_sia_gp_data = (dp[3] + dp[4] * 256) << 16; + mi->mi_sia_gp_control = (dp[0] + dp[1] * 256) << 16; + mi->mi_sia_gp_data = (dp[2] + dp[3] * 256) << 16; mi++; bad_media: break; @@ -3243,7 +3246,6 @@ sc->tulip_flags |= TULIP_INRESET; sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW); sc->tulip_if.if_flags &= ~IFF_OACTIVE; - sc->tulip_if.if_start = tulip_ifstart; } #if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) @@ -3531,14 +3533,29 @@ eh = *mtod(ms, struct ether_header *); #if NBPFILTER > 0 - if (sc->tulip_bpf != NULL) { + if (sc->tulip_bpf != NULL) if (me == ms) TULIP_BPF_TAP(sc, mtod(ms, caddr_t), total_len); else TULIP_BPF_MTAP(sc, ms); - } #endif sc->tulip_flags |= TULIP_RXACT; +#ifdef BRIDGE /* see code in if_ed.c */ + ms->m_pkthdr.rcvif = ifp; /* XXX */ + ms->m_pkthdr.len = total_len; /* XXX */ + if (do_bridge) { + struct ifnet *bdg_ifp ; + bdg_ifp = bridge_in(ms); + if (bdg_ifp == BDG_DROP) + goto next ; /* and drop */ + if (bdg_ifp != BDG_LOCAL) + bdg_forward(&ms, bdg_ifp); + if (bdg_ifp != BDG_LOCAL && bdg_ifp != BDG_BCAST && + bdg_ifp != BDG_MCAST) + goto next ; /* and drop */ + /* all others accepted locally */ + } else +#endif if ((sc->tulip_flags & (TULIP_PROMISC|TULIP_HASHONLY)) && (eh.ether_dhost[0] & 1) == 0 && !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_enaddr)) @@ -3751,8 +3768,6 @@ if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER) break; - ri->ri_free++; - descs++; d_flag = ri->ri_nextin->d_flag; if (d_flag & TULIP_DFLAG_TxLASTSEG) { if (d_flag & TULIP_DFLAG_TxSETUPPKT) { @@ -3853,6 +3868,8 @@ if (++ri->ri_nextin == ri->ri_last) ri->ri_nextin = ri->ri_first; + ri->ri_free++; + descs++; if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) sc->tulip_if.if_flags &= ~IFF_OACTIVE; } @@ -3877,7 +3894,7 @@ const char * const *msgp = tulip_status_bits; const char *sep; u_int32_t mask; - const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024"; + const char thrsh[] = "72|128\0\0\096|256\0\0\0128|512\0\0160|1024\0"; csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1; printf(TULIP_PRINTF_FMT ": abnormal interrupt:", TULIP_PRINTF_ARGS); @@ -4246,7 +4263,6 @@ TULIP_PRINTF_ARGS, (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : ""); sc->tulip_flags |= TULIP_WANTTXSTART; - sc->tulip_dbg.dbg_txput_finishes[0]++; goto finish; } #endif @@ -4269,8 +4285,8 @@ * latter case we have to recopy. */ #if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX) - again: m0 = m; + again: #endif d_status = 0; eop = nextout = ri->ri_nextout; @@ -4278,55 +4294,42 @@ free = ri->ri_free; #if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) - /* - * Reclaim some dma maps from if we are out. - */ - if (sc->tulip_txmaps_free == 0) { -#if defined(TULIP_DEBUG) - sc->tulip_dbg.dbg_no_txmaps++; -#endif - free += tulip_tx_intr(sc); - } if (sc->tulip_txmaps_free > 0) { - map = sc->tulip_txmaps[sc->tulip_txmaps_free-1]; + map = sc->tulip_txmaps[--sc->tulip_txmaps_free]; } else { sc->tulip_flags |= TULIP_WANTTXSTART; -#if defined(TULIP_DEBUG) - sc->tulip_dbg.dbg_txput_finishes[1]++; -#endif goto finish; } error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); - if (error != 0) { - if (error == EFBIG) { - /* - * The packet exceeds the number of transmit buffer - * entries that we can use for one packet, so we have - * to recopy it into one mbuf and then try again. - */ - m = tulip_mbuf_compress(m); - if (m == NULL) { -#if defined(TULIP_DEBUG) - sc->tulip_dbg.dbg_txput_finishes[2]++; -#endif - goto finish; - } - error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); - } - if (error != 0) { + if (error == EFBIG) { + /* + * The packet exceeds the number of transmit buffer + * entries that we can use for one packet, so we have + * to recopy it into one mbuf and then try again. + */ + m = tulip_mbuf_compress(m); + if (m == NULL) + goto finish; + error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); + if (error) { printf(TULIP_PRINTF_FMT ": unable to load tx map, " "error = %d\n", TULIP_PRINTF_ARGS, error); -#if defined(TULIP_DEBUG) - sc->tulip_dbg.dbg_txput_finishes[3]++; -#endif goto finish; } + } else if (error != 0) { + /* + * Some other error (possibly resource shortage?) has ocurred. + * Report it. + */ + printf(TULIP_PRINTF_FMT ": unable to load tx map, error = %d\n", + TULIP_PRINTF_ARGS, error); + goto finish; } if ((free -= (map->dm_nsegs + 1) / 2) <= 0 /* * See if there's any unclaimed space in the transmit ring. */ - && (free += tulip_tx_intr(sc)) <= 0) { + || (free += tulip_tx_intr(sc)) <= 0) { /* * There's no more room but since nothing * has been committed at this point, just @@ -4334,10 +4337,6 @@ * mbuf and return. */ sc->tulip_flags |= TULIP_WANTTXSTART; -#if defined(TULIP_DEBUG) - sc->tulip_dbg.dbg_txput_finishes[4]++; -#endif - bus_dmamap_unload(sc->tulip_dmatag, map); goto finish; } for (; map->dm_nsegs - segcnt > 1; segcnt += 2) { @@ -4366,7 +4365,6 @@ TULIP_TXMAP_PRESYNC(sc, map); M_SETCTX(m, map); map = NULL; - --sc->tulip_txmaps_free; /* commit to using the dmamap */ #else /* !TULIP_BUS_DMA */ @@ -4408,9 +4406,6 @@ * mbuf and return. */ sc->tulip_flags |= TULIP_WANTTXSTART; -#if defined(TULIP_DEBUG) - sc->tulip_dbg.dbg_txput_finishes[1]++; -#endif goto finish; } } @@ -4504,7 +4499,6 @@ if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { sc->tulip_if.if_flags |= IFF_OACTIVE; - sc->tulip_if.if_start = tulip_ifstart; TULIP_PERFEND(txput); return NULL; } @@ -4513,11 +4507,9 @@ * switch back to the single queueing ifstart. */ sc->tulip_flags &= ~TULIP_WANTTXSTART; + sc->tulip_if.if_start = tulip_ifstart_one; if (sc->tulip_txtimer == 0) sc->tulip_txtimer = TULIP_TXTIMER; -#if defined(TULIP_DEBUG) - sc->tulip_dbg.dbg_txput_finishes[5]++; -#endif /* * If we want a txstart, there must be not enough space in the @@ -4529,9 +4521,6 @@ * WANTTXSTART thereby causing TXINTR to be cleared. */ finish: -#if defined(TULIP_DEBUG) - sc->tulip_dbg.dbg_txput_finishes[6]++; -#endif if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) { sc->tulip_if.if_flags |= IFF_OACTIVE; sc->tulip_if.if_start = tulip_ifstart; @@ -4539,11 +4528,13 @@ sc->tulip_intrmask |= TULIP_STS_TXINTR; TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); } +#if 0 /* this isn't working right yet */ } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) { if (sc->tulip_intrmask & TULIP_STS_TXINTR) { sc->tulip_intrmask &= ~TULIP_STS_TXINTR; TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); } +#endif } TULIP_PERFEND(txput); return m; @@ -4862,8 +4853,6 @@ break; } } - if (sc->tulip_if.if_snd.ifq_head == NULL) - sc->tulip_if.if_start = tulip_ifstart_one; } TULIP_PERFEND(ifstart); @@ -5617,14 +5606,14 @@ #endif /* __bsdi__ */ if (PCI_VENDORID(id) == DEC_VENDORID) { - if (PCI_CHIPID(id) == CHIPID_21040) - chipid = TULIP_21040; - else if (PCI_CHIPID(id) == CHIPID_21041) - chipid = TULIP_21041; - else if (PCI_CHIPID(id) == CHIPID_21140) - chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; - else if (PCI_CHIPID(id) == CHIPID_21142) - chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; + if (PCI_CHIPID(id) == CHIPID_21040) chipid = TULIP_21040; + else if (PCI_CHIPID(id) == CHIPID_21140) { + chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; + } else if (PCI_CHIPID(id) == CHIPID_21142) { + chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; + } + else if (PCI_CHIPID(id) == CHIPID_21041) chipid = TULIP_21041; + else if (PCI_CHIPID(id) == CHIPID_21142) chipid = TULIP_21142; } if (chipid == TULIP_CHIPID_UNKNOWN) return; @@ -5665,11 +5654,11 @@ sc->tulip_features |= TULIP_HAVE_POWERMGMT; if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) { sc->tulip_features |= TULIP_HAVE_DUALSENSE; - if (chipid != TULIP_21041 || revinfo >= 0x20) + if (chipid != TULIP_21041 || sc->tulip_revinfo >= 0x20) sc->tulip_features |= TULIP_HAVE_SIANWAY; if (chipid != TULIP_21041) sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD; - if (chipid != TULIP_21041 && revinfo >= 0x20) + if (chipid != TULIP_21041 && sc->tulip_revinfo >= 0x20) sc->tulip_features |= TULIP_HAVE_SIA100; } Index: src/sys/pci/if_fxp.c =================================================================== RCS file: /home/ncvs/src/sys/pci/if_fxp.c,v retrieving revision 1.57 diff -u -r1.57 if_fxp.c --- if_fxp.c 1998/10/11 06:28:54 1.57 +++ if_fxp.c 1998/10/15 13:45:04 @@ -27,13 +27,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: if_fxp.c,v 1.57 1998/10/11 06:28:54 dg Exp $ + * $Id: if_fxp.c,v 1.55 1998/08/04 08:53:12 dg Exp $ */ /* * Intel EtherExpress Pro/100B PCI Fast Ethernet driver */ +#include "opt_bdg.h" #include "bpfilter.h" #include @@ -103,6 +104,11 @@ #endif /* __NetBSD__ */ +#ifdef BRIDGE +#include +#include +#endif + /* * NOTE! On the Alpha, we have an alignment constraint. The * card DMAs the packet immediately following the RFA. However, @@ -641,7 +647,6 @@ M_DEVBUF, M_NOWAIT); if (sc->cbl_base == NULL) goto fail; - bzero(sc->cbl_base, sizeof(struct fxp_cb_tx) * FXP_NTXCB); sc->fxp_stats = malloc(sizeof(struct fxp_stats), M_DEVBUF, M_NOWAIT); if (sc->fxp_stats == NULL) @@ -1010,31 +1015,50 @@ } m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = - total_len - - sizeof(struct ether_header); + total_len ; eh = mtod(m, struct ether_header *); #if NBPFILTER > 0 - if (ifp->if_bpf) { + if (ifp->if_bpf) bpf_tap(FXP_BPFTAP_ARG(ifp), mtod(m, caddr_t), total_len); - /* - * Only pass this packet up - * if it is for us. - */ - if ((ifp->if_flags & - IFF_PROMISC) && - (rfa->rfa_status & - FXP_RFA_STATUS_IAMATCH) && - (eh->ether_dhost[0] & 1) - == 0) { - m_freem(m); - goto rcvloop; - } - } #endif /* NBPFILTER > 0 */ +#ifdef BRIDGE + if (do_bridge) { + struct ifnet *bdg_ifp ; + bdg_ifp = bridge_in(m); + if (bdg_ifp == BDG_DROP) + goto dropit ; + if (bdg_ifp != BDG_LOCAL) + bdg_forward(&m, bdg_ifp); + if (bdg_ifp != BDG_LOCAL && + bdg_ifp != BDG_BCAST && + bdg_ifp != BDG_MCAST) + goto dropit ; + goto getit ; + } +#endif + /* + * Only pass this packet up + * if it is for us. + */ + if ((ifp->if_flags & + IFF_PROMISC) && + (rfa->rfa_status & + FXP_RFA_STATUS_IAMATCH) && + (eh->ether_dhost[0] & 1) + == 0) { +dropit: + if (m) + m_freem(m); + goto rcvloop; + } +getit: m->m_data += sizeof(struct ether_header); + m->m_len -= + sizeof(struct ether_header); + m->m_pkthdr.len = m->m_len ; ether_input(ifp, eh, m); } goto rcvloop; @@ -1170,14 +1194,10 @@ /* * Release any xmit buffers. */ - txp = sc->cbl_base; - if (txp != NULL) { - for (i = 0; i < FXP_NTXCB; i++) { - if (txp[i].mb_head != NULL) { - m_freem(txp[i].mb_head); - txp[i].mb_head = NULL; - } - } + for (txp = sc->cbl_first; txp != NULL && txp->mb_head != NULL; + txp = txp->next) { + m_freem(txp->mb_head); + txp->mb_head = NULL; } sc->tx_queued = 0; Index: src/share/man/man4/Makefile =================================================================== RCS file: Makefile diff -N Makefile --- /tmp/cvsQo1444 Thu Oct 15 16:04:31 1998 +++ /dev/null Thu Oct 15 02:06:19 1998 @@ -1,26 +0,0 @@ -# @(#)Makefile 8.1 (Berkeley) 6/18/93 - -MAN4= bpf.4 ccd.4 cd.4 ch.4 ddb.4 divert.4 drum.4 fd.4 fpa.4 \ - icmp.4 ifmib.4 inet.4 intro.4 ip.4 ipfirewall.4 \ - lkm.4 lo.4 natm.4 netintro.4 \ - null.4 od.4 pass.4 ppi.4 ppp.4 pt.4 pty.4 route.4 \ - scsi.4 sd.4 sl.4 smp.4 snp.4 sppp.4 ssc.4 st.4 su.4 tcp.4 \ - ttcp.4 termios.4 tty.4 tun.4 udp.4 uk.4 update.4 unix.4 vinum.4 vn.4 \ - worm.4 xpt.4 yp.4 zero.4 - -MLINKS+=fd.4 stderr.4 fd.4 stdin.4 fd.4 stdout.4 -MLINKS+=netintro.4 networking.4 -MLINKS+=ipfirewall.4 ipacct.4 ipfirewall.4 ipfw.4 ipfirewall.4 ipaccounting.4 -MLINKS+=fpa.4 fea.4 -MLINKS+=yp.4 YP.4 yp.4 nis.4 yp.4 NIS.4 -MLINKS+=smp.4 SMP.4 - -# XXX NOT IMPORTED: man4.hp300 man4.sparc man4.tahoe man4.vax -SUBDIR= man4.i386 -.if make(maninstall) -maninstall:: _SUBDIR -.endif - -.include - - Index: src/share/man/man4/bridge.4 =================================================================== RCS file: bridge.4 diff -N bridge.4 --- /dev/null Thu Oct 15 02:06:19 1998 +++ bridge.4 Thu Oct 15 16:08:03 1998 @@ -0,0 +1,56 @@ +.\" +.\" $Id$ +.\" +.Dd Sep 28, 1998 +.Dt BRIDGE 4 +.Os +.Sh NAME +.Nm bridge +.Nd Bridging support +.Sh DESCRIPTION +Starting from version 2.2.8, FreeBSD supports bridging on ethernet-type +interfaces. This is achieved using the following option +.Bd -literal + options BRIDGE +.Ed + +in the kernel config file, and is controlled by two +.Nm sysctl +variables: +.Bd -literal + net.link.ether.bridge +.Ed + +Set to 1 to enable bridging, set to 0 to disable it +.Bd -literal + net.link.ether.bridge_ipfw +.Ed + +Set to 1 to enable +.Nm ipfw +filtering on bridged packets (see ipfw and dummynet). + +.Sh BUGS +.Pp +Care must be taken not to construct loops in the bridge topology. +The kernel supports only a primitive form of loop detection, by disabling +some interfaces when a loop is detected. No support for a daemon running the +spanning tree algorithm is currently provided. +.Pp +With bridging active, interfaces are in promiscuous mode, +thus causing some load on the system to receive and filter +out undesired traffic. +.Pp +Extended functionality to enable bridging selectively on clusters +of interfaces is still in the works. +.Pp +Not all interface support bridging -- at the moment it only works for +``ed'', ``de'', ``fxp'', ``lnc'' interfaces. +.Sh SEE ALSO +.Xr dummynet 4 , +.Xr ip 4 , +.Xr ipfw 8 , +.Xr sysctl 8 . +.Sh HISTORY +bridging support in FreeBSD has been introduced in FreeBSD 2.2.8 +by Luigi Rizzo . Index: src/share/man/man4/dummynet.4 =================================================================== RCS file: dummynet.4 diff -N dummynet.4 --- /dev/null Thu Oct 15 02:06:19 1998 +++ dummynet.4 Thu Oct 15 16:09:16 1998 @@ -0,0 +1,183 @@ +.\" +.\" $Id$ +.\" +.Dd Sep 28, 1998 +.Dt DUMMYNET 4 +.Os +.Sh NAME +.Nm dummynet +.Nd Flexible bandwidth manager and delay emulator +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Fd #include +.Ft int +.Fn setsockopt raw_socket IPPROTO_IP "ipfw option" "struct ipfw" size +.Sh DESCRIPTION +dummynet is a system facility that permits the control of traffic +going through the various network interfaces, by applying bandwidth +and queue size limitations, and simulating delays and losses. +.Pp +In its current implementation, +packet selection is done with the +.Nm ipfw +program, by means of +.Nm ``pipe'' +rules. +A dummynet +.Nm pipe +is characterized by a bandwidth, delay, queue size, and loss +rate, which can be configured with the +.Nm ipfw +program. Pipes are +numbered from 1 to 65534, and packets can be passed through multiple +pipes depending on the ipfw configuration. +.Pp +Dummynet operates at the ip level, but if bridging extensions are +enabled, it is possible to pass bridged packets through pipes as well. +.Sh USAGE +Packets are sent to a pipe using the command +.Bd -literal + ipfw add pipe NNN .... +.Ed + +and pipes are configured as follows: +.Bd -literal + ipfw pipe NNN config bw B delay D queue Q plr P +.Ed + +where the bandwidth B can be expressed in bit/s, Kbit/s, Mbit/s, +Bytes/s, KBytes/s, MBytes/s , delay in milliseconds, queue size in +packets or Bytes, plr is the fraction of packets randomly dropped. +.Pp +Getting ipfw to work right is not very intuitive, especially when +the system is acting as a router or a bridge. +.Pp +When acting as a router, the same ruleset is applied on both the +input and the output path for routed packets, so you have to make +sure that a packet does not go through the same pipe twice (unless +this is what you really want). +.Pp +When acting as a bridge, the +.Nm ipfw +filter is invoked only once, in the input path, +for bridged packets. +.Pp +Also, when simulating true full-duplex channels, be sure to pass +traffic through two different pipes, depending on the direction. +E.g. a suitable rule set for simulating an asymmetric bidirectional +link would be the following: +.Bd -literal + ipfw add pipe 1 ip from A to B out + ipfw add pipe 2 ip from B to A in + ipfw pipe 1 config bw 1Mbit/s delay 80ms + ipfw pipe 2 config bw 128Kbit/s delay 300ms +.Ed + +.Pp +.Sh OPERATION +The +.Nm ipfw +code is used to select packets that must be subject to +bandwidth/queue/delay/losses, and returns the identifier of +the ``pipe'' describing such limitations. +.Pp +Selected packets are first queued in a bounded size queue, from which +they are extracted at the programmed rate and passed to a second queue +where delay is simulated. At the output from the second queue packets +are reinjected into the protocol stack at the same point they came +from (i.e. ip_input(), ip_output(), bdg_forward() ). +Depending on the setting of the sysctl variable + sys.net.inet.ipfw.one_pass +Packets coming from a pipe can be either forwarded to their +destination, or passed again through the +.Nm ipfw +rules, starting from the one after the matching rule. +.Pp +.Nm dummynet +performs its task once per timer tick. The granularity of operation is +thus controlled by the kernel option +.Bd -literal + options HZ +.Ed + +whose default value (100) means a granularity of 10ms. +For an accurate simulation of high data rates it might be necessary to +reduce the timer granularity to 1ms or less. Consider, however, +that some interfaces using programmed I/O may require a considerable +time to output packets. So, reducing the granularity too much might +actually cause ticks to be missed thus reducing the accuracy of +operation. + +.Sh KERNEL OPTIONS +The following options in the kernel configuration file are related +to +.Nm dummynet +operation: +.Bd -literal + IPFIREWALL - enable ipfirewall (required for dummynet). + IPFIREWALL_VERBOSE - enable firewall output. + IPFIREWALL_VERBOSE_LIMIT - limit firewall output. + DUMMYNET - enable dummynet operation. + NMBCLUSTER - set the amount of network packet buffers + HZ - sets the timer granularity +.Ed +.Pp +Generally, the following options are required: +.Bd -literal + options IPFIREWALL + options DUMMYNET +.Ed + +additionally, one may want to increase the number +of mbuf clusters (used to store network packets) according to the +sum of the bandwidth-delay products and queue sizes of all configured +pipes. + + +.Sh SYSCTL VARIABLES +.Pp +.Bd -literal + net.inet.ip.fw.one_pass +.Ed + +is set to 1 if we want packets to pass through the firewall code only +once. +.Bd -literal + net.link.ether.bridge_ipfw +.Ed + +is set if we want bridged packets to pass through the firewall code. + +.Sh COMMANDS +The following socket options are used to manage pipes: +.Pp +IP_DUMMYNET_CONFIGURE updates a pipe configuration (or creates a +new one. +.Pp +IP_DUMMYNET_DEL deletes all pipes having the matching rule number. +.Pp +IP_DUMMYNET_GET returns the pipes matching the number. +.Pp +IP_FW_FLUSH flushes the pipes matching the number. +.Pp +When the kernel security level is greater than 2, only IP_DUMMYNET_GET +is allowed. +.Sh SEE ALSO +.Xr setsockopt 2 , +.Xr bridge 4 , +.Xr ip 4 , +.Xr ipfw 8 , +.Xr sysctl 8 . +.Sh BUGS +This manpage is not illustrating all the possible ways to use +dummynet. +.Sh HISTORY +.Nm +dummynet +was initially implemented as a testing tool for TCP congestion control +by Luigi Rizzo , as described on ACM Computer +Communication Review, Jan.97 issue. Later it has been then modified +to work at the ip and bridging level, and integrated with the IPFW +packet filter.