(By Sklower) checkpoint the current state of Cherenson's work.
authorAndrew Cherenson <andrew@ucbvax.Berkeley.EDU>
Sat, 9 Jan 1993 10:42:54 +0000 (02:42 -0800)
committerAndrew Cherenson <andrew@ucbvax.Berkeley.EDU>
Sat, 9 Jan 1993 10:42:54 +0000 (02:42 -0800)
SCCS-vsn: sys/netinet/in_pcb.c 7.24
SCCS-vsn: sys/netinet/ip_icmp.h 7.6
SCCS-vsn: sys/netinet/if_ether.h 7.9
SCCS-vsn: sys/netinet/ip_output.c 7.27
SCCS-vsn: sys/netinet/in.c 7.27
SCCS-vsn: sys/netinet/in_proto.c 7.9
SCCS-vsn: sys/netinet/tcp_usrreq.c 7.18
SCCS-vsn: sys/netinet/tcp_input.c 7.30
SCCS-vsn: sys/netinet/tcp_timer.c 7.20
SCCS-vsn: sys/netinet/ip_icmp.c 7.19
SCCS-vsn: sys/netinet/ip_var.h 7.9
SCCS-vsn: sys/netinet/tcp_subr.c 7.25
SCCS-vsn: sys/netinet/icmp_var.h 7.6
SCCS-vsn: sys/netinet/udp_usrreq.c 7.27
SCCS-vsn: sys/netinet/tcp.h 7.8
SCCS-vsn: sys/netinet/tcp_var.h 7.11
SCCS-vsn: sys/netinet/udp_var.h 7.8
SCCS-vsn: sys/netinet/igmp.c 7.3
SCCS-vsn: sys/netinet/ip_input.c 7.24
SCCS-vsn: sys/netinet/raw_ip.c 7.11
SCCS-vsn: sys/netinet/tcp_output.c 7.25
SCCS-vsn: sys/netinet/if_ether.c 7.27
SCCS-vsn: sys/netinet/igmp_var.h 7.2
SCCS-vsn: sys/netinet/ip_mroute.c 7.5

24 files changed:
usr/src/sys/netinet/icmp_var.h
usr/src/sys/netinet/if_ether.c
usr/src/sys/netinet/if_ether.h
usr/src/sys/netinet/igmp.c
usr/src/sys/netinet/igmp_var.h
usr/src/sys/netinet/in.c
usr/src/sys/netinet/in_pcb.c
usr/src/sys/netinet/in_proto.c
usr/src/sys/netinet/ip_icmp.c
usr/src/sys/netinet/ip_icmp.h
usr/src/sys/netinet/ip_input.c
usr/src/sys/netinet/ip_mroute.c
usr/src/sys/netinet/ip_output.c
usr/src/sys/netinet/ip_var.h
usr/src/sys/netinet/raw_ip.c
usr/src/sys/netinet/tcp.h
usr/src/sys/netinet/tcp_input.c
usr/src/sys/netinet/tcp_output.c
usr/src/sys/netinet/tcp_subr.c
usr/src/sys/netinet/tcp_timer.c
usr/src/sys/netinet/tcp_usrreq.c
usr/src/sys/netinet/tcp_var.h
usr/src/sys/netinet/udp_usrreq.c
usr/src/sys/netinet/udp_var.h

index 632c709..a0c42ac 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)icmp_var.h  7.5 (Berkeley) %G%
+ *     @(#)icmp_var.h  7.6 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
  */
 struct icmpstat {
 /* statistics related to icmp packets generated */
  */
 struct icmpstat {
 /* statistics related to icmp packets generated */
-       int     icps_error;             /* # of calls to icmp_error */
-       int     icps_oldshort;          /* no error 'cuz old ip too short */
-       int     icps_oldicmp;           /* no error 'cuz old was icmp */
-       int     icps_outhist[ICMP_MAXTYPE + 1];
+       u_long  icps_error;             /* # of calls to icmp_error */
+       u_long  icps_oldshort;          /* no error 'cuz old ip too short */
+       u_long  icps_oldicmp;           /* no error 'cuz old was icmp */
+       u_long  icps_outhist[ICMP_MAXTYPE + 1];
 /* statistics related to input messages processed */
 /* statistics related to input messages processed */
-       int     icps_badcode;           /* icmp_code out of range */
-       int     icps_tooshort;          /* packet < ICMP_MINLEN */
-       int     icps_checksum;          /* bad checksum */
-       int     icps_badlen;            /* calculated bound mismatch */
-       int     icps_reflect;           /* number of responses */
-       int     icps_inhist[ICMP_MAXTYPE + 1];
+       u_long  icps_badcode;           /* icmp_code out of range */
+       u_long  icps_tooshort;          /* packet < ICMP_MINLEN */
+       u_long  icps_checksum;          /* bad checksum */
+       u_long  icps_badlen;            /* calculated bound mismatch */
+       u_long  icps_reflect;           /* number of responses */
+       u_long  icps_inhist[ICMP_MAXTYPE + 1];
 };
 
 #ifdef KERNEL
 };
 
 #ifdef KERNEL
index eb3e469..b665945 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)if_ether.c  7.26 (Berkeley) %G%
+ *     @(#)if_ether.c  7.27 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -271,12 +271,10 @@ arpresolve(ac, rt, m, dst, desten)
                    sizeof(etherbroadcastaddr));
                return (1);
        }
                    sizeof(etherbroadcastaddr));
                return (1);
        }
-#ifdef MULTICAST
        if (m->m_flags & M_MCAST) {     /* multicast */
                ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
                return(1);
        }
        if (m->m_flags & M_MCAST) {     /* multicast */
                ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
                return(1);
        }
-#endif
        if (rt)
                la = (struct llinfo_arp *)rt->rt_llinfo;
        else {
        if (rt)
                la = (struct llinfo_arp *)rt->rt_llinfo;
        else {
index 2c7ae3a..7fc5d3c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)if_ether.h  7.8 (Berkeley) %G%
+ *     @(#)if_ether.h  7.9 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -123,13 +123,8 @@ struct sockaddr_inarp {
 
 #ifdef KERNEL
 u_char etherbroadcastaddr[6];
 
 #ifdef KERNEL
 u_char etherbroadcastaddr[6];
-#if defined(ISO) && !defined(MULTICAST)
-#define MULTICAST 1
-#endif
-#ifdef MULTICAST
 u_char ether_ipmulticast_min[6];
 u_char ether_ipmulticast_max[6];
 u_char ether_ipmulticast_min[6];
 u_char ether_ipmulticast_max[6];
-#endif
 
 struct llinfo_arp *arptnew __P((struct in_addr *));
 struct llinfo_arp llinfo_arp;          /* head of the llinfo queue */
 
 struct llinfo_arp *arptnew __P((struct in_addr *));
 struct llinfo_arp llinfo_arp;          /* head of the llinfo queue */
@@ -144,7 +139,6 @@ struct      ifqueue arpintrq;
 void   in_arpinput __P((struct mbuf *));
 void   arpwhohas __P((struct arpcom *, struct in_addr *));
 
 void   in_arpinput __P((struct mbuf *));
 void   arpwhohas __P((struct arpcom *, struct in_addr *));
 
-#ifdef MULTICAST
 /*
  * Ethernet multicast address structure.  There is one of these for each
  * multicast address or range of multicast addresses that we are supposed
 /*
  * Ethernet multicast address structure.  There is one of these for each
  * multicast address or range of multicast addresses that we are supposed
@@ -213,4 +207,3 @@ struct ether_multistep {
 }
 #endif
 #endif
 }
 #endif
 #endif
-#endif
index fc1bb68..6dc7cdc 100644 (file)
@@ -8,12 +8,11 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)igmp.c      7.2 (Berkeley) %G%
+ *     @(#)igmp.c      7.3 (Berkeley) %G%
  */
 
 /* Internet Group Management Protocol (IGMP) routines. */
 
  */
 
 /* Internet Group Management Protocol (IGMP) routines. */
 
-#ifdef MULTICAST
 
 #include <sys/param.h>
 #include <sys/mbuf.h>
 
 #include <sys/param.h>
 #include <sys/mbuf.h>
@@ -279,4 +278,3 @@ igmp_sendreport(inm)
 
        ++igmpstat.igps_snd_reports;
 }
 
        ++igmpstat.igps_snd_reports;
 }
-#endif
index 6f080e0..2dbdfff 100644 (file)
@@ -8,7 +8,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)igmp_var.h  7.1 (Berkeley) %G%
+ *     @(#)igmp_var.h  7.2 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
  */
 
 struct igmpstat {
  */
 
 struct igmpstat {
-       u_int   igps_rcv_total;         /* total IGMP messages received */
-       u_int   igps_rcv_tooshort;      /* received with too few bytes */
-       u_int   igps_rcv_badsum;        /* received with bad checksum */
-       u_int   igps_rcv_queries;       /* received membership queries */
-       u_int   igps_rcv_badqueries;    /* received invalid queries */
-       u_int   igps_rcv_reports;       /* received membership reports */
-       u_int   igps_rcv_badreports;    /* received invalid reports */
-       u_int   igps_rcv_ourreports;    /* received reports for our groups */
-       u_int   igps_snd_reports;       /* sent membership reports */
+       u_long  igps_rcv_total;         /* total IGMP messages received */
+       u_long  igps_rcv_tooshort;      /* received with too few bytes */
+       u_long  igps_rcv_badsum;        /* received with bad checksum */
+       u_long  igps_rcv_queries;       /* received membership queries */
+       u_long  igps_rcv_badqueries;    /* received invalid queries */
+       u_long  igps_rcv_reports;       /* received membership reports */
+       u_long  igps_rcv_badreports;    /* received invalid reports */
+       u_long  igps_rcv_ourreports;    /* received reports for our groups */
+       u_long  igps_snd_reports;       /* sent membership reports */
 };
 
 #ifdef KERNEL
 };
 
 #ifdef KERNEL
@@ -57,4 +57,3 @@ void  igmp_joingroup __P((struct in_multi *));
 void   igmp_leavegroup __P((struct in_multi *));
 void   igmp_fasttimo __P(());
 #endif
 void   igmp_leavegroup __P((struct in_multi *));
 void   igmp_fasttimo __P(());
 #endif
-
index dc99505..746c05c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)in.c        7.26 (Berkeley) %G%
+ *     @(#)in.c        7.27 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -66,10 +66,8 @@ in_netof(in)
                net = i & IN_CLASSB_NET;
        else if (IN_CLASSC(i))
                net = i & IN_CLASSC_NET;
                net = i & IN_CLASSB_NET;
        else if (IN_CLASSC(i))
                net = i & IN_CLASSC_NET;
-#ifdef MULTICAST
        else if (IN_CLASSD(i))
                net = i & IN_CLASSD_NET;
        else if (IN_CLASSD(i))
                net = i & IN_CLASSD_NET;
-#endif
        else
                return (0);
 
        else
                return (0);
 
@@ -150,11 +148,9 @@ in_lnaof(in)
        } else if (IN_CLASSC(i)) {
                net = i & IN_CLASSC_NET;
                host = i & IN_CLASSC_HOST;
        } else if (IN_CLASSC(i)) {
                net = i & IN_CLASSC_NET;
                host = i & IN_CLASSC_HOST;
-#ifdef MULTICAST
        } else if (IN_CLASSD(i)) {
                net = i & IN_CLASSD_NET;
                host = i & IN_CLASSD_HOST;
        } else if (IN_CLASSD(i)) {
                net = i & IN_CLASSD_NET;
                host = i & IN_CLASSD_HOST;
-#endif
        } else
                return (i);
 
        } else
                return (i);
 
@@ -540,7 +536,6 @@ in_ifinit(ifp, ia, sin, scrub)
        }
        if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
                ia->ia_flags |= IFA_ROUTE;
        }
        if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
                ia->ia_flags |= IFA_ROUTE;
-#ifdef MULTICAST
        /*
         * If the interface supports multicast, join the "all hosts"
         * multicast group on that interface.
        /*
         * If the interface supports multicast, join the "all hosts"
         * multicast group on that interface.
@@ -551,7 +546,6 @@ in_ifinit(ifp, ia, sin, scrub)
                addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
                in_addmulti(&addr, ifp);
        }
                addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
                in_addmulti(&addr, ifp);
        }
-#endif
        return (error);
 }
 
        return (error);
 }
 
@@ -598,7 +592,6 @@ in_broadcast(in)
        return (0);
 }
 
        return (0);
 }
 
-#ifdef MULTICAST
 /*
  * Add an address to the list of IP multicast addresses for a given interface.
  */
 /*
  * Add an address to the list of IP multicast addresses for a given interface.
  */
@@ -711,4 +704,3 @@ in_delmulti(inm)
        splx(s);
 }
 #endif
        splx(s);
 }
 #endif
-#endif
index 2c3dc3d..93dd3ba 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)in_pcb.c    7.23 (Berkeley) %G%
+ *     @(#)in_pcb.c    7.24 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -26,9 +26,7 @@
 #include <netinet/in_pcb.h>
 #include <netinet/in_var.h>
 
 #include <netinet/in_pcb.h>
 #include <netinet/in_var.h>
 
-#ifdef MULTICAST
 #include <netinet/ip_var.h>
 #include <netinet/ip_var.h>
-#endif
 
 struct in_addr zeroin_addr;
 
 
 struct in_addr zeroin_addr;
 
@@ -198,7 +196,6 @@ in_pcbconnect(inp, nam)
                        if (ia == 0)
                                return (EADDRNOTAVAIL);
                }
                        if (ia == 0)
                                return (EADDRNOTAVAIL);
                }
-#ifdef MULTICAST
                /*
                 * If the destination address is multicast and an outgoing
                 * interface has been set as a multicast option, use the
                /*
                 * If the destination address is multicast and an outgoing
                 * interface has been set as a multicast option, use the
@@ -218,7 +215,6 @@ in_pcbconnect(inp, nam)
                                        return (EADDRNOTAVAIL);
                        }
                }
                                        return (EADDRNOTAVAIL);
                        }
                }
-#endif
                ifaddr = (struct sockaddr_in *)&ia->ia_addr;
        }
        if (in_pcblookup(inp->inp_head,
                ifaddr = (struct sockaddr_in *)&ia->ia_addr;
        }
        if (in_pcblookup(inp->inp_head,
@@ -259,9 +255,7 @@ in_pcbdetach(inp)
                (void)m_free(inp->inp_options);
        if (inp->inp_route.ro_rt)
                rtfree(inp->inp_route.ro_rt);
                (void)m_free(inp->inp_options);
        if (inp->inp_route.ro_rt)
                rtfree(inp->inp_route.ro_rt);
-#ifdef MULTICAST
        ip_freemoptions(inp->inp_moptions);
        ip_freemoptions(inp->inp_moptions);
-#endif
        remque(inp);
        FREE(inp, M_PCB);
 }
        remque(inp);
        FREE(inp, M_PCB);
 }
index 30bed97..06f0be9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)in_proto.c  7.8 (Berkeley) %G%
+ *     @(#)in_proto.c  7.9 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -24,9 +24,7 @@
 int    ip_output(),ip_ctloutput();
 int    ip_init(),ip_slowtimo(),ip_drain();
 int    icmp_input();
 int    ip_output(),ip_ctloutput();
 int    ip_init(),ip_slowtimo(),ip_drain();
 int    icmp_input();
-#ifdef MULTICAST
 int    igmp_init(),igmp_input(),igmp_fasttimo();
 int    igmp_init(),igmp_input(),igmp_fasttimo();
-#endif
 int    udp_input(),udp_ctlinput();
 int    udp_usrreq();
 int    udp_init();
 int    udp_input(),udp_ctlinput();
 int    udp_usrreq();
 int    udp_init();
@@ -55,7 +53,7 @@ int   tp_init(), tp_slowtimo(), tp_drain();
 
 #ifdef EON
 int    eoninput(), eonctlinput(), eonprotoinit();
 
 #ifdef EON
 int    eoninput(), eonctlinput(), eonprotoinit();
-#endif EON
+#endif /* EON */
 
 extern struct domain inetdomain;
 
 
 extern struct domain inetdomain;
 
@@ -85,6 +83,11 @@ struct protosw inetsw[] = {
   rip_usrreq,
   0,           0,              0,              0,
 },
   rip_usrreq,
   0,           0,              0,              0,
 },
+{ SOCK_RAW,    &inetdomain,    IPPROTO_IGMP,   PR_ATOMIC|PR_ADDR,
+  igmp_input,  rip_output,     0,              rip_ctloutput,
+  rip_usrreq,
+  igmp_init,   igmp_fasttimo,  0,              0,
+},
 #ifdef TPIP
 { SOCK_SEQPACKET,&inetdomain,  IPPROTO_TP,     PR_CONNREQUIRED|PR_WANTRCVD,
   tpip_input,  0,              tpip_ctlinput,  tp_ctloutput,
 #ifdef TPIP
 { SOCK_SEQPACKET,&inetdomain,  IPPROTO_TP,     PR_CONNREQUIRED|PR_WANTRCVD,
   tpip_input,  0,              tpip_ctlinput,  tp_ctloutput,
@@ -100,13 +103,6 @@ struct protosw inetsw[] = {
   eonprotoinit,        0,              0,              0,
 },
 #endif
   eonprotoinit,        0,              0,              0,
 },
 #endif
-#ifdef MULTICAST
-{ SOCK_RAW,    &inetdomain,    IPPROTO_IGMP,   PR_ATOMIC|PR_ADDR,
-  igmp_input,  rip_output,     0,              rip_ctloutput,
-  rip_usrreq,
-  igmp_init,   igmp_fasttimo,  0,              0,
-},
-#endif
 #ifdef NSIP
 { SOCK_RAW,    &inetdomain,    IPPROTO_IDP,    PR_ATOMIC|PR_ADDR,
   idpip_input, rip_output,     nsip_ctlinput,  0,
 #ifdef NSIP
 { SOCK_RAW,    &inetdomain,    IPPROTO_IDP,    PR_ATOMIC|PR_ADDR,
   idpip_input, rip_output,     nsip_ctlinput,  0,
index 362c3e2..cf6726d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ip_icmp.c   7.18 (Berkeley) %G%
+ *     @(#)ip_icmp.c   7.19 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -42,10 +42,11 @@ extern      struct protosw inetsw[];
  * in response to bad packet ip.
  */
 /*VARARGS3*/
  * in response to bad packet ip.
  */
 /*VARARGS3*/
-icmp_error(n, type, code, dest)
+icmp_error(n, type, code, dest, destifp)
        struct mbuf *n;
        int type, code;
        struct in_addr dest;
        struct mbuf *n;
        int type, code;
        struct in_addr dest;
+       struct ifnet *destifp;
 {
        register struct ip *oip = mtod(n, struct ip *), *nip;
        register unsigned oiplen = oip->ip_hl << 2;
 {
        register struct ip *oip = mtod(n, struct ip *), *nip;
        register unsigned oiplen = oip->ip_hl << 2;
@@ -73,11 +74,12 @@ icmp_error(n, type, code, dest)
                icmpstat.icps_oldicmp++;
                goto freeit;
        }
                icmpstat.icps_oldicmp++;
                goto freeit;
        }
-#ifdef MULTICAST
        /* Don't send error in response to a multicast or broadcast packet */
        /* Don't send error in response to a multicast or broadcast packet */
-       if (n->m_flags & (M_MCAST | M_BCAST))
+       if ((n->m_flags & (M_BCAST|M_MCAST)) ||
+           in_broadcast(oip->ip_dst) ||
+           IN_MULTICAST(ntohl(oip->ip_dst.s_addr)) ||
+           IN_EXPERIMENTAL(ntohl(oip->ip_dst.s_addr)))
                goto freeit;
                goto freeit;
-#endif
        /*
         * First, formulate icmp message
         */
        /*
         * First, formulate icmp message
         */
@@ -94,12 +96,21 @@ icmp_error(n, type, code, dest)
        icp->icmp_type = type;
        if (type == ICMP_REDIRECT)
                icp->icmp_gwaddr = dest;
        icp->icmp_type = type;
        if (type == ICMP_REDIRECT)
                icp->icmp_gwaddr = dest;
-       else
+       else {
                icp->icmp_void = 0;
                icp->icmp_void = 0;
-       if (type == ICMP_PARAMPROB) {
-               icp->icmp_pptr = code;
-               code = 0;
+               /* 
+                * The following assignments assume an overlay with the
+                * zeroed icmp_void field.
+                */
+               if (type == ICMP_PARAMPROB) {
+                       icp->icmp_pptr = code;
+                       code = 0;
+               } else if (type == ICMP_UNREACH &&
+                       code == ICMP_UNREACH_NEEDFRAG && destifp) {
+                       icp->icmp_nextmtu = htons(destifp->if_mtu);
+               }
        }
        }
+
        icp->icmp_code = code;
        bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
        nip = &icp->icmp_ip;
        icp->icmp_code = code;
        bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
        nip = &icp->icmp_ip;
@@ -116,11 +127,12 @@ icmp_error(n, type, code, dest)
        m->m_pkthdr.len = m->m_len;
        m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
        nip = mtod(m, struct ip *);
        m->m_pkthdr.len = m->m_len;
        m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
        nip = mtod(m, struct ip *);
-       bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
+       bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
        nip->ip_len = m->m_len;
        nip->ip_hl = sizeof(struct ip) >> 2;
        nip->ip_hl = sizeof(struct ip) >> 2;
        nip->ip_p = IPPROTO_ICMP;
        nip->ip_len = m->m_len;
        nip->ip_hl = sizeof(struct ip) >> 2;
        nip->ip_hl = sizeof(struct ip) >> 2;
        nip->ip_p = IPPROTO_ICMP;
+       nip->ip_tos = 0;
        icmp_reflect(m);
 
 freeit:
        icmp_reflect(m);
 
 freeit:
@@ -193,9 +205,35 @@ icmp_input(m, hlen)
        switch (icp->icmp_type) {
 
        case ICMP_UNREACH:
        switch (icp->icmp_type) {
 
        case ICMP_UNREACH:
-               if (code > 5)
-                       goto badcode;
-               code += PRC_UNREACH_NET;
+               switch (code) {
+                       case ICMP_UNREACH_NET:
+                       case ICMP_UNREACH_HOST:
+                       case ICMP_UNREACH_PROTOCOL:
+                       case ICMP_UNREACH_PORT:
+                       case ICMP_UNREACH_SRCFAIL:
+                               code += PRC_UNREACH_NET;
+                               break;
+
+                       case ICMP_UNREACH_NEEDFRAG:
+                               code = PRC_MSGSIZE;
+                               break;
+                               
+                       case ICMP_UNREACH_NET_UNKNOWN:
+                       case ICMP_UNREACH_NET_PROHIB:
+                       case ICMP_UNREACH_TOSNET:
+                               code = PRC_UNREACH_NET;
+                               break;
+
+                       case ICMP_UNREACH_HOST_UNKNOWN:
+                       case ICMP_UNREACH_ISOLATED:
+                       case ICMP_UNREACH_HOST_PROHIB:
+                       case ICMP_UNREACH_TOSHOST:
+                               code = PRC_UNREACH_HOST;
+                               break;
+
+                       default:
+                               goto badcode;
+               }
                goto deliver;
 
        case ICMP_TIMXCEED:
                goto deliver;
 
        case ICMP_TIMXCEED:
@@ -205,7 +243,7 @@ icmp_input(m, hlen)
                goto deliver;
 
        case ICMP_PARAMPROB:
                goto deliver;
 
        case ICMP_PARAMPROB:
-               if (code)
+               if (code > 1)
                        goto badcode;
                code = PRC_PARAMPROB;
                goto deliver;
                        goto badcode;
                code = PRC_PARAMPROB;
                goto deliver;
@@ -282,6 +320,13 @@ reflect:
                return;
 
        case ICMP_REDIRECT:
                return;
 
        case ICMP_REDIRECT:
+               if (code > 3)
+                       goto badcode;
+               if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
+                   icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
+                       icmpstat.icps_badlen++;
+                       break;
+               }
                if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
                        icmpstat.icps_badlen++;
                        break;
                if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
                        icmpstat.icps_badlen++;
                        break;
@@ -328,6 +373,8 @@ reflect:
         * just fall through to send to raw listener.
         */
        case ICMP_ECHOREPLY:
         * just fall through to send to raw listener.
         */
        case ICMP_ECHOREPLY:
+       case ICMP_ROUTERADVERT:
+       case ICMP_ROUTERSOLICIT:
        case ICMP_TSTAMPREPLY:
        case ICMP_IREQREPLY:
        case ICMP_MASKREPLY:
        case ICMP_TSTAMPREPLY:
        case ICMP_IREQREPLY:
        case ICMP_MASKREPLY:
@@ -416,17 +463,22 @@ icmp_reflect(m)
                                            break;
                            }
                            /*
                                            break;
                            }
                            /*
-                            * should check for overflow, but it "can't happen"
+                            * Should check for overflow, but it "can't happen"
                             */
                             */
-                           if (opt == IPOPT_RR || opt == IPOPT_TS) {
+                           if (opt == IPOPT_RR || opt == IPOPT_TS || 
+                               opt == IPOPT_SECURITY) {
                                    bcopy((caddr_t)cp,
                                        mtod(opts, caddr_t) + opts->m_len, len);
                                    opts->m_len += len;
                            }
                    }
                                    bcopy((caddr_t)cp,
                                        mtod(opts, caddr_t) + opts->m_len, len);
                                    opts->m_len += len;
                            }
                    }
-                   if (opts->m_len % 4 != 0) {
-                           *(mtod(opts, caddr_t) + opts->m_len) = IPOPT_EOL;
-                           opts->m_len++;
+                   /* Terminate & pad, if necessary */
+                   if (cnt = opts->m_len % 4) {
+                           for (; cnt < 4; cnt++) {
+                                   *(mtod(opts, caddr_t) + opts->m_len) =
+                                       IPOPT_EOL;
+                                   opts->m_len++;
+                           }
                    }
 #ifdef ICMPPRINTFS
                    if (icmpprintfs)
                    }
 #ifdef ICMPPRINTFS
                    if (icmpprintfs)
index fea5496..c65adc7 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ip_icmp.h   7.5 (Berkeley) %G%
+ *     @(#)ip_icmp.h   7.6 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -27,12 +27,20 @@ struct icmp {
                        n_short icd_seq;
                } ih_idseq;
                int ih_void;
                        n_short icd_seq;
                } ih_idseq;
                int ih_void;
+
+               /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
+               struct ih_pmtu {
+                       n_short ipm_void;    
+                       n_short ipm_nextmtu;
+               } ih_pmtu;
        } icmp_hun;
 #define        icmp_pptr       icmp_hun.ih_pptr
 #define        icmp_gwaddr     icmp_hun.ih_gwaddr
 #define        icmp_id         icmp_hun.ih_idseq.icd_id
 #define        icmp_seq        icmp_hun.ih_idseq.icd_seq
 #define        icmp_void       icmp_hun.ih_void
        } icmp_hun;
 #define        icmp_pptr       icmp_hun.ih_pptr
 #define        icmp_gwaddr     icmp_hun.ih_gwaddr
 #define        icmp_id         icmp_hun.ih_idseq.icd_id
 #define        icmp_seq        icmp_hun.ih_idseq.icd_seq
 #define        icmp_void       icmp_hun.ih_void
+#define        icmp_pmvoid     icmp_hun.ih_pmtu.ipm_void
+#define        icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu
        union {
                struct id_ts {
                        n_time its_otime;
        union {
                struct id_ts {
                        n_time its_otime;
@@ -80,6 +88,13 @@ struct icmp {
 #define                ICMP_UNREACH_PORT       3               /* bad port */
 #define                ICMP_UNREACH_NEEDFRAG   4               /* IP_DF caused drop */
 #define                ICMP_UNREACH_SRCFAIL    5               /* src route failed */
 #define                ICMP_UNREACH_PORT       3               /* bad port */
 #define                ICMP_UNREACH_NEEDFRAG   4               /* IP_DF caused drop */
 #define                ICMP_UNREACH_SRCFAIL    5               /* src route failed */
+#define                ICMP_UNREACH_NET_UNKNOWN 6              /* unknown net */
+#define                ICMP_UNREACH_HOST_UNKNOWN 7             /* unknown host */
+#define                ICMP_UNREACH_ISOLATED   8               /* src host isolated */
+#define                ICMP_UNREACH_NET_PROHIB 9               /* prohibited access */
+#define                ICMP_UNREACH_HOST_PROHIB 10             /* ditto */
+#define                ICMP_UNREACH_TOSNET     11              /* bad tos for net */
+#define                ICMP_UNREACH_TOSHOST    12              /* bad tos for host */
 #define        ICMP_SOURCEQUENCH       4               /* packet lost, slow down */
 #define        ICMP_REDIRECT           5               /* shorter route, codes: */
 #define                ICMP_REDIRECT_NET       0               /* for network */
 #define        ICMP_SOURCEQUENCH       4               /* packet lost, slow down */
 #define        ICMP_REDIRECT           5               /* shorter route, codes: */
 #define                ICMP_REDIRECT_NET       0               /* for network */
@@ -87,10 +102,13 @@ struct icmp {
 #define                ICMP_REDIRECT_TOSNET    2               /* for tos and net */
 #define                ICMP_REDIRECT_TOSHOST   3               /* for tos and host */
 #define        ICMP_ECHO               8               /* echo service */
 #define                ICMP_REDIRECT_TOSNET    2               /* for tos and net */
 #define                ICMP_REDIRECT_TOSHOST   3               /* for tos and host */
 #define        ICMP_ECHO               8               /* echo service */
+#define        ICMP_ROUTERADVERT       9               /* router advertisement */
+#define        ICMP_ROUTERSOLICIT      10              /* router solicitation */
 #define        ICMP_TIMXCEED           11              /* time exceeded, code: */
 #define                ICMP_TIMXCEED_INTRANS   0               /* ttl==0 in transit */
 #define                ICMP_TIMXCEED_REASS     1               /* ttl==0 in reass */
 #define        ICMP_PARAMPROB          12              /* ip header bad */
 #define        ICMP_TIMXCEED           11              /* time exceeded, code: */
 #define                ICMP_TIMXCEED_INTRANS   0               /* ttl==0 in transit */
 #define                ICMP_TIMXCEED_REASS     1               /* ttl==0 in reass */
 #define        ICMP_PARAMPROB          12              /* ip header bad */
+#define                ICMP_PARAMPROB_OPTABSENT 1              /* req. opt. absent */
 #define        ICMP_TSTAMP             13              /* timestamp request */
 #define        ICMP_TSTAMPREPLY        14              /* timestamp reply */
 #define        ICMP_IREQ               15              /* information request */
 #define        ICMP_TSTAMP             13              /* timestamp request */
 #define        ICMP_TSTAMPREPLY        14              /* timestamp reply */
 #define        ICMP_IREQ               15              /* information request */
@@ -102,6 +120,7 @@ struct icmp {
 
 #define        ICMP_INFOTYPE(type) \
        ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
 
 #define        ICMP_INFOTYPE(type) \
        ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
+       (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
        (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
        (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
        (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
        (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
        (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
        (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
index aa5819f..fe873ae 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ip_input.c  7.23 (Berkeley) %G%
+ *     @(#)ip_input.c  7.24 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -175,6 +175,9 @@ next:
                ipstat.ips_badsum++;
                goto bad;
        }
                ipstat.ips_badsum++;
                goto bad;
        }
+       if (ip->ip_v != IPVERSION) {
+               goto bad;
+       }
 
        /*
         * Convert fields to host representation.
 
        /*
         * Convert fields to host representation.
@@ -246,7 +249,6 @@ next:
                                goto ours;
                }
        }
                                goto ours;
                }
        }
-#ifdef MULTICAST
        if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
                struct in_multi *inm;
 #ifdef MROUTING
        if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
                struct in_multi *inm;
 #ifdef MROUTING
@@ -267,6 +269,7 @@ next:
                         */
                        ip->ip_id = htons(ip->ip_id);
                        if (ip_mforward(m, m->m_pkthdr.rcvif) != 0) {
                         */
                        ip->ip_id = htons(ip->ip_id);
                        if (ip_mforward(m, m->m_pkthdr.rcvif) != 0) {
+                               ipstat.ips_cantforward++;
                                m_freem(m);
                                goto next;
                        }
                                m_freem(m);
                                goto next;
                        }
@@ -279,6 +282,7 @@ next:
                         */
                        if (ip->ip_p == IPPROTO_IGMP)
                                goto ours;
                         */
                        if (ip->ip_p == IPPROTO_IGMP)
                                goto ours;
+                       ipstat.ips_forward++;
                }
 #endif
                /*
                }
 #endif
                /*
@@ -287,12 +291,12 @@ next:
                 */
                IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
                if (inm == NULL) {
                 */
                IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
                if (inm == NULL) {
+                       ipstat.ips_cantforward++;
                        m_freem(m);
                        goto next;
                }
                goto ours;
        }
                        m_freem(m);
                        goto next;
                }
                goto ours;
        }
-#endif
        if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
                goto ours;
        if (ip->ip_dst.s_addr == INADDR_ANY)
        if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
                goto ours;
        if (ip->ip_dst.s_addr == INADDR_ANY)
@@ -358,8 +362,7 @@ found:
                        ip = ip_reass((struct ipasfrag *)ip, fp);
                        if (ip == 0)
                                goto next;
                        ip = ip_reass((struct ipasfrag *)ip, fp);
                        if (ip == 0)
                                goto next;
-                       else
-                               ipstat.ips_reassembled++;
+                       ipstat.ips_reassembled++;
                        m = dtom(ip);
                } else
                        if (fp)
                        m = dtom(ip);
                } else
                        if (fp)
@@ -704,7 +707,10 @@ ip_dooptions(m)
                            (caddr_t)(cp + off), sizeof(struct in_addr));
                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
                        forward = 1;
                            (caddr_t)(cp + off), sizeof(struct in_addr));
                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
                        forward = 1;
-                       forward = 1;
+                       /*
+                        * Let ip_intr's mcast routing check handle mcast pkts
+                        */
+                       forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
                        break;
 
                case IPOPT_RR:
                        break;
 
                case IPOPT_RR:
@@ -784,10 +790,12 @@ ip_dooptions(m)
        if (forward) {
                ip_forward(m, 1);
                return (1);
        if (forward) {
                ip_forward(m, 1);
                return (1);
-       } else
-               return (0);
+       }
+       return (0);
 bad:
 bad:
+       ip->ip_len -= ip->ip_hl << 2;   /* XXX icmp_error adds in hdr length */
        icmp_error(m, type, code);
        icmp_error(m, type, code);
+       ipstat.ips_badoptions++;
        return (1);
 }
 
        return (1);
 }
 
@@ -990,6 +998,7 @@ ip_forward(m, srcrt)
        int error, type = 0, code;
        struct mbuf *mcopy;
        struct in_addr dest;
        int error, type = 0, code;
        struct mbuf *mcopy;
        struct in_addr dest;
+       struct ifnet *destifp;
 
        dest.s_addr = 0;
 #ifdef DIAGNOSTIC
 
        dest.s_addr = 0;
 #ifdef DIAGNOSTIC
@@ -1083,7 +1092,7 @@ ip_forward(m, srcrt)
                }
        }
 
                }
        }
 
-       error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING);
+       error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING, 0);
        if (error)
                ipstat.ips_cantforward++;
        else {
        if (error)
                ipstat.ips_cantforward++;
        else {
@@ -1098,6 +1107,8 @@ ip_forward(m, srcrt)
        }
        if (mcopy == NULL)
                return;
        }
        if (mcopy == NULL)
                return;
+       destifp = NULL;
+
        switch (error) {
 
        case 0:                         /* forwarded, but need redirect */
        switch (error) {
 
        case 0:                         /* forwarded, but need redirect */
@@ -1116,6 +1127,8 @@ ip_forward(m, srcrt)
        case EMSGSIZE:
                type = ICMP_UNREACH;
                code = ICMP_UNREACH_NEEDFRAG;
        case EMSGSIZE:
                type = ICMP_UNREACH;
                code = ICMP_UNREACH_NEEDFRAG;
+               if (ipforward_rt.ro_rt)
+                       destifp = ipforward_rt.ro_rt->rt_ifp;
                ipstat.ips_cantfrag++;
                break;
 
                ipstat.ips_cantfrag++;
                break;
 
@@ -1124,5 +1137,5 @@ ip_forward(m, srcrt)
                code = 0;
                break;
        }
                code = 0;
                break;
        }
-       icmp_error(mcopy, type, code, dest);
+       icmp_error(mcopy, type, code, dest, destifp);
 }
 }
index 9b7ae97..df87508 100644 (file)
@@ -8,7 +8,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ip_mroute.c 7.4 (Berkeley) %G%
+ *     @(#)ip_mroute.c 7.5 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -759,27 +759,19 @@ tunnel_send(m, vifp)
                return;
        }
 
                return;
        }
 
-       mb_copy = m_copy(m, 0, M_COPYALL);
+       /* 
+        * Get a private copy of the IP header so that changes to some 
+        * of the IP fields don't damage the original header, which is
+        * examined later in ip_input.c.
+        */
+       mb_copy = m_copy(m, IP_HDR_LEN, M_COPYALL);
        if (mb_copy == NULL)
                return;
        if (mb_copy == NULL)
                return;
-       ip_copy = mtod(mb_copy, struct ip *);
-       ip_copy->ip_ttl--;
-       ip_copy->ip_dst = vifp->v_rmt_addr;     /* remote tunnel end-point */
-       /*
-        * Adjust the ip header length to account for the tunnel options.
-        */
-       ip_copy->ip_hl += TUNNEL_LEN >> 2;
-       ip_copy->ip_len += TUNNEL_LEN;
        MGETHDR(mb_opts, M_DONTWAIT, MT_HEADER);
        if (mb_opts == NULL) {
                m_freem(mb_copy);
                return;
        }
        MGETHDR(mb_opts, M_DONTWAIT, MT_HEADER);
        if (mb_opts == NULL) {
                m_freem(mb_copy);
                return;
        }
-       /*
-        * 'Delete' the base ip header from the mb_copy chain
-        */
-       mb_copy->m_len -= IP_HDR_LEN;
-       mb_copy->m_data += IP_HDR_LEN;
        /*
         * Make mb_opts be the new head of the packet chain.
         * Any options of the packet were left in the old packet chain head
        /*
         * Make mb_opts be the new head of the packet chain.
         * Any options of the packet were left in the old packet chain head
@@ -787,14 +779,23 @@ tunnel_send(m, vifp)
        mb_opts->m_next = mb_copy;
        mb_opts->m_len = IP_HDR_LEN + TUNNEL_LEN;
        mb_opts->m_data += MSIZE - mb_opts->m_len;
        mb_opts->m_next = mb_copy;
        mb_opts->m_len = IP_HDR_LEN + TUNNEL_LEN;
        mb_opts->m_data += MSIZE - mb_opts->m_len;
+
+       ip_copy = mtod(mb_opts, struct ip *);
        /*
        /*
-        * Copy the base ip header from the mb_copy chain to the new head mbuf
+        * Copy the base ip header to the new head mbuf.
         */
         */
-       bcopy((caddr_t)ip_copy, mtod(mb_opts, caddr_t), IP_HDR_LEN);
+       *ip_copy = *ip;
+       ip_copy->ip_ttl--;
+       ip_copy->ip_dst = vifp->v_rmt_addr;     /* remote tunnel end-point */
+       /*
+        * Adjust the ip header length to account for the tunnel options.
+        */
+       ip_copy->ip_hl += TUNNEL_LEN >> 2;
+       ip_copy->ip_len += TUNNEL_LEN;
        /*
         * Add the NOP and LSRR after the base ip header
         */
        /*
         * Add the NOP and LSRR after the base ip header
         */
-       cp = mtod(mb_opts, u_char *) + IP_HDR_LEN;
+       cp = (u_char *)(ip_copy + 1);
        *cp++ = IPOPT_NOP;
        *cp++ = IPOPT_LSRR;
        *cp++ = 11;             /* LSRR option length */
        *cp++ = IPOPT_NOP;
        *cp++ = IPOPT_LSRR;
        *cp++ = 11;             /* LSRR option length */
index a826848..3508859 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ip_output.c 7.26 (Berkeley) %G%
+ *     @(#)ip_output.c 7.27 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -40,18 +40,12 @@ static      void ip_mloopback __P((struct ifnet *, struct mbuf *,
  * The mbuf opt, if present, will not be freed.
  */
 int
  * The mbuf opt, if present, will not be freed.
  */
 int
-ip_output(m0, opt, ro, flags
-#ifdef MULTICAST
-    , imo
-#endif
-    )
+ip_output(m0, opt, ro, flags, imo)
        struct mbuf *m0;
        struct mbuf *opt;
        struct route *ro;
        int flags;
        struct mbuf *m0;
        struct mbuf *opt;
        struct route *ro;
        int flags;
-#ifdef MULTICAST
        struct ip_moptions *imo;
        struct ip_moptions *imo;
-#endif
 {
        register struct ip *ip, *mhip;
        register struct ifnet *ifp;
 {
        register struct ip *ip, *mhip;
        register struct ifnet *ifp;
@@ -79,9 +73,9 @@ ip_output(m0, opt, ro, flags
                ip->ip_off &= IP_DF;
                ip->ip_id = htons(ip_id++);
                ip->ip_hl = hlen >> 2;
                ip->ip_off &= IP_DF;
                ip->ip_id = htons(ip_id++);
                ip->ip_hl = hlen >> 2;
+               ipstat.ips_localout++;
        } else {
                hlen = ip->ip_hl << 2;
        } else {
                hlen = ip->ip_hl << 2;
-               ipstat.ips_localout++;
        }
        /*
         * Route packet.
        }
        /*
         * Route packet.
@@ -116,6 +110,7 @@ ip_output(m0, opt, ro, flags
                if (ia == 0)
                        ia = in_iaonnetof(in_netof(ip->ip_dst));
                if (ia == 0) {
                if (ia == 0)
                        ia = in_iaonnetof(in_netof(ip->ip_dst));
                if (ia == 0) {
+                       ipstat.ips_noroute++;
                        error = ENETUNREACH;
                        goto bad;
                }
                        error = ENETUNREACH;
                        goto bad;
                }
@@ -124,6 +119,7 @@ ip_output(m0, opt, ro, flags
                if (ro->ro_rt == 0)
                        rtalloc(ro);
                if (ro->ro_rt == 0) {
                if (ro->ro_rt == 0)
                        rtalloc(ro);
                if (ro->ro_rt == 0) {
+                       ipstat.ips_noroute++;
                        error = EHOSTUNREACH;
                        goto bad;
                }
                        error = EHOSTUNREACH;
                        goto bad;
                }
@@ -133,7 +129,6 @@ ip_output(m0, opt, ro, flags
                if (ro->ro_rt->rt_flags & RTF_GATEWAY)
                        dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
        }
                if (ro->ro_rt->rt_flags & RTF_GATEWAY)
                        dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
        }
-#ifdef MULTICAST
        if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
                struct in_multi *inm;
                extern struct ifnet loif;
        if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
                struct in_multi *inm;
                extern struct ifnet loif;
@@ -159,6 +154,7 @@ ip_output(m0, opt, ro, flags
                 * Confirm that the outgoing interface supports multicast.
                 */
                if ((ifp->if_flags & IFF_MULTICAST) == 0) {
                 * Confirm that the outgoing interface supports multicast.
                 */
                if ((ifp->if_flags & IFF_MULTICAST) == 0) {
+                       ipstat.ips_noroute++;
                        error = ENETUNREACH;
                        goto bad;
                }
                        error = ENETUNREACH;
                        goto bad;
                }
@@ -221,7 +217,6 @@ ip_output(m0, opt, ro, flags
 
                goto sendit;
        }
 
                goto sendit;
        }
-#endif
 #ifndef notdef
        /*
         * If source address not specified yet, use address
 #ifndef notdef
        /*
         * If source address not specified yet, use address
@@ -250,11 +245,10 @@ ip_output(m0, opt, ro, flags
                        goto bad;
                }
                m->m_flags |= M_BCAST;
                        goto bad;
                }
                m->m_flags |= M_BCAST;
-       }
+       } else
+               m->m_flags &= ~M_BCAST;
 
 
-#ifdef MULTICAST
 sendit:
 sendit:
-#endif
        /*
         * If small enough for interface, can just send directly.
         */
        /*
         * If small enough for interface, can just send directly.
         */
@@ -267,13 +261,13 @@ sendit:
                                (struct sockaddr *)dst, ro->ro_rt);
                goto done;
        }
                                (struct sockaddr *)dst, ro->ro_rt);
                goto done;
        }
-       ipstat.ips_fragmented++;
        /*
         * Too large for interface; fragment if possible.
         * Must be able to put at least 8 bytes per fragment.
         */
        if (ip->ip_off & IP_DF) {
                error = EMSGSIZE;
        /*
         * Too large for interface; fragment if possible.
         * Must be able to put at least 8 bytes per fragment.
         */
        if (ip->ip_off & IP_DF) {
                error = EMSGSIZE;
+               ipstat.ips_cantfrag++;
                goto bad;
        }
        len = (ifp->if_mtu - hlen) &~ 7;
                goto bad;
        }
        len = (ifp->if_mtu - hlen) &~ 7;
@@ -296,6 +290,7 @@ sendit:
                MGETHDR(m, M_DONTWAIT, MT_HEADER);
                if (m == 0) {
                        error = ENOBUFS;
                MGETHDR(m, M_DONTWAIT, MT_HEADER);
                if (m == 0) {
                        error = ENOBUFS;
+                       ipstat.ips_odropped++;
                        goto sendorfree;
                }
                m->m_data += max_linkhdr;
                        goto sendorfree;
                }
                m->m_data += max_linkhdr;
@@ -317,6 +312,7 @@ sendit:
                m->m_next = m_copy(m0, off, len);
                if (m->m_next == 0) {
                        error = ENOBUFS;        /* ??? */
                m->m_next = m_copy(m0, off, len);
                if (m->m_next == 0) {
                        error = ENOBUFS;        /* ??? */
+                       ipstat.ips_odropped++;
                        goto sendorfree;
                }
                m->m_pkthdr.len = mhlen + len;
                        goto sendorfree;
                }
                m->m_pkthdr.len = mhlen + len;
@@ -349,6 +345,9 @@ sendorfree:
                else
                        m_freem(m);
        }
                else
                        m_freem(m);
        }
+
+       if (error == 0)
+               ipstat.ips_fragmented++;
     }
 done:
        if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
     }
 done:
        if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
@@ -423,9 +422,12 @@ ip_optcopy(ip, jp)
                opt = cp[0];
                if (opt == IPOPT_EOL)
                        break;
                opt = cp[0];
                if (opt == IPOPT_EOL)
                        break;
-               if (opt == IPOPT_NOP)
+               if (opt == IPOPT_NOP) {
+                       /* Preserve for IP mcast tunnel's LSRR alignment. */
+                       *dp++ = IPOPT_NOP;
                        optlen = 1;
                        optlen = 1;
-               else
+                       continue;
+               } else
                        optlen = cp[IPOPT_OLEN];
                /* bogus lengths should have been caught by ip_dooptions */
                if (optlen > cnt)
                        optlen = cp[IPOPT_OLEN];
                /* bogus lengths should have been caught by ip_dooptions */
                if (optlen > cnt)
@@ -509,7 +511,6 @@ ip_ctloutput(op, so, level, optname, mp)
                        break;
 #undef OPTSET
 
                        break;
 #undef OPTSET
 
-#ifdef MULTICAST
                case IP_MULTICAST_IF:
                case IP_MULTICAST_TTL:
                case IP_MULTICAST_LOOP:
                case IP_MULTICAST_IF:
                case IP_MULTICAST_TTL:
                case IP_MULTICAST_LOOP:
@@ -517,7 +518,6 @@ ip_ctloutput(op, so, level, optname, mp)
                case IP_DROP_MEMBERSHIP:
                        error = ip_setmoptions(optname, &inp->inp_moptions, m);
                        break;
                case IP_DROP_MEMBERSHIP:
                        error = ip_setmoptions(optname, &inp->inp_moptions, m);
                        break;
-#endif
 
                freeit:
                default:
 
                freeit:
                default:
@@ -575,7 +575,6 @@ ip_ctloutput(op, so, level, optname, mp)
                        *mtod(m, int *) = optval;
                        break;
 
                        *mtod(m, int *) = optval;
                        break;
 
-#ifdef MULTICAST
                case IP_MULTICAST_IF:
                case IP_MULTICAST_TTL:
                case IP_MULTICAST_LOOP:
                case IP_MULTICAST_IF:
                case IP_MULTICAST_TTL:
                case IP_MULTICAST_LOOP:
@@ -583,7 +582,6 @@ ip_ctloutput(op, so, level, optname, mp)
                case IP_DROP_MEMBERSHIP:
                        error = ip_getmoptions(optname, inp->inp_moptions, mp);
                        break;
                case IP_DROP_MEMBERSHIP:
                        error = ip_getmoptions(optname, inp->inp_moptions, mp);
                        break;
-#endif
 
                default:
                        error = EINVAL;
 
                default:
                        error = EINVAL;
@@ -701,7 +699,6 @@ bad:
        return (EINVAL);
 }
 
        return (EINVAL);
 }
 
-#ifdef MULTICAST
 /*
  * Set the IP multicast options in response to user setsockopt().
  */
 /*
  * Set the IP multicast options in response to user setsockopt().
  */
@@ -1035,4 +1032,3 @@ ip_mloopback(ifp, m, dst)
                (void) looutput(ifp, copym, (struct sockaddr *)dst);
        }
 }
                (void) looutput(ifp, copym, (struct sockaddr *)dst);
        }
 }
-#endif
index 642d5a4..4d756ae 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ip_var.h    7.8 (Berkeley) %G%
+ *     @(#)ip_var.h    7.9 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -86,26 +86,28 @@ struct ip_moptions {
 };
 
 struct ipstat {
 };
 
 struct ipstat {
-       long    ips_total;              /* total packets received */
-       long    ips_badsum;             /* checksum bad */
-       long    ips_tooshort;           /* packet too short */
-       long    ips_toosmall;           /* not enough data */
-       long    ips_badhlen;            /* ip header length < data size */
-       long    ips_badlen;             /* ip length < ip header length */
-       long    ips_fragments;          /* fragments received */
-       long    ips_fragdropped;        /* frags dropped (dups, out of space) */
-       long    ips_fragtimeout;        /* fragments timed out */
-       long    ips_forward;            /* packets forwarded */
-       long    ips_cantforward;        /* packets rcvd for unreachable dest */
-       long    ips_redirectsent;       /* packets forwarded on same net */
-       long    ips_noproto;            /* unknown or unsupported protocol */
-       long    ips_delivered;          /* packets consumed here */
-       long    ips_localout;           /* total ip packets generated here */
-       long    ips_odropped;           /* lost packets due to nobufs, etc. */
-       long    ips_reassembled;        /* total packets reassembled ok */
-       long    ips_fragmented;         /* output packets fragmented ok */
-       long    ips_ofragments;         /* output fragments created */
-       long    ips_cantfrag;           /* don't fragment flag was set, etc. */
+       u_long  ips_total;              /* total packets received */
+       u_long  ips_badsum;             /* checksum bad */
+       u_long  ips_tooshort;           /* packet too short */
+       u_long  ips_toosmall;           /* not enough data */
+       u_long  ips_badhlen;            /* ip header length < data size */
+       u_long  ips_badlen;             /* ip length < ip header length */
+       u_long  ips_fragments;          /* fragments received */
+       u_long  ips_fragdropped;        /* frags dropped (dups, out of space) */
+       u_long  ips_fragtimeout;        /* fragments timed out */
+       u_long  ips_forward;            /* packets forwarded */
+       u_long  ips_cantforward;        /* packets rcvd for unreachable dest */
+       u_long  ips_redirectsent;       /* packets forwarded on same net */
+       u_long  ips_noproto;            /* unknown or unsupported protocol */
+       u_long  ips_delivered;          /* datagrams delivered to upper level*/
+       u_long  ips_localout;           /* total ip packets generated here */
+       u_long  ips_odropped;           /* lost packets due to nobufs, etc. */
+       u_long  ips_reassembled;        /* total packets reassembled ok */
+       u_long  ips_fragmented;         /* datagrams sucessfully fragmented */
+       u_long  ips_ofragments;         /* output fragments created */
+       u_long  ips_cantfrag;           /* don't fragment flag was set, etc. */
+       u_long  ips_badoptions;         /* error in option processing */
+       u_long  ips_noroute;            /* packtes discarded due to no route */
 };
 
 #ifdef KERNEL
 };
 
 #ifdef KERNEL
index 35db513..fcca9ce 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)raw_ip.c    7.10 (Berkeley) %G%
+ *     @(#)raw_ip.c    7.11 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -127,11 +127,8 @@ rip_output(m, so, dst)
        return (ip_output(m,
           (inp->inp_flags & INP_HDRINCL)? (struct mbuf *)0: inp->inp_options,
            &inp->inp_route, 
        return (ip_output(m,
           (inp->inp_flags & INP_HDRINCL)? (struct mbuf *)0: inp->inp_options,
            &inp->inp_route, 
-          (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST
-#ifdef MULTICAST
-          , inp->inp_moptions
-#endif
-          ));
+          (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST,
+          inp->inp_moptions));
 }
 
 /*
 }
 
 /*
@@ -205,7 +202,7 @@ rip_usrreq(so, req, m, nam, control)
 {
        register int error = 0;
        register struct inpcb *inp = sotoinpcb(so);
 {
        register int error = 0;
        register struct inpcb *inp = sotoinpcb(so);
-#if defined(MULTICAST) && defined(MROUTING)
+#ifdef MROUTING
        extern struct socket *ip_mrouter;
 #endif
 
        extern struct socket *ip_mrouter;
 #endif
 
@@ -237,7 +234,7 @@ rip_usrreq(so, req, m, nam, control)
        case PRU_DETACH:
                if (inp == 0)
                        panic("rip_detach");
        case PRU_DETACH:
                if (inp == 0)
                        panic("rip_detach");
-#if defined(MULTICAST) && defined(MROUTING)
+#ifdef MROUTING
                if (so == ip_mrouter)
                        ip_mrouter_done();
 #endif
                if (so == ip_mrouter)
                        ip_mrouter_done();
 #endif
index eae3c64..eddd0cd 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)tcp.h       7.7 (Berkeley) %G%
+ *     @(#)tcp.h       7.8 (Berkeley) %G%
  */
 #ifndef BYTE_ORDER
 /*
  */
 #ifndef BYTE_ORDER
 /*
@@ -52,9 +52,21 @@ struct tcphdr {
        u_short th_urp;                 /* urgent pointer */
 };
 
        u_short th_urp;                 /* urgent pointer */
 };
 
-#define        TCPOPT_EOL      0
-#define        TCPOPT_NOP      1
-#define        TCPOPT_MAXSEG   2
+#define        TCPOPT_EOL              0
+#define        TCPOPT_NOP              1
+#define        TCPOPT_MAXSEG           2
+#define    TCPOLEN_MAXSEG              4
+#define TCPOPT_WINDOW          3
+#define    TCPOLEN_WINDOW              3
+#define TCPOPT_SACK_PERMITTED  4               /* Experimental */
+#define    TCPOLEN_SACK_PERMITTED      2
+#define TCPOPT_SACK            5               /* Experimental */
+#define TCPOPT_TIMESTAMP       8
+#define    TCPOLEN_TIMESTAMP           10
+#define    TCPOLEN_TSTAMP_APPA         (TCPOLEN_TIMESTAMP+2) /* appendix A */
+
+#define TCPOPT_TSTAMP_HDR      \
+    (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)
 
 /*
  * Default maximum segment size for TCP.
 
 /*
  * Default maximum segment size for TCP.
@@ -64,7 +76,9 @@ struct tcphdr {
  */
 #define        TCP_MSS 512
 
  */
 #define        TCP_MSS 512
 
-#define        TCP_MAXWIN      65535           /* largest value for window */
+#define        TCP_MAXWIN      65535   /* largest value for (unscaled) window */
+
+#define TCP_MAX_WINSHIFT       14      /* maximum window shift */
 
 /*
  * User-settable options (used with setsockopt).
 
 /*
  * User-settable options (used with setsockopt).
index 78b8109..52da087 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)tcp_input.c 7.29 (Berkeley) %G%
+ *     @(#)tcp_input.c 7.30 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -39,8 +39,17 @@ int  tcppcbcachemiss;
 struct tcpiphdr tcp_saveti;
 struct inpcb *tcp_last_inpcb = &tcb;
 
 struct tcpiphdr tcp_saveti;
 struct inpcb *tcp_last_inpcb = &tcb;
 
+#define TCP_PAWS_IDLE  (24 * 24 * 60 * 60 * PR_SLOWHZ)
+
+/* for modulo comparisons of timestamps */
+#define TSTMP_LT(a,b)  ((int)((a)-(b)) < 0)
+#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0)
+
 struct tcpcb *tcp_newtcpcb();
 
 struct tcpcb *tcp_newtcpcb();
 
+extern u_long sb_max;
+
+
 /*
  * Insert segment ti into reassembly queue of tcp with
  * control block tp.  Return TH_FIN if reassembly now includes
 /*
  * Insert segment ti into reassembly queue of tcp with
  * control block tp.  Return TH_FIN if reassembly now includes
@@ -181,7 +190,8 @@ tcp_input(m, iphlen)
 {
        register struct tcpiphdr *ti;
        register struct inpcb *inp;
 {
        register struct tcpiphdr *ti;
        register struct inpcb *inp;
-       struct mbuf *om = 0;
+       caddr_t optp = NULL;
+       int optlen;
        int len, tlen, off;
        register struct tcpcb *tp = 0;
        register int tiflags;
        int len, tlen, off;
        register struct tcpcb *tp = 0;
        register int tiflags;
@@ -191,6 +201,8 @@ tcp_input(m, iphlen)
        struct in_addr laddr;
        int dropsocket = 0;
        int iss = 0;
        struct in_addr laddr;
        int dropsocket = 0;
        int iss = 0;
+       u_long tiwin, ts_val, ts_ecr;
+       int ts_present = 0;
 
        tcpstat.tcps_rcvtotal++;
        /*
 
        tcpstat.tcps_rcvtotal++;
        /*
@@ -241,16 +253,24 @@ tcp_input(m, iphlen)
                        }
                        ti = mtod(m, struct tcpiphdr *);
                }
                        }
                        ti = mtod(m, struct tcpiphdr *);
                }
-               om = m_get(M_DONTWAIT, MT_DATA);
-               if (om == 0)
-                       goto drop;
-               om->m_len = off - sizeof (struct tcphdr);
-               { caddr_t op = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
-                 bcopy(op, mtod(om, caddr_t), (unsigned)om->m_len);
-                 m->m_len -= om->m_len;
-                 m->m_pkthdr.len -= om->m_len;
-                 bcopy(op+om->m_len, op,
-                  (unsigned)(m->m_len-sizeof (struct tcpiphdr)));
+               optlen = off - sizeof (struct tcphdr);
+               optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
+               /* 
+                * Do quick retrieval of timestamp options ("options
+                * prediction?").  If timestamp is the only option and it's
+                * formatted as recommended in RFC 1323 appendix A, we
+                * quickly get the values now and not bother calling
+                * tcp_dooptions(), etc.
+                */
+               if ((optlen == TCPOLEN_TSTAMP_APPA ||
+                    (optlen > TCPOLEN_TSTAMP_APPA &&
+                       optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) &&
+                    *(u_long *)optp == htonl(TCPOPT_TSTAMP_HDR) &&
+                    (ti->ti_flags & TH_SYN) == 0) {
+                       ts_present = 1;
+                       ts_val = ntohl(*(u_long *)(optp + 4));
+                       ts_ecr = ntohl(*(u_long *)(optp + 8));
+                       optp = NULL;    /* we've parsed the options */
                }
        }
        tiflags = ti->ti_flags;
                }
        }
        tiflags = ti->ti_flags;
@@ -292,6 +312,13 @@ findpcb:
                goto dropwithreset;
        if (tp->t_state == TCPS_CLOSED)
                goto drop;
                goto dropwithreset;
        if (tp->t_state == TCPS_CLOSED)
                goto drop;
+       
+       /* Unscale the window into a 32-bit value. */
+       if ((tiflags & TH_SYN) == 0)
+               tiwin = ti->ti_win << tp->snd_scale;
+       else
+               tiwin = ti->ti_win;
+
        so = inp->inp_socket;
        if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) {
                if (so->so_options & SO_DEBUG) {
        so = inp->inp_socket;
        if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) {
                if (so->so_options & SO_DEBUG) {
@@ -322,6 +349,12 @@ findpcb:
 #endif
                        tp = intotcpcb(inp);
                        tp->t_state = TCPS_LISTEN;
 #endif
                        tp = intotcpcb(inp);
                        tp->t_state = TCPS_LISTEN;
+
+                       /* Compute proper scaling value from buffer space
+                        */
+                       while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
+                          TCP_MAXWIN << tp->request_r_scale < so->so_rcv.sb_hiwat)
+                               tp->request_r_scale++;
                }
        }
 
                }
        }
 
@@ -336,10 +369,10 @@ findpcb:
         * Process options if not in LISTEN state,
         * else do it below (after getting remote address).
         */
         * Process options if not in LISTEN state,
         * else do it below (after getting remote address).
         */
-       if (om && tp->t_state != TCPS_LISTEN) {
-               tcp_dooptions(tp, om, ti);
-               om = 0;
-       }
+       if (optp && tp->t_state != TCPS_LISTEN)
+               tcp_dooptions(tp, optp, optlen, ti,
+                       &ts_present, &ts_val, &ts_ecr);
+
        /* 
         * Header prediction: check for the two common cases
         * of a uni-directional data xfer.  If the packet has
        /* 
         * Header prediction: check for the two common cases
         * of a uni-directional data xfer.  If the packet has
@@ -356,9 +389,21 @@ findpcb:
         */
        if (tp->t_state == TCPS_ESTABLISHED &&
            (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
         */
        if (tp->t_state == TCPS_ESTABLISHED &&
            (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
+           (!ts_present || TSTMP_GEQ(ts_val, tp->ts_recent)) &&
            ti->ti_seq == tp->rcv_nxt &&
            ti->ti_seq == tp->rcv_nxt &&
-           ti->ti_win && ti->ti_win == tp->snd_wnd &&
+           tiwin && tiwin == tp->snd_wnd &&
            tp->snd_nxt == tp->snd_max) {
            tp->snd_nxt == tp->snd_max) {
+
+               /* 
+                * If last ACK falls within this segment's sequence numbers,
+                *  record the timestamp.
+                */
+               if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) &&
+                  SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len)) {
+                       tp->ts_recent_age = tcp_now;
+                       tp->ts_recent = ts_val;
+               }
+
                if (ti->ti_len == 0) {
                        if (SEQ_GT(ti->ti_ack, tp->snd_una) &&
                            SEQ_LEQ(ti->ti_ack, tp->snd_max) &&
                if (ti->ti_len == 0) {
                        if (SEQ_GT(ti->ti_ack, tp->snd_una) &&
                            SEQ_LEQ(ti->ti_ack, tp->snd_max) &&
@@ -367,8 +412,11 @@ findpcb:
                                 * this is a pure ack for outstanding data.
                                 */
                                ++tcppredack;
                                 * this is a pure ack for outstanding data.
                                 */
                                ++tcppredack;
-                               if (tp->t_rtt && SEQ_GT(ti->ti_ack,tp->t_rtseq))
-                                       tcp_xmit_timer(tp);
+                               if (ts_present)
+                                       tcp_xmit_timer(tp, tcp_now-ts_ecr+1);
+                               else if (tp->t_rtt &&
+                                           SEQ_GT(ti->ti_ack, tp->t_rtseq))
+                                       tcp_xmit_timer(tp, tp->t_rtt);
                                acked = ti->ti_ack - tp->snd_una;
                                tcpstat.tcps_rcvackpack++;
                                tcpstat.tcps_rcvackbyte += acked;
                                acked = ti->ti_ack - tp->snd_una;
                                tcpstat.tcps_rcvackpack++;
                                tcpstat.tcps_rcvackbyte += acked;
@@ -409,11 +457,11 @@ findpcb:
                        tcpstat.tcps_rcvpack++;
                        tcpstat.tcps_rcvbyte += ti->ti_len;
                        /*
                        tcpstat.tcps_rcvpack++;
                        tcpstat.tcps_rcvbyte += ti->ti_len;
                        /*
-                        * Drop TCP and IP headers then add data
-                        * to socket buffer
+                        * Drop TCP, IP headers and TCP options then add data
+                        * to socket buffer.
                         */
                         */
-                       m->m_data += sizeof(struct tcpiphdr);
-                       m->m_len -= sizeof(struct tcpiphdr);
+                       m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+                       m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
                        sbappend(&so->so_rcv, m);
                        sorwakeup(so);
                        tp->t_flags |= TF_DELACK;
                        sbappend(&so->so_rcv, m);
                        sorwakeup(so);
                        tp->t_flags |= TF_DELACK;
@@ -422,10 +470,10 @@ findpcb:
        }
 
        /*
        }
 
        /*
-        * Drop TCP and IP headers; TCP options were dropped above.
+        * Drop TCP, IP headers and TCP options.
         */
         */
-       m->m_data += sizeof(struct tcpiphdr);
-       m->m_len -= sizeof(struct tcpiphdr);
+       m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+       m->m_len  -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
 
        /*
         * Calculate amount of space in receive window,
 
        /*
         * Calculate amount of space in receive window,
@@ -466,7 +514,9 @@ findpcb:
                        goto dropwithreset;
                if ((tiflags & TH_SYN) == 0)
                        goto drop;
                        goto dropwithreset;
                if ((tiflags & TH_SYN) == 0)
                        goto drop;
-               if (m->m_flags & M_BCAST)
+               /* RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN */
+               if (m->m_flags & (M_BCAST|M_MCAST) ||
+                   in_broadcast(ti->ti_dst) || IN_MULTICAST(ti->ti_dst.s_addr))
                        goto drop;
                am = m_get(M_DONTWAIT, MT_SONAME);      /* XXX */
                if (am == NULL)
                        goto drop;
                am = m_get(M_DONTWAIT, MT_SONAME);      /* XXX */
                if (am == NULL)
@@ -493,10 +543,9 @@ findpcb:
                        dropsocket = 0;         /* socket is already gone */
                        goto drop;
                }
                        dropsocket = 0;         /* socket is already gone */
                        goto drop;
                }
-               if (om) {
-                       tcp_dooptions(tp, om, ti);
-                       om = 0;
-               }
+               if (optp)
+                       tcp_dooptions(tp, optp, optlen, ti,
+                               &ts_present, &ts_val, &ts_ecr);
                if (iss)
                        tp->iss = iss;
                else
                if (iss)
                        tp->iss = iss;
                else
@@ -550,6 +599,12 @@ findpcb:
                        tcpstat.tcps_connects++;
                        soisconnected(so);
                        tp->t_state = TCPS_ESTABLISHED;
                        tcpstat.tcps_connects++;
                        soisconnected(so);
                        tp->t_state = TCPS_ESTABLISHED;
+                       /* Do window scaling on this connection? */
+                       if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
+                               (TF_RCVD_SCALE|TF_REQ_SCALE)) {
+                               tp->snd_scale = tp->requested_s_scale;
+                               tp->rcv_scale = tp->request_r_scale;
+                       }
                        (void) tcp_reass(tp, (struct tcpiphdr *)0,
                                (struct mbuf *)0);
                        /*
                        (void) tcp_reass(tp, (struct tcpiphdr *)0,
                                (struct mbuf *)0);
                        /*
@@ -557,7 +612,7 @@ findpcb:
                         * use its rtt as our initial srtt & rtt var.
                         */
                        if (tp->t_rtt)
                         * use its rtt as our initial srtt & rtt var.
                         */
                        if (tp->t_rtt)
-                               tcp_xmit_timer(tp);
+                               tcp_xmit_timer(tp, tp->t_rtt);
                } else
                        tp->t_state = TCPS_SYN_RECEIVED;
 
                } else
                        tp->t_state = TCPS_SYN_RECEIVED;
 
@@ -593,10 +648,39 @@ trimthenstep6:
 
        /*
         * States other than LISTEN or SYN_SENT.
 
        /*
         * States other than LISTEN or SYN_SENT.
-        * First check that at least some bytes of segment are within 
+        * First check timestamp, if present.
+        * Then check that at least some bytes of segment are within 
         * receive window.  If segment begins before rcv_nxt,
         * drop leading data (and SYN); if nothing left, just ack.
         * receive window.  If segment begins before rcv_nxt,
         * drop leading data (and SYN); if nothing left, just ack.
+        * 
+        * RFC 1323 PAWS: If we have a timestamp reply on this segment
+        * and it's less than ts_recent, drop it.
         */
         */
+       if (ts_present && (tiflags & TH_RST) == 0 && tp->ts_recent &&
+           TSTMP_LT(ts_val, tp->ts_recent)) {
+
+               /* Check to see if ts_recent is over 24 days old.  */
+               if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) {
+                       /*
+                        * Invalidate ts_recent.  If this segment updates
+                        * ts_recent, the age will be reset later and ts_recent
+                        * will get a valid value.  If it does not, setting
+                        * ts_recent to zero will at least satisfy the
+                        * requirement that zero be placed in the timestamp
+                        * echo reply when ts_recent isn't valid.  The
+                        * age isn't reset until we get a valid ts_recent
+                        * because we don't want out-of-order segments to be
+                        * dropped when ts_recent is old.
+                        */
+                       tp->ts_recent = 0;
+               } else {
+                       tcpstat.tcps_rcvduppack++;
+                       tcpstat.tcps_rcvdupbyte += ti->ti_len;
+                       tcpstat.tcps_pawsdrop++;
+                       goto dropafterack;
+               }
+       }
+
        todrop = tp->rcv_nxt - ti->ti_seq;
        if (todrop > 0) {
                if (tiflags & TH_SYN) {
        todrop = tp->rcv_nxt - ti->ti_seq;
        if (todrop > 0) {
                if (tiflags & TH_SYN) {
@@ -630,8 +714,15 @@ trimthenstep6:
                                todrop = ti->ti_len;
                                tiflags &= ~TH_FIN;
                                tp->t_flags |= TF_ACKNOW;
                                todrop = ti->ti_len;
                                tiflags &= ~TH_FIN;
                                tp->t_flags |= TF_ACKNOW;
-                       } else
-                               goto dropafterack;
+                       } else {
+                               /*
+                                * Handle the case when a bound socket connects
+                                * to itself. Allow packets with a SYN and
+                                * an ACK to continue with the processing.
+                                */
+                               if (todrop != 0 || (tiflags & TH_ACK) == 0)
+                                       goto dropafterack;
+                       }
                } else {
                        tcpstat.tcps_rcvpartduppack++;
                        tcpstat.tcps_rcvpartdupbyte += todrop;
                } else {
                        tcpstat.tcps_rcvpartduppack++;
                        tcpstat.tcps_rcvpartdupbyte += todrop;
@@ -709,6 +800,17 @@ trimthenstep6:
                tiflags &= ~(TH_PUSH|TH_FIN);
        }
 
                tiflags &= ~(TH_PUSH|TH_FIN);
        }
 
+       /*
+        * If last ACK falls within this segment's sequence numbers,
+        * record its timestamp.
+        */
+       if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) &&
+           SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len +
+                  ((tiflags & (TH_SYN|TH_FIN)) != 0))) {
+               tp->ts_recent_age = tcp_now;
+               tp->ts_recent = ts_val;
+       }
+
        /*
         * If the RST bit is set examine the state:
         *    SYN_RECEIVED STATE:
        /*
         * If the RST bit is set examine the state:
         *    SYN_RECEIVED STATE:
@@ -775,6 +877,12 @@ trimthenstep6:
                tcpstat.tcps_connects++;
                soisconnected(so);
                tp->t_state = TCPS_ESTABLISHED;
                tcpstat.tcps_connects++;
                soisconnected(so);
                tp->t_state = TCPS_ESTABLISHED;
+               /* Do window scaling? */
+               if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
+                       (TF_RCVD_SCALE|TF_REQ_SCALE)) {
+                       tp->snd_scale = tp->requested_s_scale;
+                       tp->rcv_scale = tp->request_r_scale;
+               }
                (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
                tp->snd_wl1 = ti->ti_seq - 1;
                /* fall into ... */
                (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
                tp->snd_wl1 = ti->ti_seq - 1;
                /* fall into ... */
@@ -796,7 +904,7 @@ trimthenstep6:
        case TCPS_TIME_WAIT:
 
                if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
        case TCPS_TIME_WAIT:
 
                if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
-                       if (ti->ti_len == 0 && ti->ti_win == tp->snd_wnd) {
+                       if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
                                tcpstat.tcps_rcvdupack++;
                                /*
                                 * If we have outstanding data (other than
                                tcpstat.tcps_rcvdupack++;
                                /*
                                 * If we have outstanding data (other than
@@ -870,14 +978,18 @@ trimthenstep6:
                tcpstat.tcps_rcvackbyte += acked;
 
                /*
                tcpstat.tcps_rcvackbyte += acked;
 
                /*
-                * If transmit timer is running and timed sequence
+                * If we have a timestamp reply, update smoothed
+                * round trip time.  If no timestamp is present but
+                * transmit timer is running and timed sequence
                 * number was acked, update smoothed round trip time.
                 * Since we now have an rtt measurement, cancel the
                 * timer backoff (cf., Phil Karn's retransmit alg.).
                 * Recompute the initial retransmit timer.
                 */
                 * number was acked, update smoothed round trip time.
                 * Since we now have an rtt measurement, cancel the
                 * timer backoff (cf., Phil Karn's retransmit alg.).
                 * Recompute the initial retransmit timer.
                 */
-               if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
-                       tcp_xmit_timer(tp);
+               if (ts_present)
+                       tcp_xmit_timer(tp, tcp_now-ts_ecr+1);
+               else if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
+                       tcp_xmit_timer(tp,tp->t_rtt);
 
                /*
                 * If all outstanding data is acked, stop retransmit
 
                /*
                 * If all outstanding data is acked, stop retransmit
@@ -905,7 +1017,7 @@ trimthenstep6:
 
                if (cw > tp->snd_ssthresh)
                        incr = incr * incr / cw + incr / 8;
 
                if (cw > tp->snd_ssthresh)
                        incr = incr * incr / cw + incr / 8;
-               tp->snd_cwnd = min(cw + incr, TCP_MAXWIN);
+               tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale);
                }
                if (acked > so->so_snd.sb_cc) {
                        tp->snd_wnd -= so->so_snd.sb_cc;
                }
                if (acked > so->so_snd.sb_cc) {
                        tp->snd_wnd -= so->so_snd.sb_cc;
@@ -993,12 +1105,12 @@ step6:
        if ((tiflags & TH_ACK) &&
            (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq &&
            (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
        if ((tiflags & TH_ACK) &&
            (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq &&
            (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
-            tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd))) {
+            tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))) {
                /* keep track of pure window updates */
                if (ti->ti_len == 0 &&
                /* keep track of pure window updates */
                if (ti->ti_len == 0 &&
-                   tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd)
+                   tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd)
                        tcpstat.tcps_rcvwinupd++;
                        tcpstat.tcps_rcvwinupd++;
-               tp->snd_wnd = ti->ti_win;
+               tp->snd_wnd = tiwin;
                tp->snd_wl1 = ti->ti_seq;
                tp->snd_wl2 = ti->ti_ack;
                if (tp->snd_wnd > tp->max_sndwnd)
                tp->snd_wl1 = ti->ti_seq;
                tp->snd_wl2 = ti->ti_ack;
                if (tp->snd_wnd > tp->max_sndwnd)
@@ -1017,7 +1129,7 @@ step6:
                 * soreceive.  It's hard to imagine someone
                 * actually wanting to send this much urgent data.
                 */
                 * soreceive.  It's hard to imagine someone
                 * actually wanting to send this much urgent data.
                 */
-               if (ti->ti_urp + so->so_rcv.sb_cc > SB_MAX) {
+               if (ti->ti_urp + so->so_rcv.sb_cc > sb_max) {
                        ti->ti_urp = 0;                 /* XXX */
                        tiflags &= ~TH_URG;             /* XXX */
                        goto dodata;                    /* XXX */
                        ti->ti_urp = 0;                 /* XXX */
                        tiflags &= ~TH_URG;             /* XXX */
                        goto dodata;                    /* XXX */
@@ -1161,16 +1273,13 @@ dropafterack:
        return;
 
 dropwithreset:
        return;
 
 dropwithreset:
-       if (om) {
-               (void) m_free(om);
-               om = 0;
-       }
        /*
         * Generate a RST, dropping incoming segment.
         * Make ACK acceptable to originator of segment.
        /*
         * Generate a RST, dropping incoming segment.
         * Make ACK acceptable to originator of segment.
-        * Don't bother to respond if destination was broadcast.
+        * Don't bother to respond if destination was broadcast/multicast.
         */
         */
-       if ((tiflags & TH_RST) || m->m_flags & M_BCAST)
+       if ((tiflags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST) ||
+           in_broadcast(ti->ti_dst) || IN_MULTICAST(ti->ti_dst.s_addr))
                goto drop;
        if (tiflags & TH_ACK)
                tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
                goto drop;
        if (tiflags & TH_ACK)
                tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
@@ -1186,8 +1295,6 @@ dropwithreset:
        return;
 
 drop:
        return;
 
 drop:
-       if (om)
-               (void) m_free(om);
        /*
         * Drop space held by incoming segment and return.
         */
        /*
         * Drop space held by incoming segment and return.
         */
@@ -1200,17 +1307,17 @@ drop:
        return;
 }
 
        return;
 }
 
-tcp_dooptions(tp, om, ti)
+tcp_dooptions(tp, cp, cnt, ti, ts_present, ts_val, ts_ecr)
        struct tcpcb *tp;
        struct tcpcb *tp;
-       struct mbuf *om;
+       u_char *cp;
+       int cnt;
        struct tcpiphdr *ti;
        struct tcpiphdr *ti;
+       int *ts_present;
+       u_long *ts_val, *ts_ecr;
 {
 {
-       register u_char *cp;
        u_short mss;
        u_short mss;
-       int opt, optlen, cnt;
+       int opt, optlen;
 
 
-       cp = mtod(om, u_char *);
-       cnt = om->m_len;
        for (; cnt > 0; cnt -= optlen, cp += optlen) {
                opt = cp[0];
                if (opt == TCPOPT_EOL)
        for (; cnt > 0; cnt -= optlen, cp += optlen) {
                opt = cp[0];
                if (opt == TCPOPT_EOL)
@@ -1228,7 +1335,7 @@ tcp_dooptions(tp, om, ti)
                        continue;
 
                case TCPOPT_MAXSEG:
                        continue;
 
                case TCPOPT_MAXSEG:
-                       if (optlen != 4)
+                       if (optlen != TCPOLEN_MAXSEG)
                                continue;
                        if (!(ti->ti_flags & TH_SYN))
                                continue;
                                continue;
                        if (!(ti->ti_flags & TH_SYN))
                                continue;
@@ -1236,9 +1343,46 @@ tcp_dooptions(tp, om, ti)
                        NTOHS(mss);
                        (void) tcp_mss(tp, mss);        /* sets t_maxseg */
                        break;
                        NTOHS(mss);
                        (void) tcp_mss(tp, mss);        /* sets t_maxseg */
                        break;
+
+               case TCPOPT_WINDOW:
+                       if (optlen != TCPOLEN_WINDOW)
+                               continue;
+                       if (!(ti->ti_flags & TH_SYN))
+                               continue;
+                       tp->t_flags |= TF_RCVD_SCALE;
+                       tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT);
+                       break;
+
+               case TCPOPT_TIMESTAMP:
+                       if (optlen != TCPOLEN_TIMESTAMP)
+                               continue;
+                       *ts_present = 1;
+                       bcopy((char *)cp + 2, (char *) ts_val, sizeof(*ts_val));
+                       NTOHL(*ts_val);
+                       bcopy((char *)cp + 6, (char *) ts_ecr, sizeof(*ts_ecr));
+                       NTOHL(*ts_ecr);
+
+                       /* 
+                        * A timestamp received in a SYN makes
+                        * it ok to send timestamp requests and replies.
+                        */
+                       if (ti->ti_flags & TH_SYN) {
+                               tp->t_flags |= TF_RCVD_TSTMP;
+                               tp->ts_recent = *ts_val;
+                               tp->ts_recent_age = tcp_now;
+                       }
+                       break;
+#ifdef DO_SACK
+               case TCPOPT_SACK_PERMITTED:
+                       if (optlen != TCPOLEN_SACK_PERMITTED)
+                               continue;
+                       if (!(ti->ti_flags & TH_SYN))
+                               continue;
+                       tp->t_flags |= TF_SACK_PERMIT;
+                       break;
+#endif
                }
        }
                }
        }
-       (void) m_free(om);
 }
 
 /*
 }
 
 /*
@@ -1277,8 +1421,9 @@ tcp_pulloutofband(so, ti, m)
  * Collect new round-trip time estimate
  * and update averages and current timeout.
  */
  * Collect new round-trip time estimate
  * and update averages and current timeout.
  */
-tcp_xmit_timer(tp)
+tcp_xmit_timer(tp, rtt)
        register struct tcpcb *tp;
        register struct tcpcb *tp;
+       short   rtt;
 {
        register short delta;
 
 {
        register short delta;
 
@@ -1289,9 +1434,9 @@ tcp_xmit_timer(tp)
                 * binary point (i.e., scaled by 8).  The following magic
                 * is equivalent to the smoothing algorithm in rfc793 with
                 * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed
                 * binary point (i.e., scaled by 8).  The following magic
                 * is equivalent to the smoothing algorithm in rfc793 with
                 * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed
-                * point).  Adjust t_rtt to origin 0.
+                * point).  Adjust rtt to origin 0.
                 */
                 */
-               delta = tp->t_rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT);
+               delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT);
                if ((tp->t_srtt += delta) <= 0)
                        tp->t_srtt = 1;
                /*
                if ((tp->t_srtt += delta) <= 0)
                        tp->t_srtt = 1;
                /*
@@ -1315,8 +1460,8 @@ tcp_xmit_timer(tp)
                 * Set the variance to half the rtt (so our first
                 * retransmit happens at 3*rtt).
                 */
                 * Set the variance to half the rtt (so our first
                 * retransmit happens at 3*rtt).
                 */
-               tp->t_srtt = tp->t_rtt << TCP_RTT_SHIFT;
-               tp->t_rttvar = tp->t_rtt << (TCP_RTTVAR_SHIFT - 1);
+               tp->t_srtt = rtt << TCP_RTT_SHIFT;
+               tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1);
        }
        tp->t_rtt = 0;
        tp->t_rxtshift = 0;
        }
        tp->t_rtt = 0;
        tp->t_rxtshift = 0;
@@ -1359,6 +1504,8 @@ tcp_xmit_timer(tp)
  * window to be a single segment if the destination isn't local.
  * While looking at the routing entry, we also initialize other path-dependent
  * parameters from pre-set or cached values in the routing entry.
  * window to be a single segment if the destination isn't local.
  * While looking at the routing entry, we also initialize other path-dependent
  * parameters from pre-set or cached values in the routing entry.
+ * We must also take into account that timestamp options may be placed in
+ * each segment.
  */
 
 tcp_mss(tp, offer)
  */
 
 tcp_mss(tp, offer)
@@ -1373,6 +1520,11 @@ tcp_mss(tp, offer)
        struct inpcb *inp;
        struct socket *so;
        extern int tcp_mssdflt, tcp_rttdflt;
        struct inpcb *inp;
        struct socket *so;
        extern int tcp_mssdflt, tcp_rttdflt;
+       int room_for_options = 0;
+
+       /* Leave room for timestamping */
+       if (tp->t_flags & TF_REQ_TSTMP)
+               room_for_options += TCPOLEN_TSTAMP_APPA;
 
        inp = tp->t_inpcb;
        ro = &inp->inp_route;
 
        inp = tp->t_inpcb;
        ro = &inp->inp_route;
@@ -1387,7 +1539,7 @@ tcp_mss(tp, offer)
                        rtalloc(ro);
                }
                if ((rt = ro->ro_rt) == (struct rtentry *)0)
                        rtalloc(ro);
                }
                if ((rt = ro->ro_rt) == (struct rtentry *)0)
-                       return (tcp_mssdflt);
+                       return (tcp_mssdflt - room_for_options);
        }
        ifp = rt->rt_ifp;
        so = inp->inp_socket;
        }
        ifp = rt->rt_ifp;
        so = inp->inp_socket;
@@ -1421,11 +1573,12 @@ tcp_mss(tp, offer)
         * if there's an mtu associated with the route, use it
         */
        if (rt->rt_rmx.rmx_mtu)
         * if there's an mtu associated with the route, use it
         */
        if (rt->rt_rmx.rmx_mtu)
-               mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr);
+               mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr)
+                       - room_for_options;
        else
 #endif /* RTV_MTU */
        {
        else
 #endif /* RTV_MTU */
        {
-               mss = ifp->if_mtu - sizeof(struct tcpiphdr);
+               mss = ifp->if_mtu - sizeof(struct tcpiphdr) - room_for_options;
 #if    (MCLBYTES & (MCLBYTES - 1)) == 0
                if (mss > MCLBYTES)
                        mss &= ~(MCLBYTES-1);
 #if    (MCLBYTES & (MCLBYTES - 1)) == 0
                if (mss > MCLBYTES)
                        mss &= ~(MCLBYTES-1);
@@ -1434,7 +1587,7 @@ tcp_mss(tp, offer)
                        mss = mss / MCLBYTES * MCLBYTES;
 #endif
                if (!in_localaddr(inp->inp_faddr))
                        mss = mss / MCLBYTES * MCLBYTES;
 #endif
                if (!in_localaddr(inp->inp_faddr))
-                       mss = min(mss, tcp_mssdflt);
+                       mss = min(mss, tcp_mssdflt-room_for_options);
        }
        /*
         * The current mss, t_maxseg, is initialized to the default value.
        }
        /*
         * The current mss, t_maxseg, is initialized to the default value.
@@ -1462,8 +1615,8 @@ tcp_mss(tp, offer)
                        mss = bufsize;
                else {
                        bufsize = roundup(bufsize, mss);
                        mss = bufsize;
                else {
                        bufsize = roundup(bufsize, mss);
-                       if (bufsize > SB_MAX)
-                               bufsize = SB_MAX;
+                       if (bufsize > sb_max)
+                               bufsize = sb_max;
                        (void)sbreserve(&so->so_snd, bufsize);
                }
                tp->t_maxseg = mss;
                        (void)sbreserve(&so->so_snd, bufsize);
                }
                tp->t_maxseg = mss;
@@ -1474,8 +1627,8 @@ tcp_mss(tp, offer)
                        bufsize = so->so_rcv.sb_hiwat;
                if (bufsize > mss) {
                        bufsize = roundup(bufsize, mss);
                        bufsize = so->so_rcv.sb_hiwat;
                if (bufsize > mss) {
                        bufsize = roundup(bufsize, mss);
-                       if (bufsize > SB_MAX)
-                               bufsize = SB_MAX;
+                       if (bufsize > sb_max)
+                               bufsize = sb_max;
                        (void)sbreserve(&so->so_rcv, bufsize);
                }
        }
                        (void)sbreserve(&so->so_rcv, bufsize);
                }
        }
index 2078ca1..c946f2b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)tcp_output.c        7.24 (Berkeley) %G%
+ *     @(#)tcp_output.c        7.25 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
 extern struct mbuf *m_copypack();
 #endif
 
 extern struct mbuf *m_copypack();
 #endif
 
-/*
- * Initial options.
- */
-u_char tcp_initopt[4] = { TCPOPT_MAXSEG, 4, 0x0, 0x0, };
+
+#define MAX_TCPOPTLEN  32      /* max # bytes that go in options */
 
 /*
  * Tcp output routine: figure out what should be sent and send it.
 
 /*
  * Tcp output routine: figure out what should be sent and send it.
@@ -52,7 +50,7 @@ tcp_output(tp)
        int off, flags, error;
        register struct mbuf *m;
        register struct tcpiphdr *ti;
        int off, flags, error;
        register struct mbuf *m;
        register struct tcpiphdr *ti;
-       u_char *opt;
+       u_char opt[MAX_TCPOPTLEN];
        unsigned optlen, hdrlen;
        int idle, sendalot;
 
        unsigned optlen, hdrlen;
        int idle, sendalot;
 
@@ -151,7 +149,13 @@ again:
         * window, then want to send a window update to peer.
         */
        if (win > 0) {
         * window, then want to send a window update to peer.
         */
        if (win > 0) {
-               long adv = win - (tp->rcv_adv - tp->rcv_nxt);
+               /* 
+                * "adv" is the amount we can increase the window,
+                * taking into account that we are limited by
+                * TCP_MAXWIN << tp->rcv_scale.
+                */
+               long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) -
+                       (tp->rcv_adv - tp->rcv_nxt);
 
                if (adv >= (long) (2 * tp->t_maxseg))
                        goto send;
 
                if (adv >= (long) (2 * tp->t_maxseg))
                        goto send;
@@ -224,16 +228,119 @@ send:
        if (flags & TH_SYN && (tp->t_flags & TF_NOOPT) == 0) {
                u_short mss;
 
        if (flags & TH_SYN && (tp->t_flags & TF_NOOPT) == 0) {
                u_short mss;
 
-               opt = tcp_initopt;
-               optlen = sizeof (tcp_initopt);
-               hdrlen += sizeof (tcp_initopt);
+               opt[0] = TCPOPT_MAXSEG;
+               opt[1] = 4;
                mss = htons((u_short) tcp_mss(tp, 0));
                bcopy((caddr_t)&mss, (caddr_t)(opt + 2), sizeof(mss));
                mss = htons((u_short) tcp_mss(tp, 0));
                bcopy((caddr_t)&mss, (caddr_t)(opt + 2), sizeof(mss));
+               optlen = 4;
+               if ((tp->t_flags & TF_REQ_SCALE) &&
+                   ((flags & TH_ACK) == 0 || (tp->t_flags & TF_RCVD_SCALE))) {
+                       *((u_long *) (opt + optlen)) = htonl(
+                               TCPOPT_NOP<<24 |
+                               TCPOPT_WINDOW<<16 |
+                               TCPOLEN_WINDOW<<8 |
+                               tp->request_r_scale);
+                       optlen += 4;
+               }
+#ifdef DO_SACK
+               /* Send a SACK_PERMITTED option in the SYN segment. */
+               *((u_long *) (opt + optlen)) = htonl(
+                               TCPOPT_NOP<<24 |
+                               TCPOPT_NOP<<16 |
+                               TCPOPT_SACK_PERMITTED<<8 |
+                               TCPOLEN_SACK_PERMITTED);
+               optlen += 4;
+#endif
+       }
+       /*
+        * Send a timestamp and echo-reply if this is a SYN and our side 
+        * wants to use timestamps (TF_REQ_TSTMP is set) or both our side
+        * and our peer have sent timestamps in our SYN's.
+        */
+       if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
+            (flags & TH_RST) == 0 &&
+           ((flags & (TH_SYN|TH_ACK)) == TH_SYN ||
+            (tp->t_flags & TF_RCVD_TSTMP))) {
+               u_long *lp = (u_long *)(opt + optlen);
+               /* Form timestamp option as shown in appendix A of RFC 1323. */
+               *lp++ = htonl(TCPOPT_TSTAMP_HDR);
+               *lp++ = htonl(tcp_now);
+               *lp   = htonl(tp->ts_recent);
+               optlen += TCPOLEN_TSTAMP_APPA;
+       }
+#ifdef DO_SACK
+       /* Send SACK if needed. Don't tack a SACK onto a non-empty segment. */
+       if (tp->seg_next != (struct tcpiphdr *)tp && len == 0 &&
+           (tp->t_flags & (TF_SACK_PERMIT|TF_NOOPT)) == TF_SACK_PERMIT) {
+               register struct tcpiphdr *q = tp->seg_next;
+               register u_long *optl = (u_long *)(opt + optlen) + 1;
+               tcp_seq block_start;
+               u_long  block_size;
+               int sack_len = 2;
+               /*
+                * Use these to gather runs of received segments.
+                * The first segment in the queue becomes the initial run.
+                */
+               block_start = q->ti_seq;
+               block_size = q->ti_len;
+               do {
+                       q = (struct tcpiphdr *) q->ti_next;
+                       if (q == (struct tcpiphdr *) tp ||
+                               block_start + block_size != q->ti_seq) {
+                               
+                               /*
+                                * Stick the relative origin and block size
+                                * in the SACK option.
+                                */
+                               *optl++ = htonl(block_start-tp->rcv_nxt);
+                               *optl++ = htonl(block_size);
+                               sack_len += 8;
+                               /* If no more will fit into options, quit. */
+                               if (sack_len + optlen > MAX_TCPOPTLEN - 8)
+                                       break;
+                               if (q != (struct tcpiphdr *) tp) {
+                                       block_start = q->ti_seq;
+                                       block_size = q->ti_len;
+                               }
+                       } else {
+                               /* 
+                                * This segment just accumulates into previous
+                                * run.
+                                */
+                               block_size += q->ti_len;
+                       }
+               } while (q != (struct tcpiphdr *) tp);
+               *((u_long *) (opt + optlen)) = htonl(TCPOPT_NOP << 24 |
+                       TCPOPT_NOP << 16 | TCPOPT_SACK << 8 | sack_len);
+               optlen += sack_len + 2;
+       }
+#endif
+       hdrlen += optlen;
+       /*
+        * Adjust data length if insertion of options will
+        * bump the packet length beyond the t_maxseg length.
+        */
+        if (len > tp->t_maxseg - optlen) {
+               len = tp->t_maxseg - optlen;
+               sendalot = 1;
+        }
+
+
 #ifdef DIAGNOSTIC
 #ifdef DIAGNOSTIC
-               if (max_linkhdr + hdrlen > MHLEN)
-                       panic("tcphdr too big");
+       if (max_linkhdr + hdrlen > MHLEN)
+               panic("tcphdr too big");
 #endif
 #endif
-       }
 
        /*
         * Grab a header mbuf, attaching a copy of data to
 
        /*
         * Grab a header mbuf, attaching a copy of data to
@@ -327,13 +434,13 @@ send:
         */
        if (win < (long)(so->so_rcv.sb_hiwat / 4) && win < (long)tp->t_maxseg)
                win = 0;
         */
        if (win < (long)(so->so_rcv.sb_hiwat / 4) && win < (long)tp->t_maxseg)
                win = 0;
-       if (win > TCP_MAXWIN)
-               win = TCP_MAXWIN;
+       if (win > (long)TCP_MAXWIN << tp->rcv_scale)
+               win = (long)TCP_MAXWIN << tp->rcv_scale;
        if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
                win = (long)(tp->rcv_adv - tp->rcv_nxt);
        if (win > IP_MAXPACKET)
                win = IP_MAXPACKET;
        if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
                win = (long)(tp->rcv_adv - tp->rcv_nxt);
        if (win > IP_MAXPACKET)
                win = IP_MAXPACKET;
-       ti->ti_win = htons((u_short)win);
+       ti->ti_win = htons((u_short) (win>>tp->rcv_scale));
        if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
                ti->ti_urp = htons((u_short)(tp->snd_up - tp->snd_nxt));
                ti->ti_flags |= TH_URG;
        if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
                ti->ti_urp = htons((u_short)(tp->snd_up - tp->snd_nxt));
                ti->ti_flags |= TH_URG;
@@ -426,7 +533,7 @@ send:
 #if BSD >= 43
 #if BSD>=43
        error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
 #if BSD >= 43
 #if BSD>=43
        error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
-           so->so_options & SO_DONTROUTE);
+           so->so_options & SO_DONTROUTE, 0);
 #else
        error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route, 
            so->so_options & SO_DONTROUTE);
 #else
        error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route, 
            so->so_options & SO_DONTROUTE);
@@ -458,6 +565,7 @@ out:
         */
        if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
                tp->rcv_adv = tp->rcv_nxt + win;
         */
        if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
                tp->rcv_adv = tp->rcv_nxt + win;
+       tp->last_ack_sent = tp->rcv_nxt;
        tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);
        if (sendalot)
                goto again;
        tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);
        if (sendalot)
                goto again;
index b4d57e6..4cd4ca4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)tcp_subr.c  7.24 (Berkeley) %G%
+ *     @(#)tcp_subr.c  7.25 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -37,6 +37,7 @@
 int    tcp_ttl = TCP_TTL;
 int    tcp_mssdflt = TCP_MSS;
 int    tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
 int    tcp_ttl = TCP_TTL;
 int    tcp_mssdflt = TCP_MSS;
 int    tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
+int    tcp_do_rfc1323 = 1;
 
 extern struct inpcb *tcp_last_inpcb;
 
 
 extern struct inpcb *tcp_last_inpcb;
 
@@ -158,8 +159,12 @@ tcp_respond(tp, ti, m, ack, seq, flags)
        ti->ti_x2 = 0;
        ti->ti_off = sizeof (struct tcphdr) >> 2;
        ti->ti_flags = flags;
        ti->ti_x2 = 0;
        ti->ti_off = sizeof (struct tcphdr) >> 2;
        ti->ti_flags = flags;
-       ti->ti_win = htons((u_short)win);
+       if (tp)
+               ti->ti_win = htons((u_short) (win >> tp->rcv_scale));
+       else
+               ti->ti_win = htons((u_short)win);
        ti->ti_urp = 0;
        ti->ti_urp = 0;
+       ti->ti_sum = 0;
        ti->ti_sum = in_cksum(m, tlen);
        ((struct ip *)ti)->ip_len = tlen;
        ((struct ip *)ti)->ip_ttl = tcp_ttl;
        ti->ti_sum = in_cksum(m, tlen);
        ((struct ip *)ti)->ip_len = tlen;
        ((struct ip *)ti)->ip_ttl = tcp_ttl;
@@ -175,16 +180,16 @@ struct tcpcb *
 tcp_newtcpcb(inp)
        struct inpcb *inp;
 {
 tcp_newtcpcb(inp)
        struct inpcb *inp;
 {
-       struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
        register struct tcpcb *tp;
 
        register struct tcpcb *tp;
 
-       if (m == NULL)
+       tp = malloc(sizeof(*tp), M_PCB, M_NOWAIT);
+       if (tp == NULL)
                return ((struct tcpcb *)0);
                return ((struct tcpcb *)0);
-       tp = mtod(m, struct tcpcb *);
+       bzero((char *) tp, sizeof(struct tcpcb));
        tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
        tp->t_maxseg = tcp_mssdflt;
 
        tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
        tp->t_maxseg = tcp_mssdflt;
 
-       tp->t_flags = 0;                /* sends options! */
+       tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
        tp->t_inpcb = inp;
        /*
         * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
        tp->t_inpcb = inp;
        /*
         * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
@@ -197,8 +202,8 @@ tcp_newtcpcb(inp)
        TCPT_RANGESET(tp->t_rxtcur, 
            ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
            TCPTV_MIN, TCPTV_REXMTMAX);
        TCPT_RANGESET(tp->t_rxtcur, 
            ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
            TCPTV_MIN, TCPTV_REXMTMAX);
-       tp->snd_cwnd = TCP_MAXWIN;
-       tp->snd_ssthresh = TCP_MAXWIN;
+       tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
+       tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
        inp->inp_ip.ip_ttl = tcp_ttl;
        inp->inp_ppcb = (caddr_t)tp;
        return (tp);
        inp->inp_ip.ip_ttl = tcp_ttl;
        inp->inp_ppcb = (caddr_t)tp;
        return (tp);
@@ -322,7 +327,7 @@ tcp_close(tp)
        }
        if (tp->t_template)
                (void) m_free(dtom(tp->t_template));
        }
        if (tp->t_template)
                (void) m_free(dtom(tp->t_template));
-       (void) m_free(dtom(tp));
+       free(tp, M_PCB);
        inp->inp_ppcb = 0;
        soisdisconnected(so);
        /* clobber input pcb cache if we're closing the cached connection */
        inp->inp_ppcb = 0;
        soisdisconnected(so);
        /* clobber input pcb cache if we're closing the cached connection */
@@ -351,15 +356,20 @@ tcp_notify(inp, error)
        register struct socket *so = inp->inp_socket;
 
        /*
        register struct socket *so = inp->inp_socket;
 
        /*
+        * Ignore some errors if we are hooked up.
         * If connection hasn't completed, has retransmitted several times,
         * and receives a second error, give up now.  This is better
         * than waiting a long time to establish a connection that
         * can never complete.
         */
         * If connection hasn't completed, has retransmitted several times,
         * and receives a second error, give up now.  This is better
         * than waiting a long time to establish a connection that
         * can never complete.
         */
-       if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 &&
+       if (tp->t_state == TCPS_ESTABLISHED &&
+            (error == EHOSTUNREACH || error == ENETUNREACH ||
+             error == EHOSTDOWN)) {
+               return;
+       } else if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 &&
            tp->t_softerror)
                so->so_error = error;
            tp->t_softerror)
                so->so_error = error;
-       else
+       else 
                tp->t_softerror = error;
        wakeup((caddr_t) &so->so_timeo);
        sorwakeup(so);
                tp->t_softerror = error;
        wakeup((caddr_t) &so->so_timeo);
        sorwakeup(so);
@@ -378,7 +388,8 @@ tcp_ctlinput(cmd, sa, ip)
 
        if (cmd == PRC_QUENCH)
                notify = tcp_quench;
 
        if (cmd == PRC_QUENCH)
                notify = tcp_quench;
-       else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
+       else if (!PRC_IS_REDIRECT(cmd) &&
+                ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0))
                return;
        if (ip) {
                th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
                return;
        if (ip) {
                th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
index 78a0489..3339e52 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)tcp_timer.c 7.19 (Berkeley) %G%
+ *     @(#)tcp_timer.c 7.20 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -102,6 +102,7 @@ tpgone:
        if ((int)tcp_iss < 0)
                tcp_iss = 0;                            /* XXX */
 #endif
        if ((int)tcp_iss < 0)
                tcp_iss = 0;                            /* XXX */
 #endif
+       tcp_now++;                                      /* for timestamps */
        splx(s);
 }
 
        splx(s);
 }
 
index 0e56af8..f9db771 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)tcp_usrreq.c        7.17 (Berkeley) %G%
+ *     @(#)tcp_usrreq.c        7.18 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -161,6 +161,10 @@ tcp_usrreq(so, req, m, nam, control)
                        error = ENOBUFS;
                        break;
                }
                        error = ENOBUFS;
                        break;
                }
+               /* Compute window scaling to request.  */
+               while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
+                   (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
+                       tp->request_r_scale++;
                soisconnecting(so);
                tcpstat.tcps_connattempt++;
                tp->t_state = TCPS_SYN_SENT;
                soisconnecting(so);
                tcpstat.tcps_connattempt++;
                tp->t_state = TCPS_SYN_SENT;
@@ -320,14 +324,24 @@ tcp_ctloutput(op, so, level, optname, mp)
        int level, optname;
        struct mbuf **mp;
 {
        int level, optname;
        struct mbuf **mp;
 {
-       int error = 0;
-       struct inpcb *inp = sotoinpcb(so);
-       register struct tcpcb *tp = intotcpcb(inp);
+       int error = 0, s;
+       struct inpcb *inp;
+       register struct tcpcb *tp;
        register struct mbuf *m;
        register int i;
 
        register struct mbuf *m;
        register int i;
 
-       if (level != IPPROTO_TCP)
-               return (ip_ctloutput(op, so, level, optname, mp));
+       s = splnet();
+       inp = sotoinpcb(so);
+       if (inp == NULL) {
+               splx(s);
+               return (ECONNRESET);
+       }
+       if (level != IPPROTO_TCP) {
+               error = ip_ctloutput(op, so, level, optname, mp);
+               splx(s);
+               return (error);
+       }
+       tp = intotcpcb(inp);
 
        switch (op) {
 
 
        switch (op) {
 
@@ -376,6 +390,7 @@ tcp_ctloutput(op, so, level, optname, mp)
                }
                break;
        }
                }
                break;
        }
+       splx(s);
        return (error);
 }
 #endif
        return (error);
 }
 #endif
index b06a058..2227718 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)tcp_var.h   7.10 (Berkeley) %G%
+ *     @(#)tcp_var.h   7.11 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -74,12 +74,18 @@ struct tcpcb {
        short   t_dupacks;              /* consecutive dup acks recd */
        u_short t_maxseg;               /* maximum segment size */
        char    t_force;                /* 1 if forcing out a byte */
        short   t_dupacks;              /* consecutive dup acks recd */
        u_short t_maxseg;               /* maximum segment size */
        char    t_force;                /* 1 if forcing out a byte */
-       u_char  t_flags;
-#define        TF_ACKNOW       0x01            /* ack peer immediately */
-#define        TF_DELACK       0x02            /* ack, but try to delay it */
-#define        TF_NODELAY      0x04            /* don't delay packets to coalesce */
-#define        TF_NOOPT        0x08            /* don't use tcp options */
-#define        TF_SENTFIN      0x10            /* have sent FIN */
+       u_short t_flags;
+#define        TF_ACKNOW       0x0001          /* ack peer immediately */
+#define        TF_DELACK       0x0002          /* ack, but try to delay it */
+#define        TF_NODELAY      0x0004          /* don't delay packets to coalesce */
+#define        TF_NOOPT        0x0008          /* don't use tcp options */
+#define        TF_SENTFIN      0x0010          /* have sent FIN */
+#define        TF_REQ_SCALE    0x0020          /* have/will request window scaling */
+#define        TF_RCVD_SCALE   0x0040          /* other side has requested scaling */
+#define        TF_REQ_TSTMP    0x0080          /* have/will request timestamps */
+#define        TF_RCVD_TSTMP   0x0100          /* a timestamp was received in SYN */
+#define        TF_SACK_PERMIT  0x0200          /* other side said I could SACK */
+
        struct  tcpiphdr *t_template;   /* skeletal packet for transmit */
        struct  inpcb *t_inpcb;         /* back pointer to internet pcb */
 /*
        struct  tcpiphdr *t_template;   /* skeletal packet for transmit */
        struct  inpcb *t_inpcb;         /* back pointer to internet pcb */
 /*
@@ -93,9 +99,9 @@ struct tcpcb {
        tcp_seq snd_wl1;                /* window update seg seq number */
        tcp_seq snd_wl2;                /* window update seg ack number */
        tcp_seq iss;                    /* initial send sequence number */
        tcp_seq snd_wl1;                /* window update seg seq number */
        tcp_seq snd_wl2;                /* window update seg ack number */
        tcp_seq iss;                    /* initial send sequence number */
-       u_short snd_wnd;                /* send window */
+       u_long  snd_wnd;                /* send window */
 /* receive sequence variables */
 /* receive sequence variables */
-       u_short rcv_wnd;                /* receive window */
+       u_long  rcv_wnd;                /* receive window */
        tcp_seq rcv_nxt;                /* receive next */
        tcp_seq rcv_up;                 /* receive urgent pointer */
        tcp_seq irs;                    /* initial receive sequence number */
        tcp_seq rcv_nxt;                /* receive next */
        tcp_seq rcv_up;                 /* receive urgent pointer */
        tcp_seq irs;                    /* initial receive sequence number */
@@ -109,8 +115,8 @@ struct tcpcb {
                                         * used to recognize retransmits
                                         */
 /* congestion control (for slow start, source quench, retransmit after loss) */
                                         * used to recognize retransmits
                                         */
 /* congestion control (for slow start, source quench, retransmit after loss) */
-       u_short snd_cwnd;               /* congestion-controlled window */
-       u_short snd_ssthresh;           /* snd_cwnd size threshhold for
+       u_long  snd_cwnd;               /* congestion-controlled window */
+       u_long  snd_ssthresh;           /* snd_cwnd size threshhold for
                                         * for slow start exponential to
                                         * linear switch
                                         */
                                         * for slow start exponential to
                                         * linear switch
                                         */
@@ -124,7 +130,7 @@ struct tcpcb {
        short   t_srtt;                 /* smoothed round-trip time */
        short   t_rttvar;               /* variance in round-trip time */
        u_short t_rttmin;               /* minimum rtt allowed */
        short   t_srtt;                 /* smoothed round-trip time */
        short   t_rttvar;               /* variance in round-trip time */
        u_short t_rttmin;               /* minimum rtt allowed */
-       u_short max_sndwnd;             /* largest window peer has offered */
+       u_long  max_sndwnd;             /* largest window peer has offered */
 
 /* out-of-band data */
        char    t_oobflags;             /* have some */
 
 /* out-of-band data */
        char    t_oobflags;             /* have some */
@@ -132,6 +138,15 @@ struct tcpcb {
 #define        TCPOOB_HAVEDATA 0x01
 #define        TCPOOB_HADDATA  0x02
        short   t_softerror;            /* possible error not yet reported */
 #define        TCPOOB_HAVEDATA 0x01
 #define        TCPOOB_HADDATA  0x02
        short   t_softerror;            /* possible error not yet reported */
+
+/* RFC 1323 variables */
+       u_char  snd_scale;              /* window scaling for send window */
+       u_char  rcv_scale;              /* window scaling for recv window */
+       u_char  request_r_scale;        /* pending window scaling */
+       u_char  requested_s_scale;
+       u_long  ts_recent;              /* timestamp echo data */
+       u_long  ts_recent_age;          /* when last updated */
+       tcp_seq last_ack_sent;
 };
 
 #define        intotcpcb(ip)   ((struct tcpcb *)(ip)->inp_ppcb)
 };
 
 #define        intotcpcb(ip)   ((struct tcpcb *)(ip)->inp_ppcb)
@@ -248,11 +263,13 @@ struct    tcpstat {
        u_long  tcps_rcvackpack;        /* rcvd ack packets */
        u_long  tcps_rcvackbyte;        /* bytes acked by rcvd acks */
        u_long  tcps_rcvwinupd;         /* rcvd window update packets */
        u_long  tcps_rcvackpack;        /* rcvd ack packets */
        u_long  tcps_rcvackbyte;        /* bytes acked by rcvd acks */
        u_long  tcps_rcvwinupd;         /* rcvd window update packets */
+       u_long  tcps_pawsdrop;          /* segments dropped due to PAWS */
 };
 
 #ifdef KERNEL
 struct inpcb tcb;              /* head of queue of active tcpcb's */
 struct tcpstat tcpstat;        /* tcp statistics */
 };
 
 #ifdef KERNEL
 struct inpcb tcb;              /* head of queue of active tcpcb's */
 struct tcpstat tcpstat;        /* tcp statistics */
+u_long tcp_now;                /* for RFC 1323 timestamps */
 struct tcpiphdr *tcp_template();
 struct tcpcb *tcp_close(), *tcp_drop();
 struct tcpcb *tcp_timers(), *tcp_disconnect(), *tcp_usrclosed();
 struct tcpiphdr *tcp_template();
 struct tcpcb *tcp_close(), *tcp_drop();
 struct tcpcb *tcp_timers(), *tcp_disconnect(), *tcp_usrclosed();
index c27eb30..3850a35 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)udp_usrreq.c        7.26 (Berkeley) %G%
+ *     @(#)udp_usrreq.c        7.27 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -36,7 +36,6 @@ struct        inpcb *udp_last_inpcb = &udb;
  */
 udp_init()
 {
  */
 udp_init()
 {
-
        udb.inp_next = udb.inp_prev = &udb;
 }
 
        udb.inp_next = udb.inp_prev = &udb;
 }
 
@@ -120,7 +119,6 @@ udp_input(m, iphlen)
                }
        }
 
                }
        }
 
-#ifdef MULTICAST
        if (IN_MULTICAST(ntohl(ip->ip_src.s_addr)) ||
            in_broadcast(ip->ip_dst)) {
                struct socket *last;
        if (IN_MULTICAST(ntohl(ip->ip_src.s_addr)) ||
            in_broadcast(ip->ip_dst)) {
                struct socket *last;
@@ -137,7 +135,7 @@ udp_input(m, iphlen)
                 * Those applications open the multiple sockets to overcome an
                 * inadequacy of the UDP socket interface, but for backwards
                 * compatibility we avoid the problem here rather than
                 * Those applications open the multiple sockets to overcome an
                 * inadequacy of the UDP socket interface, but for backwards
                 * compatibility we avoid the problem here rather than
-                * fixing the interface.  Maybe 4.4BSD will remedy this?)
+                * fixing the interface.  Maybe 4.5BSD will remedy this?)
                 */
 
                /*
                 */
 
                /*
@@ -173,9 +171,10 @@ udp_input(m, iphlen)
                                if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
                                        if (sbappendaddr(&last->so_rcv,
                                                (struct sockaddr *)&udp_in,
                                if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
                                        if (sbappendaddr(&last->so_rcv,
                                                (struct sockaddr *)&udp_in,
-                                               n, (struct mbuf *)0) == 0)
+                                               n, (struct mbuf *)0) == 0) {
                                                m_freem(n);
                                                m_freem(n);
-                                       else
+                                               udpstat.udps_fullsock++;
+                                       } else
                                                sorwakeup(last);
                                }
                        }
                                                sorwakeup(last);
                                }
                        }
@@ -198,15 +197,17 @@ udp_input(m, iphlen)
                         * (No need to send an ICMP Port Unreachable
                         * for a broadcast or multicast datgram.)
                         */
                         * (No need to send an ICMP Port Unreachable
                         * for a broadcast or multicast datgram.)
                         */
+                       udpstat.udps_noportbcast++;
                        goto bad;
                }
                if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in,
                        goto bad;
                }
                if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in,
-                    m, (struct mbuf *)0) == 0)
+                    m, (struct mbuf *)0) == 0) {
+                       udpstat.udps_fullsock++;
                        goto bad;
                        goto bad;
+               }
                sorwakeup(last);
                return;
        }
                sorwakeup(last);
                return;
        }
-#endif
        /*
         * Locate pcb for datagram.
         */
        /*
         * Locate pcb for datagram.
         */
@@ -222,15 +223,7 @@ udp_input(m, iphlen)
                udpstat.udpps_pcbcachemiss++;
        }
        if (inp == 0) {
                udpstat.udpps_pcbcachemiss++;
        }
        if (inp == 0) {
-               /* don't send ICMP response for broadcast packet */
                udpstat.udps_noport++;
                udpstat.udps_noport++;
-#ifndef MULTICAST
-               /* XXX why don't we do this with MULTICAST? */
-               if (m->m_flags & (M_BCAST | M_MCAST)) {
-                       udpstat.udps_noportbcast++;
-                       goto bad;
-               }
-#endif
                *ip = save_ip;
                ip->ip_len += iphlen;
                icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT);
                *ip = save_ip;
                ip->ip_len += iphlen;
                icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT);
@@ -320,7 +313,6 @@ udp_notify(inp, errno)
        register struct inpcb *inp;
        int errno;
 {
        register struct inpcb *inp;
        int errno;
 {
-
        inp->inp_socket->so_error = errno;
        sorwakeup(inp->inp_socket);
        sowwakeup(inp->inp_socket);
        inp->inp_socket->so_error = errno;
        sorwakeup(inp->inp_socket);
        sowwakeup(inp->inp_socket);
@@ -335,7 +327,8 @@ udp_ctlinput(cmd, sa, ip)
        extern struct in_addr zeroin_addr;
        extern u_char inetctlerrmap[];
 
        extern struct in_addr zeroin_addr;
        extern u_char inetctlerrmap[];
 
-       if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
+       if (!PRC_IS_REDIRECT(cmd) &&
+           ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0))
                return;
        if (ip) {
                uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
                return;
        if (ip) {
                uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
@@ -417,11 +410,8 @@ udp_output(inp, m, addr, control)
        ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
        udpstat.udps_opackets++;
        error = ip_output(m, inp->inp_options, &inp->inp_route,
        ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
        udpstat.udps_opackets++;
        error = ip_output(m, inp->inp_options, &inp->inp_route,
-           inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)
-#ifdef MULTICAST
-           , inp->inp_moptions
-#endif
-           );
+           inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
+           inp->inp_moptions);
 
        if (addr) {
                in_pcbdisconnect(inp);
 
        if (addr) {
                in_pcbdisconnect(inp);
index 3933347..d75ae98 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)udp_var.h   7.7 (Berkeley) %G%
+ *     @(#)udp_var.h   7.8 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -28,16 +28,16 @@ struct      udpiphdr {
 
 struct udpstat {
                                /* input statistics: */
 
 struct udpstat {
                                /* input statistics: */
-       int     udps_ipackets;          /* total input packets */
-       int     udps_hdrops;            /* packet shorter than header */
-       int     udps_badsum;            /* checksum error */
-       int     udps_badlen;            /* data length larger than packet */
-       int     udps_noport;            /* no socket on port */
-       int     udps_noportbcast;       /* of above, arrived as broadcast */
-       int     udps_fullsock;          /* not delivered, input socket full */
-       int     udpps_pcbcachemiss;     /* input packets missing pcb cache */
+       u_long  udps_ipackets;          /* total input packets */
+       u_long  udps_hdrops;            /* packet shorter than header */
+       u_long  udps_badsum;            /* checksum error */
+       u_long  udps_badlen;            /* data length larger than packet */
+       u_long  udps_noport;            /* no socket on port */
+       u_long  udps_noportbcast;       /* of above, arrived as broadcast */
+       u_long  udps_fullsock;          /* not delivered, input socket full */
+       u_long  udpps_pcbcachemiss;     /* input packets missing pcb cache */
                                /* output statistics: */
                                /* output statistics: */
-       int     udps_opackets;          /* total output packets */
+       u_long  udps_opackets;          /* total output packets */
 };
 
 #define        UDP_TTL         30      /* default time to live for UDP packets */
 };
 
 #define        UDP_TTL         30      /* default time to live for UDP packets */