ron@brl-tgr.UUCP (05/15/84)
Subject: 4.2BSD as Gateway bug Newsgroups: net.bugs.4bsd Subject: Fragmentation bug on packet forwarding Index: sys/netinet/ip_output.c 4.2BSD Description: When the packets are being forwarded through a 4.2 BSD system a problem sometimes shows up that results in lost packets and transmission of illegally formatted internet packets. The problem occurs when a 4.2 BSD system is gatewaying from nets that have unequal Maximum Transfer Units (MTU). When a fragmented packet arriving from an outside source must be fragmented again the MORE FRAGMENTS bit is never set on the last fragment even though it may be required. When other than the last fragment of the original packet is fragmented, the MORE FRAGMENTS bit must be set to indicate that the subsequent fragments of the original packet still follow (got that?). This problem does not happen when you are not playing gateway because ip_output does not get passed already fragmented packets in that situation. Example: Host X sends ip packet A to BSD-HOST in two fragments, A1 and A2. BSD-HOST must then fragment A1 into A1a and A1b. A1b should have MF set because fragment A2 still follows. Repeat-By: Set the MTU on you host to some small number, and then try to forward already fragmented packets through it. Fix: Set the bit on the last fragment to what it was on the packet before fragmenting began. Below is the fragmentation code from ip_ouptut(): /* * Discard IP header from logical mbuf for m_copy's sake. * Loop through length of segment, make a copy of each * part and output. */ m->m_len -= sizeof (struct ip); m->m_off += sizeof (struct ip); for (off = 0; off < ip->ip_len-hlen; off += len) { struct mbuf *mh = m_get(M_DONTWAIT, MT_HEADER); struct ip *mhip; if (mh == 0) { error = ENOBUFS; goto bad; } mh->m_off = MMAXOFF - hlen; mhip = mtod(mh, struct ip *); *mhip = *ip; if (hlen > sizeof (struct ip)) { int olen = ip_optcopy(ip, mhip, off); mh->m_len = sizeof (struct ip) + olen; } else mh->m_len = sizeof (struct ip); mhip->ip_off = off >> 3; /*******************************************************\ |* *| |* A D D T H I S L I N E *| |* *| |* If the packet we're fragmenting has fragments from *| |* other systems, propagate the MORE_FRAGMENTS flag. *| \*******************************************************/ if(ip->ip_off & IP_MF) mhip->ip_off |= IP_MF; if (off + len >= ip->ip_len-hlen) len = mhip->ip_len = ip->ip_len - hlen - off; else { mhip->ip_len = len; mhip->ip_off |= IP_MF; }