--- linux-2.6.15.1/net/ipv4/ip_options.c.orig	2006-01-27 09:14:33.000000000 +0900
+++ linux-2.6.15.1/net/ipv4/ip_options.c	2006-01-27 09:45:26.000000000 +0900
@@ -211,29 +211,59 @@
 	struct ip_options * opt = &(IPCB(skb)->opt);
 	int  l = opt->optlen;
 	int  optlen;
+	int  optneed = 0;
+	unsigned char * pp_ptr = optptr;
 
 	while (l > 0) {
 		switch (*optptr) {
 		case IPOPT_END:
-			return;
+			goto end;
 		case IPOPT_NOOP:
 			l--;
+			if(optptr != pp_ptr)
+				memcpy(pp_ptr, optptr, 1);
 			optptr++;
+			pp_ptr++;
 			continue;
 		}
 		optlen = optptr[1];
-		if (optlen<2 || optlen>l)
-		  return;
-		if (!IPOPT_COPIED(*optptr))
-			memset(optptr, IPOPT_NOOP, optlen);
+		if (optlen<2 || optlen>l) {
+			if(optptr != pp_ptr)
+				memcpy(pp_ptr, optptr, l);
+			optptr += l;
+			pp_ptr += l;
+			optneed = 1;
+			goto error;
+		}
+		if (IPOPT_COPIED(*optptr)) {
+			if(optptr != pp_ptr)
+				memcpy(pp_ptr, optptr, optlen);
+			pp_ptr += optlen;
+			optneed = 1;
+		}
 		l -= optlen;
 		optptr += optlen;
 	}
+end:
 	opt->ts = 0;
 	opt->rr = 0;
 	opt->rr_needaddr = 0;
 	opt->ts_needaddr = 0;
 	opt->ts_needtime = 0;
+error:
+	if (pp_ptr != optptr) {
+		if (optneed == 1) {
+			opt->optlen -= optptr - pp_ptr;
+			if (opt->optlen & 0x03) {
+				for (l = 0; l < 4 - (opt->optlen & 0x03); l++)
+					*pp_ptr++ = IPOPT_END;
+				opt->optlen = (opt->optlen + 3) & ~3;
+			}
+		} else {
+			opt->optlen = 0;
+		}
+		skb->nh.iph->ihl = 5 + (opt->optlen >> 2);
+	}
 	return;
 }
 
--- linux-2.6.15.1/net/ipv4/ip_output.c.orig	2006-01-27 09:49:17.339815360 +0900
+++ linux-2.6.15.1/net/ipv4/ip_output.c	2006-01-23 09:09:13.000000000 +0900
@@ -503,12 +503,19 @@
 				frag->h.raw = frag->data;
 				frag->nh.raw = __skb_push(frag, hlen);
 				memcpy(frag->nh.raw, iph, hlen);
+				offset += skb->len - hlen;
+				if (offset == skb->len - hlen) {
+					ip_options_fragment(frag);
+					len = frag->nh.iph->ihl * 4;
+					if (hlen != len) {
+						memmove(frag->nh.raw, frag->h.raw - len, len);
+						frag->nh.raw = __skb_pull(frag, hlen - len);
+						hlen = len;
+					}
+				}
 				iph = frag->nh.iph;
 				iph->tot_len = htons(frag->len);
 				ip_copy_metadata(frag, skb);
-				if (offset == 0)
-					ip_options_fragment(frag);
-				offset += skb->len - hlen;
 				iph->frag_off = htons(offset>>3);
 				if (frag->next != NULL)
 					iph->frag_off |= htons(IP_MF);
@@ -619,6 +626,7 @@
 		 */
 		iph = skb2->nh.iph;
 		iph->frag_off = htons((offset >> 3));
+		iph->tot_len = htons(len + hlen);
 
 		/* ANK: dirty, but effective trick. Upgrade options only if
 		 * the segment to be fragmented was THE FIRST (otherwise,
@@ -626,8 +634,11 @@
 		 * on the initial skb, so that all the following fragments
 		 * will inherit fixed options.
 		 */
-		if (offset == 0)
+		if (offset == 0) {
 			ip_options_fragment(skb);
+			hlen = skb->nh.iph->ihl * 4;
+			mtu = dst_pmtu(&rt->u.dst) - hlen;
+		}
 
 		/*
 		 *	Added AC : If we are fragmenting a fragment that's not the
@@ -644,8 +655,6 @@
 
 		IP_INC_STATS(IPSTATS_MIB_FRAGCREATES);
 
-		iph->tot_len = htons(len + hlen);
-
 		ip_send_check(iph);
 
 		err = output(skb2);
