Deleted Added
full compact
ip_input.c (54221) ip_input.c (55009)
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
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 * $FreeBSD: head/sys/netinet/ip_input.c 54221 1999-12-06 20:36:50Z guido $
34 * $FreeBSD: head/sys/netinet/ip_input.c 55009 1999-12-22 19:13:38Z shin $
35 */
36
37#define _IP_VHL
38
39#include "opt_bootp.h"
40#include "opt_ipfw.h"
41#include "opt_ipdn.h"
42#include "opt_ipdivert.h"
43#include "opt_ipfilter.h"
44#include "opt_ipstealth.h"
35 */
36
37#define _IP_VHL
38
39#include "opt_bootp.h"
40#include "opt_ipfw.h"
41#include "opt_ipdn.h"
42#include "opt_ipdivert.h"
43#include "opt_ipfilter.h"
44#include "opt_ipstealth.h"
45#include "opt_ipsec.h"
45
46#include <stddef.h>
47
48#include <sys/param.h>
49#include <sys/systm.h>
50#include <sys/mbuf.h>
51#include <sys/malloc.h>
52#include <sys/domain.h>
53#include <sys/protosw.h>
54#include <sys/socket.h>
55#include <sys/time.h>
56#include <sys/kernel.h>
57#include <sys/syslog.h>
58#include <sys/sysctl.h>
59
60#include <net/if.h>
61#include <net/if_var.h>
62#include <net/if_dl.h>
63#include <net/route.h>
64#include <net/netisr.h>
65
66#include <netinet/in.h>
67#include <netinet/in_systm.h>
68#include <netinet/in_var.h>
69#include <netinet/ip.h>
70#include <netinet/in_pcb.h>
71#include <netinet/ip_var.h>
72#include <netinet/ip_icmp.h>
73#include <machine/in_cksum.h>
74
46
47#include <stddef.h>
48
49#include <sys/param.h>
50#include <sys/systm.h>
51#include <sys/mbuf.h>
52#include <sys/malloc.h>
53#include <sys/domain.h>
54#include <sys/protosw.h>
55#include <sys/socket.h>
56#include <sys/time.h>
57#include <sys/kernel.h>
58#include <sys/syslog.h>
59#include <sys/sysctl.h>
60
61#include <net/if.h>
62#include <net/if_var.h>
63#include <net/if_dl.h>
64#include <net/route.h>
65#include <net/netisr.h>
66
67#include <netinet/in.h>
68#include <netinet/in_systm.h>
69#include <netinet/in_var.h>
70#include <netinet/ip.h>
71#include <netinet/in_pcb.h>
72#include <netinet/ip_var.h>
73#include <netinet/ip_icmp.h>
74#include <machine/in_cksum.h>
75
76#include <netinet/ipprotosw.h>
77
75#include <sys/socketvar.h>
76
77#include <netinet/ip_fw.h>
78
78#include <sys/socketvar.h>
79
80#include <netinet/ip_fw.h>
81
82#ifdef IPSEC
83#include <netinet6/ipsec.h>
84#include <netkey/key.h>
85#ifdef IPSEC_DEBUG
86#include <netkey/key_debug.h>
87#else
88#define KEYDEBUG(lev,arg)
89#endif
90#endif
91
92#include "faith.h"
93#if defined(NFAITH) && NFAITH > 0
94#include <net/if_types.h>
95#endif
96
79#ifdef DUMMYNET
80#include <netinet/ip_dummynet.h>
81#endif
82
83int rsvp_on = 0;
84static int ip_rsvp_on;
85struct socket *ip_rsvpd;
86
87int ipforwarding = 0;
88SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW,
89 &ipforwarding, 0, "Enable IP forwarding between interfaces");
90
91static int ipsendredirects = 1; /* XXX */
92SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW,
93 &ipsendredirects, 0, "Enable sending IP redirects");
94
95int ip_defttl = IPDEFTTL;
96SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW,
97 &ip_defttl, 0, "Maximum TTL on IP packets");
98
99static int ip_dosourceroute = 0;
100SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW,
101 &ip_dosourceroute, 0, "Enable forwarding source routed IP packets");
102
103static int ip_acceptsourceroute = 0;
104SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute,
105 CTLFLAG_RW, &ip_acceptsourceroute, 0,
106 "Enable accepting source routed IP packets");
97#ifdef DUMMYNET
98#include <netinet/ip_dummynet.h>
99#endif
100
101int rsvp_on = 0;
102static int ip_rsvp_on;
103struct socket *ip_rsvpd;
104
105int ipforwarding = 0;
106SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW,
107 &ipforwarding, 0, "Enable IP forwarding between interfaces");
108
109static int ipsendredirects = 1; /* XXX */
110SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW,
111 &ipsendredirects, 0, "Enable sending IP redirects");
112
113int ip_defttl = IPDEFTTL;
114SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW,
115 &ip_defttl, 0, "Maximum TTL on IP packets");
116
117static int ip_dosourceroute = 0;
118SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW,
119 &ip_dosourceroute, 0, "Enable forwarding source routed IP packets");
120
121static int ip_acceptsourceroute = 0;
122SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute,
123 CTLFLAG_RW, &ip_acceptsourceroute, 0,
124 "Enable accepting source routed IP packets");
125
126static int ip_keepfaith = 0;
127SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW,
128 &ip_keepfaith, 0,
129 "Enable packet capture for FAITH IPv4->IPv6 translater daemon");
130
107#ifdef DIAGNOSTIC
108static int ipprintfs = 0;
109#endif
110
111extern struct domain inetdomain;
131#ifdef DIAGNOSTIC
132static int ipprintfs = 0;
133#endif
134
135extern struct domain inetdomain;
112extern struct protosw inetsw[];
136extern struct ipprotosw inetsw[];
113u_char ip_protox[IPPROTO_MAX];
114static int ipqmaxlen = IFQ_MAXLEN;
115struct in_ifaddrhead in_ifaddrhead; /* first inet address */
116struct ifqueue ipintrq;
117SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW,
118 &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue");
119SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD,
120 &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue");
121
122struct ipstat ipstat;
123SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RD,
124 &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)");
125
126/* Packet reassembly stuff */
127#define IPREASS_NHASH_LOG2 6
128#define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2)
129#define IPREASS_HMASK (IPREASS_NHASH - 1)
130#define IPREASS_HASH(x,y) \
131 (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK)
132
133static struct ipq ipq[IPREASS_NHASH];
134static int nipq = 0; /* total # of reass queues */
135static int maxnipq;
136
137#ifdef IPCTL_DEFMTU
138SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW,
139 &ip_mtu, 0, "Default MTU");
140#endif
141
142#ifdef IPSTEALTH
143static int ipstealth = 0;
144SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW,
145 &ipstealth, 0, "");
146#endif
147
148
149/* Firewall hooks */
150ip_fw_chk_t *ip_fw_chk_ptr;
151ip_fw_ctl_t *ip_fw_ctl_ptr;
152
153#ifdef DUMMYNET
154ip_dn_ctl_t *ip_dn_ctl_ptr;
155#endif
156
157#if defined(IPFILTER_LKM) || defined(IPFILTER)
158int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)) = NULL;
159#endif
160
161
162/*
163 * We need to save the IP options in case a protocol wants to respond
164 * to an incoming packet over the same route if the packet got here
165 * using IP source routing. This allows connection establishment and
166 * maintenance when the remote end is on a network that is not known
167 * to us.
168 */
169static int ip_nhops = 0;
170static struct ip_srcrt {
171 struct in_addr dst; /* final destination */
172 char nop; /* one NOP to align */
173 char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */
174 struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
175} ip_srcrt;
176
177struct sockaddr_in *ip_fw_fwd_addr;
178
179static void save_rte __P((u_char *, struct in_addr));
180static int ip_dooptions __P((struct mbuf *));
181static void ip_forward __P((struct mbuf *, int));
182static void ip_freef __P((struct ipq *));
183#ifdef IPDIVERT
137u_char ip_protox[IPPROTO_MAX];
138static int ipqmaxlen = IFQ_MAXLEN;
139struct in_ifaddrhead in_ifaddrhead; /* first inet address */
140struct ifqueue ipintrq;
141SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW,
142 &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue");
143SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD,
144 &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue");
145
146struct ipstat ipstat;
147SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RD,
148 &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)");
149
150/* Packet reassembly stuff */
151#define IPREASS_NHASH_LOG2 6
152#define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2)
153#define IPREASS_HMASK (IPREASS_NHASH - 1)
154#define IPREASS_HASH(x,y) \
155 (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK)
156
157static struct ipq ipq[IPREASS_NHASH];
158static int nipq = 0; /* total # of reass queues */
159static int maxnipq;
160
161#ifdef IPCTL_DEFMTU
162SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW,
163 &ip_mtu, 0, "Default MTU");
164#endif
165
166#ifdef IPSTEALTH
167static int ipstealth = 0;
168SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW,
169 &ipstealth, 0, "");
170#endif
171
172
173/* Firewall hooks */
174ip_fw_chk_t *ip_fw_chk_ptr;
175ip_fw_ctl_t *ip_fw_ctl_ptr;
176
177#ifdef DUMMYNET
178ip_dn_ctl_t *ip_dn_ctl_ptr;
179#endif
180
181#if defined(IPFILTER_LKM) || defined(IPFILTER)
182int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)) = NULL;
183#endif
184
185
186/*
187 * We need to save the IP options in case a protocol wants to respond
188 * to an incoming packet over the same route if the packet got here
189 * using IP source routing. This allows connection establishment and
190 * maintenance when the remote end is on a network that is not known
191 * to us.
192 */
193static int ip_nhops = 0;
194static struct ip_srcrt {
195 struct in_addr dst; /* final destination */
196 char nop; /* one NOP to align */
197 char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */
198 struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
199} ip_srcrt;
200
201struct sockaddr_in *ip_fw_fwd_addr;
202
203static void save_rte __P((u_char *, struct in_addr));
204static int ip_dooptions __P((struct mbuf *));
205static void ip_forward __P((struct mbuf *, int));
206static void ip_freef __P((struct ipq *));
207#ifdef IPDIVERT
184static struct ip *ip_reass __P((struct mbuf *,
208static struct mbuf *ip_reass __P((struct mbuf *,
185 struct ipq *, struct ipq *, u_int32_t *, u_int16_t *));
186#else
209 struct ipq *, struct ipq *, u_int32_t *, u_int16_t *));
210#else
187static struct ip *ip_reass __P((struct mbuf *, struct ipq *, struct ipq *));
211static struct mbuf *ip_reass __P((struct mbuf *, struct ipq *, struct ipq *));
188#endif
189static struct in_ifaddr *ip_rtaddr __P((struct in_addr));
190static void ipintr __P((void));
191
192/*
193 * IP initialization: fill in IP protocol switch table.
194 * All protocols not implemented in kernel go to raw IP protocol handler.
195 */
196void
197ip_init()
198{
212#endif
213static struct in_ifaddr *ip_rtaddr __P((struct in_addr));
214static void ipintr __P((void));
215
216/*
217 * IP initialization: fill in IP protocol switch table.
218 * All protocols not implemented in kernel go to raw IP protocol handler.
219 */
220void
221ip_init()
222{
199 register struct protosw *pr;
223 register struct ipprotosw *pr;
200 register int i;
201
202 TAILQ_INIT(&in_ifaddrhead);
224 register int i;
225
226 TAILQ_INIT(&in_ifaddrhead);
203 pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
227 pr = (struct ipprotosw *)pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
204 if (pr == 0)
205 panic("ip_init");
206 for (i = 0; i < IPPROTO_MAX; i++)
207 ip_protox[i] = pr - inetsw;
228 if (pr == 0)
229 panic("ip_init");
230 for (i = 0; i < IPPROTO_MAX; i++)
231 ip_protox[i] = pr - inetsw;
208 for (pr = inetdomain.dom_protosw;
209 pr < inetdomain.dom_protoswNPROTOSW; pr++)
232 for (pr = (struct ipprotosw *)inetdomain.dom_protosw;
233 pr < (struct ipprotosw *)inetdomain.dom_protoswNPROTOSW; pr++)
210 if (pr->pr_domain->dom_family == PF_INET &&
211 pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
212 ip_protox[pr->pr_protocol] = pr - inetsw;
213
214 for (i = 0; i < IPREASS_NHASH; i++)
215 ipq[i].next = ipq[i].prev = &ipq[i];
216
217 maxnipq = nmbclusters/4;
218
219 ip_id = time_second & 0xffff;
220 ipintrq.ifq_maxlen = ipqmaxlen;
221}
222
223static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
224static struct route ipforward_rt;
225
226/*
227 * Ip input routine. Checksum and byte swap header. If fragmented
228 * try to reassemble. Process options. Pass to next level.
229 */
230void
231ip_input(struct mbuf *m)
232{
233 struct ip *ip;
234 struct ipq *fp;
235 struct in_ifaddr *ia;
236 int i, hlen, mff;
237 u_short sum;
238 u_int16_t divert_cookie; /* firewall cookie */
239#ifdef IPDIVERT
240 u_int32_t divert_info = 0; /* packet divert/tee info */
241#endif
242 struct ip_fw_chain *rule = NULL;
243
244#ifdef IPDIVERT
245 /* Get and reset firewall cookie */
246 divert_cookie = ip_divert_cookie;
247 ip_divert_cookie = 0;
248#else
249 divert_cookie = 0;
250#endif
251
252#if defined(IPFIREWALL) && defined(DUMMYNET)
253 /*
254 * dummynet packet are prepended a vestigial mbuf with
255 * m_type = MT_DUMMYNET and m_data pointing to the matching
256 * rule.
257 */
258 if (m->m_type == MT_DUMMYNET) {
259 rule = (struct ip_fw_chain *)(m->m_data) ;
260 m = m->m_next ;
261 ip = mtod(m, struct ip *);
262 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
263 goto iphack ;
264 } else
265 rule = NULL ;
266#endif
267
268#ifdef DIAGNOSTIC
269 if (m == NULL || (m->m_flags & M_PKTHDR) == 0)
270 panic("ip_input no HDR");
271#endif
272 ipstat.ips_total++;
273
274 if (m->m_pkthdr.len < sizeof(struct ip))
275 goto tooshort;
276
277 if (m->m_len < sizeof (struct ip) &&
278 (m = m_pullup(m, sizeof (struct ip))) == 0) {
279 ipstat.ips_toosmall++;
280 return;
281 }
282 ip = mtod(m, struct ip *);
283
284 if (IP_VHL_V(ip->ip_vhl) != IPVERSION) {
285 ipstat.ips_badvers++;
286 goto bad;
287 }
288
289 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
290 if (hlen < sizeof(struct ip)) { /* minimum header length */
291 ipstat.ips_badhlen++;
292 goto bad;
293 }
294 if (hlen > m->m_len) {
295 if ((m = m_pullup(m, hlen)) == 0) {
296 ipstat.ips_badhlen++;
297 return;
298 }
299 ip = mtod(m, struct ip *);
300 }
301 if (hlen == sizeof(struct ip)) {
302 sum = in_cksum_hdr(ip);
303 } else {
304 sum = in_cksum(m, hlen);
305 }
306 if (sum) {
307 ipstat.ips_badsum++;
308 goto bad;
309 }
310
311 /*
312 * Convert fields to host representation.
313 */
314 NTOHS(ip->ip_len);
315 if (ip->ip_len < hlen) {
316 ipstat.ips_badlen++;
317 goto bad;
318 }
319 NTOHS(ip->ip_id);
320 NTOHS(ip->ip_off);
321
322 /*
323 * Check that the amount of data in the buffers
324 * is as at least much as the IP header would have us expect.
325 * Trim mbufs if longer than we expect.
326 * Drop packet if shorter than we expect.
327 */
328 if (m->m_pkthdr.len < ip->ip_len) {
329tooshort:
330 ipstat.ips_tooshort++;
331 goto bad;
332 }
333 if (m->m_pkthdr.len > ip->ip_len) {
334 if (m->m_len == m->m_pkthdr.len) {
335 m->m_len = ip->ip_len;
336 m->m_pkthdr.len = ip->ip_len;
337 } else
338 m_adj(m, ip->ip_len - m->m_pkthdr.len);
339 }
340 /*
341 * IpHack's section.
342 * Right now when no processing on packet has done
343 * and it is still fresh out of network we do our black
344 * deals with it.
345 * - Firewall: deny/allow/divert
346 * - Xlate: translate packet's addr/port (NAT).
347 * - Pipe: pass pkt through dummynet.
348 * - Wrap: fake packet's addr/port <unimpl.>
349 * - Encapsulate: put it in another IP and send out. <unimp.>
350 */
351
352#if defined(IPFIREWALL) && defined(DUMMYNET)
353iphack:
354#endif
355#if defined(IPFILTER) || defined(IPFILTER_LKM)
356 /*
357 * Check if we want to allow this packet to be processed.
358 * Consider it to be bad if not.
359 */
360 if (fr_checkp) {
361 struct mbuf *m1 = m;
362
363 if ((*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m1) || !m1)
364 return;
365 ip = mtod(m = m1, struct ip *);
366 }
367#endif
368 if (ip_fw_chk_ptr) {
369#ifdef IPFIREWALL_FORWARD
370 /*
371 * If we've been forwarded from the output side, then
372 * skip the firewall a second time
373 */
374 if (ip_fw_fwd_addr)
375 goto ours;
376#endif /* IPFIREWALL_FORWARD */
377 /*
378 * See the comment in ip_output for the return values
379 * produced by the firewall.
380 */
381 i = (*ip_fw_chk_ptr)(&ip,
382 hlen, NULL, &divert_cookie, &m, &rule, &ip_fw_fwd_addr);
383 if (m == NULL) /* Packet discarded by firewall */
384 return;
385 if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */
386 goto pass;
387#ifdef DUMMYNET
388 if ((i & IP_FW_PORT_DYNT_FLAG) != 0) {
389 /* Send packet to the appropriate pipe */
234 if (pr->pr_domain->dom_family == PF_INET &&
235 pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
236 ip_protox[pr->pr_protocol] = pr - inetsw;
237
238 for (i = 0; i < IPREASS_NHASH; i++)
239 ipq[i].next = ipq[i].prev = &ipq[i];
240
241 maxnipq = nmbclusters/4;
242
243 ip_id = time_second & 0xffff;
244 ipintrq.ifq_maxlen = ipqmaxlen;
245}
246
247static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
248static struct route ipforward_rt;
249
250/*
251 * Ip input routine. Checksum and byte swap header. If fragmented
252 * try to reassemble. Process options. Pass to next level.
253 */
254void
255ip_input(struct mbuf *m)
256{
257 struct ip *ip;
258 struct ipq *fp;
259 struct in_ifaddr *ia;
260 int i, hlen, mff;
261 u_short sum;
262 u_int16_t divert_cookie; /* firewall cookie */
263#ifdef IPDIVERT
264 u_int32_t divert_info = 0; /* packet divert/tee info */
265#endif
266 struct ip_fw_chain *rule = NULL;
267
268#ifdef IPDIVERT
269 /* Get and reset firewall cookie */
270 divert_cookie = ip_divert_cookie;
271 ip_divert_cookie = 0;
272#else
273 divert_cookie = 0;
274#endif
275
276#if defined(IPFIREWALL) && defined(DUMMYNET)
277 /*
278 * dummynet packet are prepended a vestigial mbuf with
279 * m_type = MT_DUMMYNET and m_data pointing to the matching
280 * rule.
281 */
282 if (m->m_type == MT_DUMMYNET) {
283 rule = (struct ip_fw_chain *)(m->m_data) ;
284 m = m->m_next ;
285 ip = mtod(m, struct ip *);
286 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
287 goto iphack ;
288 } else
289 rule = NULL ;
290#endif
291
292#ifdef DIAGNOSTIC
293 if (m == NULL || (m->m_flags & M_PKTHDR) == 0)
294 panic("ip_input no HDR");
295#endif
296 ipstat.ips_total++;
297
298 if (m->m_pkthdr.len < sizeof(struct ip))
299 goto tooshort;
300
301 if (m->m_len < sizeof (struct ip) &&
302 (m = m_pullup(m, sizeof (struct ip))) == 0) {
303 ipstat.ips_toosmall++;
304 return;
305 }
306 ip = mtod(m, struct ip *);
307
308 if (IP_VHL_V(ip->ip_vhl) != IPVERSION) {
309 ipstat.ips_badvers++;
310 goto bad;
311 }
312
313 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
314 if (hlen < sizeof(struct ip)) { /* minimum header length */
315 ipstat.ips_badhlen++;
316 goto bad;
317 }
318 if (hlen > m->m_len) {
319 if ((m = m_pullup(m, hlen)) == 0) {
320 ipstat.ips_badhlen++;
321 return;
322 }
323 ip = mtod(m, struct ip *);
324 }
325 if (hlen == sizeof(struct ip)) {
326 sum = in_cksum_hdr(ip);
327 } else {
328 sum = in_cksum(m, hlen);
329 }
330 if (sum) {
331 ipstat.ips_badsum++;
332 goto bad;
333 }
334
335 /*
336 * Convert fields to host representation.
337 */
338 NTOHS(ip->ip_len);
339 if (ip->ip_len < hlen) {
340 ipstat.ips_badlen++;
341 goto bad;
342 }
343 NTOHS(ip->ip_id);
344 NTOHS(ip->ip_off);
345
346 /*
347 * Check that the amount of data in the buffers
348 * is as at least much as the IP header would have us expect.
349 * Trim mbufs if longer than we expect.
350 * Drop packet if shorter than we expect.
351 */
352 if (m->m_pkthdr.len < ip->ip_len) {
353tooshort:
354 ipstat.ips_tooshort++;
355 goto bad;
356 }
357 if (m->m_pkthdr.len > ip->ip_len) {
358 if (m->m_len == m->m_pkthdr.len) {
359 m->m_len = ip->ip_len;
360 m->m_pkthdr.len = ip->ip_len;
361 } else
362 m_adj(m, ip->ip_len - m->m_pkthdr.len);
363 }
364 /*
365 * IpHack's section.
366 * Right now when no processing on packet has done
367 * and it is still fresh out of network we do our black
368 * deals with it.
369 * - Firewall: deny/allow/divert
370 * - Xlate: translate packet's addr/port (NAT).
371 * - Pipe: pass pkt through dummynet.
372 * - Wrap: fake packet's addr/port <unimpl.>
373 * - Encapsulate: put it in another IP and send out. <unimp.>
374 */
375
376#if defined(IPFIREWALL) && defined(DUMMYNET)
377iphack:
378#endif
379#if defined(IPFILTER) || defined(IPFILTER_LKM)
380 /*
381 * Check if we want to allow this packet to be processed.
382 * Consider it to be bad if not.
383 */
384 if (fr_checkp) {
385 struct mbuf *m1 = m;
386
387 if ((*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m1) || !m1)
388 return;
389 ip = mtod(m = m1, struct ip *);
390 }
391#endif
392 if (ip_fw_chk_ptr) {
393#ifdef IPFIREWALL_FORWARD
394 /*
395 * If we've been forwarded from the output side, then
396 * skip the firewall a second time
397 */
398 if (ip_fw_fwd_addr)
399 goto ours;
400#endif /* IPFIREWALL_FORWARD */
401 /*
402 * See the comment in ip_output for the return values
403 * produced by the firewall.
404 */
405 i = (*ip_fw_chk_ptr)(&ip,
406 hlen, NULL, &divert_cookie, &m, &rule, &ip_fw_fwd_addr);
407 if (m == NULL) /* Packet discarded by firewall */
408 return;
409 if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */
410 goto pass;
411#ifdef DUMMYNET
412 if ((i & IP_FW_PORT_DYNT_FLAG) != 0) {
413 /* Send packet to the appropriate pipe */
390 dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule);
414 dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule,
415 0);
391 return;
392 }
393#endif
394#ifdef IPDIVERT
395 if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
396 /* Divert or tee packet */
397 divert_info = i;
398 goto ours;
399 }
400#endif
401#ifdef IPFIREWALL_FORWARD
402 if (i == 0 && ip_fw_fwd_addr != NULL)
403 goto pass;
404#endif
405 /*
406 * if we get here, the packet must be dropped
407 */
408 m_freem(m);
409 return;
410 }
411pass:
412
413 /*
414 * Process options and, if not destined for us,
415 * ship it on. ip_dooptions returns 1 when an
416 * error was detected (causing an icmp message
417 * to be sent and the original packet to be freed).
418 */
419 ip_nhops = 0; /* for source routed packets */
420 if (hlen > sizeof (struct ip) && ip_dooptions(m)) {
421#ifdef IPFIREWALL_FORWARD
422 ip_fw_fwd_addr = NULL;
423#endif
424 return;
425 }
426
427 /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
428 * matter if it is destined to another node, or whether it is
429 * a multicast one, RSVP wants it! and prevents it from being forwarded
430 * anywhere else. Also checks if the rsvp daemon is running before
431 * grabbing the packet.
432 */
433 if (rsvp_on && ip->ip_p==IPPROTO_RSVP)
434 goto ours;
435
436 /*
437 * Check our list of addresses, to see if the packet is for us.
438 * If we don't have any addresses, assume any unicast packet
439 * we receive might be for us (and let the upper layers deal
440 * with it).
441 */
442 if (TAILQ_EMPTY(&in_ifaddrhead) &&
443 (m->m_flags & (M_MCAST|M_BCAST)) == 0)
444 goto ours;
445
446 for (ia = TAILQ_FIRST(&in_ifaddrhead); ia;
447 ia = TAILQ_NEXT(ia, ia_link)) {
448#define satosin(sa) ((struct sockaddr_in *)(sa))
449
450#ifdef BOOTP_COMPAT
451 if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
452 goto ours;
453#endif
454#ifdef IPFIREWALL_FORWARD
455 /*
456 * If the addr to forward to is one of ours, we pretend to
457 * be the destination for this packet.
458 */
459 if (ip_fw_fwd_addr == NULL) {
460 if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
461 goto ours;
462 } else if (IA_SIN(ia)->sin_addr.s_addr ==
463 ip_fw_fwd_addr->sin_addr.s_addr)
464 goto ours;
465#else
466 if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
467 goto ours;
468#endif
469 if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) {
470 if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
471 ip->ip_dst.s_addr)
472 goto ours;
473 if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
474 goto ours;
475 }
476 }
477 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
478 struct in_multi *inm;
479 if (ip_mrouter) {
480 /*
481 * If we are acting as a multicast router, all
482 * incoming multicast packets are passed to the
483 * kernel-level multicast forwarding function.
484 * The packet is returned (relatively) intact; if
485 * ip_mforward() returns a non-zero value, the packet
486 * must be discarded, else it may be accepted below.
487 *
488 * (The IP ident field is put in the same byte order
489 * as expected when ip_mforward() is called from
490 * ip_output().)
491 */
492 ip->ip_id = htons(ip->ip_id);
493 if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) {
494 ipstat.ips_cantforward++;
495 m_freem(m);
496 return;
497 }
498 ip->ip_id = ntohs(ip->ip_id);
499
500 /*
501 * The process-level routing demon needs to receive
502 * all multicast IGMP packets, whether or not this
503 * host belongs to their destination groups.
504 */
505 if (ip->ip_p == IPPROTO_IGMP)
506 goto ours;
507 ipstat.ips_forward++;
508 }
509 /*
510 * See if we belong to the destination multicast group on the
511 * arrival interface.
512 */
513 IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
514 if (inm == NULL) {
515 ipstat.ips_notmember++;
516 m_freem(m);
517 return;
518 }
519 goto ours;
520 }
521 if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
522 goto ours;
523 if (ip->ip_dst.s_addr == INADDR_ANY)
524 goto ours;
525
416 return;
417 }
418#endif
419#ifdef IPDIVERT
420 if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
421 /* Divert or tee packet */
422 divert_info = i;
423 goto ours;
424 }
425#endif
426#ifdef IPFIREWALL_FORWARD
427 if (i == 0 && ip_fw_fwd_addr != NULL)
428 goto pass;
429#endif
430 /*
431 * if we get here, the packet must be dropped
432 */
433 m_freem(m);
434 return;
435 }
436pass:
437
438 /*
439 * Process options and, if not destined for us,
440 * ship it on. ip_dooptions returns 1 when an
441 * error was detected (causing an icmp message
442 * to be sent and the original packet to be freed).
443 */
444 ip_nhops = 0; /* for source routed packets */
445 if (hlen > sizeof (struct ip) && ip_dooptions(m)) {
446#ifdef IPFIREWALL_FORWARD
447 ip_fw_fwd_addr = NULL;
448#endif
449 return;
450 }
451
452 /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
453 * matter if it is destined to another node, or whether it is
454 * a multicast one, RSVP wants it! and prevents it from being forwarded
455 * anywhere else. Also checks if the rsvp daemon is running before
456 * grabbing the packet.
457 */
458 if (rsvp_on && ip->ip_p==IPPROTO_RSVP)
459 goto ours;
460
461 /*
462 * Check our list of addresses, to see if the packet is for us.
463 * If we don't have any addresses, assume any unicast packet
464 * we receive might be for us (and let the upper layers deal
465 * with it).
466 */
467 if (TAILQ_EMPTY(&in_ifaddrhead) &&
468 (m->m_flags & (M_MCAST|M_BCAST)) == 0)
469 goto ours;
470
471 for (ia = TAILQ_FIRST(&in_ifaddrhead); ia;
472 ia = TAILQ_NEXT(ia, ia_link)) {
473#define satosin(sa) ((struct sockaddr_in *)(sa))
474
475#ifdef BOOTP_COMPAT
476 if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
477 goto ours;
478#endif
479#ifdef IPFIREWALL_FORWARD
480 /*
481 * If the addr to forward to is one of ours, we pretend to
482 * be the destination for this packet.
483 */
484 if (ip_fw_fwd_addr == NULL) {
485 if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
486 goto ours;
487 } else if (IA_SIN(ia)->sin_addr.s_addr ==
488 ip_fw_fwd_addr->sin_addr.s_addr)
489 goto ours;
490#else
491 if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
492 goto ours;
493#endif
494 if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) {
495 if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
496 ip->ip_dst.s_addr)
497 goto ours;
498 if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
499 goto ours;
500 }
501 }
502 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
503 struct in_multi *inm;
504 if (ip_mrouter) {
505 /*
506 * If we are acting as a multicast router, all
507 * incoming multicast packets are passed to the
508 * kernel-level multicast forwarding function.
509 * The packet is returned (relatively) intact; if
510 * ip_mforward() returns a non-zero value, the packet
511 * must be discarded, else it may be accepted below.
512 *
513 * (The IP ident field is put in the same byte order
514 * as expected when ip_mforward() is called from
515 * ip_output().)
516 */
517 ip->ip_id = htons(ip->ip_id);
518 if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) {
519 ipstat.ips_cantforward++;
520 m_freem(m);
521 return;
522 }
523 ip->ip_id = ntohs(ip->ip_id);
524
525 /*
526 * The process-level routing demon needs to receive
527 * all multicast IGMP packets, whether or not this
528 * host belongs to their destination groups.
529 */
530 if (ip->ip_p == IPPROTO_IGMP)
531 goto ours;
532 ipstat.ips_forward++;
533 }
534 /*
535 * See if we belong to the destination multicast group on the
536 * arrival interface.
537 */
538 IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
539 if (inm == NULL) {
540 ipstat.ips_notmember++;
541 m_freem(m);
542 return;
543 }
544 goto ours;
545 }
546 if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
547 goto ours;
548 if (ip->ip_dst.s_addr == INADDR_ANY)
549 goto ours;
550
551#if defined(NFAITH) && 0 < NFAITH
526 /*
552 /*
553 * FAITH(Firewall Aided Internet Translator)
554 */
555 if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
556 if (ip_keepfaith) {
557 if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP)
558 goto ours;
559 }
560 m_freem(m);
561 return;
562 }
563#endif
564 /*
527 * Not for us; forward if possible and desirable.
528 */
529 if (ipforwarding == 0) {
530 ipstat.ips_cantforward++;
531 m_freem(m);
532 } else
533 ip_forward(m, 0);
534#ifdef IPFIREWALL_FORWARD
535 ip_fw_fwd_addr = NULL;
536#endif
537 return;
538
539ours:
540
541 /*
542 * If offset or IP_MF are set, must reassemble.
543 * Otherwise, nothing need be done.
544 * (We could look in the reassembly queue to see
545 * if the packet was previously fragmented,
546 * but it's not worth the time; just let them time out.)
547 */
548 if (ip->ip_off & (IP_MF | IP_OFFMASK | IP_RF)) {
565 * Not for us; forward if possible and desirable.
566 */
567 if (ipforwarding == 0) {
568 ipstat.ips_cantforward++;
569 m_freem(m);
570 } else
571 ip_forward(m, 0);
572#ifdef IPFIREWALL_FORWARD
573 ip_fw_fwd_addr = NULL;
574#endif
575 return;
576
577ours:
578
579 /*
580 * If offset or IP_MF are set, must reassemble.
581 * Otherwise, nothing need be done.
582 * (We could look in the reassembly queue to see
583 * if the packet was previously fragmented,
584 * but it's not worth the time; just let them time out.)
585 */
586 if (ip->ip_off & (IP_MF | IP_OFFMASK | IP_RF)) {
587
588#if 0 /*
589 * Reassembly should be able to treat a mbuf cluster, for later
590 * operation of contiguous protocol headers on the cluster. (KAME)
591 */
549 if (m->m_flags & M_EXT) { /* XXX */
550 if ((m = m_pullup(m, hlen)) == 0) {
551 ipstat.ips_toosmall++;
552#ifdef IPFIREWALL_FORWARD
553 ip_fw_fwd_addr = NULL;
554#endif
555 return;
556 }
557 ip = mtod(m, struct ip *);
558 }
592 if (m->m_flags & M_EXT) { /* XXX */
593 if ((m = m_pullup(m, hlen)) == 0) {
594 ipstat.ips_toosmall++;
595#ifdef IPFIREWALL_FORWARD
596 ip_fw_fwd_addr = NULL;
597#endif
598 return;
599 }
600 ip = mtod(m, struct ip *);
601 }
602#endif
559 sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
560 /*
561 * Look for queue of fragments
562 * of this datagram.
563 */
564 for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next)
565 if (ip->ip_id == fp->ipq_id &&
566 ip->ip_src.s_addr == fp->ipq_src.s_addr &&
567 ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
568 ip->ip_p == fp->ipq_p)
569 goto found;
570
571 fp = 0;
572
573 /* check if there's a place for the new queue */
574 if (nipq > maxnipq) {
575 /*
576 * drop something from the tail of the current queue
577 * before proceeding further
578 */
579 if (ipq[sum].prev == &ipq[sum]) { /* gak */
580 for (i = 0; i < IPREASS_NHASH; i++) {
581 if (ipq[i].prev != &ipq[i]) {
582 ip_freef(ipq[i].prev);
583 break;
584 }
585 }
586 } else
587 ip_freef(ipq[sum].prev);
588 }
589found:
590 /*
591 * Adjust ip_len to not reflect header,
592 * set ip_mff if more fragments are expected,
593 * convert offset of this to bytes.
594 */
595 ip->ip_len -= hlen;
596 mff = (ip->ip_off & IP_MF) != 0;
597 if (mff) {
598 /*
599 * Make sure that fragments have a data length
600 * that's a non-zero multiple of 8 bytes.
601 */
602 if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
603 ipstat.ips_toosmall++; /* XXX */
604 goto bad;
605 }
606 m->m_flags |= M_FRAG;
607 }
608 ip->ip_off <<= 3;
609
610 /*
611 * If datagram marked as having more fragments
612 * or if this is not the first fragment,
613 * attempt reassembly; if it succeeds, proceed.
614 */
615 if (mff || ip->ip_off) {
616 ipstat.ips_fragments++;
617 m->m_pkthdr.header = ip;
618#ifdef IPDIVERT
603 sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
604 /*
605 * Look for queue of fragments
606 * of this datagram.
607 */
608 for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next)
609 if (ip->ip_id == fp->ipq_id &&
610 ip->ip_src.s_addr == fp->ipq_src.s_addr &&
611 ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
612 ip->ip_p == fp->ipq_p)
613 goto found;
614
615 fp = 0;
616
617 /* check if there's a place for the new queue */
618 if (nipq > maxnipq) {
619 /*
620 * drop something from the tail of the current queue
621 * before proceeding further
622 */
623 if (ipq[sum].prev == &ipq[sum]) { /* gak */
624 for (i = 0; i < IPREASS_NHASH; i++) {
625 if (ipq[i].prev != &ipq[i]) {
626 ip_freef(ipq[i].prev);
627 break;
628 }
629 }
630 } else
631 ip_freef(ipq[sum].prev);
632 }
633found:
634 /*
635 * Adjust ip_len to not reflect header,
636 * set ip_mff if more fragments are expected,
637 * convert offset of this to bytes.
638 */
639 ip->ip_len -= hlen;
640 mff = (ip->ip_off & IP_MF) != 0;
641 if (mff) {
642 /*
643 * Make sure that fragments have a data length
644 * that's a non-zero multiple of 8 bytes.
645 */
646 if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
647 ipstat.ips_toosmall++; /* XXX */
648 goto bad;
649 }
650 m->m_flags |= M_FRAG;
651 }
652 ip->ip_off <<= 3;
653
654 /*
655 * If datagram marked as having more fragments
656 * or if this is not the first fragment,
657 * attempt reassembly; if it succeeds, proceed.
658 */
659 if (mff || ip->ip_off) {
660 ipstat.ips_fragments++;
661 m->m_pkthdr.header = ip;
662#ifdef IPDIVERT
619 ip = ip_reass(m,
663 m = ip_reass(m,
620 fp, &ipq[sum], &divert_info, &divert_cookie);
621#else
664 fp, &ipq[sum], &divert_info, &divert_cookie);
665#else
622 ip = ip_reass(m, fp, &ipq[sum]);
666 m = ip_reass(m, fp, &ipq[sum]);
623#endif
667#endif
624 if (ip == 0) {
668 if (m == 0) {
625#ifdef IPFIREWALL_FORWARD
626 ip_fw_fwd_addr = NULL;
627#endif
628 return;
629 }
630 /* Get the length of the reassembled packets header */
631 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
632 ipstat.ips_reassembled++;
669#ifdef IPFIREWALL_FORWARD
670 ip_fw_fwd_addr = NULL;
671#endif
672 return;
673 }
674 /* Get the length of the reassembled packets header */
675 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
676 ipstat.ips_reassembled++;
633 m = dtom(ip);
677 ip = mtod(m, struct ip *);
634#ifdef IPDIVERT
635 /* Restore original checksum before diverting packet */
636 if (divert_info != 0) {
637 ip->ip_len += hlen;
638 HTONS(ip->ip_len);
639 HTONS(ip->ip_off);
640 HTONS(ip->ip_id);
641 ip->ip_sum = 0;
642 ip->ip_sum = in_cksum_hdr(ip);
643 NTOHS(ip->ip_id);
644 NTOHS(ip->ip_off);
645 NTOHS(ip->ip_len);
646 ip->ip_len -= hlen;
647 }
648#endif
649 } else
650 if (fp)
651 ip_freef(fp);
652 } else
653 ip->ip_len -= hlen;
654
655#ifdef IPDIVERT
656 /*
657 * Divert or tee packet to the divert protocol if required.
658 *
659 * If divert_info is zero then cookie should be too, so we shouldn't
660 * need to clear them here. Assume divert_packet() does so also.
661 */
662 if (divert_info != 0) {
663 struct mbuf *clone = NULL;
664
665 /* Clone packet if we're doing a 'tee' */
666 if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
667 clone = m_dup(m, M_DONTWAIT);
668
669 /* Restore packet header fields to original values */
670 ip->ip_len += hlen;
671 HTONS(ip->ip_len);
672 HTONS(ip->ip_off);
673 HTONS(ip->ip_id);
674
675 /* Deliver packet to divert input routine */
676 ip_divert_cookie = divert_cookie;
677 divert_packet(m, 1, divert_info & 0xffff);
678 ipstat.ips_delivered++;
679
680 /* If 'tee', continue with original packet */
681 if (clone == NULL)
682 return;
683 m = clone;
684 ip = mtod(m, struct ip *);
685 }
686#endif
687
688 /*
689 * Switch out to protocol's input routine.
690 */
691 ipstat.ips_delivered++;
678#ifdef IPDIVERT
679 /* Restore original checksum before diverting packet */
680 if (divert_info != 0) {
681 ip->ip_len += hlen;
682 HTONS(ip->ip_len);
683 HTONS(ip->ip_off);
684 HTONS(ip->ip_id);
685 ip->ip_sum = 0;
686 ip->ip_sum = in_cksum_hdr(ip);
687 NTOHS(ip->ip_id);
688 NTOHS(ip->ip_off);
689 NTOHS(ip->ip_len);
690 ip->ip_len -= hlen;
691 }
692#endif
693 } else
694 if (fp)
695 ip_freef(fp);
696 } else
697 ip->ip_len -= hlen;
698
699#ifdef IPDIVERT
700 /*
701 * Divert or tee packet to the divert protocol if required.
702 *
703 * If divert_info is zero then cookie should be too, so we shouldn't
704 * need to clear them here. Assume divert_packet() does so also.
705 */
706 if (divert_info != 0) {
707 struct mbuf *clone = NULL;
708
709 /* Clone packet if we're doing a 'tee' */
710 if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
711 clone = m_dup(m, M_DONTWAIT);
712
713 /* Restore packet header fields to original values */
714 ip->ip_len += hlen;
715 HTONS(ip->ip_len);
716 HTONS(ip->ip_off);
717 HTONS(ip->ip_id);
718
719 /* Deliver packet to divert input routine */
720 ip_divert_cookie = divert_cookie;
721 divert_packet(m, 1, divert_info & 0xffff);
722 ipstat.ips_delivered++;
723
724 /* If 'tee', continue with original packet */
725 if (clone == NULL)
726 return;
727 m = clone;
728 ip = mtod(m, struct ip *);
729 }
730#endif
731
732 /*
733 * Switch out to protocol's input routine.
734 */
735 ipstat.ips_delivered++;
692 (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
736 {
737 int off = hlen, nh = ip->ip_p;
738
739 (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, off, nh);
693#ifdef IPFIREWALL_FORWARD
694 ip_fw_fwd_addr = NULL; /* tcp needed it */
695#endif
696 return;
740#ifdef IPFIREWALL_FORWARD
741 ip_fw_fwd_addr = NULL; /* tcp needed it */
742#endif
743 return;
744 }
697bad:
698#ifdef IPFIREWALL_FORWARD
699 ip_fw_fwd_addr = NULL;
700#endif
701 m_freem(m);
702}
703
704/*
705 * IP software interrupt routine - to go away sometime soon
706 */
707static void
708ipintr(void)
709{
710 int s;
711 struct mbuf *m;
712
713 while(1) {
714 s = splimp();
715 IF_DEQUEUE(&ipintrq, m);
716 splx(s);
717 if (m == 0)
718 return;
719 ip_input(m);
720 }
721}
722
723NETISR_SET(NETISR_IP, ipintr);
724
725/*
726 * Take incoming datagram fragment and try to reassemble it into
727 * whole datagram. If a chain for reassembly of this datagram already
728 * exists, then it is given as fp; otherwise have to make a chain.
729 *
730 * When IPDIVERT enabled, keep additional state with each packet that
731 * tells us if we need to divert or tee the packet we're building.
732 */
733
745bad:
746#ifdef IPFIREWALL_FORWARD
747 ip_fw_fwd_addr = NULL;
748#endif
749 m_freem(m);
750}
751
752/*
753 * IP software interrupt routine - to go away sometime soon
754 */
755static void
756ipintr(void)
757{
758 int s;
759 struct mbuf *m;
760
761 while(1) {
762 s = splimp();
763 IF_DEQUEUE(&ipintrq, m);
764 splx(s);
765 if (m == 0)
766 return;
767 ip_input(m);
768 }
769}
770
771NETISR_SET(NETISR_IP, ipintr);
772
773/*
774 * Take incoming datagram fragment and try to reassemble it into
775 * whole datagram. If a chain for reassembly of this datagram already
776 * exists, then it is given as fp; otherwise have to make a chain.
777 *
778 * When IPDIVERT enabled, keep additional state with each packet that
779 * tells us if we need to divert or tee the packet we're building.
780 */
781
734static struct ip *
782static struct mbuf *
735#ifdef IPDIVERT
736ip_reass(m, fp, where, divinfo, divcookie)
737#else
738ip_reass(m, fp, where)
739#endif
740 register struct mbuf *m;
741 register struct ipq *fp;
742 struct ipq *where;
743#ifdef IPDIVERT
744 u_int32_t *divinfo;
745 u_int16_t *divcookie;
746#endif
747{
748 struct ip *ip = mtod(m, struct ip *);
749 register struct mbuf *p = 0, *q, *nq;
750 struct mbuf *t;
751 int hlen = IP_VHL_HL(ip->ip_vhl) << 2;
752 int i, next;
753
754 /*
755 * Presence of header sizes in mbufs
756 * would confuse code below.
757 */
758 m->m_data += hlen;
759 m->m_len -= hlen;
760
761 /*
762 * If first fragment to arrive, create a reassembly queue.
763 */
764 if (fp == 0) {
765 if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
766 goto dropfrag;
767 fp = mtod(t, struct ipq *);
768 insque(fp, where);
769 nipq++;
770 fp->ipq_ttl = IPFRAGTTL;
771 fp->ipq_p = ip->ip_p;
772 fp->ipq_id = ip->ip_id;
773 fp->ipq_src = ip->ip_src;
774 fp->ipq_dst = ip->ip_dst;
775 fp->ipq_frags = m;
776 m->m_nextpkt = NULL;
777#ifdef IPDIVERT
778 fp->ipq_div_info = 0;
779 fp->ipq_div_cookie = 0;
780#endif
781 goto inserted;
782 }
783
784#define GETIP(m) ((struct ip*)((m)->m_pkthdr.header))
785
786 /*
787 * Find a segment which begins after this one does.
788 */
789 for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
790 if (GETIP(q)->ip_off > ip->ip_off)
791 break;
792
793 /*
794 * If there is a preceding segment, it may provide some of
795 * our data already. If so, drop the data from the incoming
796 * segment. If it provides all of our data, drop us, otherwise
797 * stick new segment in the proper place.
798 */
799 if (p) {
800 i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off;
801 if (i > 0) {
802 if (i >= ip->ip_len)
803 goto dropfrag;
783#ifdef IPDIVERT
784ip_reass(m, fp, where, divinfo, divcookie)
785#else
786ip_reass(m, fp, where)
787#endif
788 register struct mbuf *m;
789 register struct ipq *fp;
790 struct ipq *where;
791#ifdef IPDIVERT
792 u_int32_t *divinfo;
793 u_int16_t *divcookie;
794#endif
795{
796 struct ip *ip = mtod(m, struct ip *);
797 register struct mbuf *p = 0, *q, *nq;
798 struct mbuf *t;
799 int hlen = IP_VHL_HL(ip->ip_vhl) << 2;
800 int i, next;
801
802 /*
803 * Presence of header sizes in mbufs
804 * would confuse code below.
805 */
806 m->m_data += hlen;
807 m->m_len -= hlen;
808
809 /*
810 * If first fragment to arrive, create a reassembly queue.
811 */
812 if (fp == 0) {
813 if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
814 goto dropfrag;
815 fp = mtod(t, struct ipq *);
816 insque(fp, where);
817 nipq++;
818 fp->ipq_ttl = IPFRAGTTL;
819 fp->ipq_p = ip->ip_p;
820 fp->ipq_id = ip->ip_id;
821 fp->ipq_src = ip->ip_src;
822 fp->ipq_dst = ip->ip_dst;
823 fp->ipq_frags = m;
824 m->m_nextpkt = NULL;
825#ifdef IPDIVERT
826 fp->ipq_div_info = 0;
827 fp->ipq_div_cookie = 0;
828#endif
829 goto inserted;
830 }
831
832#define GETIP(m) ((struct ip*)((m)->m_pkthdr.header))
833
834 /*
835 * Find a segment which begins after this one does.
836 */
837 for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
838 if (GETIP(q)->ip_off > ip->ip_off)
839 break;
840
841 /*
842 * If there is a preceding segment, it may provide some of
843 * our data already. If so, drop the data from the incoming
844 * segment. If it provides all of our data, drop us, otherwise
845 * stick new segment in the proper place.
846 */
847 if (p) {
848 i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off;
849 if (i > 0) {
850 if (i >= ip->ip_len)
851 goto dropfrag;
804 m_adj(dtom(ip), i);
852 m_adj(m, i);
805 ip->ip_off += i;
806 ip->ip_len -= i;
807 }
808 m->m_nextpkt = p->m_nextpkt;
809 p->m_nextpkt = m;
810 } else {
811 m->m_nextpkt = fp->ipq_frags;
812 fp->ipq_frags = m;
813 }
814
815 /*
816 * While we overlap succeeding segments trim them or,
817 * if they are completely covered, dequeue them.
818 */
819 for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off;
820 q = nq) {
821 i = (ip->ip_off + ip->ip_len) -
822 GETIP(q)->ip_off;
823 if (i < GETIP(q)->ip_len) {
824 GETIP(q)->ip_len -= i;
825 GETIP(q)->ip_off += i;
826 m_adj(q, i);
827 break;
828 }
829 nq = q->m_nextpkt;
830 m->m_nextpkt = nq;
831 m_freem(q);
832 }
833
834inserted:
835
836#ifdef IPDIVERT
837 /*
838 * Transfer firewall instructions to the fragment structure.
839 * Any fragment diverting causes the whole packet to divert.
840 */
841 fp->ipq_div_info = *divinfo;
842 fp->ipq_div_cookie = *divcookie;
843 *divinfo = 0;
844 *divcookie = 0;
845#endif
846
847 /*
848 * Check for complete reassembly.
849 */
850 next = 0;
851 for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
852 if (GETIP(q)->ip_off != next)
853 return (0);
854 next += GETIP(q)->ip_len;
855 }
856 /* Make sure the last packet didn't have the IP_MF flag */
857 if (p->m_flags & M_FRAG)
858 return (0);
859
860 /*
861 * Reassembly is complete. Make sure the packet is a sane size.
862 */
863 q = fp->ipq_frags;
864 ip = GETIP(q);
865 if (next + (IP_VHL_HL(ip->ip_vhl) << 2) > IP_MAXPACKET) {
866 ipstat.ips_toolong++;
867 ip_freef(fp);
868 return (0);
869 }
870
871 /*
872 * Concatenate fragments.
873 */
874 m = q;
875 t = m->m_next;
876 m->m_next = 0;
877 m_cat(m, t);
878 nq = q->m_nextpkt;
879 q->m_nextpkt = 0;
880 for (q = nq; q != NULL; q = nq) {
881 nq = q->m_nextpkt;
882 q->m_nextpkt = NULL;
883 m_cat(m, q);
884 }
885
886#ifdef IPDIVERT
887 /*
888 * Extract firewall instructions from the fragment structure.
889 */
890 *divinfo = fp->ipq_div_info;
891 *divcookie = fp->ipq_div_cookie;
892#endif
893
894 /*
895 * Create header for new ip packet by
896 * modifying header of first packet;
897 * dequeue and discard fragment reassembly header.
898 * Make header visible.
899 */
900 ip->ip_len = next;
901 ip->ip_src = fp->ipq_src;
902 ip->ip_dst = fp->ipq_dst;
903 remque(fp);
904 nipq--;
905 (void) m_free(dtom(fp));
906 m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2);
907 m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2);
908 /* some debugging cruft by sklower, below, will go away soon */
909 if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
910 register int plen = 0;
853 ip->ip_off += i;
854 ip->ip_len -= i;
855 }
856 m->m_nextpkt = p->m_nextpkt;
857 p->m_nextpkt = m;
858 } else {
859 m->m_nextpkt = fp->ipq_frags;
860 fp->ipq_frags = m;
861 }
862
863 /*
864 * While we overlap succeeding segments trim them or,
865 * if they are completely covered, dequeue them.
866 */
867 for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off;
868 q = nq) {
869 i = (ip->ip_off + ip->ip_len) -
870 GETIP(q)->ip_off;
871 if (i < GETIP(q)->ip_len) {
872 GETIP(q)->ip_len -= i;
873 GETIP(q)->ip_off += i;
874 m_adj(q, i);
875 break;
876 }
877 nq = q->m_nextpkt;
878 m->m_nextpkt = nq;
879 m_freem(q);
880 }
881
882inserted:
883
884#ifdef IPDIVERT
885 /*
886 * Transfer firewall instructions to the fragment structure.
887 * Any fragment diverting causes the whole packet to divert.
888 */
889 fp->ipq_div_info = *divinfo;
890 fp->ipq_div_cookie = *divcookie;
891 *divinfo = 0;
892 *divcookie = 0;
893#endif
894
895 /*
896 * Check for complete reassembly.
897 */
898 next = 0;
899 for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
900 if (GETIP(q)->ip_off != next)
901 return (0);
902 next += GETIP(q)->ip_len;
903 }
904 /* Make sure the last packet didn't have the IP_MF flag */
905 if (p->m_flags & M_FRAG)
906 return (0);
907
908 /*
909 * Reassembly is complete. Make sure the packet is a sane size.
910 */
911 q = fp->ipq_frags;
912 ip = GETIP(q);
913 if (next + (IP_VHL_HL(ip->ip_vhl) << 2) > IP_MAXPACKET) {
914 ipstat.ips_toolong++;
915 ip_freef(fp);
916 return (0);
917 }
918
919 /*
920 * Concatenate fragments.
921 */
922 m = q;
923 t = m->m_next;
924 m->m_next = 0;
925 m_cat(m, t);
926 nq = q->m_nextpkt;
927 q->m_nextpkt = 0;
928 for (q = nq; q != NULL; q = nq) {
929 nq = q->m_nextpkt;
930 q->m_nextpkt = NULL;
931 m_cat(m, q);
932 }
933
934#ifdef IPDIVERT
935 /*
936 * Extract firewall instructions from the fragment structure.
937 */
938 *divinfo = fp->ipq_div_info;
939 *divcookie = fp->ipq_div_cookie;
940#endif
941
942 /*
943 * Create header for new ip packet by
944 * modifying header of first packet;
945 * dequeue and discard fragment reassembly header.
946 * Make header visible.
947 */
948 ip->ip_len = next;
949 ip->ip_src = fp->ipq_src;
950 ip->ip_dst = fp->ipq_dst;
951 remque(fp);
952 nipq--;
953 (void) m_free(dtom(fp));
954 m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2);
955 m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2);
956 /* some debugging cruft by sklower, below, will go away soon */
957 if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
958 register int plen = 0;
911 for (t = m; m; m = m->m_next)
912 plen += m->m_len;
913 t->m_pkthdr.len = plen;
959 for (t = m; t; t = t->m_next)
960 plen += t->m_len;
961 m->m_pkthdr.len = plen;
914 }
962 }
915 return (ip);
963 return (m);
916
917dropfrag:
918#ifdef IPDIVERT
919 *divinfo = 0;
920 *divcookie = 0;
921#endif
922 ipstat.ips_fragdropped++;
923 m_freem(m);
924 return (0);
925
926#undef GETIP
927}
928
929/*
930 * Free a fragment reassembly header and all
931 * associated datagrams.
932 */
933static void
934ip_freef(fp)
935 struct ipq *fp;
936{
937 register struct mbuf *q;
938
939 while (fp->ipq_frags) {
940 q = fp->ipq_frags;
941 fp->ipq_frags = q->m_nextpkt;
942 m_freem(q);
943 }
944 remque(fp);
945 (void) m_free(dtom(fp));
946 nipq--;
947}
948
949/*
950 * IP timer processing;
951 * if a timer expires on a reassembly
952 * queue, discard it.
953 */
954void
955ip_slowtimo()
956{
957 register struct ipq *fp;
958 int s = splnet();
959 int i;
960
961 for (i = 0; i < IPREASS_NHASH; i++) {
962 fp = ipq[i].next;
963 if (fp == 0)
964 continue;
965 while (fp != &ipq[i]) {
966 --fp->ipq_ttl;
967 fp = fp->next;
968 if (fp->prev->ipq_ttl == 0) {
969 ipstat.ips_fragtimeout++;
970 ip_freef(fp->prev);
971 }
972 }
973 }
974 ipflow_slowtimo();
975 splx(s);
976}
977
978/*
979 * Drain off all datagram fragments.
980 */
981void
982ip_drain()
983{
984 int i;
985
986 for (i = 0; i < IPREASS_NHASH; i++) {
987 while (ipq[i].next != &ipq[i]) {
988 ipstat.ips_fragdropped++;
989 ip_freef(ipq[i].next);
990 }
991 }
992 in_rtqdrain();
993}
994
995/*
996 * Do option processing on a datagram,
997 * possibly discarding it if bad options are encountered,
998 * or forwarding it if source-routed.
999 * Returns 1 if packet has been forwarded/freed,
1000 * 0 if the packet should be processed further.
1001 */
1002static int
1003ip_dooptions(m)
1004 struct mbuf *m;
1005{
1006 register struct ip *ip = mtod(m, struct ip *);
1007 register u_char *cp;
1008 register struct ip_timestamp *ipt;
1009 register struct in_ifaddr *ia;
1010 int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
1011 struct in_addr *sin, dst;
1012 n_time ntime;
1013
1014 dst = ip->ip_dst;
1015 cp = (u_char *)(ip + 1);
1016 cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1017 for (; cnt > 0; cnt -= optlen, cp += optlen) {
1018 opt = cp[IPOPT_OPTVAL];
1019 if (opt == IPOPT_EOL)
1020 break;
1021 if (opt == IPOPT_NOP)
1022 optlen = 1;
1023 else {
1024 optlen = cp[IPOPT_OLEN];
1025 if (optlen <= 0 || optlen > cnt) {
1026 code = &cp[IPOPT_OLEN] - (u_char *)ip;
1027 goto bad;
1028 }
1029 }
1030 switch (opt) {
1031
1032 default:
1033 break;
1034
1035 /*
1036 * Source routing with record.
1037 * Find interface with current destination address.
1038 * If none on this machine then drop if strictly routed,
1039 * or do nothing if loosely routed.
1040 * Record interface address and bring up next address
1041 * component. If strictly routed make sure next
1042 * address is on directly accessible net.
1043 */
1044 case IPOPT_LSRR:
1045 case IPOPT_SSRR:
1046 if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1047 code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1048 goto bad;
1049 }
1050 ipaddr.sin_addr = ip->ip_dst;
1051 ia = (struct in_ifaddr *)
1052 ifa_ifwithaddr((struct sockaddr *)&ipaddr);
1053 if (ia == 0) {
1054 if (opt == IPOPT_SSRR) {
1055 type = ICMP_UNREACH;
1056 code = ICMP_UNREACH_SRCFAIL;
1057 goto bad;
1058 }
1059 if (!ip_dosourceroute)
1060 goto nosourcerouting;
1061 /*
1062 * Loose routing, and not at next destination
1063 * yet; nothing to do except forward.
1064 */
1065 break;
1066 }
1067 off--; /* 0 origin */
1068 if (off > optlen - sizeof(struct in_addr)) {
1069 /*
1070 * End of source route. Should be for us.
1071 */
1072 if (!ip_acceptsourceroute)
1073 goto nosourcerouting;
1074 save_rte(cp, ip->ip_src);
1075 break;
1076 }
1077
1078 if (!ip_dosourceroute) {
1079 if (ipforwarding) {
1080 char buf[16]; /* aaa.bbb.ccc.ddd\0 */
1081 /*
1082 * Acting as a router, so generate ICMP
1083 */
1084nosourcerouting:
1085 strcpy(buf, inet_ntoa(ip->ip_dst));
1086 log(LOG_WARNING,
1087 "attempted source route from %s to %s\n",
1088 inet_ntoa(ip->ip_src), buf);
1089 type = ICMP_UNREACH;
1090 code = ICMP_UNREACH_SRCFAIL;
1091 goto bad;
1092 } else {
1093 /*
1094 * Not acting as a router, so silently drop.
1095 */
1096 ipstat.ips_cantforward++;
1097 m_freem(m);
1098 return (1);
1099 }
1100 }
1101
1102 /*
1103 * locate outgoing interface
1104 */
1105 (void)memcpy(&ipaddr.sin_addr, cp + off,
1106 sizeof(ipaddr.sin_addr));
1107
1108 if (opt == IPOPT_SSRR) {
1109#define INA struct in_ifaddr *
1110#define SA struct sockaddr *
1111 if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
1112 ia = (INA)ifa_ifwithnet((SA)&ipaddr);
1113 } else
1114 ia = ip_rtaddr(ipaddr.sin_addr);
1115 if (ia == 0) {
1116 type = ICMP_UNREACH;
1117 code = ICMP_UNREACH_SRCFAIL;
1118 goto bad;
1119 }
1120 ip->ip_dst = ipaddr.sin_addr;
1121 (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
1122 sizeof(struct in_addr));
1123 cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1124 /*
1125 * Let ip_intr's mcast routing check handle mcast pkts
1126 */
1127 forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
1128 break;
1129
1130 case IPOPT_RR:
1131 if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1132 code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1133 goto bad;
1134 }
1135 /*
1136 * If no space remains, ignore.
1137 */
1138 off--; /* 0 origin */
1139 if (off > optlen - sizeof(struct in_addr))
1140 break;
1141 (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
1142 sizeof(ipaddr.sin_addr));
1143 /*
1144 * locate outgoing interface; if we're the destination,
1145 * use the incoming interface (should be same).
1146 */
1147 if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
1148 (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
1149 type = ICMP_UNREACH;
1150 code = ICMP_UNREACH_HOST;
1151 goto bad;
1152 }
1153 (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
1154 sizeof(struct in_addr));
1155 cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1156 break;
1157
1158 case IPOPT_TS:
1159 code = cp - (u_char *)ip;
1160 ipt = (struct ip_timestamp *)cp;
1161 if (ipt->ipt_len < 5)
1162 goto bad;
1163 if (ipt->ipt_ptr > ipt->ipt_len - sizeof(int32_t)) {
1164 if (++ipt->ipt_oflw == 0)
1165 goto bad;
1166 break;
1167 }
1168 sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
1169 switch (ipt->ipt_flg) {
1170
1171 case IPOPT_TS_TSONLY:
1172 break;
1173
1174 case IPOPT_TS_TSANDADDR:
1175 if (ipt->ipt_ptr - 1 + sizeof(n_time) +
1176 sizeof(struct in_addr) > ipt->ipt_len)
1177 goto bad;
1178 ipaddr.sin_addr = dst;
1179 ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
1180 m->m_pkthdr.rcvif);
1181 if (ia == 0)
1182 continue;
1183 (void)memcpy(sin, &IA_SIN(ia)->sin_addr,
1184 sizeof(struct in_addr));
1185 ipt->ipt_ptr += sizeof(struct in_addr);
1186 break;
1187
1188 case IPOPT_TS_PRESPEC:
1189 if (ipt->ipt_ptr - 1 + sizeof(n_time) +
1190 sizeof(struct in_addr) > ipt->ipt_len)
1191 goto bad;
1192 (void)memcpy(&ipaddr.sin_addr, sin,
1193 sizeof(struct in_addr));
1194 if (ifa_ifwithaddr((SA)&ipaddr) == 0)
1195 continue;
1196 ipt->ipt_ptr += sizeof(struct in_addr);
1197 break;
1198
1199 default:
1200 goto bad;
1201 }
1202 ntime = iptime();
1203 (void)memcpy(cp + ipt->ipt_ptr - 1, &ntime,
1204 sizeof(n_time));
1205 ipt->ipt_ptr += sizeof(n_time);
1206 }
1207 }
1208 if (forward && ipforwarding) {
1209 ip_forward(m, 1);
1210 return (1);
1211 }
1212 return (0);
1213bad:
1214 ip->ip_len -= IP_VHL_HL(ip->ip_vhl) << 2; /* XXX icmp_error adds in hdr length */
1215 icmp_error(m, type, code, 0, 0);
1216 ipstat.ips_badoptions++;
1217 return (1);
1218}
1219
1220/*
1221 * Given address of next destination (final or next hop),
1222 * return internet address info of interface to be used to get there.
1223 */
1224static struct in_ifaddr *
1225ip_rtaddr(dst)
1226 struct in_addr dst;
1227{
1228 register struct sockaddr_in *sin;
1229
1230 sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
1231
1232 if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
1233 if (ipforward_rt.ro_rt) {
1234 RTFREE(ipforward_rt.ro_rt);
1235 ipforward_rt.ro_rt = 0;
1236 }
1237 sin->sin_family = AF_INET;
1238 sin->sin_len = sizeof(*sin);
1239 sin->sin_addr = dst;
1240
1241 rtalloc_ign(&ipforward_rt, RTF_PRCLONING);
1242 }
1243 if (ipforward_rt.ro_rt == 0)
1244 return ((struct in_ifaddr *)0);
1245 return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa);
1246}
1247
1248/*
1249 * Save incoming source route for use in replies,
1250 * to be picked up later by ip_srcroute if the receiver is interested.
1251 */
1252void
1253save_rte(option, dst)
1254 u_char *option;
1255 struct in_addr dst;
1256{
1257 unsigned olen;
1258
1259 olen = option[IPOPT_OLEN];
1260#ifdef DIAGNOSTIC
1261 if (ipprintfs)
1262 printf("save_rte: olen %d\n", olen);
1263#endif
1264 if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
1265 return;
1266 bcopy(option, ip_srcrt.srcopt, olen);
1267 ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
1268 ip_srcrt.dst = dst;
1269}
1270
1271/*
1272 * Retrieve incoming source route for use in replies,
1273 * in the same form used by setsockopt.
1274 * The first hop is placed before the options, will be removed later.
1275 */
1276struct mbuf *
1277ip_srcroute()
1278{
1279 register struct in_addr *p, *q;
1280 register struct mbuf *m;
1281
1282 if (ip_nhops == 0)
1283 return ((struct mbuf *)0);
1284 m = m_get(M_DONTWAIT, MT_HEADER);
1285 if (m == 0)
1286 return ((struct mbuf *)0);
1287
1288#define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
1289
1290 /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
1291 m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
1292 OPTSIZ;
1293#ifdef DIAGNOSTIC
1294 if (ipprintfs)
1295 printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
1296#endif
1297
1298 /*
1299 * First save first hop for return route
1300 */
1301 p = &ip_srcrt.route[ip_nhops - 1];
1302 *(mtod(m, struct in_addr *)) = *p--;
1303#ifdef DIAGNOSTIC
1304 if (ipprintfs)
1305 printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr));
1306#endif
1307
1308 /*
1309 * Copy option fields and padding (nop) to mbuf.
1310 */
1311 ip_srcrt.nop = IPOPT_NOP;
1312 ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
1313 (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),
1314 &ip_srcrt.nop, OPTSIZ);
1315 q = (struct in_addr *)(mtod(m, caddr_t) +
1316 sizeof(struct in_addr) + OPTSIZ);
1317#undef OPTSIZ
1318 /*
1319 * Record return path as an IP source route,
1320 * reversing the path (pointers are now aligned).
1321 */
1322 while (p >= ip_srcrt.route) {
1323#ifdef DIAGNOSTIC
1324 if (ipprintfs)
1325 printf(" %lx", (u_long)ntohl(q->s_addr));
1326#endif
1327 *q++ = *p--;
1328 }
1329 /*
1330 * Last hop goes to final destination.
1331 */
1332 *q = ip_srcrt.dst;
1333#ifdef DIAGNOSTIC
1334 if (ipprintfs)
1335 printf(" %lx\n", (u_long)ntohl(q->s_addr));
1336#endif
1337 return (m);
1338}
1339
1340/*
1341 * Strip out IP options, at higher
1342 * level protocol in the kernel.
1343 * Second argument is buffer to which options
1344 * will be moved, and return value is their length.
1345 * XXX should be deleted; last arg currently ignored.
1346 */
1347void
1348ip_stripoptions(m, mopt)
1349 register struct mbuf *m;
1350 struct mbuf *mopt;
1351{
1352 register int i;
1353 struct ip *ip = mtod(m, struct ip *);
1354 register caddr_t opts;
1355 int olen;
1356
1357 olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1358 opts = (caddr_t)(ip + 1);
1359 i = m->m_len - (sizeof (struct ip) + olen);
1360 bcopy(opts + olen, opts, (unsigned)i);
1361 m->m_len -= olen;
1362 if (m->m_flags & M_PKTHDR)
1363 m->m_pkthdr.len -= olen;
1364 ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2);
1365}
1366
1367u_char inetctlerrmap[PRC_NCMDS] = {
1368 0, 0, 0, 0,
1369 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH,
1370 EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
1371 EMSGSIZE, EHOSTUNREACH, 0, 0,
1372 0, 0, 0, 0,
1373 ENOPROTOOPT
1374};
1375
1376/*
1377 * Forward a packet. If some error occurs return the sender
1378 * an icmp packet. Note we can't always generate a meaningful
1379 * icmp message because icmp doesn't have a large enough repertoire
1380 * of codes and types.
1381 *
1382 * If not forwarding, just drop the packet. This could be confusing
1383 * if ipforwarding was zero but some routing protocol was advancing
1384 * us as a gateway to somewhere. However, we must let the routing
1385 * protocol deal with that.
1386 *
1387 * The srcrt parameter indicates whether the packet is being forwarded
1388 * via a source route.
1389 */
1390static void
1391ip_forward(m, srcrt)
1392 struct mbuf *m;
1393 int srcrt;
1394{
1395 register struct ip *ip = mtod(m, struct ip *);
1396 register struct sockaddr_in *sin;
1397 register struct rtentry *rt;
1398 int error, type = 0, code = 0;
1399 struct mbuf *mcopy;
1400 n_long dest;
1401 struct ifnet *destifp;
964
965dropfrag:
966#ifdef IPDIVERT
967 *divinfo = 0;
968 *divcookie = 0;
969#endif
970 ipstat.ips_fragdropped++;
971 m_freem(m);
972 return (0);
973
974#undef GETIP
975}
976
977/*
978 * Free a fragment reassembly header and all
979 * associated datagrams.
980 */
981static void
982ip_freef(fp)
983 struct ipq *fp;
984{
985 register struct mbuf *q;
986
987 while (fp->ipq_frags) {
988 q = fp->ipq_frags;
989 fp->ipq_frags = q->m_nextpkt;
990 m_freem(q);
991 }
992 remque(fp);
993 (void) m_free(dtom(fp));
994 nipq--;
995}
996
997/*
998 * IP timer processing;
999 * if a timer expires on a reassembly
1000 * queue, discard it.
1001 */
1002void
1003ip_slowtimo()
1004{
1005 register struct ipq *fp;
1006 int s = splnet();
1007 int i;
1008
1009 for (i = 0; i < IPREASS_NHASH; i++) {
1010 fp = ipq[i].next;
1011 if (fp == 0)
1012 continue;
1013 while (fp != &ipq[i]) {
1014 --fp->ipq_ttl;
1015 fp = fp->next;
1016 if (fp->prev->ipq_ttl == 0) {
1017 ipstat.ips_fragtimeout++;
1018 ip_freef(fp->prev);
1019 }
1020 }
1021 }
1022 ipflow_slowtimo();
1023 splx(s);
1024}
1025
1026/*
1027 * Drain off all datagram fragments.
1028 */
1029void
1030ip_drain()
1031{
1032 int i;
1033
1034 for (i = 0; i < IPREASS_NHASH; i++) {
1035 while (ipq[i].next != &ipq[i]) {
1036 ipstat.ips_fragdropped++;
1037 ip_freef(ipq[i].next);
1038 }
1039 }
1040 in_rtqdrain();
1041}
1042
1043/*
1044 * Do option processing on a datagram,
1045 * possibly discarding it if bad options are encountered,
1046 * or forwarding it if source-routed.
1047 * Returns 1 if packet has been forwarded/freed,
1048 * 0 if the packet should be processed further.
1049 */
1050static int
1051ip_dooptions(m)
1052 struct mbuf *m;
1053{
1054 register struct ip *ip = mtod(m, struct ip *);
1055 register u_char *cp;
1056 register struct ip_timestamp *ipt;
1057 register struct in_ifaddr *ia;
1058 int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
1059 struct in_addr *sin, dst;
1060 n_time ntime;
1061
1062 dst = ip->ip_dst;
1063 cp = (u_char *)(ip + 1);
1064 cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1065 for (; cnt > 0; cnt -= optlen, cp += optlen) {
1066 opt = cp[IPOPT_OPTVAL];
1067 if (opt == IPOPT_EOL)
1068 break;
1069 if (opt == IPOPT_NOP)
1070 optlen = 1;
1071 else {
1072 optlen = cp[IPOPT_OLEN];
1073 if (optlen <= 0 || optlen > cnt) {
1074 code = &cp[IPOPT_OLEN] - (u_char *)ip;
1075 goto bad;
1076 }
1077 }
1078 switch (opt) {
1079
1080 default:
1081 break;
1082
1083 /*
1084 * Source routing with record.
1085 * Find interface with current destination address.
1086 * If none on this machine then drop if strictly routed,
1087 * or do nothing if loosely routed.
1088 * Record interface address and bring up next address
1089 * component. If strictly routed make sure next
1090 * address is on directly accessible net.
1091 */
1092 case IPOPT_LSRR:
1093 case IPOPT_SSRR:
1094 if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1095 code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1096 goto bad;
1097 }
1098 ipaddr.sin_addr = ip->ip_dst;
1099 ia = (struct in_ifaddr *)
1100 ifa_ifwithaddr((struct sockaddr *)&ipaddr);
1101 if (ia == 0) {
1102 if (opt == IPOPT_SSRR) {
1103 type = ICMP_UNREACH;
1104 code = ICMP_UNREACH_SRCFAIL;
1105 goto bad;
1106 }
1107 if (!ip_dosourceroute)
1108 goto nosourcerouting;
1109 /*
1110 * Loose routing, and not at next destination
1111 * yet; nothing to do except forward.
1112 */
1113 break;
1114 }
1115 off--; /* 0 origin */
1116 if (off > optlen - sizeof(struct in_addr)) {
1117 /*
1118 * End of source route. Should be for us.
1119 */
1120 if (!ip_acceptsourceroute)
1121 goto nosourcerouting;
1122 save_rte(cp, ip->ip_src);
1123 break;
1124 }
1125
1126 if (!ip_dosourceroute) {
1127 if (ipforwarding) {
1128 char buf[16]; /* aaa.bbb.ccc.ddd\0 */
1129 /*
1130 * Acting as a router, so generate ICMP
1131 */
1132nosourcerouting:
1133 strcpy(buf, inet_ntoa(ip->ip_dst));
1134 log(LOG_WARNING,
1135 "attempted source route from %s to %s\n",
1136 inet_ntoa(ip->ip_src), buf);
1137 type = ICMP_UNREACH;
1138 code = ICMP_UNREACH_SRCFAIL;
1139 goto bad;
1140 } else {
1141 /*
1142 * Not acting as a router, so silently drop.
1143 */
1144 ipstat.ips_cantforward++;
1145 m_freem(m);
1146 return (1);
1147 }
1148 }
1149
1150 /*
1151 * locate outgoing interface
1152 */
1153 (void)memcpy(&ipaddr.sin_addr, cp + off,
1154 sizeof(ipaddr.sin_addr));
1155
1156 if (opt == IPOPT_SSRR) {
1157#define INA struct in_ifaddr *
1158#define SA struct sockaddr *
1159 if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
1160 ia = (INA)ifa_ifwithnet((SA)&ipaddr);
1161 } else
1162 ia = ip_rtaddr(ipaddr.sin_addr);
1163 if (ia == 0) {
1164 type = ICMP_UNREACH;
1165 code = ICMP_UNREACH_SRCFAIL;
1166 goto bad;
1167 }
1168 ip->ip_dst = ipaddr.sin_addr;
1169 (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
1170 sizeof(struct in_addr));
1171 cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1172 /*
1173 * Let ip_intr's mcast routing check handle mcast pkts
1174 */
1175 forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
1176 break;
1177
1178 case IPOPT_RR:
1179 if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1180 code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1181 goto bad;
1182 }
1183 /*
1184 * If no space remains, ignore.
1185 */
1186 off--; /* 0 origin */
1187 if (off > optlen - sizeof(struct in_addr))
1188 break;
1189 (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
1190 sizeof(ipaddr.sin_addr));
1191 /*
1192 * locate outgoing interface; if we're the destination,
1193 * use the incoming interface (should be same).
1194 */
1195 if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
1196 (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
1197 type = ICMP_UNREACH;
1198 code = ICMP_UNREACH_HOST;
1199 goto bad;
1200 }
1201 (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
1202 sizeof(struct in_addr));
1203 cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1204 break;
1205
1206 case IPOPT_TS:
1207 code = cp - (u_char *)ip;
1208 ipt = (struct ip_timestamp *)cp;
1209 if (ipt->ipt_len < 5)
1210 goto bad;
1211 if (ipt->ipt_ptr > ipt->ipt_len - sizeof(int32_t)) {
1212 if (++ipt->ipt_oflw == 0)
1213 goto bad;
1214 break;
1215 }
1216 sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
1217 switch (ipt->ipt_flg) {
1218
1219 case IPOPT_TS_TSONLY:
1220 break;
1221
1222 case IPOPT_TS_TSANDADDR:
1223 if (ipt->ipt_ptr - 1 + sizeof(n_time) +
1224 sizeof(struct in_addr) > ipt->ipt_len)
1225 goto bad;
1226 ipaddr.sin_addr = dst;
1227 ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
1228 m->m_pkthdr.rcvif);
1229 if (ia == 0)
1230 continue;
1231 (void)memcpy(sin, &IA_SIN(ia)->sin_addr,
1232 sizeof(struct in_addr));
1233 ipt->ipt_ptr += sizeof(struct in_addr);
1234 break;
1235
1236 case IPOPT_TS_PRESPEC:
1237 if (ipt->ipt_ptr - 1 + sizeof(n_time) +
1238 sizeof(struct in_addr) > ipt->ipt_len)
1239 goto bad;
1240 (void)memcpy(&ipaddr.sin_addr, sin,
1241 sizeof(struct in_addr));
1242 if (ifa_ifwithaddr((SA)&ipaddr) == 0)
1243 continue;
1244 ipt->ipt_ptr += sizeof(struct in_addr);
1245 break;
1246
1247 default:
1248 goto bad;
1249 }
1250 ntime = iptime();
1251 (void)memcpy(cp + ipt->ipt_ptr - 1, &ntime,
1252 sizeof(n_time));
1253 ipt->ipt_ptr += sizeof(n_time);
1254 }
1255 }
1256 if (forward && ipforwarding) {
1257 ip_forward(m, 1);
1258 return (1);
1259 }
1260 return (0);
1261bad:
1262 ip->ip_len -= IP_VHL_HL(ip->ip_vhl) << 2; /* XXX icmp_error adds in hdr length */
1263 icmp_error(m, type, code, 0, 0);
1264 ipstat.ips_badoptions++;
1265 return (1);
1266}
1267
1268/*
1269 * Given address of next destination (final or next hop),
1270 * return internet address info of interface to be used to get there.
1271 */
1272static struct in_ifaddr *
1273ip_rtaddr(dst)
1274 struct in_addr dst;
1275{
1276 register struct sockaddr_in *sin;
1277
1278 sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
1279
1280 if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
1281 if (ipforward_rt.ro_rt) {
1282 RTFREE(ipforward_rt.ro_rt);
1283 ipforward_rt.ro_rt = 0;
1284 }
1285 sin->sin_family = AF_INET;
1286 sin->sin_len = sizeof(*sin);
1287 sin->sin_addr = dst;
1288
1289 rtalloc_ign(&ipforward_rt, RTF_PRCLONING);
1290 }
1291 if (ipforward_rt.ro_rt == 0)
1292 return ((struct in_ifaddr *)0);
1293 return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa);
1294}
1295
1296/*
1297 * Save incoming source route for use in replies,
1298 * to be picked up later by ip_srcroute if the receiver is interested.
1299 */
1300void
1301save_rte(option, dst)
1302 u_char *option;
1303 struct in_addr dst;
1304{
1305 unsigned olen;
1306
1307 olen = option[IPOPT_OLEN];
1308#ifdef DIAGNOSTIC
1309 if (ipprintfs)
1310 printf("save_rte: olen %d\n", olen);
1311#endif
1312 if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
1313 return;
1314 bcopy(option, ip_srcrt.srcopt, olen);
1315 ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
1316 ip_srcrt.dst = dst;
1317}
1318
1319/*
1320 * Retrieve incoming source route for use in replies,
1321 * in the same form used by setsockopt.
1322 * The first hop is placed before the options, will be removed later.
1323 */
1324struct mbuf *
1325ip_srcroute()
1326{
1327 register struct in_addr *p, *q;
1328 register struct mbuf *m;
1329
1330 if (ip_nhops == 0)
1331 return ((struct mbuf *)0);
1332 m = m_get(M_DONTWAIT, MT_HEADER);
1333 if (m == 0)
1334 return ((struct mbuf *)0);
1335
1336#define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
1337
1338 /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
1339 m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
1340 OPTSIZ;
1341#ifdef DIAGNOSTIC
1342 if (ipprintfs)
1343 printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
1344#endif
1345
1346 /*
1347 * First save first hop for return route
1348 */
1349 p = &ip_srcrt.route[ip_nhops - 1];
1350 *(mtod(m, struct in_addr *)) = *p--;
1351#ifdef DIAGNOSTIC
1352 if (ipprintfs)
1353 printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr));
1354#endif
1355
1356 /*
1357 * Copy option fields and padding (nop) to mbuf.
1358 */
1359 ip_srcrt.nop = IPOPT_NOP;
1360 ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
1361 (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),
1362 &ip_srcrt.nop, OPTSIZ);
1363 q = (struct in_addr *)(mtod(m, caddr_t) +
1364 sizeof(struct in_addr) + OPTSIZ);
1365#undef OPTSIZ
1366 /*
1367 * Record return path as an IP source route,
1368 * reversing the path (pointers are now aligned).
1369 */
1370 while (p >= ip_srcrt.route) {
1371#ifdef DIAGNOSTIC
1372 if (ipprintfs)
1373 printf(" %lx", (u_long)ntohl(q->s_addr));
1374#endif
1375 *q++ = *p--;
1376 }
1377 /*
1378 * Last hop goes to final destination.
1379 */
1380 *q = ip_srcrt.dst;
1381#ifdef DIAGNOSTIC
1382 if (ipprintfs)
1383 printf(" %lx\n", (u_long)ntohl(q->s_addr));
1384#endif
1385 return (m);
1386}
1387
1388/*
1389 * Strip out IP options, at higher
1390 * level protocol in the kernel.
1391 * Second argument is buffer to which options
1392 * will be moved, and return value is their length.
1393 * XXX should be deleted; last arg currently ignored.
1394 */
1395void
1396ip_stripoptions(m, mopt)
1397 register struct mbuf *m;
1398 struct mbuf *mopt;
1399{
1400 register int i;
1401 struct ip *ip = mtod(m, struct ip *);
1402 register caddr_t opts;
1403 int olen;
1404
1405 olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1406 opts = (caddr_t)(ip + 1);
1407 i = m->m_len - (sizeof (struct ip) + olen);
1408 bcopy(opts + olen, opts, (unsigned)i);
1409 m->m_len -= olen;
1410 if (m->m_flags & M_PKTHDR)
1411 m->m_pkthdr.len -= olen;
1412 ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2);
1413}
1414
1415u_char inetctlerrmap[PRC_NCMDS] = {
1416 0, 0, 0, 0,
1417 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH,
1418 EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
1419 EMSGSIZE, EHOSTUNREACH, 0, 0,
1420 0, 0, 0, 0,
1421 ENOPROTOOPT
1422};
1423
1424/*
1425 * Forward a packet. If some error occurs return the sender
1426 * an icmp packet. Note we can't always generate a meaningful
1427 * icmp message because icmp doesn't have a large enough repertoire
1428 * of codes and types.
1429 *
1430 * If not forwarding, just drop the packet. This could be confusing
1431 * if ipforwarding was zero but some routing protocol was advancing
1432 * us as a gateway to somewhere. However, we must let the routing
1433 * protocol deal with that.
1434 *
1435 * The srcrt parameter indicates whether the packet is being forwarded
1436 * via a source route.
1437 */
1438static void
1439ip_forward(m, srcrt)
1440 struct mbuf *m;
1441 int srcrt;
1442{
1443 register struct ip *ip = mtod(m, struct ip *);
1444 register struct sockaddr_in *sin;
1445 register struct rtentry *rt;
1446 int error, type = 0, code = 0;
1447 struct mbuf *mcopy;
1448 n_long dest;
1449 struct ifnet *destifp;
1450#ifdef IPSEC
1451 struct ifnet dummyifp;
1452#endif
1402
1403 dest = 0;
1404#ifdef DIAGNOSTIC
1405 if (ipprintfs)
1406 printf("forward: src %lx dst %lx ttl %x\n",
1407 (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr,
1408 ip->ip_ttl);
1409#endif
1410
1411
1412 if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
1413 ipstat.ips_cantforward++;
1414 m_freem(m);
1415 return;
1416 }
1417 HTONS(ip->ip_id);
1418#ifdef IPSTEALTH
1419 if (!ipstealth) {
1420#endif
1421 if (ip->ip_ttl <= IPTTLDEC) {
1422 icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
1423 dest, 0);
1424 return;
1425 }
1426 ip->ip_ttl -= IPTTLDEC;
1427#ifdef IPSTEALTH
1428 }
1429#endif
1430
1431 sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
1432 if ((rt = ipforward_rt.ro_rt) == 0 ||
1433 ip->ip_dst.s_addr != sin->sin_addr.s_addr) {
1434 if (ipforward_rt.ro_rt) {
1435 RTFREE(ipforward_rt.ro_rt);
1436 ipforward_rt.ro_rt = 0;
1437 }
1438 sin->sin_family = AF_INET;
1439 sin->sin_len = sizeof(*sin);
1440 sin->sin_addr = ip->ip_dst;
1441
1442 rtalloc_ign(&ipforward_rt, RTF_PRCLONING);
1443 if (ipforward_rt.ro_rt == 0) {
1444 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
1445 return;
1446 }
1447 rt = ipforward_rt.ro_rt;
1448 }
1449
1450 /*
1451 * Save at most 64 bytes of the packet in case
1452 * we need to generate an ICMP message to the src.
1453 */
1454 mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64));
1455
1456 /*
1457 * If forwarding packet using same interface that it came in on,
1458 * perhaps should send a redirect to sender to shortcut a hop.
1459 * Only send redirect if source is sending directly to us,
1460 * and if packet was not source routed (or has any options).
1461 * Also, don't send redirect if forwarding using a default route
1462 * or a route modified by a redirect.
1463 */
1464#define satosin(sa) ((struct sockaddr_in *)(sa))
1465 if (rt->rt_ifp == m->m_pkthdr.rcvif &&
1466 (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
1467 satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
1468 ipsendredirects && !srcrt) {
1469#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa))
1470 u_long src = ntohl(ip->ip_src.s_addr);
1471
1472 if (RTA(rt) &&
1473 (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
1474 if (rt->rt_flags & RTF_GATEWAY)
1475 dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
1476 else
1477 dest = ip->ip_dst.s_addr;
1478 /* Router requirements says to only send host redirects */
1479 type = ICMP_REDIRECT;
1480 code = ICMP_REDIRECT_HOST;
1481#ifdef DIAGNOSTIC
1482 if (ipprintfs)
1483 printf("redirect (%d) to %lx\n", code, (u_long)dest);
1484#endif
1485 }
1486 }
1487
1488 error = ip_output(m, (struct mbuf *)0, &ipforward_rt,
1489 IP_FORWARDING, 0);
1490 if (error)
1491 ipstat.ips_cantforward++;
1492 else {
1493 ipstat.ips_forward++;
1494 if (type)
1495 ipstat.ips_redirectsent++;
1496 else {
1497 if (mcopy) {
1498 ipflow_create(&ipforward_rt, mcopy);
1499 m_freem(mcopy);
1500 }
1501 return;
1502 }
1503 }
1504 if (mcopy == NULL)
1505 return;
1506 destifp = NULL;
1507
1508 switch (error) {
1509
1510 case 0: /* forwarded, but need redirect */
1511 /* type, code set above */
1512 break;
1513
1514 case ENETUNREACH: /* shouldn't happen, checked above */
1515 case EHOSTUNREACH:
1516 case ENETDOWN:
1517 case EHOSTDOWN:
1518 default:
1519 type = ICMP_UNREACH;
1520 code = ICMP_UNREACH_HOST;
1521 break;
1522
1523 case EMSGSIZE:
1524 type = ICMP_UNREACH;
1525 code = ICMP_UNREACH_NEEDFRAG;
1453
1454 dest = 0;
1455#ifdef DIAGNOSTIC
1456 if (ipprintfs)
1457 printf("forward: src %lx dst %lx ttl %x\n",
1458 (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr,
1459 ip->ip_ttl);
1460#endif
1461
1462
1463 if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
1464 ipstat.ips_cantforward++;
1465 m_freem(m);
1466 return;
1467 }
1468 HTONS(ip->ip_id);
1469#ifdef IPSTEALTH
1470 if (!ipstealth) {
1471#endif
1472 if (ip->ip_ttl <= IPTTLDEC) {
1473 icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
1474 dest, 0);
1475 return;
1476 }
1477 ip->ip_ttl -= IPTTLDEC;
1478#ifdef IPSTEALTH
1479 }
1480#endif
1481
1482 sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
1483 if ((rt = ipforward_rt.ro_rt) == 0 ||
1484 ip->ip_dst.s_addr != sin->sin_addr.s_addr) {
1485 if (ipforward_rt.ro_rt) {
1486 RTFREE(ipforward_rt.ro_rt);
1487 ipforward_rt.ro_rt = 0;
1488 }
1489 sin->sin_family = AF_INET;
1490 sin->sin_len = sizeof(*sin);
1491 sin->sin_addr = ip->ip_dst;
1492
1493 rtalloc_ign(&ipforward_rt, RTF_PRCLONING);
1494 if (ipforward_rt.ro_rt == 0) {
1495 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
1496 return;
1497 }
1498 rt = ipforward_rt.ro_rt;
1499 }
1500
1501 /*
1502 * Save at most 64 bytes of the packet in case
1503 * we need to generate an ICMP message to the src.
1504 */
1505 mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64));
1506
1507 /*
1508 * If forwarding packet using same interface that it came in on,
1509 * perhaps should send a redirect to sender to shortcut a hop.
1510 * Only send redirect if source is sending directly to us,
1511 * and if packet was not source routed (or has any options).
1512 * Also, don't send redirect if forwarding using a default route
1513 * or a route modified by a redirect.
1514 */
1515#define satosin(sa) ((struct sockaddr_in *)(sa))
1516 if (rt->rt_ifp == m->m_pkthdr.rcvif &&
1517 (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
1518 satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
1519 ipsendredirects && !srcrt) {
1520#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa))
1521 u_long src = ntohl(ip->ip_src.s_addr);
1522
1523 if (RTA(rt) &&
1524 (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
1525 if (rt->rt_flags & RTF_GATEWAY)
1526 dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
1527 else
1528 dest = ip->ip_dst.s_addr;
1529 /* Router requirements says to only send host redirects */
1530 type = ICMP_REDIRECT;
1531 code = ICMP_REDIRECT_HOST;
1532#ifdef DIAGNOSTIC
1533 if (ipprintfs)
1534 printf("redirect (%d) to %lx\n", code, (u_long)dest);
1535#endif
1536 }
1537 }
1538
1539 error = ip_output(m, (struct mbuf *)0, &ipforward_rt,
1540 IP_FORWARDING, 0);
1541 if (error)
1542 ipstat.ips_cantforward++;
1543 else {
1544 ipstat.ips_forward++;
1545 if (type)
1546 ipstat.ips_redirectsent++;
1547 else {
1548 if (mcopy) {
1549 ipflow_create(&ipforward_rt, mcopy);
1550 m_freem(mcopy);
1551 }
1552 return;
1553 }
1554 }
1555 if (mcopy == NULL)
1556 return;
1557 destifp = NULL;
1558
1559 switch (error) {
1560
1561 case 0: /* forwarded, but need redirect */
1562 /* type, code set above */
1563 break;
1564
1565 case ENETUNREACH: /* shouldn't happen, checked above */
1566 case EHOSTUNREACH:
1567 case ENETDOWN:
1568 case EHOSTDOWN:
1569 default:
1570 type = ICMP_UNREACH;
1571 code = ICMP_UNREACH_HOST;
1572 break;
1573
1574 case EMSGSIZE:
1575 type = ICMP_UNREACH;
1576 code = ICMP_UNREACH_NEEDFRAG;
1577#ifndef IPSEC
1526 if (ipforward_rt.ro_rt)
1527 destifp = ipforward_rt.ro_rt->rt_ifp;
1578 if (ipforward_rt.ro_rt)
1579 destifp = ipforward_rt.ro_rt->rt_ifp;
1580#else
1581 /*
1582 * If the packet is routed over IPsec tunnel, tell the
1583 * originator the tunnel MTU.
1584 * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
1585 * XXX quickhack!!!
1586 */
1587 if (ipforward_rt.ro_rt) {
1588 struct secpolicy *sp = NULL;
1589 int ipsecerror;
1590 int ipsechdr;
1591 struct route *ro;
1592
1593 sp = ipsec4_getpolicybyaddr(mcopy,
1594 IPSEC_DIR_OUTBOUND,
1595 IP_FORWARDING,
1596 &ipsecerror);
1597
1598 if (sp == NULL)
1599 destifp = ipforward_rt.ro_rt->rt_ifp;
1600 else {
1601 /* count IPsec header size */
1602 ipsechdr = ipsec4_hdrsiz(mcopy,
1603 IPSEC_DIR_OUTBOUND,
1604 NULL);
1605
1606 /*
1607 * find the correct route for outer IPv4
1608 * header, compute tunnel MTU.
1609 *
1610 * XXX BUG ALERT
1611 * The "dummyifp" code relies upon the fact
1612 * that icmp_error() touches only ifp->if_mtu.
1613 */
1614 /*XXX*/
1615 destifp = NULL;
1616 if (sp->req != NULL
1617 && sp->req->sav != NULL
1618 && sp->req->sav->sah != NULL) {
1619 ro = &sp->req->sav->sah->sa_route;
1620 if (ro->ro_rt && ro->ro_rt->rt_ifp) {
1621 dummyifp.if_mtu =
1622 ro->ro_rt->rt_ifp->if_mtu;
1623 dummyifp.if_mtu -= ipsechdr;
1624 destifp = &dummyifp;
1625 }
1626 }
1627
1628 key_freesp(sp);
1629 }
1630 }
1631#endif /*IPSEC*/
1528 ipstat.ips_cantfrag++;
1529 break;
1530
1531 case ENOBUFS:
1532 type = ICMP_SOURCEQUENCH;
1533 code = 0;
1534 break;
1535 }
1536 icmp_error(mcopy, type, code, dest, destifp);
1537}
1538
1539void
1540ip_savecontrol(inp, mp, ip, m)
1541 register struct inpcb *inp;
1542 register struct mbuf **mp;
1543 register struct ip *ip;
1544 register struct mbuf *m;
1545{
1546 if (inp->inp_socket->so_options & SO_TIMESTAMP) {
1547 struct timeval tv;
1548
1549 microtime(&tv);
1550 *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
1551 SCM_TIMESTAMP, SOL_SOCKET);
1552 if (*mp)
1553 mp = &(*mp)->m_next;
1554 }
1555 if (inp->inp_flags & INP_RECVDSTADDR) {
1556 *mp = sbcreatecontrol((caddr_t) &ip->ip_dst,
1557 sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP);
1558 if (*mp)
1559 mp = &(*mp)->m_next;
1560 }
1561#ifdef notyet
1562 /* XXX
1563 * Moving these out of udp_input() made them even more broken
1564 * than they already were.
1565 */
1566 /* options were tossed already */
1567 if (inp->inp_flags & INP_RECVOPTS) {
1568 *mp = sbcreatecontrol((caddr_t) opts_deleted_above,
1569 sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP);
1570 if (*mp)
1571 mp = &(*mp)->m_next;
1572 }
1573 /* ip_srcroute doesn't do what we want here, need to fix */
1574 if (inp->inp_flags & INP_RECVRETOPTS) {
1575 *mp = sbcreatecontrol((caddr_t) ip_srcroute(),
1576 sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP);
1577 if (*mp)
1578 mp = &(*mp)->m_next;
1579 }
1580#endif
1581 if (inp->inp_flags & INP_RECVIF) {
1582 struct ifnet *ifp;
1583 struct sdlbuf {
1584 struct sockaddr_dl sdl;
1585 u_char pad[32];
1586 } sdlbuf;
1587 struct sockaddr_dl *sdp;
1588 struct sockaddr_dl *sdl2 = &sdlbuf.sdl;
1589
1590 if (((ifp = m->m_pkthdr.rcvif))
1591 && ( ifp->if_index && (ifp->if_index <= if_index))) {
1592 sdp = (struct sockaddr_dl *)(ifnet_addrs
1593 [ifp->if_index - 1]->ifa_addr);
1594 /*
1595 * Change our mind and don't try copy.
1596 */
1597 if ((sdp->sdl_family != AF_LINK)
1598 || (sdp->sdl_len > sizeof(sdlbuf))) {
1599 goto makedummy;
1600 }
1601 bcopy(sdp, sdl2, sdp->sdl_len);
1602 } else {
1603makedummy:
1604 sdl2->sdl_len
1605 = offsetof(struct sockaddr_dl, sdl_data[0]);
1606 sdl2->sdl_family = AF_LINK;
1607 sdl2->sdl_index = 0;
1608 sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0;
1609 }
1610 *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len,
1611 IP_RECVIF, IPPROTO_IP);
1612 if (*mp)
1613 mp = &(*mp)->m_next;
1614 }
1615}
1616
1617int
1618ip_rsvp_init(struct socket *so)
1619{
1620 if (so->so_type != SOCK_RAW ||
1621 so->so_proto->pr_protocol != IPPROTO_RSVP)
1622 return EOPNOTSUPP;
1623
1624 if (ip_rsvpd != NULL)
1625 return EADDRINUSE;
1626
1627 ip_rsvpd = so;
1628 /*
1629 * This may seem silly, but we need to be sure we don't over-increment
1630 * the RSVP counter, in case something slips up.
1631 */
1632 if (!ip_rsvp_on) {
1633 ip_rsvp_on = 1;
1634 rsvp_on++;
1635 }
1636
1637 return 0;
1638}
1639
1640int
1641ip_rsvp_done(void)
1642{
1643 ip_rsvpd = NULL;
1644 /*
1645 * This may seem silly, but we need to be sure we don't over-decrement
1646 * the RSVP counter, in case something slips up.
1647 */
1648 if (ip_rsvp_on) {
1649 ip_rsvp_on = 0;
1650 rsvp_on--;
1651 }
1652 return 0;
1653}
1632 ipstat.ips_cantfrag++;
1633 break;
1634
1635 case ENOBUFS:
1636 type = ICMP_SOURCEQUENCH;
1637 code = 0;
1638 break;
1639 }
1640 icmp_error(mcopy, type, code, dest, destifp);
1641}
1642
1643void
1644ip_savecontrol(inp, mp, ip, m)
1645 register struct inpcb *inp;
1646 register struct mbuf **mp;
1647 register struct ip *ip;
1648 register struct mbuf *m;
1649{
1650 if (inp->inp_socket->so_options & SO_TIMESTAMP) {
1651 struct timeval tv;
1652
1653 microtime(&tv);
1654 *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
1655 SCM_TIMESTAMP, SOL_SOCKET);
1656 if (*mp)
1657 mp = &(*mp)->m_next;
1658 }
1659 if (inp->inp_flags & INP_RECVDSTADDR) {
1660 *mp = sbcreatecontrol((caddr_t) &ip->ip_dst,
1661 sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP);
1662 if (*mp)
1663 mp = &(*mp)->m_next;
1664 }
1665#ifdef notyet
1666 /* XXX
1667 * Moving these out of udp_input() made them even more broken
1668 * than they already were.
1669 */
1670 /* options were tossed already */
1671 if (inp->inp_flags & INP_RECVOPTS) {
1672 *mp = sbcreatecontrol((caddr_t) opts_deleted_above,
1673 sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP);
1674 if (*mp)
1675 mp = &(*mp)->m_next;
1676 }
1677 /* ip_srcroute doesn't do what we want here, need to fix */
1678 if (inp->inp_flags & INP_RECVRETOPTS) {
1679 *mp = sbcreatecontrol((caddr_t) ip_srcroute(),
1680 sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP);
1681 if (*mp)
1682 mp = &(*mp)->m_next;
1683 }
1684#endif
1685 if (inp->inp_flags & INP_RECVIF) {
1686 struct ifnet *ifp;
1687 struct sdlbuf {
1688 struct sockaddr_dl sdl;
1689 u_char pad[32];
1690 } sdlbuf;
1691 struct sockaddr_dl *sdp;
1692 struct sockaddr_dl *sdl2 = &sdlbuf.sdl;
1693
1694 if (((ifp = m->m_pkthdr.rcvif))
1695 && ( ifp->if_index && (ifp->if_index <= if_index))) {
1696 sdp = (struct sockaddr_dl *)(ifnet_addrs
1697 [ifp->if_index - 1]->ifa_addr);
1698 /*
1699 * Change our mind and don't try copy.
1700 */
1701 if ((sdp->sdl_family != AF_LINK)
1702 || (sdp->sdl_len > sizeof(sdlbuf))) {
1703 goto makedummy;
1704 }
1705 bcopy(sdp, sdl2, sdp->sdl_len);
1706 } else {
1707makedummy:
1708 sdl2->sdl_len
1709 = offsetof(struct sockaddr_dl, sdl_data[0]);
1710 sdl2->sdl_family = AF_LINK;
1711 sdl2->sdl_index = 0;
1712 sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0;
1713 }
1714 *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len,
1715 IP_RECVIF, IPPROTO_IP);
1716 if (*mp)
1717 mp = &(*mp)->m_next;
1718 }
1719}
1720
1721int
1722ip_rsvp_init(struct socket *so)
1723{
1724 if (so->so_type != SOCK_RAW ||
1725 so->so_proto->pr_protocol != IPPROTO_RSVP)
1726 return EOPNOTSUPP;
1727
1728 if (ip_rsvpd != NULL)
1729 return EADDRINUSE;
1730
1731 ip_rsvpd = so;
1732 /*
1733 * This may seem silly, but we need to be sure we don't over-increment
1734 * the RSVP counter, in case something slips up.
1735 */
1736 if (!ip_rsvp_on) {
1737 ip_rsvp_on = 1;
1738 rsvp_on++;
1739 }
1740
1741 return 0;
1742}
1743
1744int
1745ip_rsvp_done(void)
1746{
1747 ip_rsvpd = NULL;
1748 /*
1749 * This may seem silly, but we need to be sure we don't over-decrement
1750 * the RSVP counter, in case something slips up.
1751 */
1752 if (ip_rsvp_on) {
1753 ip_rsvp_on = 0;
1754 rsvp_on--;
1755 }
1756 return 0;
1757}