ip_output.c revision 88190
1193323Sed/*
2193323Sed * Copyright (c) 1982, 1986, 1988, 1990, 1993
3193323Sed *	The Regents of the University of California.  All rights reserved.
4193323Sed *
5193323Sed * Redistribution and use in source and binary forms, with or without
6193323Sed * modification, are permitted provided that the following conditions
7193323Sed * are met:
8193323Sed * 1. Redistributions of source code must retain the above copyright
9193323Sed *    notice, this list of conditions and the following disclaimer.
10193323Sed * 2. Redistributions in binary form must reproduce the above copyright
11193323Sed *    notice, this list of conditions and the following disclaimer in the
12193323Sed *    documentation and/or other materials provided with the distribution.
13193323Sed * 3. All advertising materials mentioning features or use of this software
14193323Sed *    must display the following acknowledgement:
15193323Sed *	This product includes software developed by the University of
16193323Sed *	California, Berkeley and its contributors.
17193323Sed * 4. Neither the name of the University nor the names of its contributors
18193323Sed *    may be used to endorse or promote products derived from this software
19193323Sed *    without specific prior written permission.
20198090Srdivacky *
21193323Sed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24198090Srdivacky * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28198396Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31198396Srdivacky * SUCH DAMAGE.
32193323Sed *
33193323Sed *	@(#)ip_output.c	8.3 (Berkeley) 1/21/94
34193323Sed * $FreeBSD: head/sys/netinet/ip_output.c 88190 2001-12-19 14:54:13Z yar $
35193323Sed */
36193323Sed
37193323Sed#define _IP_VHL
38193323Sed
39193323Sed#include "opt_ipfw.h"
40193323Sed#include "opt_ipdn.h"
41193323Sed#include "opt_ipdivert.h"
42199989Srdivacky#include "opt_ipfilter.h"
43198090Srdivacky#include "opt_ipsec.h"
44193323Sed#include "opt_pfil_hooks.h"
45200581Srdivacky#include "opt_random_ip_id.h"
46198090Srdivacky
47193323Sed#include <sys/param.h>
48193323Sed#include <sys/systm.h>
49198090Srdivacky#include <sys/kernel.h>
50193323Sed#include <sys/malloc.h>
51193323Sed#include <sys/mbuf.h>
52193323Sed#include <sys/protosw.h>
53198090Srdivacky#include <sys/socket.h>
54193323Sed#include <sys/socketvar.h>
55193323Sed
56193323Sed#include <net/if.h>
57198090Srdivacky#include <net/route.h>
58193323Sed
59193323Sed#include <netinet/in.h>
60193323Sed#include <netinet/in_systm.h>
61198090Srdivacky#include <netinet/ip.h>
62193323Sed#include <netinet/in_pcb.h>
63193323Sed#include <netinet/in_var.h>
64193323Sed#include <netinet/ip_var.h>
65193323Sed
66198090Srdivacky#include <machine/in_cksum.h>
67198090Srdivacky
68194710Sedstatic MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
69198090Srdivacky
70198090Srdivacky#ifdef IPSEC
71198090Srdivacky#include <netinet6/ipsec.h>
72194710Sed#include <netkey/key.h>
73198090Srdivacky#ifdef IPSEC_DEBUG
74198090Srdivacky#include <netkey/key_debug.h>
75198090Srdivacky#else
76194710Sed#define	KEYDEBUG(lev,arg)
77194710Sed#endif
78198090Srdivacky#endif /*IPSEC*/
79194710Sed
80198090Srdivacky#include <netinet/ip_fw.h>
81194710Sed#include <netinet/ip_dummynet.h>
82198090Srdivacky
83198090Srdivacky#ifdef IPFIREWALL_FORWARD_DEBUG
84198090Srdivacky#define print_ip(a)	 printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\
85198090Srdivacky				 		  (ntohl(a.s_addr)>>16)&0xFF,\
86198090Srdivacky						  (ntohl(a.s_addr)>>8)&0xFF,\
87198090Srdivacky						  (ntohl(a.s_addr))&0xFF);
88198090Srdivacky#endif
89198090Srdivacky
90198090Srdivackyu_short ip_id;
91198090Srdivacky
92198090Srdivackystatic struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
93194710Sedstatic struct ifnet *ip_multicast_if __P((struct in_addr *, int *));
94198090Srdivackystatic void	ip_mloopback
95198090Srdivacky	__P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int));
96198090Srdivackystatic int	ip_getmoptions
97194710Sed	__P((struct sockopt *, struct ip_moptions *));
98194710Sedstatic int	ip_pcbopts __P((int, struct mbuf **, struct mbuf *));
99194710Sedstatic int	ip_setmoptions
100194710Sed	__P((struct sockopt *, struct ip_moptions **));
101198090Srdivacky
102198090Srdivackyint	ip_optcopy __P((struct ip *, struct ip *));
103198090Srdivacky
104198090Srdivacky
105198090Srdivackyextern	struct protosw inetsw[];
106198090Srdivacky
107198090Srdivacky/*
108198090Srdivacky * IP output.  The packet in mbuf chain m contains a skeletal IP
109198090Srdivacky * header (with len, off, ttl, proto, tos, src, dst).
110194710Sed * The mbuf chain containing the packet will be freed.
111198090Srdivacky * The mbuf opt, if present, will not be freed.
112198090Srdivacky */
113198090Srdivackyint
114198090Srdivackyip_output(m0, opt, ro, flags, imo)
115198090Srdivacky	struct mbuf *m0;
116198090Srdivacky	struct mbuf *opt;
117198090Srdivacky	struct route *ro;
118198090Srdivacky	int flags;
119194710Sed	struct ip_moptions *imo;
120194710Sed{
121198090Srdivacky	struct ip *ip, *mhip;
122194710Sed	struct ifnet *ifp;
123194710Sed	struct mbuf *m = m0;
124194710Sed	int hlen = sizeof (struct ip);
125194710Sed	int len, off, error = 0;
126198090Srdivacky	struct route iproute;
127194710Sed	struct sockaddr_in *dst;
128194710Sed	struct in_ifaddr *ia;
129194710Sed	int isbroadcast, sw_csum;
130194710Sed#ifdef IPSEC
131198090Srdivacky	struct socket *so = NULL;
132198090Srdivacky	struct secpolicy *sp = NULL;
133198090Srdivacky#endif
134198090Srdivacky	u_int16_t divert_cookie;		/* firewall cookie */
135198090Srdivacky#ifdef PFIL_HOOKS
136198090Srdivacky	struct packet_filter_hook *pfh;
137193323Sed	struct mbuf *m1;
138199481Srdivacky	int rv;
139193323Sed#endif /* PFIL_HOOKS */
140193323Sed#ifdef IPFIREWALL_FORWARD
141193323Sed	int fwd_rewrite_src = 0;
142193323Sed#endif
143193323Sed	struct ip_fw *rule = NULL;
144193323Sed
145193323Sed#ifdef IPDIVERT
146193323Sed	/* Get and reset firewall cookie */
147193323Sed	divert_cookie = ip_divert_cookie;
148193323Sed	ip_divert_cookie = 0;
149193323Sed#else
150193323Sed	divert_cookie = 0;
151193323Sed#endif
152193323Sed
153193323Sed        /*
154193323Sed         * dummynet packet are prepended a vestigial mbuf with
155193323Sed         * m_type = MT_DUMMYNET and m_data pointing to the matching
156193323Sed         * rule.
157193323Sed         */
158193323Sed        if (m->m_type == MT_DUMMYNET) {
159193323Sed            /*
160193323Sed             * the packet was already tagged, so part of the
161193323Sed             * processing was already done, and we need to go down.
162193323Sed             * Get parameters from the header.
163193323Sed             */
164193323Sed            rule = (struct ip_fw *)(m->m_data) ;
165193323Sed	    opt = NULL ;
166193323Sed	    ro = & ( ((struct dn_pkt *)m)->ro ) ;
167193323Sed	    imo = NULL ;
168193323Sed	    dst = ((struct dn_pkt *)m)->dn_dst ;
169193323Sed	    ifp = ((struct dn_pkt *)m)->ifp ;
170193323Sed	    flags = ((struct dn_pkt *)m)->flags ;
171193323Sed
172193323Sed            m0 = m = m->m_next ;
173193323Sed#ifdef IPSEC
174193323Sed	    so = ipsec_getsocket(m);
175193323Sed	    (void)ipsec_setsocket(m, NULL);
176193323Sed#endif
177193323Sed            ip = mtod(m, struct ip *);
178193323Sed            hlen = IP_VHL_HL(ip->ip_vhl) << 2 ;
179193323Sed            ia = ifatoia(ro->ro_rt->rt_ifa);
180193323Sed            goto sendit;
181193323Sed        } else
182193323Sed            rule = NULL ;
183193323Sed#ifdef IPSEC
184193323Sed	so = ipsec_getsocket(m);
185193323Sed	(void)ipsec_setsocket(m, NULL);
186193323Sed#endif
187193323Sed
188193323Sed#ifdef	DIAGNOSTIC
189193323Sed	if ((m->m_flags & M_PKTHDR) == 0)
190193323Sed		panic("ip_output no HDR");
191193323Sed#endif
192193323Sed	if (opt) {
193193323Sed		m = ip_insertoptions(m, opt, &len);
194193323Sed		hlen = len;
195193323Sed	}
196193323Sed	ip = mtod(m, struct ip *);
197193323Sed	/*
198193323Sed	 * Fill in IP header.
199193323Sed	 */
200193323Sed	if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
201193323Sed		ip->ip_vhl = IP_MAKE_VHL(IPVERSION, hlen >> 2);
202193323Sed		ip->ip_off &= IP_DF;
203193323Sed#ifdef RANDOM_IP_ID
204193323Sed		ip->ip_id = ip_randomid();
205193323Sed#else
206193323Sed		ip->ip_id = htons(ip_id++);
207193323Sed#endif
208193323Sed		ipstat.ips_localout++;
209193323Sed	} else {
210193323Sed		hlen = IP_VHL_HL(ip->ip_vhl) << 2;
211193323Sed	}
212193323Sed
213193323Sed	/* Route packet. */
214193323Sed	if (ro == NULL) {
215193323Sed		ro = &iproute;
216193323Sed		bzero(ro, sizeof(*ro));
217193323Sed	}
218193323Sed	dst = (struct sockaddr_in *)&ro->ro_dst;
219193323Sed	/*
220193323Sed	 * If there is a cached route,
221193323Sed	 * check that it is to the same destination
222193323Sed	 * and is still up.  If not, free it and try again.
223198090Srdivacky	 */
224198090Srdivacky	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
225198090Srdivacky	   dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
226198090Srdivacky		RTFREE(ro->ro_rt);
227198090Srdivacky		ro->ro_rt = (struct rtentry *)0;
228198090Srdivacky	}
229198090Srdivacky	if (ro->ro_rt == 0) {
230198090Srdivacky		dst->sin_family = AF_INET;
231198090Srdivacky		dst->sin_len = sizeof(*dst);
232198090Srdivacky		dst->sin_addr = ip->ip_dst;
233193323Sed	}
234193323Sed	/*
235193323Sed	 * If routing to interface only,
236198090Srdivacky	 * short circuit routing lookup.
237193323Sed	 */
238193323Sed	if (flags & IP_ROUTETOIF) {
239193323Sed		if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
240193323Sed		    (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
241193323Sed			ipstat.ips_noroute++;
242194710Sed			error = ENETUNREACH;
243194710Sed			goto bad;
244194710Sed		}
245194710Sed		ifp = ia->ia_ifp;
246194710Sed		ip->ip_ttl = 1;
247194710Sed		isbroadcast = in_broadcast(dst->sin_addr, ifp);
248194710Sed	} else if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) &&
249194710Sed	    imo != NULL && imo->imo_multicast_ifp != NULL) {
250194710Sed		/*
251194710Sed		 * Bypass the normal routing lookup for multicast
252194710Sed		 * packets if the interface is specified.
253194710Sed		 */
254194710Sed		ifp = imo->imo_multicast_ifp;
255194710Sed		IFP_TO_IA(ifp, ia);
256194710Sed		isbroadcast = 0;	/* fool gcc */
257198090Srdivacky	} else {
258198090Srdivacky		/*
259198090Srdivacky		 * If this is the case, we probably don't want to allocate
260198090Srdivacky		 * a protocol-cloned route since we didn't get one from the
261198090Srdivacky		 * ULP.  This lets TCP do its thing, while not burdening
262198090Srdivacky		 * forwarding or ICMP with the overhead of cloning a route.
263198090Srdivacky		 * Of course, we still want to do any cloning requested by
264198090Srdivacky		 * the link layer, as this is probably required in all cases
265198090Srdivacky		 * for correct operation (as it is for ARP).
266198090Srdivacky		 */
267198090Srdivacky		if (ro->ro_rt == 0)
268198090Srdivacky			rtalloc_ign(ro, RTF_PRCLONING);
269198090Srdivacky		if (ro->ro_rt == 0) {
270198090Srdivacky			ipstat.ips_noroute++;
271198090Srdivacky			error = EHOSTUNREACH;
272198090Srdivacky			goto bad;
273198090Srdivacky		}
274198090Srdivacky		ia = ifatoia(ro->ro_rt->rt_ifa);
275198090Srdivacky		ifp = ro->ro_rt->rt_ifp;
276198090Srdivacky		ro->ro_rt->rt_use++;
277198090Srdivacky		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
278198090Srdivacky			dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
279198090Srdivacky		if (ro->ro_rt->rt_flags & RTF_HOST)
280198090Srdivacky			isbroadcast = (ro->ro_rt->rt_flags & RTF_BROADCAST);
281198090Srdivacky		else
282198090Srdivacky			isbroadcast = in_broadcast(dst->sin_addr, ifp);
283198090Srdivacky	}
284198090Srdivacky	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
285198090Srdivacky		struct in_multi *inm;
286198090Srdivacky
287198090Srdivacky		m->m_flags |= M_MCAST;
288198090Srdivacky		/*
289198090Srdivacky		 * IP destination address is multicast.  Make sure "dst"
290194710Sed		 * still points to the address in "ro".  (It may have been
291194710Sed		 * changed to point to a gateway address, above.)
292194710Sed		 */
293194710Sed		dst = (struct sockaddr_in *)&ro->ro_dst;
294194710Sed		/*
295194710Sed		 * See if the caller provided any multicast options
296194710Sed		 */
297194710Sed		if (imo != NULL) {
298194710Sed			ip->ip_ttl = imo->imo_multicast_ttl;
299193323Sed			if (imo->imo_multicast_vif != -1)
300193323Sed				ip->ip_src.s_addr =
301193323Sed				    ip_mcast_src(imo->imo_multicast_vif);
302193323Sed		} else
303193323Sed			ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
304193323Sed		/*
305193323Sed		 * Confirm that the outgoing interface supports multicast.
306193323Sed		 */
307193323Sed		if ((imo == NULL) || (imo->imo_multicast_vif == -1)) {
308195340Sed			if ((ifp->if_flags & IFF_MULTICAST) == 0) {
309195340Sed				ipstat.ips_noroute++;
310195340Sed				error = ENETUNREACH;
311195340Sed				goto bad;
312195340Sed			}
313195340Sed		}
314195340Sed		/*
315195340Sed		 * If source address not specified yet, use address
316195340Sed		 * of outgoing interface.
317195340Sed		 */
318195340Sed		if (ip->ip_src.s_addr == INADDR_ANY) {
319195340Sed			/* Interface may have no addresses. */
320193323Sed			if (ia != NULL)
321193323Sed				ip->ip_src = IA_SIN(ia)->sin_addr;
322193323Sed		}
323198090Srdivacky
324193323Sed		IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
325193323Sed		if (inm != NULL &&
326193323Sed		   (imo == NULL || imo->imo_multicast_loop)) {
327193323Sed			/*
328193323Sed			 * If we belong to the destination multicast group
329193323Sed			 * on the outgoing interface, and the caller did not
330193323Sed			 * forbid loopback, loop back a copy.
331193323Sed			 */
332193323Sed			ip_mloopback(ifp, m, dst, hlen);
333193323Sed		}
334193323Sed		else {
335198892Srdivacky			/*
336198892Srdivacky			 * If we are acting as a multicast router, perform
337198892Srdivacky			 * multicast forwarding as if the packet had just
338193323Sed			 * arrived on the interface to which we are about
339193323Sed			 * to send.  The multicast forwarding function
340193323Sed			 * recursively calls this function, using the
341193323Sed			 * IP_FORWARDING flag to prevent infinite recursion.
342193323Sed			 *
343202878Srdivacky			 * Multicasts that are looped back by ip_mloopback(),
344193323Sed			 * above, will be forwarded by the ip_input() routine,
345195098Sed			 * if necessary.
346193323Sed			 */
347193323Sed			if (ip_mrouter && (flags & IP_FORWARDING) == 0) {
348193323Sed				/*
349193323Sed				 * Check if rsvp daemon is running. If not, don't
350193323Sed				 * set ip_moptions. This ensures that the packet
351193323Sed				 * is multicast and not just sent down one link
352193323Sed				 * as prescribed by rsvpd.
353193323Sed				 */
354193323Sed				if (!rsvp_on)
355193323Sed				  imo = NULL;
356193323Sed				if (ip_mforward(ip, ifp, m, imo) != 0) {
357193323Sed					m_freem(m);
358193323Sed					goto done;
359193323Sed				}
360193323Sed			}
361193323Sed		}
362193323Sed
363193323Sed		/*
364198892Srdivacky		 * Multicasts with a time-to-live of zero may be looped-
365193323Sed		 * back, above, but must not be transmitted on a network.
366193323Sed		 * Also, multicasts addressed to the loopback interface
367193323Sed		 * are not sent -- the above call to ip_mloopback() will
368193323Sed		 * loop back a copy if this host actually belongs to the
369193323Sed		 * destination group on the loopback interface.
370193323Sed		 */
371193323Sed		if (ip->ip_ttl == 0 || ifp->if_flags & IFF_LOOPBACK) {
372193323Sed			m_freem(m);
373198090Srdivacky			goto done;
374198090Srdivacky		}
375198090Srdivacky
376198090Srdivacky		goto sendit;
377198090Srdivacky	}
378198090Srdivacky#ifndef notdef
379198090Srdivacky	/*
380198090Srdivacky	 * If source address not specified yet, use address
381200581Srdivacky	 * of outgoing interface.
382193323Sed	 */
383195340Sed	if (ip->ip_src.s_addr == INADDR_ANY) {
384193323Sed		/* Interface may have no addresses. */
385193323Sed		if (ia != NULL) {
386193323Sed			ip->ip_src = IA_SIN(ia)->sin_addr;
387193323Sed#ifdef IPFIREWALL_FORWARD
388193323Sed			/* Keep note that we did this - if the firewall changes
389198090Srdivacky		 	* the next-hop, our interface may change, changing the
390202878Srdivacky		 	* default source IP. It's a shame so much effort happens
391202878Srdivacky		 	* twice. Oh well.
392193323Sed		 	*/
393193323Sed			fwd_rewrite_src++;
394193323Sed#endif /* IPFIREWALL_FORWARD */
395193323Sed		}
396193323Sed	}
397193323Sed#endif /* notdef */
398193323Sed	/*
399193323Sed	 * Verify that we have any chance at all of being able to queue
400193323Sed	 *      the packet or packet fragments
401193323Sed	 */
402193323Sed	if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >=
403193323Sed		ifp->if_snd.ifq_maxlen) {
404193323Sed			error = ENOBUFS;
405193323Sed			ipstat.ips_odropped++;
406193323Sed			goto bad;
407193323Sed	}
408193323Sed
409193323Sed	/*
410193323Sed	 * Look for broadcast address and
411193323Sed	 * and verify user is allowed to send
412193323Sed	 * such a packet.
413193323Sed	 */
414193323Sed	if (isbroadcast) {
415193323Sed		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
416193323Sed			error = EADDRNOTAVAIL;
417193323Sed			goto bad;
418193323Sed		}
419193323Sed		if ((flags & IP_ALLOWBROADCAST) == 0) {
420198090Srdivacky			error = EACCES;
421193323Sed			goto bad;
422193323Sed		}
423193323Sed		/* don't allow broadcast messages to be fragmented */
424193323Sed		if ((u_short)ip->ip_len > ifp->if_mtu) {
425193323Sed			error = EMSGSIZE;
426193323Sed			goto bad;
427193323Sed		}
428198090Srdivacky		m->m_flags |= M_BCAST;
429193323Sed	} else {
430193323Sed		m->m_flags &= ~M_BCAST;
431193323Sed	}
432193323Sed
433193323Sedsendit:
434193323Sed#ifdef IPSEC
435193323Sed	/* get SP for this packet */
436199481Srdivacky	if (so == NULL)
437193323Sed		sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error);
438193323Sed	else
439193323Sed		sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error);
440193323Sed
441193323Sed	if (sp == NULL) {
442193323Sed		ipsecstat.out_inval++;
443198090Srdivacky		goto bad;
444198090Srdivacky	}
445198090Srdivacky
446198090Srdivacky	error = 0;
447198090Srdivacky
448198090Srdivacky	/* check policy */
449198090Srdivacky	switch (sp->policy) {
450198090Srdivacky	case IPSEC_POLICY_DISCARD:
451198090Srdivacky		/*
452198090Srdivacky		 * This packet is just discarded.
453198090Srdivacky		 */
454198090Srdivacky		ipsecstat.out_polvio++;
455194612Sed		goto bad;
456194612Sed
457193323Sed	case IPSEC_POLICY_BYPASS:
458193323Sed	case IPSEC_POLICY_NONE:
459193323Sed		/* no need to do IPsec. */
460193323Sed		goto skip_ipsec;
461193323Sed
462193323Sed	case IPSEC_POLICY_IPSEC:
463193323Sed		if (sp->req == NULL) {
464193323Sed			/* acquire a policy */
465193323Sed			error = key_spdacquire(sp);
466193323Sed			goto bad;
467193323Sed		}
468193323Sed		break;
469193323Sed
470193323Sed	case IPSEC_POLICY_ENTRUST:
471193323Sed	default:
472193323Sed		printf("ip_output: Invalid policy found. %d\n", sp->policy);
473193323Sed	}
474193323Sed    {
475198090Srdivacky	struct ipsec_output_state state;
476193323Sed	bzero(&state, sizeof(state));
477193323Sed	state.m = m;
478193323Sed	if (flags & IP_ROUTETOIF) {
479195340Sed		state.ro = &iproute;
480193323Sed		bzero(&iproute, sizeof(iproute));
481193323Sed	} else
482193323Sed		state.ro = ro;
483193323Sed	state.dst = (struct sockaddr *)dst;
484193323Sed
485193323Sed	ip->ip_sum = 0;
486202878Srdivacky
487202878Srdivacky	/*
488193323Sed	 * XXX
489193323Sed	 * delayed checksums are not currently compatible with IPsec
490193323Sed	 */
491193323Sed	if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
492193323Sed		in_delayed_cksum(m);
493193323Sed		m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
494193323Sed	}
495193323Sed
496193323Sed	HTONS(ip->ip_len);
497199481Srdivacky	HTONS(ip->ip_off);
498199481Srdivacky
499193323Sed	error = ipsec4_output(&state, sp, flags);
500198892Srdivacky
501198892Srdivacky	m = state.m;
502198892Srdivacky	if (flags & IP_ROUTETOIF) {
503193323Sed		/*
504194710Sed		 * if we have tunnel mode SA, we may need to ignore
505198090Srdivacky		 * IP_ROUTETOIF.
506198090Srdivacky		 */
507200581Srdivacky		if (state.ro != &iproute || state.ro->ro_rt != NULL) {
508200581Srdivacky			flags &= ~IP_ROUTETOIF;
509200581Srdivacky			ro = state.ro;
510194710Sed		}
511194710Sed	} else
512194710Sed		ro = state.ro;
513194710Sed	dst = (struct sockaddr_in *)state.dst;
514194710Sed	if (error) {
515194710Sed		/* mbuf is already reclaimed in ipsec4_output. */
516194710Sed		m0 = NULL;
517194710Sed		switch (error) {
518194710Sed		case EHOSTUNREACH:
519194710Sed		case ENETUNREACH:
520194710Sed		case EMSGSIZE:
521194710Sed		case ENOBUFS:
522194710Sed		case ENOMEM:
523194710Sed			break;
524194710Sed		default:
525194710Sed			printf("ip4_output (ipsec): error code %d\n", error);
526194710Sed			/*fall through*/
527194710Sed		case ENOENT:
528194710Sed			/* don't show these error codes to the user */
529194710Sed			error = 0;
530194710Sed			break;
531194710Sed		}
532194710Sed		goto bad;
533194710Sed	}
534194710Sed    }
535194710Sed
536194710Sed	/* be sure to update variables that are affected by ipsec4_output() */
537194710Sed	ip = mtod(m, struct ip *);
538198090Srdivacky#ifdef _IP_VHL
539198090Srdivacky	hlen = IP_VHL_HL(ip->ip_vhl) << 2;
540198090Srdivacky#else
541198090Srdivacky	hlen = ip->ip_hl << 2;
542198090Srdivacky#endif
543198090Srdivacky	if (ro->ro_rt == NULL) {
544198090Srdivacky		if ((flags & IP_ROUTETOIF) == 0) {
545198090Srdivacky			printf("ip_output: "
546198090Srdivacky				"can't update route after IPsec processing\n");
547193323Sed			error = EHOSTUNREACH;	/*XXX*/
548193323Sed			goto bad;
549193323Sed		}
550195340Sed	} else {
551195340Sed		ia = ifatoia(ro->ro_rt->rt_ifa);
552198090Srdivacky		ifp = ro->ro_rt->rt_ifp;
553195340Sed	}
554195340Sed
555193323Sed	/* make it flipped, again. */
556193323Sed	NTOHS(ip->ip_len);
557193323Sed	NTOHS(ip->ip_off);
558193323Sedskip_ipsec:
559193323Sed#endif /*IPSEC*/
560193323Sed
561193323Sed	/*
562198090Srdivacky	 * IpHack's section.
563193323Sed	 * - Xlate: translate packet's addr/port (NAT).
564193323Sed	 * - Firewall: deny/allow/etc.
565193323Sed	 * - Wrap: fake packet's addr/port <unimpl.>
566193323Sed	 * - Encapsulate: put it in another IP and send out. <unimp.>
567193323Sed	 */
568193323Sed#ifdef PFIL_HOOKS
569193323Sed	/*
570193323Sed	 * Run through list of hooks for output packets.
571193323Sed	 */
572193323Sed	m1 = m;
573193323Sed	pfh = pfil_hook_get(PFIL_OUT, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
574193323Sed	for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link))
575193323Sed		if (pfh->pfil_func) {
576198090Srdivacky			rv = pfh->pfil_func(ip, hlen, ifp, 1, &m1);
577198090Srdivacky			if (rv) {
578193323Sed				error = EHOSTUNREACH;
579193323Sed				goto done;
580193323Sed			}
581198090Srdivacky			m = m1;
582193323Sed			if (m == NULL)
583193323Sed				goto done;
584193323Sed			ip = mtod(m, struct ip *);
585193323Sed		}
586193323Sed#endif /* PFIL_HOOKS */
587193323Sed
588193323Sed	/*
589198090Srdivacky	 * Check with the firewall...
590193323Sed	 */
591193323Sed	if (fw_enable && IPFW_LOADED) {
592193323Sed		struct sockaddr_in *old = dst;
593193323Sed
594193323Sed		off = ip_fw_chk_ptr(&ip,
595193323Sed		    hlen, ifp, &divert_cookie, &m, &rule, &dst);
596193323Sed                /*
597193323Sed                 * On return we must do the following:
598193323Sed                 * m == NULL         -> drop the pkt (old interface, deprecated)
599193323Sed                 * (off & IP_FW_PORT_DENY_FLAG)	-> drop the pkt (new interface)
600193323Sed                 * 1<=off<= 0xffff		-> DIVERT
601193323Sed                 * (off & IP_FW_PORT_DYNT_FLAG)	-> send to a DUMMYNET pipe
602193323Sed                 * (off & IP_FW_PORT_TEE_FLAG)	-> TEE the packet
603193323Sed                 * dst != old			-> IPFIREWALL_FORWARD
604193323Sed                 * off==0, dst==old		-> accept
605193323Sed                 * If some of the above modules are not compiled in, then
606193323Sed                 * we should't have to check the corresponding condition
607193323Sed                 * (because the ipfw control socket should not accept
608193323Sed                 * unsupported rules), but better play safe and drop
609193323Sed                 * packets in case of doubt.
610193323Sed                 */
611193323Sed		if (off & IP_FW_PORT_DENY_FLAG) { /* XXX new interface-denied */
612198090Srdivacky			if (m)
613194710Sed				m_freem(m);
614194710Sed			error = EACCES;
615194710Sed			goto done;
616193323Sed		}
617194710Sed		if (!m) {			/* firewall said to reject */
618194710Sed			static int __debug=10;
619194710Sed
620194710Sed			if (__debug > 0) {
621194710Sed				printf(
622194710Sed				    "firewall returns NULL, please update!\n");
623194710Sed				__debug--;
624193323Sed			}
625194710Sed			error = EACCES;
626194710Sed			goto done;
627194710Sed		}
628194710Sed		if (off == 0 && dst == old)		/* common case */
629194710Sed			goto pass;
630194710Sed                if (DUMMYNET_LOADED && (off & IP_FW_PORT_DYNT_FLAG) != 0) {
631193323Sed			/*
632194710Sed			 * pass the pkt to dummynet. Need to include
633194710Sed			 * pipe number, m, ifp, ro, dst because these are
634194710Sed			 * not recomputed in the next pass.
635193323Sed			 * All other parameters have been already used and
636193323Sed			 * so they are not needed anymore.
637193323Sed			 * XXX note: if the ifp or ro entry are deleted
638194710Sed			 * while a pkt is in dummynet, we are in trouble!
639194710Sed			 */
640194710Sed			error = ip_dn_io_ptr(off & 0xffff, DN_TO_IP_OUT, m,
641194710Sed			    ifp, ro, dst, rule, flags);
642198090Srdivacky			goto done;
643194710Sed		}
644194710Sed#ifdef IPDIVERT
645194710Sed		if (off != 0 && (off & IP_FW_PORT_DYNT_FLAG) == 0) {
646194710Sed			struct mbuf *clone = NULL;
647194710Sed
648194710Sed			/* Clone packet if we're doing a 'tee' */
649194710Sed			if ((off & IP_FW_PORT_TEE_FLAG) != 0)
650194710Sed				clone = m_dup(m, M_DONTWAIT);
651193323Sed
652193323Sed			/*
653193323Sed			 * XXX
654193323Sed			 * delayed checksums are not currently compatible
655198090Srdivacky			 * with divert sockets.
656194710Sed			 */
657194710Sed			if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
658193323Sed				in_delayed_cksum(m);
659193323Sed				m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
660193323Sed			}
661193323Sed
662194710Sed			/* Restore packet header fields to original values */
663194710Sed			HTONS(ip->ip_len);
664194710Sed			HTONS(ip->ip_off);
665194710Sed
666193323Sed			/* Deliver packet to divert input routine */
667194710Sed			ip_divert_cookie = divert_cookie;
668194710Sed			divert_packet(m, 0, off & 0xffff);
669194710Sed
670194710Sed			/* If 'tee', continue with original packet */
671194710Sed			if (clone != NULL) {
672194710Sed				m = clone;
673194710Sed				ip = mtod(m, struct ip *);
674193323Sed				goto pass;
675193323Sed			}
676193323Sed			goto done;
677193323Sed		}
678193323Sed#endif
679194710Sed
680193323Sed#ifdef IPFIREWALL_FORWARD
681194710Sed		/* Here we check dst to make sure it's directly reachable on the
682194710Sed		 * interface we previously thought it was.
683194710Sed		 * If it isn't (which may be likely in some situations) we have
684194710Sed		 * to re-route it (ie, find a route for the next-hop and the
685198090Srdivacky		 * associated interface) and set them here. This is nested
686194710Sed		 * forwarding which in most cases is undesirable, except where
687194710Sed		 * such control is nigh impossible. So we do it here.
688194710Sed		 * And I'm babbling.
689194710Sed		 */
690194710Sed		if (off == 0 && old != dst) {
691194710Sed			struct in_ifaddr *ia;
692194710Sed
693194710Sed			/* It's changed... */
694193323Sed			/* There must be a better way to do this next line... */
695193323Sed			static struct route sro_fwd, *ro_fwd = &sro_fwd;
696193323Sed#ifdef IPFIREWALL_FORWARD_DEBUG
697198090Srdivacky			printf("IPFIREWALL_FORWARD: New dst ip: ");
698194710Sed			print_ip(dst->sin_addr);
699193323Sed			printf("\n");
700193323Sed#endif
701193323Sed			/*
702193323Sed			 * We need to figure out if we have been forwarded
703193323Sed			 * to a local socket. If so then we should somehow
704193323Sed			 * "loop back" to ip_input, and get directed to the
705193323Sed			 * PCB as if we had received this packet. This is
706193323Sed			 * because it may be dificult to identify the packets
707193323Sed			 * you want to forward until they are being output
708193323Sed			 * and have selected an interface. (e.g. locally
709193323Sed			 * initiated packets) If we used the loopback inteface,
710193323Sed			 * we would not be able to control what happens
711194710Sed			 * as the packet runs through ip_input() as
712193323Sed			 * it is done through a ISR.
713194710Sed			 */
714194710Sed			LIST_FOREACH(ia,
715194710Sed			    INADDR_HASH(dst->sin_addr.s_addr), ia_hash) {
716194710Sed				/*
717198090Srdivacky				 * If the addr to forward to is one
718194710Sed				 * of ours, we pretend to
719194710Sed				 * be the destination for this packet.
720194710Sed				 */
721194710Sed				if (IA_SIN(ia)->sin_addr.s_addr ==
722194710Sed						 dst->sin_addr.s_addr)
723194710Sed					break;
724194710Sed			}
725193323Sed			if (ia) {
726193323Sed				/* tell ip_input "dont filter" */
727193323Sed				ip_fw_fwd_addr = dst;
728198090Srdivacky				if (m->m_pkthdr.rcvif == NULL)
729193323Sed					m->m_pkthdr.rcvif = ifunit("lo0");
730193323Sed				if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
731193323Sed					m->m_pkthdr.csum_flags |=
732193323Sed					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
733193323Sed					m0->m_pkthdr.csum_data = 0xffff;
734193323Sed				}
735193323Sed				m->m_pkthdr.csum_flags |=
736194612Sed				    CSUM_IP_CHECKED | CSUM_IP_VALID;
737194612Sed				HTONS(ip->ip_len);
738198090Srdivacky				HTONS(ip->ip_off);
739198090Srdivacky				ip_input(m);
740198090Srdivacky				goto done;
741194612Sed			}
742194612Sed			/* Some of the logic for this was
743198090Srdivacky			 * nicked from above.
744194612Sed			 *
745194612Sed			 * This rewrites the cached route in a local PCB.
746198090Srdivacky			 * Is this what we want to do?
747198090Srdivacky			 */
748198090Srdivacky			bcopy(dst, &ro_fwd->ro_dst, sizeof(*dst));
749198090Srdivacky
750198090Srdivacky			ro_fwd->ro_rt = 0;
751198090Srdivacky			rtalloc_ign(ro_fwd, RTF_PRCLONING);
752198090Srdivacky
753198090Srdivacky			if (ro_fwd->ro_rt == 0) {
754198090Srdivacky				ipstat.ips_noroute++;
755194612Sed				error = EHOSTUNREACH;
756198090Srdivacky				goto bad;
757194612Sed			}
758198090Srdivacky
759194612Sed			ia = ifatoia(ro_fwd->ro_rt->rt_ifa);
760198090Srdivacky			ifp = ro_fwd->ro_rt->rt_ifp;
761194612Sed			ro_fwd->ro_rt->rt_use++;
762194612Sed			if (ro_fwd->ro_rt->rt_flags & RTF_GATEWAY)
763194612Sed				dst = (struct sockaddr_in *)ro_fwd->ro_rt->rt_gateway;
764198090Srdivacky			if (ro_fwd->ro_rt->rt_flags & RTF_HOST)
765198090Srdivacky				isbroadcast =
766198090Srdivacky				    (ro_fwd->ro_rt->rt_flags & RTF_BROADCAST);
767198090Srdivacky			else
768198090Srdivacky				isbroadcast = in_broadcast(dst->sin_addr, ifp);
769198090Srdivacky			if (ro->ro_rt)
770198090Srdivacky				RTFREE(ro->ro_rt);
771198090Srdivacky			ro->ro_rt = ro_fwd->ro_rt;
772193323Sed			dst = (struct sockaddr_in *)&ro_fwd->ro_dst;
773193323Sed
774193323Sed			/*
775198090Srdivacky			 * If we added a default src ip earlier,
776198090Srdivacky			 * which would have been gotten from the-then
777198090Srdivacky			 * interface, do it again, from the new one.
778198090Srdivacky			 */
779198090Srdivacky			if (fwd_rewrite_src)
780193323Sed				ip->ip_src = IA_SIN(ia)->sin_addr;
781193323Sed			goto pass ;
782193323Sed		}
783193323Sed#endif /* IPFIREWALL_FORWARD */
784193323Sed                /*
785193323Sed                 * if we get here, none of the above matches, and
786193323Sed                 * we have to drop the pkt
787194710Sed                 */
788193323Sed		m_freem(m);
789193323Sed                error = EACCES; /* not sure this is the right error msg */
790193323Sed                goto done;
791193323Sed	}
792193323Sed
793193323Sedpass:
794193323Sed	m->m_pkthdr.csum_flags |= CSUM_IP;
795193323Sed	sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_hwassist;
796193323Sed	if (sw_csum & CSUM_DELAY_DATA) {
797199481Srdivacky		in_delayed_cksum(m);
798194710Sed		sw_csum &= ~CSUM_DELAY_DATA;
799194710Sed	}
800194710Sed	m->m_pkthdr.csum_flags &= ifp->if_hwassist;
801194710Sed
802194710Sed	/*
803194710Sed	 * If small enough for interface, or the interface will take
804194710Sed	 * care of the fragmentation for us, can just send directly.
805194710Sed	 */
806194710Sed	if ((u_short)ip->ip_len <= ifp->if_mtu ||
807194710Sed	    ifp->if_hwassist & CSUM_FRAGMENT) {
808194710Sed		HTONS(ip->ip_len);
809194710Sed		HTONS(ip->ip_off);
810194710Sed		ip->ip_sum = 0;
811194710Sed		if (sw_csum & CSUM_DELAY_IP) {
812199481Srdivacky			if (ip->ip_vhl == IP_VHL_BORING) {
813194710Sed				ip->ip_sum = in_cksum_hdr(ip);
814194710Sed			} else {
815194710Sed				ip->ip_sum = in_cksum(m, hlen);
816193323Sed			}
817193323Sed		}
818193323Sed
819193323Sed		/* Record statistics for this interface address. */
820193323Sed		if (!(flags & IP_FORWARDING) && ia) {
821193323Sed			ia->ia_ifa.if_opackets++;
822193323Sed			ia->ia_ifa.if_obytes += m->m_pkthdr.len;
823193323Sed		}
824198090Srdivacky
825193323Sed#ifdef IPSEC
826193323Sed		/* clean ipsec history once it goes out of the node */
827193323Sed		ipsec_delaux(m);
828193323Sed#endif
829193323Sed
830193323Sed		error = (*ifp->if_output)(ifp, m,
831198090Srdivacky				(struct sockaddr *)dst, ro->ro_rt);
832193323Sed		goto done;
833193323Sed	}
834198090Srdivacky	/*
835193323Sed	 * Too large for interface; fragment if possible.
836193323Sed	 * Must be able to put at least 8 bytes per fragment.
837193323Sed	 */
838193323Sed	if (ip->ip_off & IP_DF) {
839193323Sed		error = EMSGSIZE;
840193323Sed		/*
841193323Sed		 * This case can happen if the user changed the MTU
842193323Sed		 * of an interface after enabling IP on it.  Because
843193323Sed		 * most netifs don't keep track of routes pointing to
844193323Sed		 * them, there is no way for one to update all its
845193323Sed		 * routes when the MTU is changed.
846193323Sed		 */
847193323Sed		if ((ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST))
848193323Sed		    && !(ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU)
849193323Sed		    && (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)) {
850193323Sed			ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu;
851193323Sed		}
852193323Sed		ipstat.ips_cantfrag++;
853193323Sed		goto bad;
854198090Srdivacky	}
855198090Srdivacky	len = (ifp->if_mtu - hlen) &~ 7;
856198090Srdivacky	if (len < 8) {
857198090Srdivacky		error = EMSGSIZE;
858198090Srdivacky		goto bad;
859193323Sed	}
860193323Sed
861193323Sed	/*
862193323Sed	 * if the interface will not calculate checksums on
863193323Sed	 * fragmented packets, then do it here.
864193323Sed	 */
865193323Sed	if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA &&
866193323Sed	    (ifp->if_hwassist & CSUM_IP_FRAGS) == 0) {
867193323Sed		in_delayed_cksum(m);
868193323Sed		m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
869198090Srdivacky	}
870194710Sed
871194710Sed    {
872194710Sed	int mhlen, firstlen = len;
873194710Sed	struct mbuf **mnext = &m->m_nextpkt;
874194710Sed	int nfrags = 1;
875194710Sed
876194710Sed	/*
877199481Srdivacky	 * Loop through length of segment after first fragment,
878194710Sed	 * make new header and copy data of each part and link onto chain.
879194710Sed	 */
880194710Sed	m0 = m;
881194710Sed	mhlen = sizeof (struct ip);
882194710Sed	for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
883194710Sed		MGETHDR(m, M_DONTWAIT, MT_HEADER);
884194710Sed		if (m == 0) {
885194710Sed			error = ENOBUFS;
886194710Sed			ipstat.ips_odropped++;
887194710Sed			goto sendorfree;
888198090Srdivacky		}
889198090Srdivacky		m->m_flags |= (m0->m_flags & M_MCAST) | M_FRAG;
890198090Srdivacky		m->m_data += max_linkhdr;
891194710Sed		mhip = mtod(m, struct ip *);
892194710Sed		*mhip = *ip;
893194710Sed		if (hlen > sizeof (struct ip)) {
894198090Srdivacky			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
895193323Sed			mhip->ip_vhl = IP_MAKE_VHL(IPVERSION, mhlen >> 2);
896193323Sed		}
897198090Srdivacky		m->m_len = mhlen;
898198090Srdivacky		mhip->ip_off = ((off - hlen) >> 3) + ip->ip_off;
899198090Srdivacky		if (off + len >= (u_short)ip->ip_len)
900198090Srdivacky			len = (u_short)ip->ip_len - off;
901198090Srdivacky		else
902198090Srdivacky			mhip->ip_off |= IP_MF;
903198090Srdivacky		mhip->ip_len = htons((u_short)(len + mhlen));
904198090Srdivacky		m->m_next = m_copy(m0, off, len);
905193323Sed		if (m->m_next == 0) {
906193323Sed			(void) m_free(m);
907193323Sed			error = ENOBUFS;	/* ??? */
908198090Srdivacky			ipstat.ips_odropped++;
909198090Srdivacky			goto sendorfree;
910198090Srdivacky		}
911198090Srdivacky		m->m_pkthdr.len = mhlen + len;
912198090Srdivacky		m->m_pkthdr.rcvif = (struct ifnet *)0;
913193323Sed		m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags;
914193323Sed		HTONS(mhip->ip_off);
915193323Sed		mhip->ip_sum = 0;
916193323Sed		if (sw_csum & CSUM_DELAY_IP) {
917193323Sed			if (mhip->ip_vhl == IP_VHL_BORING) {
918193323Sed				mhip->ip_sum = in_cksum_hdr(mhip);
919193323Sed			} else {
920193323Sed				mhip->ip_sum = in_cksum(m, mhlen);
921193323Sed			}
922193323Sed		}
923194710Sed		*mnext = m;
924193323Sed		mnext = &m->m_nextpkt;
925193323Sed		nfrags++;
926193323Sed	}
927193323Sed	ipstat.ips_ofragments += nfrags;
928193323Sed
929193323Sed	/* set first/last markers for fragment chain */
930193323Sed	m->m_flags |= M_LASTFRAG;
931193323Sed	m0->m_flags |= M_FIRSTFRAG | M_FRAG;
932198090Srdivacky	m0->m_pkthdr.csum_data = nfrags;
933198090Srdivacky
934193323Sed	/*
935193323Sed	 * Update first fragment by trimming what's been copied out
936193323Sed	 * and updating header, then send each fragment (in order).
937198090Srdivacky	 */
938193323Sed	m = m0;
939193323Sed	m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
940193323Sed	m->m_pkthdr.len = hlen + firstlen;
941193323Sed	ip->ip_len = htons((u_short)m->m_pkthdr.len);
942193323Sed	ip->ip_off |= IP_MF;
943193323Sed	HTONS(ip->ip_off);
944193323Sed	ip->ip_sum = 0;
945193323Sed	if (sw_csum & CSUM_DELAY_IP) {
946193323Sed		if (ip->ip_vhl == IP_VHL_BORING) {
947193323Sed			ip->ip_sum = in_cksum_hdr(ip);
948193323Sed		} else {
949193323Sed			ip->ip_sum = in_cksum(m, hlen);
950193323Sed		}
951193323Sed	}
952193323Sedsendorfree:
953198090Srdivacky	for (m = m0; m; m = m0) {
954193323Sed		m0 = m->m_nextpkt;
955194710Sed		m->m_nextpkt = 0;
956194710Sed#ifdef IPSEC
957194710Sed		/* clean ipsec history once it goes out of the node */
958194710Sed		ipsec_delaux(m);
959194710Sed#endif
960193323Sed		if (error == 0) {
961198090Srdivacky			/* Record statistics for this interface address. */
962194710Sed			if (ia != NULL) {
963194710Sed				ia->ia_ifa.if_opackets++;
964194710Sed				ia->ia_ifa.if_obytes += m->m_pkthdr.len;
965194710Sed			}
966198090Srdivacky
967194710Sed			error = (*ifp->if_output)(ifp, m,
968194710Sed			    (struct sockaddr *)dst, ro->ro_rt);
969194710Sed		} else
970194710Sed			m_freem(m);
971194710Sed	}
972194710Sed
973198090Srdivacky	if (error == 0)
974198090Srdivacky		ipstat.ips_fragmented++;
975194710Sed    }
976194710Seddone:
977198090Srdivacky#ifdef IPSEC
978194710Sed	if (ro == &iproute && ro->ro_rt) {
979193323Sed		RTFREE(ro->ro_rt);
980193323Sed		ro->ro_rt = NULL;
981193323Sed	}
982193323Sed	if (sp != NULL) {
983193323Sed		KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
984193323Sed			printf("DP ip_output call free SP:%p\n", sp));
985193323Sed		key_freesp(sp);
986193323Sed	}
987198090Srdivacky#endif /* IPSEC */
988198090Srdivacky	return (error);
989193323Sedbad:
990193323Sed	m_freem(m);
991193323Sed	goto done;
992193323Sed}
993193323Sed
994193323Sedvoid
995193323Sedin_delayed_cksum(struct mbuf *m)
996193323Sed{
997193323Sed	struct ip *ip;
998193323Sed	u_short csum, offset;
999193323Sed
1000193323Sed	ip = mtod(m, struct ip *);
1001193323Sed	offset = IP_VHL_HL(ip->ip_vhl) << 2 ;
1002193323Sed	csum = in_cksum_skip(m, ip->ip_len, offset);
1003193323Sed	if (m->m_pkthdr.csum_flags & CSUM_UDP && csum == 0)
1004193323Sed		csum = 0xffff;
1005193323Sed	offset += m->m_pkthdr.csum_data;	/* checksum offset */
1006193323Sed
1007193323Sed	if (offset + sizeof(u_short) > m->m_len) {
1008193323Sed		printf("delayed m_pullup, m->len: %d  off: %d  p: %d\n",
1009193323Sed		    m->m_len, offset, ip->ip_p);
1010193323Sed		/*
1011199481Srdivacky		 * XXX
1012199481Srdivacky		 * this shouldn't happen, but if it does, the
1013193323Sed		 * correct behavior may be to insert the checksum
1014193323Sed		 * in the existing chain instead of rearranging it.
1015193323Sed		 */
1016198090Srdivacky		m = m_pullup(m, offset + sizeof(u_short));
1017193323Sed	}
1018193323Sed	*(u_short *)(m->m_data + offset) = csum;
1019193323Sed}
1020193323Sed
1021193323Sed/*
1022193323Sed * Insert IP options into preformed packet.
1023198090Srdivacky * Adjust IP destination as required for IP source routing,
1024199481Srdivacky * as indicated by a non-zero in_addr at the start of the options.
1025198090Srdivacky *
1026198090Srdivacky * XXX This routine assumes that the packet has no options in place.
1027198090Srdivacky */
1028193323Sedstatic struct mbuf *
1029193323Sedip_insertoptions(m, opt, phlen)
1030193323Sed	register struct mbuf *m;
1031198892Srdivacky	struct mbuf *opt;
1032198892Srdivacky	int *phlen;
1033199481Srdivacky{
1034193323Sed	register struct ipoption *p = mtod(opt, struct ipoption *);
1035193323Sed	struct mbuf *n;
1036193323Sed	register struct ip *ip = mtod(m, struct ip *);
1037193323Sed	unsigned optlen;
1038193323Sed
1039193323Sed	optlen = opt->m_len - sizeof(p->ipopt_dst);
1040193323Sed	if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
1041193323Sed		return (m);		/* XXX should fail */
1042193323Sed	if (p->ipopt_dst.s_addr)
1043193323Sed		ip->ip_dst = p->ipopt_dst;
1044193323Sed	if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
1045198090Srdivacky		MGETHDR(n, M_DONTWAIT, MT_HEADER);
1046199481Srdivacky		if (n == 0)
1047198090Srdivacky			return (m);
1048198090Srdivacky		n->m_pkthdr.rcvif = (struct ifnet *)0;
1049193323Sed		n->m_pkthdr.len = m->m_pkthdr.len + optlen;
1050193323Sed		m->m_len -= sizeof(struct ip);
1051193323Sed		m->m_data += sizeof(struct ip);
1052198892Srdivacky		n->m_next = m;
1053198892Srdivacky		m = n;
1054199481Srdivacky		m->m_len = optlen + sizeof(struct ip);
1055193323Sed		m->m_data += max_linkhdr;
1056193323Sed		(void)memcpy(mtod(m, void *), ip, sizeof(struct ip));
1057193323Sed	} else {
1058193323Sed		m->m_data -= optlen;
1059193323Sed		m->m_len += optlen;
1060193323Sed		m->m_pkthdr.len += optlen;
1061193323Sed		ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
1062193323Sed	}
1063193323Sed	ip = mtod(m, struct ip *);
1064198090Srdivacky	bcopy(p->ipopt_list, ip + 1, optlen);
1065193323Sed	*phlen = sizeof(struct ip) + optlen;
1066193323Sed	ip->ip_vhl = IP_MAKE_VHL(IPVERSION, *phlen >> 2);
1067193323Sed	ip->ip_len += optlen;
1068193323Sed	return (m);
1069193323Sed}
1070193323Sed
1071193323Sed/*
1072193323Sed * Copy options from ip to jp,
1073198090Srdivacky * omitting those not copied during fragmentation.
1074193323Sed */
1075193323Sedint
1076193323Sedip_optcopy(ip, jp)
1077193323Sed	struct ip *ip, *jp;
1078193323Sed{
1079193323Sed	register u_char *cp, *dp;
1080193323Sed	int opt, optlen, cnt;
1081193323Sed
1082193323Sed	cp = (u_char *)(ip + 1);
1083193323Sed	dp = (u_char *)(jp + 1);
1084193323Sed	cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1085193323Sed	for (; cnt > 0; cnt -= optlen, cp += optlen) {
1086193323Sed		opt = cp[0];
1087193323Sed		if (opt == IPOPT_EOL)
1088193323Sed			break;
1089193323Sed		if (opt == IPOPT_NOP) {
1090193323Sed			/* Preserve for IP mcast tunnel's LSRR alignment. */
1091193323Sed			*dp++ = IPOPT_NOP;
1092193323Sed			optlen = 1;
1093193323Sed			continue;
1094193323Sed		}
1095193323Sed#ifdef DIAGNOSTIC
1096193323Sed		if (cnt < IPOPT_OLEN + sizeof(*cp))
1097193323Sed			panic("malformed IPv4 option passed to ip_optcopy");
1098198090Srdivacky#endif
1099193323Sed		optlen = cp[IPOPT_OLEN];
1100193323Sed#ifdef DIAGNOSTIC
1101193323Sed		if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt)
1102193323Sed			panic("malformed IPv4 option passed to ip_optcopy");
1103198090Srdivacky#endif
1104198090Srdivacky		/* bogus lengths should have been caught by ip_dooptions */
1105193323Sed		if (optlen > cnt)
1106193323Sed			optlen = cnt;
1107198090Srdivacky		if (IPOPT_COPIED(opt)) {
1108198090Srdivacky			bcopy(cp, dp, optlen);
1109198090Srdivacky			dp += optlen;
1110198090Srdivacky		}
1111198090Srdivacky	}
1112193323Sed	for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
1113193323Sed		*dp++ = IPOPT_EOL;
1114193323Sed	return (optlen);
1115193323Sed}
1116193323Sed
1117198090Srdivacky/*
1118198090Srdivacky * IP socket option processing.
1119193323Sed */
1120198090Srdivackyint
1121198090Srdivackyip_ctloutput(so, sopt)
1122198090Srdivacky	struct socket *so;
1123193323Sed	struct sockopt *sopt;
1124193323Sed{
1125193323Sed	struct	inpcb *inp = sotoinpcb(so);
1126193323Sed	int	error, optval;
1127193323Sed
1128193323Sed	error = optval = 0;
1129193323Sed	if (sopt->sopt_level != IPPROTO_IP) {
1130193323Sed		return (EINVAL);
1131193323Sed	}
1132193323Sed
1133193323Sed	switch (sopt->sopt_dir) {
1134193323Sed	case SOPT_SET:
1135193323Sed		switch (sopt->sopt_name) {
1136193323Sed		case IP_OPTIONS:
1137193323Sed#ifdef notyet
1138193323Sed		case IP_RETOPTS:
1139193323Sed#endif
1140193323Sed		{
1141198090Srdivacky			struct mbuf *m;
1142193323Sed			if (sopt->sopt_valsize > MLEN) {
1143193323Sed				error = EMSGSIZE;
1144198090Srdivacky				break;
1145193323Sed			}
1146193323Sed			MGET(m, sopt->sopt_td ? M_TRYWAIT : M_DONTWAIT, MT_HEADER);
1147193323Sed			if (m == 0) {
1148193323Sed				error = ENOBUFS;
1149193323Sed				break;
1150193323Sed			}
1151193323Sed			m->m_len = sopt->sopt_valsize;
1152194710Sed			error = sooptcopyin(sopt, mtod(m, char *), m->m_len,
1153194710Sed					    m->m_len);
1154194710Sed
1155194710Sed			return (ip_pcbopts(sopt->sopt_name, &inp->inp_options,
1156199481Srdivacky					   m));
1157194710Sed		}
1158194710Sed
1159194710Sed		case IP_TOS:
1160194710Sed		case IP_TTL:
1161194710Sed		case IP_RECVOPTS:
1162194710Sed		case IP_RECVRETOPTS:
1163194710Sed		case IP_RECVDSTADDR:
1164194710Sed		case IP_RECVIF:
1165194710Sed		case IP_FAITH:
1166194710Sed			error = sooptcopyin(sopt, &optval, sizeof optval,
1167194710Sed					    sizeof optval);
1168194710Sed			if (error)
1169194710Sed				break;
1170194710Sed
1171194710Sed			switch (sopt->sopt_name) {
1172194710Sed			case IP_TOS:
1173199481Srdivacky				inp->inp_ip_tos = optval;
1174193323Sed				break;
1175193323Sed
1176193323Sed			case IP_TTL:
1177193323Sed				inp->inp_ip_ttl = optval;
1178193323Sed				break;
1179193323Sed#define	OPTSET(bit) \
1180193323Sed	if (optval) \
1181193323Sed		inp->inp_flags |= bit; \
1182193323Sed	else \
1183193323Sed		inp->inp_flags &= ~bit;
1184193323Sed
1185193323Sed			case IP_RECVOPTS:
1186193323Sed				OPTSET(INP_RECVOPTS);
1187193323Sed				break;
1188193323Sed
1189193323Sed			case IP_RECVRETOPTS:
1190193323Sed				OPTSET(INP_RECVRETOPTS);
1191193323Sed				break;
1192193323Sed
1193193323Sed			case IP_RECVDSTADDR:
1194193323Sed				OPTSET(INP_RECVDSTADDR);
1195193323Sed				break;
1196193323Sed
1197193323Sed			case IP_RECVIF:
1198198090Srdivacky				OPTSET(INP_RECVIF);
1199193323Sed				break;
1200193323Sed
1201193323Sed			case IP_FAITH:
1202193323Sed				OPTSET(INP_FAITH);
1203193323Sed				break;
1204198090Srdivacky			}
1205193323Sed			break;
1206193323Sed#undef OPTSET
1207193323Sed
1208193323Sed		case IP_MULTICAST_IF:
1209193323Sed		case IP_MULTICAST_VIF:
1210193323Sed		case IP_MULTICAST_TTL:
1211193323Sed		case IP_MULTICAST_LOOP:
1212193323Sed		case IP_ADD_MEMBERSHIP:
1213193323Sed		case IP_DROP_MEMBERSHIP:
1214193323Sed			error = ip_setmoptions(sopt, &inp->inp_moptions);
1215193323Sed			break;
1216193323Sed
1217193323Sed		case IP_PORTRANGE:
1218198892Srdivacky			error = sooptcopyin(sopt, &optval, sizeof optval,
1219199481Srdivacky					    sizeof optval);
1220199481Srdivacky			if (error)
1221199481Srdivacky				break;
1222198892Srdivacky
1223198892Srdivacky			switch (optval) {
1224198892Srdivacky			case IP_PORTRANGE_DEFAULT:
1225198892Srdivacky				inp->inp_flags &= ~(INP_LOWPORT);
1226198892Srdivacky				inp->inp_flags &= ~(INP_HIGHPORT);
1227198892Srdivacky				break;
1228198892Srdivacky
1229198892Srdivacky			case IP_PORTRANGE_HIGH:
1230198892Srdivacky				inp->inp_flags &= ~(INP_LOWPORT);
1231199481Srdivacky				inp->inp_flags |= INP_HIGHPORT;
1232198892Srdivacky				break;
1233198892Srdivacky
1234198892Srdivacky			case IP_PORTRANGE_LOW:
1235198892Srdivacky				inp->inp_flags &= ~(INP_HIGHPORT);
1236198892Srdivacky				inp->inp_flags |= INP_LOWPORT;
1237198892Srdivacky				break;
1238198892Srdivacky
1239198892Srdivacky			default:
1240198892Srdivacky				error = EINVAL;
1241198892Srdivacky				break;
1242199481Srdivacky			}
1243198892Srdivacky			break;
1244198892Srdivacky
1245198892Srdivacky#ifdef IPSEC
1246193323Sed		case IP_IPSEC_POLICY:
1247193323Sed		{
1248193323Sed			caddr_t req;
1249193323Sed			size_t len = 0;
1250193323Sed			int priv;
1251198090Srdivacky			struct mbuf *m;
1252193323Sed			int optname;
1253199481Srdivacky
1254199481Srdivacky			if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */
1255199481Srdivacky				break;
1256193323Sed			if ((error = soopt_mcopyin(sopt, m)) != 0) /* XXX */
1257198090Srdivacky				break;
1258198090Srdivacky			priv = (sopt->sopt_td != NULL &&
1259193323Sed				suser_td(sopt->sopt_td) != 0) ? 0 : 1;
1260193323Sed			req = mtod(m, caddr_t);
1261198892Srdivacky			len = m->m_len;
1262198892Srdivacky			optname = sopt->sopt_name;
1263193323Sed			error = ipsec4_set_policy(inp, optname, req, len, priv);
1264193323Sed			m_freem(m);
1265199481Srdivacky			break;
1266193323Sed		}
1267193323Sed#endif /*IPSEC*/
1268193323Sed
1269193323Sed		default:
1270193323Sed			error = ENOPROTOOPT;
1271193323Sed			break;
1272198090Srdivacky		}
1273193323Sed		break;
1274193323Sed
1275193323Sed	case SOPT_GET:
1276198090Srdivacky		switch (sopt->sopt_name) {
1277198090Srdivacky		case IP_OPTIONS:
1278198090Srdivacky		case IP_RETOPTS:
1279201360Srdivacky			if (inp->inp_options)
1280201360Srdivacky				error = sooptcopyout(sopt,
1281193323Sed						     mtod(inp->inp_options,
1282193323Sed							  char *),
1283193323Sed						     inp->inp_options->m_len);
1284193323Sed			else
1285193323Sed				sopt->sopt_valsize = 0;
1286193323Sed			break;
1287193323Sed
1288193323Sed		case IP_TOS:
1289193323Sed		case IP_TTL:
1290193323Sed		case IP_RECVOPTS:
1291193323Sed		case IP_RECVRETOPTS:
1292193323Sed		case IP_RECVDSTADDR:
1293198090Srdivacky		case IP_RECVIF:
1294193323Sed		case IP_PORTRANGE:
1295193323Sed		case IP_FAITH:
1296193323Sed			switch (sopt->sopt_name) {
1297198090Srdivacky
1298199481Srdivacky			case IP_TOS:
1299199481Srdivacky				optval = inp->inp_ip_tos;
1300199481Srdivacky				break;
1301199481Srdivacky
1302193323Sed			case IP_TTL:
1303193323Sed				optval = inp->inp_ip_ttl;
1304198090Srdivacky				break;
1305198090Srdivacky
1306193323Sed#define	OPTBIT(bit)	(inp->inp_flags & bit ? 1 : 0)
1307193323Sed
1308198892Srdivacky			case IP_RECVOPTS:
1309198892Srdivacky				optval = OPTBIT(INP_RECVOPTS);
1310193323Sed				break;
1311193323Sed
1312199481Srdivacky			case IP_RECVRETOPTS:
1313193323Sed				optval = OPTBIT(INP_RECVRETOPTS);
1314193323Sed				break;
1315198892Srdivacky
1316198892Srdivacky			case IP_RECVDSTADDR:
1317193323Sed				optval = OPTBIT(INP_RECVDSTADDR);
1318193323Sed				break;
1319198090Srdivacky
1320193323Sed			case IP_RECVIF:
1321193323Sed				optval = OPTBIT(INP_RECVIF);
1322198892Srdivacky				break;
1323198892Srdivacky
1324193323Sed			case IP_PORTRANGE:
1325193323Sed				if (inp->inp_flags & INP_HIGHPORT)
1326193323Sed					optval = IP_PORTRANGE_HIGH;
1327193323Sed				else if (inp->inp_flags & INP_LOWPORT)
1328193323Sed					optval = IP_PORTRANGE_LOW;
1329193323Sed				else
1330193323Sed					optval = 0;
1331193323Sed				break;
1332193323Sed
1333193323Sed			case IP_FAITH:
1334193323Sed				optval = OPTBIT(INP_FAITH);
1335193323Sed				break;
1336193323Sed			}
1337193323Sed			error = sooptcopyout(sopt, &optval, sizeof optval);
1338193323Sed			break;
1339193323Sed
1340193323Sed		case IP_MULTICAST_IF:
1341193323Sed		case IP_MULTICAST_VIF:
1342193323Sed		case IP_MULTICAST_TTL:
1343193323Sed		case IP_MULTICAST_LOOP:
1344193323Sed		case IP_ADD_MEMBERSHIP:
1345193323Sed		case IP_DROP_MEMBERSHIP:
1346193323Sed			error = ip_getmoptions(sopt, inp->inp_moptions);
1347198090Srdivacky			break;
1348193323Sed
1349193323Sed#ifdef IPSEC
1350193323Sed		case IP_IPSEC_POLICY:
1351193323Sed		{
1352193323Sed			struct mbuf *m = NULL;
1353193323Sed			caddr_t req = NULL;
1354198090Srdivacky			size_t len = 0;
1355193323Sed
1356193323Sed			if (m != 0) {
1357193323Sed				req = mtod(m, caddr_t);
1358198090Srdivacky				len = m->m_len;
1359198090Srdivacky			}
1360193323Sed			error = ipsec4_get_policy(sotoinpcb(so), req, len, &m);
1361193323Sed			if (error == 0)
1362193323Sed				error = soopt_mcopyout(sopt, m); /* XXX */
1363193323Sed			if (error == 0)
1364198090Srdivacky				m_freem(m);
1365198090Srdivacky			break;
1366193323Sed		}
1367193323Sed#endif /*IPSEC*/
1368199989Srdivacky
1369199989Srdivacky		default:
1370199989Srdivacky			error = ENOPROTOOPT;
1371199989Srdivacky			break;
1372199989Srdivacky		}
1373199989Srdivacky		break;
1374199989Srdivacky	}
1375199989Srdivacky	return (error);
1376199989Srdivacky}
1377199989Srdivacky
1378199989Srdivacky/*
1379193323Sed * Set up IP options in pcb for insertion in output packets.
1380193323Sed * Store in mbuf with pointer in pcbopt, adding pseudo-option
1381193323Sed * with destination address if source routed.
1382193323Sed */
1383193323Sedstatic int
1384199481Srdivackyip_pcbopts(optname, pcbopt, m)
1385199481Srdivacky	int optname;
1386199481Srdivacky	struct mbuf **pcbopt;
1387198090Srdivacky	register struct mbuf *m;
1388193323Sed{
1389193323Sed	register int cnt, optlen;
1390193323Sed	register u_char *cp;
1391193323Sed	u_char opt;
1392193323Sed
1393193323Sed	/* turn off any old options */
1394193323Sed	if (*pcbopt)
1395199481Srdivacky		(void)m_free(*pcbopt);
1396198090Srdivacky	*pcbopt = 0;
1397198090Srdivacky	if (m == (struct mbuf *)0 || m->m_len == 0) {
1398198090Srdivacky		/*
1399193323Sed		 * Only turning off any previous options.
1400193323Sed		 */
1401193323Sed		if (m)
1402193323Sed			(void)m_free(m);
1403198892Srdivacky		return (0);
1404198892Srdivacky	}
1405193323Sed
1406193323Sed	if (m->m_len % sizeof(int32_t))
1407193323Sed		goto bad;
1408199481Srdivacky	/*
1409193323Sed	 * IP first-hop destination address will be stored before
1410193323Sed	 * actual options; move other options back
1411198090Srdivacky	 * and clear it when none present.
1412198090Srdivacky	 */
1413198892Srdivacky	if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
1414198892Srdivacky		goto bad;
1415193323Sed	cnt = m->m_len;
1416193323Sed	m->m_len += sizeof(struct in_addr);
1417193323Sed	cp = mtod(m, u_char *) + sizeof(struct in_addr);
1418193323Sed	ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
1419193323Sed	bzero(mtod(m, caddr_t), sizeof(struct in_addr));
1420193323Sed
1421193323Sed	for (; cnt > 0; cnt -= optlen, cp += optlen) {
1422193323Sed		opt = cp[IPOPT_OPTVAL];
1423199481Srdivacky		if (opt == IPOPT_EOL)
1424199481Srdivacky			break;
1425199481Srdivacky		if (opt == IPOPT_NOP)
1426198090Srdivacky			optlen = 1;
1427193323Sed		else {
1428193323Sed			if (cnt < IPOPT_OLEN + sizeof(*cp))
1429198090Srdivacky				goto bad;
1430198090Srdivacky			optlen = cp[IPOPT_OLEN];
1431198090Srdivacky			if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt)
1432193323Sed				goto bad;
1433193323Sed		}
1434198090Srdivacky		switch (opt) {
1435198090Srdivacky
1436199481Srdivacky		default:
1437193323Sed			break;
1438193323Sed
1439193323Sed		case IPOPT_LSRR:
1440193323Sed		case IPOPT_SSRR:
1441193323Sed			/*
1442193323Sed			 * user process specifies route as:
1443193323Sed			 *	->A->B->C->D
1444193323Sed			 * D must be our final destination (but we can't
1445193323Sed			 * check that since we may not have connected yet).
1446198090Srdivacky			 * A is first hop destination, which doesn't appear in
1447198090Srdivacky			 * actual IP option, but is stored before the options.
1448198090Srdivacky			 */
1449198090Srdivacky			if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
1450198090Srdivacky				goto bad;
1451198090Srdivacky			m->m_len -= sizeof(struct in_addr);
1452199481Srdivacky			cnt -= sizeof(struct in_addr);
1453199481Srdivacky			optlen -= sizeof(struct in_addr);
1454198090Srdivacky			cp[IPOPT_OLEN] = optlen;
1455198090Srdivacky			/*
1456198090Srdivacky			 * Move first hop before start of options.
1457198090Srdivacky			 */
1458198090Srdivacky			bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
1459198090Srdivacky			    sizeof(struct in_addr));
1460198090Srdivacky			/*
1461198090Srdivacky			 * Then copy rest of options back
1462198090Srdivacky			 * to close up the deleted entry.
1463198090Srdivacky			 */
1464198090Srdivacky			ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
1465198090Srdivacky			    sizeof(struct in_addr)),
1466198892Srdivacky			    (caddr_t)&cp[IPOPT_OFFSET+1],
1467198892Srdivacky			    (unsigned)cnt + sizeof(struct in_addr));
1468198090Srdivacky			break;
1469198090Srdivacky		}
1470198090Srdivacky	}
1471199481Srdivacky	if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
1472198090Srdivacky		goto bad;
1473198090Srdivacky	*pcbopt = m;
1474198090Srdivacky	return (0);
1475198090Srdivacky
1476193323Sedbad:
1477198090Srdivacky	(void)m_free(m);
1478193323Sed	return (EINVAL);
1479193323Sed}
1480193323Sed
1481200581Srdivacky/*
1482200581Srdivacky * XXX
1483200581Srdivacky * The whole multicast option thing needs to be re-thought.
1484200581Srdivacky * Several of these options are equally applicable to non-multicast
1485200581Srdivacky * transmission, and one (IP_MULTICAST_TTL) totally duplicates a
1486200581Srdivacky * standard option (IP_TTL).
1487200581Srdivacky */
1488200581Srdivacky
1489200581Srdivacky/*
1490200581Srdivacky * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index.
1491200581Srdivacky */
1492200581Srdivackystatic struct ifnet *
1493200581Srdivackyip_multicast_if(a, ifindexp)
1494200581Srdivacky	struct in_addr *a;
1495200581Srdivacky	int *ifindexp;
1496200581Srdivacky{
1497200581Srdivacky	int ifindex;
1498200581Srdivacky	struct ifnet *ifp;
1499200581Srdivacky
1500200581Srdivacky	if (ifindexp)
1501200581Srdivacky		*ifindexp = 0;
1502200581Srdivacky	if (ntohl(a->s_addr) >> 24 == 0) {
1503193323Sed		ifindex = ntohl(a->s_addr) & 0xffffff;
1504193323Sed		if (ifindex < 0 || if_index < ifindex)
1505193323Sed			return NULL;
1506193323Sed		ifp = ifnet_byindex(ifindex);
1507193323Sed		if (ifindexp)
1508198090Srdivacky			*ifindexp = ifindex;
1509193323Sed	} else {
1510193323Sed		INADDR_TO_IFP(*a, ifp);
1511193323Sed	}
1512193323Sed	return ifp;
1513193323Sed}
1514193323Sed
1515198090Srdivacky/*
1516198090Srdivacky * Set the IP multicast options in response to user setsockopt().
1517198090Srdivacky */
1518198090Srdivackystatic int
1519198090Srdivackyip_setmoptions(sopt, imop)
1520198090Srdivacky	struct sockopt *sopt;
1521198090Srdivacky	struct ip_moptions **imop;
1522198090Srdivacky{
1523198090Srdivacky	int error = 0;
1524198090Srdivacky	int i;
1525198090Srdivacky	struct in_addr addr;
1526198090Srdivacky	struct ip_mreq mreq;
1527198090Srdivacky	struct ifnet *ifp;
1528198090Srdivacky	struct ip_moptions *imo = *imop;
1529198090Srdivacky	struct route ro;
1530198090Srdivacky	struct sockaddr_in *dst;
1531198090Srdivacky	int ifindex;
1532198090Srdivacky	int s;
1533198090Srdivacky
1534198090Srdivacky	if (imo == NULL) {
1535198090Srdivacky		/*
1536198090Srdivacky		 * No multicast option buffer attached to the pcb;
1537198090Srdivacky		 * allocate one and initialize to default values.
1538198090Srdivacky		 */
1539198090Srdivacky		imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS,
1540198090Srdivacky		    M_WAITOK);
1541198090Srdivacky
1542198090Srdivacky		if (imo == NULL)
1543198090Srdivacky			return (ENOBUFS);
1544198090Srdivacky		*imop = imo;
1545198090Srdivacky		imo->imo_multicast_ifp = NULL;
1546198090Srdivacky		imo->imo_multicast_addr.s_addr = INADDR_ANY;
1547198090Srdivacky		imo->imo_multicast_vif = -1;
1548198090Srdivacky		imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
1549198090Srdivacky		imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
1550198090Srdivacky		imo->imo_num_memberships = 0;
1551198090Srdivacky	}
1552198090Srdivacky
1553198090Srdivacky	switch (sopt->sopt_name) {
1554198090Srdivacky	/* store an index number for the vif you wanna use in the send */
1555198090Srdivacky	case IP_MULTICAST_VIF:
1556198090Srdivacky		if (legal_vif_num == 0) {
1557198090Srdivacky			error = EOPNOTSUPP;
1558198090Srdivacky			break;
1559198090Srdivacky		}
1560198090Srdivacky		error = sooptcopyin(sopt, &i, sizeof i, sizeof i);
1561198090Srdivacky		if (error)
1562194710Sed			break;
1563194710Sed		if (!legal_vif_num(i) && (i != -1)) {
1564194710Sed			error = EINVAL;
1565194710Sed			break;
1566194710Sed		}
1567194710Sed		imo->imo_multicast_vif = i;
1568194710Sed		break;
1569198090Srdivacky
1570194710Sed	case IP_MULTICAST_IF:
1571194710Sed		/*
1572194710Sed		 * Select the interface for outgoing multicast packets.
1573194710Sed		 */
1574194710Sed		error = sooptcopyin(sopt, &addr, sizeof addr, sizeof addr);
1575194710Sed		if (error)
1576194710Sed			break;
1577194710Sed		/*
1578194710Sed		 * INADDR_ANY is used to remove a previous selection.
1579194710Sed		 * When no interface is selected, a default one is
1580194710Sed		 * chosen every time a multicast packet is sent.
1581194710Sed		 */
1582199481Srdivacky		if (addr.s_addr == INADDR_ANY) {
1583199481Srdivacky			imo->imo_multicast_ifp = NULL;
1584194710Sed			break;
1585194710Sed		}
1586194710Sed		/*
1587198892Srdivacky		 * The selected interface is identified by its local
1588198892Srdivacky		 * IP address.  Find the interface and confirm that
1589194710Sed		 * it supports multicasting.
1590194710Sed		 */
1591194710Sed		s = splimp();
1592194710Sed		ifp = ip_multicast_if(&addr, &ifindex);
1593194710Sed		if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
1594199481Srdivacky			splx(s);
1595194710Sed			error = EADDRNOTAVAIL;
1596194710Sed			break;
1597194710Sed		}
1598198090Srdivacky		imo->imo_multicast_ifp = ifp;
1599198090Srdivacky		if (ifindex)
1600198090Srdivacky			imo->imo_multicast_addr = addr;
1601198090Srdivacky		else
1602198090Srdivacky			imo->imo_multicast_addr.s_addr = INADDR_ANY;
1603198090Srdivacky		splx(s);
1604198090Srdivacky		break;
1605193323Sed
1606193323Sed	case IP_MULTICAST_TTL:
1607193323Sed		/*
1608193323Sed		 * Set the IP time-to-live for outgoing multicast packets.
1609193323Sed		 * The original multicast API required a char argument,
1610193323Sed		 * which is inconsistent with the rest of the socket API.
1611193323Sed		 * We allow either a char or an int.
1612198090Srdivacky		 */
1613198090Srdivacky		if (sopt->sopt_valsize == 1) {
1614198090Srdivacky			u_char ttl;
1615198090Srdivacky			error = sooptcopyin(sopt, &ttl, 1, 1);
1616198090Srdivacky			if (error)
1617193323Sed				break;
1618193323Sed			imo->imo_multicast_ttl = ttl;
1619193323Sed		} else {
1620193323Sed			u_int ttl;
1621193323Sed			error = sooptcopyin(sopt, &ttl, sizeof ttl,
1622193323Sed					    sizeof ttl);
1623193323Sed			if (error)
1624193323Sed				break;
1625198090Srdivacky			if (ttl > 255)
1626193323Sed				error = EINVAL;
1627194710Sed			else
1628194710Sed				imo->imo_multicast_ttl = ttl;
1629194710Sed		}
1630194710Sed		break;
1631193323Sed
1632193323Sed	case IP_MULTICAST_LOOP:
1633194710Sed		/*
1634194710Sed		 * Set the loopback flag for outgoing multicast packets.
1635198090Srdivacky		 * Must be zero or one.  The original multicast API required a
1636194710Sed		 * char argument, which is inconsistent with the rest
1637194710Sed		 * of the socket API.  We allow either a char or an int.
1638198090Srdivacky		 */
1639194710Sed		if (sopt->sopt_valsize == 1) {
1640194710Sed			u_char loop;
1641194710Sed			error = sooptcopyin(sopt, &loop, 1, 1);
1642194710Sed			if (error)
1643194710Sed				break;
1644194710Sed			imo->imo_multicast_loop = !!loop;
1645198090Srdivacky		} else {
1646193323Sed			u_int loop;
1647194710Sed			error = sooptcopyin(sopt, &loop, sizeof loop,
1648194710Sed					    sizeof loop);
1649198090Srdivacky			if (error)
1650198090Srdivacky				break;
1651194710Sed			imo->imo_multicast_loop = !!loop;
1652198090Srdivacky		}
1653194710Sed		break;
1654198090Srdivacky
1655198090Srdivacky	case IP_ADD_MEMBERSHIP:
1656198090Srdivacky		/*
1657198090Srdivacky		 * Add a multicast group membership.
1658198090Srdivacky		 * Group must be a valid IP multicast address.
1659194710Sed		 */
1660198090Srdivacky		error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq);
1661193323Sed		if (error)
1662194710Sed			break;
1663194710Sed
1664198090Srdivacky		if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) {
1665193323Sed			error = EINVAL;
1666193323Sed			break;
1667193323Sed		}
1668193323Sed		s = splimp();
1669193323Sed		/*
1670193323Sed		 * If no interface address was provided, use the interface of
1671198090Srdivacky		 * the route to the given multicast address.
1672193323Sed		 */
1673193323Sed		if (mreq.imr_interface.s_addr == INADDR_ANY) {
1674193323Sed			bzero((caddr_t)&ro, sizeof(ro));
1675193323Sed			dst = (struct sockaddr_in *)&ro.ro_dst;
1676193323Sed			dst->sin_len = sizeof(*dst);
1677193323Sed			dst->sin_family = AF_INET;
1678193323Sed			dst->sin_addr = mreq.imr_multiaddr;
1679193323Sed			rtalloc(&ro);
1680193323Sed			if (ro.ro_rt == NULL) {
1681193323Sed				error = EADDRNOTAVAIL;
1682193323Sed				splx(s);
1683193323Sed				break;
1684193323Sed			}
1685193323Sed			ifp = ro.ro_rt->rt_ifp;
1686193323Sed			rtfree(ro.ro_rt);
1687193323Sed		}
1688198090Srdivacky		else {
1689193323Sed			ifp = ip_multicast_if(&mreq.imr_interface, NULL);
1690193323Sed		}
1691193323Sed
1692193323Sed		/*
1693193323Sed		 * See if we found an interface, and confirm that it
1694193323Sed		 * supports multicast.
1695193323Sed		 */
1696193323Sed		if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
1697199481Srdivacky			error = EADDRNOTAVAIL;
1698199481Srdivacky			splx(s);
1699193323Sed			break;
1700193323Sed		}
1701193323Sed		/*
1702198892Srdivacky		 * See if the membership already exists or if all the
1703198892Srdivacky		 * membership slots are full.
1704193323Sed		 */
1705193323Sed		for (i = 0; i < imo->imo_num_memberships; ++i) {
1706193323Sed			if (imo->imo_membership[i]->inm_ifp == ifp &&
1707193323Sed			    imo->imo_membership[i]->inm_addr.s_addr
1708193323Sed						== mreq.imr_multiaddr.s_addr)
1709193323Sed				break;
1710193323Sed		}
1711193323Sed		if (i < imo->imo_num_memberships) {
1712193323Sed			error = EADDRINUSE;
1713193323Sed			splx(s);
1714193323Sed			break;
1715193323Sed		}
1716193323Sed		if (i == IP_MAX_MEMBERSHIPS) {
1717193323Sed			error = ETOOMANYREFS;
1718193323Sed			splx(s);
1719198892Srdivacky			break;
1720193323Sed		}
1721193323Sed		/*
1722193323Sed		 * Everything looks good; add a new record to the multicast
1723193323Sed		 * address list for the given interface.
1724193323Sed		 */
1725193323Sed		if ((imo->imo_membership[i] =
1726199481Srdivacky		    in_addmulti(&mreq.imr_multiaddr, ifp)) == NULL) {
1727199481Srdivacky			error = ENOBUFS;
1728193323Sed			splx(s);
1729193323Sed			break;
1730193323Sed		}
1731193323Sed		++imo->imo_num_memberships;
1732193323Sed		splx(s);
1733198090Srdivacky		break;
1734193323Sed
1735193323Sed	case IP_DROP_MEMBERSHIP:
1736193323Sed		/*
1737193323Sed		 * Drop a multicast group membership.
1738193323Sed		 * Group must be a valid IP multicast address.
1739198090Srdivacky		 */
1740198892Srdivacky		error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq);
1741198892Srdivacky		if (error)
1742193323Sed			break;
1743193323Sed
1744193323Sed		if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) {
1745193323Sed			error = EINVAL;
1746193323Sed			break;
1747198090Srdivacky		}
1748198090Srdivacky
1749193323Sed		s = splimp();
1750193323Sed		/*
1751199481Srdivacky		 * If an interface address was specified, get a pointer
1752193323Sed		 * to its ifnet structure.
1753193323Sed		 */
1754198090Srdivacky		if (mreq.imr_interface.s_addr == INADDR_ANY)
1755193323Sed			ifp = NULL;
1756193323Sed		else {
1757193323Sed			ifp = ip_multicast_if(&mreq.imr_interface, NULL);
1758193323Sed			if (ifp == NULL) {
1759193323Sed				error = EADDRNOTAVAIL;
1760193323Sed				splx(s);
1761193323Sed				break;
1762193323Sed			}
1763193323Sed		}
1764193323Sed		/*
1765193323Sed		 * Find the membership in the membership array.
1766193323Sed		 */
1767193323Sed		for (i = 0; i < imo->imo_num_memberships; ++i) {
1768193323Sed			if ((ifp == NULL ||
1769193323Sed			     imo->imo_membership[i]->inm_ifp == ifp) &&
1770193323Sed			     imo->imo_membership[i]->inm_addr.s_addr ==
1771193323Sed			     mreq.imr_multiaddr.s_addr)
1772193323Sed				break;
1773193323Sed		}
1774193323Sed		if (i == imo->imo_num_memberships) {
1775199481Srdivacky			error = EADDRNOTAVAIL;
1776199481Srdivacky			splx(s);
1777199481Srdivacky			break;
1778193323Sed		}
1779193323Sed		/*
1780199481Srdivacky		 * Give up the multicast address record to which the
1781193323Sed		 * membership points.
1782193323Sed		 */
1783193323Sed		in_delmulti(imo->imo_membership[i]);
1784193323Sed		/*
1785193323Sed		 * Remove the gap in the membership array.
1786199481Srdivacky		 */
1787193323Sed		for (++i; i < imo->imo_num_memberships; ++i)
1788193323Sed			imo->imo_membership[i-1] = imo->imo_membership[i];
1789193323Sed		--imo->imo_num_memberships;
1790193323Sed		splx(s);
1791193323Sed		break;
1792193323Sed
1793199481Srdivacky	default:
1794193323Sed		error = EOPNOTSUPP;
1795193323Sed		break;
1796193323Sed	}
1797193323Sed
1798193323Sed	/*
1799193323Sed	 * If all options have default values, no need to keep the mbuf.
1800199481Srdivacky	 */
1801193323Sed	if (imo->imo_multicast_ifp == NULL &&
1802193323Sed	    imo->imo_multicast_vif == -1 &&
1803193323Sed	    imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
1804193323Sed	    imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
1805193323Sed	    imo->imo_num_memberships == 0) {
1806193323Sed		free(*imop, M_IPMOPTS);
1807199481Srdivacky		*imop = NULL;
1808193323Sed	}
1809193323Sed
1810193323Sed	return (error);
1811193323Sed}
1812193323Sed
1813193323Sed/*
1814193323Sed * Return the IP multicast options in response to user getsockopt().
1815193323Sed */
1816193323Sedstatic int
1817193323Sedip_getmoptions(sopt, imo)
1818193323Sed	struct sockopt *sopt;
1819193323Sed	register struct ip_moptions *imo;
1820193323Sed{
1821193323Sed	struct in_addr addr;
1822193323Sed	struct in_ifaddr *ia;
1823193323Sed	int error, optval;
1824195340Sed	u_char coptval;
1825195340Sed
1826193323Sed	error = 0;
1827193323Sed	switch (sopt->sopt_name) {
1828193323Sed	case IP_MULTICAST_VIF:
1829193323Sed		if (imo != NULL)
1830193323Sed			optval = imo->imo_multicast_vif;
1831193323Sed		else
1832193323Sed			optval = -1;
1833193323Sed		error = sooptcopyout(sopt, &optval, sizeof optval);
1834193323Sed		break;
1835193323Sed
1836193323Sed	case IP_MULTICAST_IF:
1837193323Sed		if (imo == NULL || imo->imo_multicast_ifp == NULL)
1838193323Sed			addr.s_addr = INADDR_ANY;
1839193323Sed		else if (imo->imo_multicast_addr.s_addr) {
1840193323Sed			/* return the value user has set */
1841193323Sed			addr = imo->imo_multicast_addr;
1842193323Sed		} else {
1843199481Srdivacky			IFP_TO_IA(imo->imo_multicast_ifp, ia);
1844198090Srdivacky			addr.s_addr = (ia == NULL) ? INADDR_ANY
1845193323Sed				: IA_SIN(ia)->sin_addr.s_addr;
1846193323Sed		}
1847193323Sed		error = sooptcopyout(sopt, &addr, sizeof addr);
1848193323Sed		break;
1849193323Sed
1850193323Sed	case IP_MULTICAST_TTL:
1851193323Sed		if (imo == 0)
1852193323Sed			optval = coptval = IP_DEFAULT_MULTICAST_TTL;
1853193323Sed		else
1854193323Sed			optval = coptval = imo->imo_multicast_ttl;
1855199481Srdivacky		if (sopt->sopt_valsize == 1)
1856193323Sed			error = sooptcopyout(sopt, &coptval, 1);
1857193323Sed		else
1858193323Sed			error = sooptcopyout(sopt, &optval, sizeof optval);
1859193323Sed		break;
1860198090Srdivacky
1861193323Sed	case IP_MULTICAST_LOOP:
1862193323Sed		if (imo == 0)
1863193323Sed			optval = coptval = IP_DEFAULT_MULTICAST_LOOP;
1864193323Sed		else
1865193323Sed			optval = coptval = imo->imo_multicast_loop;
1866193323Sed		if (sopt->sopt_valsize == 1)
1867193323Sed			error = sooptcopyout(sopt, &coptval, 1);
1868193323Sed		else
1869193323Sed			error = sooptcopyout(sopt, &optval, sizeof optval);
1870193323Sed		break;
1871193323Sed
1872193323Sed	default:
1873193323Sed		error = ENOPROTOOPT;
1874193323Sed		break;
1875193323Sed	}
1876193323Sed	return (error);
1877199481Srdivacky}
1878193323Sed
1879193323Sed/*
1880193323Sed * Discard the IP multicast options.
1881193323Sed */
1882193323Sedvoid
1883193323Sedip_freemoptions(imo)
1884193323Sed	register struct ip_moptions *imo;
1885193323Sed{
1886193323Sed	register int i;
1887193323Sed
1888199481Srdivacky	if (imo != NULL) {
1889193323Sed		for (i = 0; i < imo->imo_num_memberships; ++i)
1890193323Sed			in_delmulti(imo->imo_membership[i]);
1891193323Sed		free(imo, M_IPMOPTS);
1892193323Sed	}
1893193323Sed}
1894193323Sed
1895198090Srdivacky/*
1896193323Sed * Routine called from ip_output() to loop back a copy of an IP multicast
1897193323Sed * packet to the input queue of a specified interface.  Note that this
1898193323Sed * calls the output routine of the loopback "driver", but with an interface
1899193323Sed * pointer that might NOT be a loopback interface -- evil, but easier than
1900193323Sed * replicating that code here.
1901193323Sed */
1902193323Sedstatic void
1903193323Sedip_mloopback(ifp, m, dst, hlen)
1904193323Sed	struct ifnet *ifp;
1905193323Sed	register struct mbuf *m;
1906193323Sed	register struct sockaddr_in *dst;
1907193323Sed	int hlen;
1908193323Sed{
1909193323Sed	register struct ip *ip;
1910193323Sed	struct mbuf *copym;
1911193323Sed
1912193323Sed	copym = m_copy(m, 0, M_COPYALL);
1913193323Sed	if (copym != NULL && (copym->m_flags & M_EXT || copym->m_len < hlen))
1914193323Sed		copym = m_pullup(copym, hlen);
1915193323Sed	if (copym != NULL) {
1916193323Sed		/*
1917198090Srdivacky		 * We don't bother to fragment if the IP length is greater
1918193323Sed		 * than the interface's MTU.  Can this possibly matter?
1919193323Sed		 */
1920198090Srdivacky		ip = mtod(copym, struct ip *);
1921193323Sed		HTONS(ip->ip_len);
1922193323Sed		HTONS(ip->ip_off);
1923193323Sed		ip->ip_sum = 0;
1924193323Sed		if (ip->ip_vhl == IP_VHL_BORING) {
1925198090Srdivacky			ip->ip_sum = in_cksum_hdr(ip);
1926198090Srdivacky		} else {
1927198090Srdivacky			ip->ip_sum = in_cksum(copym, hlen);
1928198090Srdivacky		}
1929198090Srdivacky		/*
1930198090Srdivacky		 * NB:
1931198090Srdivacky		 * It's not clear whether there are any lingering
1932198090Srdivacky		 * reentrancy problems in other areas which might
1933198090Srdivacky		 * be exposed by using ip_input directly (in
1934198892Srdivacky		 * particular, everything which modifies the packet
1935198892Srdivacky		 * in-place).  Yet another option is using the
1936198090Srdivacky		 * protosw directly to deliver the looped back
1937193323Sed		 * packet.  For the moment, we'll err on the side
1938198090Srdivacky		 * of safety by using if_simloop().
1939198090Srdivacky		 */
1940198892Srdivacky#if 1 /* XXX */
1941198892Srdivacky		if (dst->sin_family != AF_INET) {
1942198090Srdivacky			printf("ip_mloopback: bad address family %d\n",
1943198090Srdivacky						dst->sin_family);
1944198090Srdivacky			dst->sin_family = AF_INET;
1945193323Sed		}
1946193323Sed#endif
1947193323Sed
1948193323Sed#ifdef notdef
1949193323Sed		copym->m_pkthdr.rcvif = ifp;
1950193323Sed		ip_input(copym);
1951193323Sed#else
1952193323Sed		/* if the checksum hasn't been computed, mark it as valid */
1953193323Sed		if (copym->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
1954193323Sed			copym->m_pkthdr.csum_flags |=
1955193323Sed			    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
1956198090Srdivacky			copym->m_pkthdr.csum_data = 0xffff;
1957193323Sed		}
1958193323Sed		if_simloop(ifp, copym, dst->sin_family, 0);
1959193323Sed#endif
1960193323Sed	}
1961193323Sed}
1962193323Sed