symbian-qemu-0.9.1-12/qemu-symbian-svp/slirp/ip_input.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * Copyright (c) 1982, 1986, 1988, 1993
       
     3  *	The Regents of the University of California.  All rights reserved.
       
     4  *
       
     5  * Redistribution and use in source and binary forms, with or without
       
     6  * modification, are permitted provided that the following conditions
       
     7  * are met:
       
     8  * 1. Redistributions of source code must retain the above copyright
       
     9  *    notice, this list of conditions and the following disclaimer.
       
    10  * 2. Redistributions in binary form must reproduce the above copyright
       
    11  *    notice, this list of conditions and the following disclaimer in the
       
    12  *    documentation and/or other materials provided with the distribution.
       
    13  * 3. All advertising materials mentioning features or use of this software
       
    14  *    must display the following acknowledgement:
       
    15  *	This product includes software developed by the University of
       
    16  *	California, Berkeley and its contributors.
       
    17  * 4. Neither the name of the University nor the names of its contributors
       
    18  *    may be used to endorse or promote products derived from this software
       
    19  *    without specific prior written permission.
       
    20  *
       
    21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
       
    22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
       
    24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
       
    25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
       
    26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
       
    27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
       
    28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
       
    29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
       
    30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
       
    31  * SUCH DAMAGE.
       
    32  *
       
    33  *	@(#)ip_input.c	8.2 (Berkeley) 1/4/94
       
    34  * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp
       
    35  */
       
    36 
       
    37 /*
       
    38  * Changes and additions relating to SLiRP are
       
    39  * Copyright (c) 1995 Danny Gasparovski.
       
    40  *
       
    41  * Please read the file COPYRIGHT for the
       
    42  * terms and conditions of the copyright.
       
    43  */
       
    44 
       
    45 #include <slirp.h>
       
    46 #include "ip_icmp.h"
       
    47 
       
    48 #ifdef LOG_ENABLED
       
    49 struct ipstat ipstat;
       
    50 #endif
       
    51 
       
    52 struct ipq ipq;
       
    53 
       
    54 static struct ip *ip_reass(register struct ipasfrag *ip,
       
    55                            register struct ipq *fp);
       
    56 static void ip_freef(struct ipq *fp);
       
    57 static void ip_enq(register struct ipasfrag *p,
       
    58                    register struct ipasfrag *prev);
       
    59 static void ip_deq(register struct ipasfrag *p);
       
    60 
       
    61 /*
       
    62  * IP initialization: fill in IP protocol switch table.
       
    63  * All protocols not implemented in kernel go to raw IP protocol handler.
       
    64  */
       
    65 void
       
    66 ip_init()
       
    67 {
       
    68 	ipq.next = ipq.prev = (ipqp_32)&ipq;
       
    69 	ip_id = tt.tv_sec & 0xffff;
       
    70 	udp_init();
       
    71 	tcp_init();
       
    72 }
       
    73 
       
    74 /*
       
    75  * Ip input routine.  Checksum and byte swap header.  If fragmented
       
    76  * try to reassemble.  Process options.  Pass to next level.
       
    77  */
       
    78 void
       
    79 ip_input(m)
       
    80 	struct mbuf *m;
       
    81 {
       
    82 	register struct ip *ip;
       
    83 	int hlen;
       
    84 
       
    85 	DEBUG_CALL("ip_input");
       
    86 	DEBUG_ARG("m = %lx", (long)m);
       
    87 	DEBUG_ARG("m_len = %d", m->m_len);
       
    88 
       
    89 	STAT(ipstat.ips_total++);
       
    90 
       
    91 	if (m->m_len < sizeof (struct ip)) {
       
    92 		STAT(ipstat.ips_toosmall++);
       
    93 		return;
       
    94 	}
       
    95 
       
    96 	ip = mtod(m, struct ip *);
       
    97 
       
    98 	if (ip->ip_v != IPVERSION) {
       
    99 		STAT(ipstat.ips_badvers++);
       
   100 		goto bad;
       
   101 	}
       
   102 
       
   103 	hlen = ip->ip_hl << 2;
       
   104 	if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */
       
   105 	  STAT(ipstat.ips_badhlen++);                     /* or packet too short */
       
   106 	  goto bad;
       
   107 	}
       
   108 
       
   109         /* keep ip header intact for ICMP reply
       
   110 	 * ip->ip_sum = cksum(m, hlen);
       
   111 	 * if (ip->ip_sum) {
       
   112 	 */
       
   113 	if(cksum(m,hlen)) {
       
   114 	  STAT(ipstat.ips_badsum++);
       
   115 	  goto bad;
       
   116 	}
       
   117 
       
   118 	/*
       
   119 	 * Convert fields to host representation.
       
   120 	 */
       
   121 	NTOHS(ip->ip_len);
       
   122 	if (ip->ip_len < hlen) {
       
   123 		STAT(ipstat.ips_badlen++);
       
   124 		goto bad;
       
   125 	}
       
   126 	NTOHS(ip->ip_id);
       
   127 	NTOHS(ip->ip_off);
       
   128 
       
   129 	/*
       
   130 	 * Check that the amount of data in the buffers
       
   131 	 * is as at least much as the IP header would have us expect.
       
   132 	 * Trim mbufs if longer than we expect.
       
   133 	 * Drop packet if shorter than we expect.
       
   134 	 */
       
   135 	if (m->m_len < ip->ip_len) {
       
   136 		STAT(ipstat.ips_tooshort++);
       
   137 		goto bad;
       
   138 	}
       
   139 	/* Should drop packet if mbuf too long? hmmm... */
       
   140 	if (m->m_len > ip->ip_len)
       
   141 	   m_adj(m, ip->ip_len - m->m_len);
       
   142 
       
   143 	/* check ip_ttl for a correct ICMP reply */
       
   144 	if(ip->ip_ttl==0 || ip->ip_ttl==1) {
       
   145 	  icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");
       
   146 	  goto bad;
       
   147 	}
       
   148 
       
   149 	/*
       
   150 	 * Process options and, if not destined for us,
       
   151 	 * ship it on.  ip_dooptions returns 1 when an
       
   152 	 * error was detected (causing an icmp message
       
   153 	 * to be sent and the original packet to be freed).
       
   154 	 */
       
   155 /* We do no IP options */
       
   156 /*	if (hlen > sizeof (struct ip) && ip_dooptions(m))
       
   157  *		goto next;
       
   158  */
       
   159 	/*
       
   160 	 * If offset or IP_MF are set, must reassemble.
       
   161 	 * Otherwise, nothing need be done.
       
   162 	 * (We could look in the reassembly queue to see
       
   163 	 * if the packet was previously fragmented,
       
   164 	 * but it's not worth the time; just let them time out.)
       
   165 	 *
       
   166 	 * XXX This should fail, don't fragment yet
       
   167 	 */
       
   168 	if (ip->ip_off &~ IP_DF) {
       
   169 	  register struct ipq *fp;
       
   170 		/*
       
   171 		 * Look for queue of fragments
       
   172 		 * of this datagram.
       
   173 		 */
       
   174 		for (fp = (struct ipq *) ipq.next; fp != &ipq;
       
   175 		     fp = (struct ipq *) fp->next)
       
   176 		  if (ip->ip_id == fp->ipq_id &&
       
   177 		      ip->ip_src.s_addr == fp->ipq_src.s_addr &&
       
   178 		      ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
       
   179 		      ip->ip_p == fp->ipq_p)
       
   180 		    goto found;
       
   181 		fp = 0;
       
   182 	found:
       
   183 
       
   184 		/*
       
   185 		 * Adjust ip_len to not reflect header,
       
   186 		 * set ip_mff if more fragments are expected,
       
   187 		 * convert offset of this to bytes.
       
   188 		 */
       
   189 		ip->ip_len -= hlen;
       
   190 		if (ip->ip_off & IP_MF)
       
   191 		  ((struct ipasfrag *)ip)->ipf_mff |= 1;
       
   192 		else
       
   193 		  ((struct ipasfrag *)ip)->ipf_mff &= ~1;
       
   194 
       
   195 		ip->ip_off <<= 3;
       
   196 
       
   197 		/*
       
   198 		 * If datagram marked as having more fragments
       
   199 		 * or if this is not the first fragment,
       
   200 		 * attempt reassembly; if it succeeds, proceed.
       
   201 		 */
       
   202 		if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) {
       
   203 			STAT(ipstat.ips_fragments++);
       
   204 			ip = ip_reass((struct ipasfrag *)ip, fp);
       
   205 			if (ip == 0)
       
   206 				return;
       
   207 			STAT(ipstat.ips_reassembled++);
       
   208 			m = dtom(ip);
       
   209 		} else
       
   210 			if (fp)
       
   211 		   	   ip_freef(fp);
       
   212 
       
   213 	} else
       
   214 		ip->ip_len -= hlen;
       
   215 
       
   216 	/*
       
   217 	 * Switch out to protocol's input routine.
       
   218 	 */
       
   219 	STAT(ipstat.ips_delivered++);
       
   220 	switch (ip->ip_p) {
       
   221 	 case IPPROTO_TCP:
       
   222 		tcp_input(m, hlen, (struct socket *)NULL);
       
   223 		break;
       
   224 	 case IPPROTO_UDP:
       
   225 		udp_input(m, hlen);
       
   226 		break;
       
   227 	 case IPPROTO_ICMP:
       
   228 		icmp_input(m, hlen);
       
   229 		break;
       
   230 	 default:
       
   231 		STAT(ipstat.ips_noproto++);
       
   232 		m_free(m);
       
   233 	}
       
   234 	return;
       
   235 bad:
       
   236 	m_freem(m);
       
   237 	return;
       
   238 }
       
   239 
       
   240 /*
       
   241  * Take incoming datagram fragment and try to
       
   242  * reassemble it into whole datagram.  If a chain for
       
   243  * reassembly of this datagram already exists, then it
       
   244  * is given as fp; otherwise have to make a chain.
       
   245  */
       
   246 static struct ip *
       
   247 ip_reass(register struct ipasfrag *ip, register struct ipq *fp)
       
   248 {
       
   249 	register struct mbuf *m = dtom(ip);
       
   250 	register struct ipasfrag *q;
       
   251 	int hlen = ip->ip_hl << 2;
       
   252 	int i, next;
       
   253 
       
   254 	DEBUG_CALL("ip_reass");
       
   255 	DEBUG_ARG("ip = %lx", (long)ip);
       
   256 	DEBUG_ARG("fp = %lx", (long)fp);
       
   257 	DEBUG_ARG("m = %lx", (long)m);
       
   258 
       
   259 	/*
       
   260 	 * Presence of header sizes in mbufs
       
   261 	 * would confuse code below.
       
   262          * Fragment m_data is concatenated.
       
   263 	 */
       
   264 	m->m_data += hlen;
       
   265 	m->m_len -= hlen;
       
   266 
       
   267 	/*
       
   268 	 * If first fragment to arrive, create a reassembly queue.
       
   269 	 */
       
   270 	if (fp == 0) {
       
   271 	  struct mbuf *t;
       
   272 	  if ((t = m_get()) == NULL) goto dropfrag;
       
   273 	  fp = mtod(t, struct ipq *);
       
   274 	  insque_32(fp, &ipq);
       
   275 	  fp->ipq_ttl = IPFRAGTTL;
       
   276 	  fp->ipq_p = ip->ip_p;
       
   277 	  fp->ipq_id = ip->ip_id;
       
   278 	  fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp;
       
   279 	  fp->ipq_src = ((struct ip *)ip)->ip_src;
       
   280 	  fp->ipq_dst = ((struct ip *)ip)->ip_dst;
       
   281 	  q = (struct ipasfrag *)fp;
       
   282 	  goto insert;
       
   283 	}
       
   284 
       
   285 	/*
       
   286 	 * Find a segment which begins after this one does.
       
   287 	 */
       
   288 	for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp;
       
   289 	    q = (struct ipasfrag *)q->ipf_next)
       
   290 		if (q->ip_off > ip->ip_off)
       
   291 			break;
       
   292 
       
   293 	/*
       
   294 	 * If there is a preceding segment, it may provide some of
       
   295 	 * our data already.  If so, drop the data from the incoming
       
   296 	 * segment.  If it provides all of our data, drop us.
       
   297 	 */
       
   298 	if (q->ipf_prev != (ipasfragp_32)fp) {
       
   299 		i = ((struct ipasfrag *)(q->ipf_prev))->ip_off +
       
   300 		  ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off;
       
   301 		if (i > 0) {
       
   302 			if (i >= ip->ip_len)
       
   303 				goto dropfrag;
       
   304 			m_adj(dtom(ip), i);
       
   305 			ip->ip_off += i;
       
   306 			ip->ip_len -= i;
       
   307 		}
       
   308 	}
       
   309 
       
   310 	/*
       
   311 	 * While we overlap succeeding segments trim them or,
       
   312 	 * if they are completely covered, dequeue them.
       
   313 	 */
       
   314 	while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
       
   315 		i = (ip->ip_off + ip->ip_len) - q->ip_off;
       
   316 		if (i < q->ip_len) {
       
   317 			q->ip_len -= i;
       
   318 			q->ip_off += i;
       
   319 			m_adj(dtom(q), i);
       
   320 			break;
       
   321 		}
       
   322 		q = (struct ipasfrag *) q->ipf_next;
       
   323 		m_freem(dtom((struct ipasfrag *) q->ipf_prev));
       
   324 		ip_deq((struct ipasfrag *) q->ipf_prev);
       
   325 	}
       
   326 
       
   327 insert:
       
   328 	/*
       
   329 	 * Stick new segment in its place;
       
   330 	 * check for complete reassembly.
       
   331 	 */
       
   332 	ip_enq(ip, (struct ipasfrag *) q->ipf_prev);
       
   333 	next = 0;
       
   334 	for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp;
       
   335 	     q = (struct ipasfrag *) q->ipf_next) {
       
   336 		if (q->ip_off != next)
       
   337 			return (0);
       
   338 		next += q->ip_len;
       
   339 	}
       
   340 	if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1)
       
   341 		return (0);
       
   342 
       
   343 	/*
       
   344 	 * Reassembly is complete; concatenate fragments.
       
   345 	 */
       
   346 	q = (struct ipasfrag *) fp->ipq_next;
       
   347 	m = dtom(q);
       
   348 
       
   349 	q = (struct ipasfrag *) q->ipf_next;
       
   350 	while (q != (struct ipasfrag *)fp) {
       
   351 	  struct mbuf *t;
       
   352 	  t = dtom(q);
       
   353 	  q = (struct ipasfrag *) q->ipf_next;
       
   354 	  m_cat(m, t);
       
   355 	}
       
   356 
       
   357 	/*
       
   358 	 * Create header for new ip packet by
       
   359 	 * modifying header of first packet;
       
   360 	 * dequeue and discard fragment reassembly header.
       
   361 	 * Make header visible.
       
   362 	 */
       
   363 	ip = (struct ipasfrag *) fp->ipq_next;
       
   364 
       
   365 	/*
       
   366 	 * If the fragments concatenated to an mbuf that's
       
   367 	 * bigger than the total size of the fragment, then and
       
   368 	 * m_ext buffer was alloced. But fp->ipq_next points to
       
   369 	 * the old buffer (in the mbuf), so we must point ip
       
   370 	 * into the new buffer.
       
   371 	 */
       
   372 	if (m->m_flags & M_EXT) {
       
   373 	  int delta;
       
   374 	  delta = (char *)ip - m->m_dat;
       
   375 	  ip = (struct ipasfrag *)(m->m_ext + delta);
       
   376 	}
       
   377 
       
   378 	/* DEBUG_ARG("ip = %lx", (long)ip);
       
   379 	 * ip=(struct ipasfrag *)m->m_data; */
       
   380 
       
   381 	ip->ip_len = next;
       
   382 	ip->ipf_mff &= ~1;
       
   383 	((struct ip *)ip)->ip_src = fp->ipq_src;
       
   384 	((struct ip *)ip)->ip_dst = fp->ipq_dst;
       
   385 	remque_32(fp);
       
   386 	(void) m_free(dtom(fp));
       
   387 	m = dtom(ip);
       
   388 	m->m_len += (ip->ip_hl << 2);
       
   389 	m->m_data -= (ip->ip_hl << 2);
       
   390 
       
   391 	return ((struct ip *)ip);
       
   392 
       
   393 dropfrag:
       
   394 	STAT(ipstat.ips_fragdropped++);
       
   395 	m_freem(m);
       
   396 	return (0);
       
   397 }
       
   398 
       
   399 /*
       
   400  * Free a fragment reassembly header and all
       
   401  * associated datagrams.
       
   402  */
       
   403 static void
       
   404 ip_freef(struct ipq *fp)
       
   405 {
       
   406 	register struct ipasfrag *q, *p;
       
   407 
       
   408 	for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp;
       
   409 	    q = p) {
       
   410 		p = (struct ipasfrag *) q->ipf_next;
       
   411 		ip_deq(q);
       
   412 		m_freem(dtom(q));
       
   413 	}
       
   414 	remque_32(fp);
       
   415 	(void) m_free(dtom(fp));
       
   416 }
       
   417 
       
   418 /*
       
   419  * Put an ip fragment on a reassembly chain.
       
   420  * Like insque, but pointers in middle of structure.
       
   421  */
       
   422 static void
       
   423 ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev)
       
   424 {
       
   425 	DEBUG_CALL("ip_enq");
       
   426 	DEBUG_ARG("prev = %lx", (long)prev);
       
   427 	p->ipf_prev = (ipasfragp_32) prev;
       
   428 	p->ipf_next = prev->ipf_next;
       
   429 	((struct ipasfrag *)(prev->ipf_next))->ipf_prev = (ipasfragp_32) p;
       
   430 	prev->ipf_next = (ipasfragp_32) p;
       
   431 }
       
   432 
       
   433 /*
       
   434  * To ip_enq as remque is to insque.
       
   435  */
       
   436 static void
       
   437 ip_deq(register struct ipasfrag *p)
       
   438 {
       
   439 	((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next;
       
   440 	((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev;
       
   441 }
       
   442 
       
   443 /*
       
   444  * IP timer processing;
       
   445  * if a timer expires on a reassembly
       
   446  * queue, discard it.
       
   447  */
       
   448 void
       
   449 ip_slowtimo()
       
   450 {
       
   451 	register struct ipq *fp;
       
   452 
       
   453 	DEBUG_CALL("ip_slowtimo");
       
   454 
       
   455 	fp = (struct ipq *) ipq.next;
       
   456 	if (fp == 0)
       
   457 	   return;
       
   458 
       
   459 	while (fp != &ipq) {
       
   460 		--fp->ipq_ttl;
       
   461 		fp = (struct ipq *) fp->next;
       
   462 		if (((struct ipq *)(fp->prev))->ipq_ttl == 0) {
       
   463 			STAT(ipstat.ips_fragtimeout++);
       
   464 			ip_freef((struct ipq *) fp->prev);
       
   465 		}
       
   466 	}
       
   467 }
       
   468 
       
   469 /*
       
   470  * Do option processing on a datagram,
       
   471  * possibly discarding it if bad options are encountered,
       
   472  * or forwarding it if source-routed.
       
   473  * Returns 1 if packet has been forwarded/freed,
       
   474  * 0 if the packet should be processed further.
       
   475  */
       
   476 
       
   477 #ifdef notdef
       
   478 
       
   479 int
       
   480 ip_dooptions(m)
       
   481 	struct mbuf *m;
       
   482 {
       
   483 	register struct ip *ip = mtod(m, struct ip *);
       
   484 	register u_char *cp;
       
   485 	register struct ip_timestamp *ipt;
       
   486 	register struct in_ifaddr *ia;
       
   487 /*	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; */
       
   488 	int opt, optlen, cnt, off, code, type, forward = 0;
       
   489 	struct in_addr *sin, dst;
       
   490 typedef u_int32_t n_time;
       
   491 	n_time ntime;
       
   492 
       
   493 	dst = ip->ip_dst;
       
   494 	cp = (u_char *)(ip + 1);
       
   495 	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
       
   496 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
       
   497 		opt = cp[IPOPT_OPTVAL];
       
   498 		if (opt == IPOPT_EOL)
       
   499 			break;
       
   500 		if (opt == IPOPT_NOP)
       
   501 			optlen = 1;
       
   502 		else {
       
   503 			optlen = cp[IPOPT_OLEN];
       
   504 			if (optlen <= 0 || optlen > cnt) {
       
   505 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
       
   506 				goto bad;
       
   507 			}
       
   508 		}
       
   509 		switch (opt) {
       
   510 
       
   511 		default:
       
   512 			break;
       
   513 
       
   514 		/*
       
   515 		 * Source routing with record.
       
   516 		 * Find interface with current destination address.
       
   517 		 * If none on this machine then drop if strictly routed,
       
   518 		 * or do nothing if loosely routed.
       
   519 		 * Record interface address and bring up next address
       
   520 		 * component.  If strictly routed make sure next
       
   521 		 * address is on directly accessible net.
       
   522 		 */
       
   523 		case IPOPT_LSRR:
       
   524 		case IPOPT_SSRR:
       
   525 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
       
   526 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
       
   527 				goto bad;
       
   528 			}
       
   529 			ipaddr.sin_addr = ip->ip_dst;
       
   530 			ia = (struct in_ifaddr *)
       
   531 				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
       
   532 			if (ia == 0) {
       
   533 				if (opt == IPOPT_SSRR) {
       
   534 					type = ICMP_UNREACH;
       
   535 					code = ICMP_UNREACH_SRCFAIL;
       
   536 					goto bad;
       
   537 				}
       
   538 				/*
       
   539 				 * Loose routing, and not at next destination
       
   540 				 * yet; nothing to do except forward.
       
   541 				 */
       
   542 				break;
       
   543 			}
       
   544 			off--;			/ * 0 origin *  /
       
   545 			if (off > optlen - sizeof(struct in_addr)) {
       
   546 				/*
       
   547 				 * End of source route.  Should be for us.
       
   548 				 */
       
   549 				save_rte(cp, ip->ip_src);
       
   550 				break;
       
   551 			}
       
   552 			/*
       
   553 			 * locate outgoing interface
       
   554 			 */
       
   555 			bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,
       
   556 			    sizeof(ipaddr.sin_addr));
       
   557 			if (opt == IPOPT_SSRR) {
       
   558 #define	INA	struct in_ifaddr *
       
   559 #define	SA	struct sockaddr *
       
   560  			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
       
   561 				ia = (INA)ifa_ifwithnet((SA)&ipaddr);
       
   562 			} else
       
   563 				ia = ip_rtaddr(ipaddr.sin_addr);
       
   564 			if (ia == 0) {
       
   565 				type = ICMP_UNREACH;
       
   566 				code = ICMP_UNREACH_SRCFAIL;
       
   567 				goto bad;
       
   568 			}
       
   569 			ip->ip_dst = ipaddr.sin_addr;
       
   570 			bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
       
   571 			    (caddr_t)(cp + off), sizeof(struct in_addr));
       
   572 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
       
   573 			/*
       
   574 			 * Let ip_intr's mcast routing check handle mcast pkts
       
   575 			 */
       
   576 			forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
       
   577 			break;
       
   578 
       
   579 		case IPOPT_RR:
       
   580 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
       
   581 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
       
   582 				goto bad;
       
   583 			}
       
   584 			/*
       
   585 			 * If no space remains, ignore.
       
   586 			 */
       
   587 			off--;			 * 0 origin *
       
   588 			if (off > optlen - sizeof(struct in_addr))
       
   589 				break;
       
   590 			bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
       
   591 			    sizeof(ipaddr.sin_addr));
       
   592 			/*
       
   593 			 * locate outgoing interface; if we're the destination,
       
   594 			 * use the incoming interface (should be same).
       
   595 			 */
       
   596 			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
       
   597 			    (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
       
   598 				type = ICMP_UNREACH;
       
   599 				code = ICMP_UNREACH_HOST;
       
   600 				goto bad;
       
   601 			}
       
   602 			bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
       
   603 			    (caddr_t)(cp + off), sizeof(struct in_addr));
       
   604 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
       
   605 			break;
       
   606 
       
   607 		case IPOPT_TS:
       
   608 			code = cp - (u_char *)ip;
       
   609 			ipt = (struct ip_timestamp *)cp;
       
   610 			if (ipt->ipt_len < 5)
       
   611 				goto bad;
       
   612 			if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) {
       
   613 				if (++ipt->ipt_oflw == 0)
       
   614 					goto bad;
       
   615 				break;
       
   616 			}
       
   617 			sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
       
   618 			switch (ipt->ipt_flg) {
       
   619 
       
   620 			case IPOPT_TS_TSONLY:
       
   621 				break;
       
   622 
       
   623 			case IPOPT_TS_TSANDADDR:
       
   624 				if (ipt->ipt_ptr + sizeof(n_time) +
       
   625 				    sizeof(struct in_addr) > ipt->ipt_len)
       
   626 					goto bad;
       
   627 				ipaddr.sin_addr = dst;
       
   628 				ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr,
       
   629 							    m->m_pkthdr.rcvif);
       
   630 				if (ia == 0)
       
   631 					continue;
       
   632 				bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
       
   633 				    (caddr_t)sin, sizeof(struct in_addr));
       
   634 				ipt->ipt_ptr += sizeof(struct in_addr);
       
   635 				break;
       
   636 
       
   637 			case IPOPT_TS_PRESPEC:
       
   638 				if (ipt->ipt_ptr + sizeof(n_time) +
       
   639 				    sizeof(struct in_addr) > ipt->ipt_len)
       
   640 					goto bad;
       
   641 				bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
       
   642 				    sizeof(struct in_addr));
       
   643 				if (ifa_ifwithaddr((SA)&ipaddr) == 0)
       
   644 					continue;
       
   645 				ipt->ipt_ptr += sizeof(struct in_addr);
       
   646 				break;
       
   647 
       
   648 			default:
       
   649 				goto bad;
       
   650 			}
       
   651 			ntime = iptime();
       
   652 			bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
       
   653 			    sizeof(n_time));
       
   654 			ipt->ipt_ptr += sizeof(n_time);
       
   655 		}
       
   656 	}
       
   657 	if (forward) {
       
   658 		ip_forward(m, 1);
       
   659 		return (1);
       
   660 	}
       
   661 		}
       
   662 	}
       
   663 	return (0);
       
   664 bad:
       
   665 	/* ip->ip_len -= ip->ip_hl << 2;   XXX icmp_error adds in hdr length */
       
   666 
       
   667 /* Not yet */
       
   668  	icmp_error(m, type, code, 0, 0);
       
   669 
       
   670 	STAT(ipstat.ips_badoptions++);
       
   671 	return (1);
       
   672 }
       
   673 
       
   674 #endif /* notdef */
       
   675 
       
   676 /*
       
   677  * Strip out IP options, at higher
       
   678  * level protocol in the kernel.
       
   679  * Second argument is buffer to which options
       
   680  * will be moved, and return value is their length.
       
   681  * (XXX) should be deleted; last arg currently ignored.
       
   682  */
       
   683 void
       
   684 ip_stripoptions(m, mopt)
       
   685 	register struct mbuf *m;
       
   686 	struct mbuf *mopt;
       
   687 {
       
   688 	register int i;
       
   689 	struct ip *ip = mtod(m, struct ip *);
       
   690 	register caddr_t opts;
       
   691 	int olen;
       
   692 
       
   693 	olen = (ip->ip_hl<<2) - sizeof (struct ip);
       
   694 	opts = (caddr_t)(ip + 1);
       
   695 	i = m->m_len - (sizeof (struct ip) + olen);
       
   696 	memcpy(opts, opts  + olen, (unsigned)i);
       
   697 	m->m_len -= olen;
       
   698 
       
   699 	ip->ip_hl = sizeof(struct ip) >> 2;
       
   700 }