]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/ip_fastfwd.c
This commit was generated by cvs2svn to compensate for changes in r128345,
[FreeBSD/FreeBSD.git] / sys / netinet / ip_fastfwd.c
1 /*
2  * Copyright (c) 2003 Andre Oppermann, Internet Business Solutions AG
3  * 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. The name of the author may not be used to endorse or promote
14  *    products derived from this software without specific prior written
15  *    permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 /*
33  * ip_fastforward gets its speed from processing the forwarded packet to
34  * completion (if_output on the other side) without any queues or netisr's.
35  * The receiving interface DMAs the packet into memory, the upper half of
36  * driver calls ip_fastforward, we do our routing table lookup and directly
37  * send it off to the outgoing interface which DMAs the packet to the
38  * network card. The only part of the packet we touch with the CPU is the
39  * IP header (unless there are complex firewall rules touching other parts
40  * of the packet, but that is up to you). We are essentially limited by bus
41  * bandwidth and how fast the network card/driver can set up receives and
42  * transmits.
43  *
44  * We handle basic errors, ip header errors, checksum errors,
45  * destination unreachable, fragmentation and fragmentation needed and
46  * report them via icmp to the sender.
47  *
48  * Else if something is not pure IPv4 unicast forwarding we fall back to
49  * the normal ip_input processing path. We should only be called from
50  * interfaces connected to the outside world.
51  *
52  * Firewalling is fully supported including divert, ipfw fwd and ipfilter
53  * ipnat and address rewrite.
54  *
55  * IPSEC is not supported if this host is a tunnel broker. IPSEC is
56  * supported for connections to/from local host.
57  *
58  * We try to do the least expensive (in CPU ops) checks and operations
59  * first to catch junk with as little overhead as possible.
60  * 
61  * We take full advantage of hardware support for ip checksum and
62  * fragmentation offloading.
63  *
64  * We don't do ICMP redirect in the fast forwarding path. I have had my own
65  * cases where two core routers with Zebra routing suite would send millions
66  * ICMP redirects to connected hosts if the router to dest was not the default
67  * gateway. In one case it was filling the routing table of a host with close
68  * 300'000 cloned redirect entries until it ran out of kernel memory. However
69  * the networking code proved very robust and it didn't crash or went ill
70  * otherwise.
71  */
72
73 /*
74  * Many thanks to Matt Thomas of NetBSD for basic structure of ip_flow.c which
75  * is being followed here.
76  */
77
78 #include "opt_ipfw.h"
79 #include "opt_ipdn.h"
80 #include "opt_ipdivert.h"
81 #include "opt_ipfilter.h"
82 #include "opt_ipstealth.h"
83 #include "opt_mac.h"
84 #include "opt_pfil_hooks.h"
85
86 #include <sys/param.h>
87 #include <sys/systm.h>
88 #include <sys/kernel.h>
89 #include <sys/mac.h>
90 #include <sys/malloc.h>
91 #include <sys/mbuf.h>
92 #include <sys/protosw.h>
93 #include <sys/socket.h>
94 #include <sys/sysctl.h>
95
96 #include <net/pfil.h>
97 #include <net/if.h>
98 #include <net/if_types.h>
99 #include <net/if_var.h>
100 #include <net/if_dl.h>
101 #include <net/route.h>
102
103 #include <netinet/in.h>
104 #include <netinet/in_systm.h>
105 #include <netinet/in_var.h>
106 #include <netinet/ip.h>
107 #include <netinet/ip_var.h>
108 #include <netinet/ip_icmp.h>
109
110 #include <machine/in_cksum.h>
111
112 #include <netinet/ip_fw.h>
113 #include <netinet/ip_divert.h>
114 #include <netinet/ip_dummynet.h>
115
116 static int ipfastforward_active = 0;
117 SYSCTL_INT(_net_inet_ip, OID_AUTO, fastforwarding, CTLFLAG_RW,
118     &ipfastforward_active, 0, "Enable fast IP forwarding");
119
120 /*
121  * Try to forward a packet based on the destination address.
122  * This is a fast path optimized for the plain forwarding case.
123  * If the packet is handled (and consumed) here then we return 1;
124  * otherwise 0 is returned and the packet should be delivered
125  * to ip_input for full processing.
126  */
127 int
128 ip_fastforward(struct mbuf *m)
129 {
130         struct ip *ip;
131         struct mbuf *m0 = NULL;
132 #ifdef IPDIVERT
133         struct ip *tip;
134         struct mbuf *clone = NULL;
135 #endif
136         struct route ro;
137         struct sockaddr_in *dst = NULL;
138         struct in_ifaddr *ia = NULL;
139         struct ifaddr *ifa = NULL;
140         struct ifnet *ifp = NULL;
141         struct ip_fw_args args;
142         in_addr_t odest, dest;
143         u_short sum;
144         int error = 0;
145         int hlen, ipfw, mtu;
146
147         /*
148          * Are we active and forwarding packets?
149          */
150         if (!ipfastforward_active || !ipforwarding)
151                 return 0;
152
153         M_ASSERTVALID(m);
154         M_ASSERTPKTHDR(m);
155
156         /*
157          * Step 1: check for packet drop conditions (and sanity checks)
158          */
159
160         /*
161          * Is entire packet big enough?
162          */
163         if (m->m_pkthdr.len < sizeof(struct ip)) {
164                 ipstat.ips_tooshort++;
165                 goto drop;
166         }
167
168         /*
169          * Is first mbuf large enough for ip header and is header present?
170          */
171         if (m->m_len < sizeof (struct ip) &&
172            (m = m_pullup(m, sizeof (struct ip))) == 0) {
173                 ipstat.ips_toosmall++;
174                 goto drop;
175         }
176
177         ip = mtod(m, struct ip *);
178
179         /*
180          * Is it IPv4?
181          */
182         if (ip->ip_v != IPVERSION) {
183                 ipstat.ips_badvers++;
184                 goto drop;
185         }
186
187         /*
188          * Is IP header length correct and is it in first mbuf?
189          */
190         hlen = ip->ip_hl << 2;
191         if (hlen < sizeof(struct ip)) { /* minimum header length */
192                 ipstat.ips_badlen++;
193                 goto drop;
194         }
195         if (hlen > m->m_len) {
196                 if ((m = m_pullup(m, hlen)) == 0) {
197                         ipstat.ips_badhlen++;
198                         goto drop;
199                 }
200                 ip = mtod(m, struct ip *);
201         }
202
203         /*
204          * Checksum correct?
205          */
206         if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED)
207                 sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
208         else {
209                 if (hlen == sizeof(struct ip))
210                         sum = in_cksum_hdr(ip);
211                 else
212                         sum = in_cksum(m, hlen);
213         }
214         if (sum) {
215                 ipstat.ips_badsum++;
216                 goto drop;
217         }
218         m->m_pkthdr.csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID);
219
220         /*
221          * Convert to host representation
222          */
223         ip->ip_len = ntohs(ip->ip_len);
224         ip->ip_off = ntohs(ip->ip_off);
225
226         /*
227          * Is IP length longer than packet we have got?
228          */
229         if (m->m_pkthdr.len < ip->ip_len) {
230                 ipstat.ips_tooshort++;
231                 goto drop;
232         }
233
234         /*
235          * Is packet longer than IP header tells us? If yes, truncate packet.
236          */
237         if (m->m_pkthdr.len > ip->ip_len) {
238                 if (m->m_len == m->m_pkthdr.len) {
239                         m->m_len = ip->ip_len;
240                         m->m_pkthdr.len = ip->ip_len;
241                 } else
242                         m_adj(m, ip->ip_len - m->m_pkthdr.len);
243         }
244
245         /*
246          * Is packet from or to 127/8?
247          */
248         if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
249             (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
250                 ipstat.ips_badaddr++;
251                 goto drop;
252         }
253
254         /*
255          * Step 2: fallback conditions to normal ip_input path processing
256          */
257
258         /*
259          * Only IP packets without options
260          */
261         if (ip->ip_hl != (sizeof(struct ip) >> 2))
262                 goto fallback;
263
264         /*
265          * Only unicast IP, not from loopback, no L2 or IP broadcast,
266          * no multicast, no INADDR_ANY
267          *
268          * XXX: Probably some of these checks could be direct drop
269          * conditions.  However it is not clear whether there are some
270          * hacks or obscure behaviours which make it neccessary to
271          * let ip_input handle it.  We play safe here and let ip_input
272          * deal with it until it is proven that we can directly drop it.
273          */
274         if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) ||
275             ntohl(ip->ip_src.s_addr) == (u_long)INADDR_BROADCAST ||
276             ntohl(ip->ip_dst.s_addr) == (u_long)INADDR_BROADCAST ||
277             IN_MULTICAST(ntohl(ip->ip_src.s_addr)) ||
278             IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
279             ip->ip_dst.s_addr == INADDR_ANY )
280                 goto fallback;
281
282         /*
283          * Is it for a local address on this host?
284          */
285         LIST_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) {
286                 if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
287                         goto fallback;
288         }
289
290         /*
291          * Or is it for a local IP broadcast address on this host?
292          */
293         if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) {
294                 TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) {
295                         if (ifa->ifa_addr->sa_family != AF_INET)
296                                 continue;
297                         ia = ifatoia(ifa);
298                         if (ia->ia_netbroadcast.s_addr == ip->ip_dst.s_addr)
299                                 goto fallback;
300                         if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
301                             ip->ip_dst.s_addr)
302                                 goto fallback;
303                         continue;
304 fallback:
305                         /* return packet back to netisr for slow processing */
306                         ip->ip_len = htons(ip->ip_len);
307                         ip->ip_off = htons(ip->ip_off);
308                         return 0;
309                 }
310         }
311         ipstat.ips_total++;
312
313         /*
314          * Step 3: incoming packet firewall processing
315          */
316
317         odest = dest = ip->ip_dst.s_addr;
318 #ifdef PFIL_HOOKS
319         /*
320          * Run through list of ipfilter hooks for input packets
321          */
322         if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN) ||
323             m == NULL)
324                 return 1;
325
326         M_ASSERTVALID(m);
327         M_ASSERTPKTHDR(m);
328
329         ip = mtod(m, struct ip *);      /* m may have changed by pfil hook */
330         dest = ip->ip_dst.s_addr;
331 #endif
332
333         /*
334          * Run through ipfw for input packets
335          */
336         if (fw_enable && IPFW_LOADED) {
337                 bzero(&args, sizeof(args));
338                 args.m = m;
339
340                 ipfw = ip_fw_chk_ptr(&args);
341                 m = args.m;
342
343                 M_ASSERTVALID(m);
344                 M_ASSERTPKTHDR(m);
345
346                 /*
347                  * Packet denied, drop it
348                  */
349                 if ((ipfw & IP_FW_PORT_DENY_FLAG) || m == NULL)
350                         goto drop;
351                 /*
352                  * Send packet to the appropriate pipe
353                  */
354                 if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
355                         ip_dn_io_ptr(m, ipfw & 0xffff, DN_TO_IP_IN, &args);
356                         return 1;
357                 }
358 #ifdef IPDIVERT
359                 /*
360                  * Divert packet
361                  */
362                 if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
363                         /*
364                          * See if this is a fragment
365                          */
366                         if (ip->ip_off & (IP_MF | IP_OFFMASK))
367                                 goto droptoours;
368                         /*
369                          * Tee packet
370                          */
371                         if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
372                                 clone = divert_clone(m);
373                         else
374                                 clone = m;
375                         if (clone == NULL)
376                                 goto passin;
377
378                         /*
379                          * Delayed checksums are not compatible
380                          */
381                         if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
382                                 in_delayed_cksum(m);
383                                 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
384                         }
385                         /*
386                          * Restore packet header fields to original values
387                          */
388                         tip = mtod(m, struct ip *);
389                         tip->ip_len = htons(tip->ip_len);
390                         tip->ip_off = htons(tip->ip_off);
391                         /*
392                          * Deliver packet to divert input routine
393                          */
394                         divert_packet(m, 0);
395                         /*
396                          * If this was not tee, we are done
397                          */
398                         m = clone;
399                         if ((ipfw & IP_FW_PORT_TEE_FLAG) == 0)
400                                 return 1;
401                         /* Continue if it was tee */
402                         goto passin;
403                 }
404 #endif
405                 if (ipfw == 0 && args.next_hop != NULL) {
406                         dest = args.next_hop->sin_addr.s_addr;
407                         goto passin;
408                 }
409                 /*
410                  * Let through or not?
411                  */
412                 if (ipfw != 0)
413                         goto drop;
414         }
415 passin:
416         ip = mtod(m, struct ip *);      /* if m changed during fw processing */
417
418         /*
419          * Destination address changed?
420          */
421         if (odest != dest) {
422                 /*
423                  * Is it now for a local address on this host?
424                  */
425                 LIST_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) {
426                         if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
427                                 goto forwardlocal;
428                 }
429                 /*
430                  * Go on with new destination address
431                  */
432         }
433
434         /*
435          * Step 4: decrement TTL and look up route
436          */
437
438         /*
439          * Check TTL
440          */
441 #ifdef IPSTEALTH
442         if (!ipstealth) {
443 #endif
444         if (ip->ip_ttl <= IPTTLDEC) {
445                 icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, NULL);
446                 return 1;
447         }
448
449         /*
450          * Decrement the TTL and incrementally change the checksum.
451          * Don't bother doing this with hw checksum offloading.
452          */
453         ip->ip_ttl -= IPTTLDEC;
454         if (ip->ip_sum >= (u_int16_t) ~htons(IPTTLDEC << 8))
455                 ip->ip_sum -= ~htons(IPTTLDEC << 8);
456         else
457                 ip->ip_sum += htons(IPTTLDEC << 8);
458 #ifdef IPSTEALTH
459         }
460 #endif
461
462         /*
463          * Find route to destination.
464          */
465         bzero(&ro, sizeof(ro));
466         dst = (struct sockaddr_in *)&ro.ro_dst;
467         dst->sin_family = AF_INET;
468         dst->sin_len = sizeof(*dst);
469         dst->sin_addr.s_addr = dest;
470         rtalloc_ign(&ro, RTF_CLONING);
471
472         /*
473          * Route there and interface still up?
474          */
475         if (ro.ro_rt &&
476             (ro.ro_rt->rt_flags & RTF_UP) &&
477             (ro.ro_rt->rt_ifp->if_flags & IFF_UP)) {
478                 ia = ifatoia(ro.ro_rt->rt_ifa);
479                 ifp = ro.ro_rt->rt_ifp;
480                 if (ro.ro_rt->rt_flags & RTF_GATEWAY)
481                         dst = (struct sockaddr_in *)ro.ro_rt->rt_gateway;
482         } else {
483                 ipstat.ips_noroute++;
484                 ipstat.ips_cantforward++;
485                 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, NULL);
486                 if (ro.ro_rt)
487                         RTFREE(ro.ro_rt);
488                 return 1;
489         }
490
491         /*
492          * Step 5: outgoing firewall packet processing
493          */
494
495 #ifdef PFIL_HOOKS
496         /*
497          * Run through list of hooks for output packets.
498          */
499         if (pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT) || m == NULL) {
500                 RTFREE(ro.ro_rt);
501                 return 1;
502         }
503
504         M_ASSERTVALID(m);
505         M_ASSERTPKTHDR(m);
506
507         ip = mtod(m, struct ip *);
508         dest = ip->ip_dst.s_addr;
509 #endif
510         if (fw_enable && IPFW_LOADED && !args.next_hop) {
511                 bzero(&args, sizeof(args));
512                 args.m = m;
513                 args.oif = ifp;
514
515                 ipfw = ip_fw_chk_ptr(&args);
516                 m = args.m;
517
518                 M_ASSERTVALID(m);
519                 M_ASSERTPKTHDR(m);
520
521                 if ((ipfw & IP_FW_PORT_DENY_FLAG) || m == NULL) {
522                         RTFREE(ro.ro_rt);
523                         goto drop;
524                 }
525                 if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
526                         /*
527                          * XXX note: if the ifp or rt entry are deleted
528                          * while a pkt is in dummynet, we are in trouble!
529                          */
530                         args.ro = &ro;          /* dummynet does not save it */
531                         args.dst = dst;
532
533                         ip_dn_io_ptr(m, ipfw & 0xffff, DN_TO_IP_OUT, &args);
534                         RTFREE(ro.ro_rt);
535                         return 1;
536                 }
537 #ifdef IPDIVERT
538                 if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
539                         /*
540                          * See if this is a fragment
541                          */
542                         if (ip->ip_off & (IP_MF | IP_OFFMASK))
543                                 goto droptoours;
544                         /*
545                          * Tee packet
546                          */
547                         if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
548                                 clone = divert_clone(m);
549                         else
550                                 clone = m;
551                         if (clone == NULL)
552                                 goto passout;
553
554                         /*
555                          * Delayed checksums are not compatible with divert
556                          */
557                         if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
558                                 in_delayed_cksum(m);
559                                 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
560                         }
561                         /*
562                          * Restore packet header fields to original values
563                          */
564                         tip = mtod(m, struct ip *);
565                         tip->ip_len = htons(tip->ip_len);
566                         tip->ip_off = htons(tip->ip_off);
567                         /*
568                          * Deliver packet to divert input routine
569                          */
570                         divert_packet(m, 0);
571                         /*
572                          * If this was not tee, we are done
573                          */
574                         m = clone;
575                         if ((ipfw & IP_FW_PORT_TEE_FLAG) == 0) {
576                                 RTFREE(ro.ro_rt);
577                                 return 1;
578                         }
579                         /* Continue if it was tee */
580                         goto passout;
581                 }
582 #endif
583                 if (ipfw == 0 && args.next_hop != NULL) {
584                         dest = args.next_hop->sin_addr.s_addr;
585                         goto passout;
586                 }
587                 /*
588                  * Let through or not?
589                  */
590                 if (ipfw != 0)
591                         goto drop;
592         }
593 passout:
594         ip = mtod(m, struct ip *);
595
596         /*
597          * Destination address changed?
598          */
599         if (odest != dest) {
600                 /*
601                  * Is it now for a local address on this host?
602                  */
603                 LIST_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) {
604                         if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) {
605 forwardlocal:
606                                 if (args.next_hop) {
607                                         struct m_tag *mtag = m_tag_get(
608                                             PACKET_TAG_IPFORWARD,
609                                             sizeof(struct sockaddr_in *),
610                                             M_NOWAIT);
611                                         if (mtag == NULL) {
612                                                 if (ro.ro_rt)
613                                                         RTFREE(ro.ro_rt);
614                                                 goto drop;
615                                         }
616                                         *(struct sockaddr_in **)(mtag+1) =
617                                             args.next_hop;
618                                         m_tag_prepend(m, mtag);
619                                 }
620 #ifdef IPDIVERT
621 droptoours:     /* Used for DIVERT */
622 #endif
623                                 /* for ip_input */
624                                 m->m_flags |= M_FASTFWD_OURS;
625
626                                 /* ip still points to the real packet */
627                                 ip->ip_len = htons(ip->ip_len);
628                                 ip->ip_off = htons(ip->ip_off);
629
630                                 /*
631                                  * Return packet for processing by ip_input
632                                  */
633                                 if (ro.ro_rt)
634                                         RTFREE(ro.ro_rt);
635                                 return 0;
636                         }
637                 }
638                 /*
639                  * Redo route lookup with new destination address
640                  */
641                 RTFREE(ro.ro_rt);
642                 bzero(&ro, sizeof(ro));
643                 dst = (struct sockaddr_in *)&ro.ro_dst;
644                 dst->sin_family = AF_INET;
645                 dst->sin_len = sizeof(*dst);
646                 dst->sin_addr.s_addr = dest;
647                 rtalloc_ign(&ro, RTF_CLONING);
648
649                 /*
650                  * Route there and interface still up?
651                  */
652                 if (ro.ro_rt &&
653                     (ro.ro_rt->rt_flags & RTF_UP) &&
654                     (ro.ro_rt->rt_ifp->if_flags & IFF_UP)) {
655                         ia = ifatoia(ro.ro_rt->rt_ifa);
656                         ifp = ro.ro_rt->rt_ifp;
657                         if (ro.ro_rt->rt_flags & RTF_GATEWAY)
658                                 dst = (struct sockaddr_in *)ro.ro_rt->rt_gateway;
659                 } else {
660                         ipstat.ips_noroute++;
661                         ipstat.ips_cantforward++;
662                         icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, NULL);
663                         if (ro.ro_rt)
664                                 RTFREE(ro.ro_rt);
665                         return 1;
666                 }
667         }
668
669         /*
670          * Step 6: send off the packet
671          */
672
673         /*
674          * Check if packet fits MTU or if hardware will fragement for us
675          */
676         if (ro.ro_rt->rt_rmx.rmx_mtu)
677                 mtu = min(ro.ro_rt->rt_rmx.rmx_mtu, ifp->if_mtu);
678         else
679                 mtu = ifp->if_mtu;
680
681         if (ip->ip_len <= mtu ||
682             (ifp->if_hwassist & CSUM_FRAGMENT && (ip->ip_off & IP_DF) == 0)) {
683                 /*
684                  * Restore packet header fields to original values
685                  */
686                 ip->ip_len = htons(ip->ip_len);
687                 ip->ip_off = htons(ip->ip_off);
688                 /*
689                  * Send off the packet via outgoing interface
690                  */
691                 error = (*ifp->if_output)(ifp, m,
692                                 (struct sockaddr *)dst, ro.ro_rt);
693                 if (ia) {
694                         ia->ia_ifa.if_opackets++;
695                         ia->ia_ifa.if_obytes += m->m_pkthdr.len;
696                 }
697         } else {
698                 /*
699                  * Handle EMSGSIZE with icmp reply
700                  * needfrag for TCP MTU discovery
701                  */
702                 if (ip->ip_off & IP_DF) {
703                         icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG,
704                                 0, ifp);
705                         ipstat.ips_cantfrag++;
706                         RTFREE(ro.ro_rt);
707                         return 1;
708                 } else {
709                         /*
710                          * We have to fragement the packet
711                          */
712                         m->m_pkthdr.csum_flags |= CSUM_IP;
713                         if (ip_fragment(ip, &m, mtu, ifp->if_hwassist,
714                                         (~ifp->if_hwassist & CSUM_DELAY_IP))) {
715                                 RTFREE(ro.ro_rt);
716                                 goto drop;
717                         }
718                         KASSERT(m != NULL, ("null mbuf and no error"));
719                         /*
720                          * Send off the fragments via outgoing interface
721                          */
722                         error = 0;
723                         do {
724                                 m0 = m->m_nextpkt;
725                                 m->m_nextpkt = NULL;
726
727                                 error = (*ifp->if_output)(ifp, m,
728                                         (struct sockaddr *)dst, ro.ro_rt);
729                                 if (error)
730                                         break;
731                         } while ((m = m0) != NULL);
732                         if (error) {
733                                 /* Reclaim remaining fragments */
734                                 for (; m; m = m0) {
735                                         m0 = m->m_nextpkt;
736                                         m->m_nextpkt = NULL;
737                                         m_freem(m);
738                                 }
739                         } else
740                                 ipstat.ips_fragmented++;
741                 }
742         }
743
744         if (error != 0)
745                 ipstat.ips_odropped++;
746         else {
747                 ro.ro_rt->rt_rmx.rmx_pksent++;
748                 ipstat.ips_forward++;
749                 ipstat.ips_fastforward++;
750         }
751         RTFREE(ro.ro_rt);
752         return 1;
753 drop:
754         if (m)
755                 m_freem(m);
756         return 1;
757 }