+#endif /* IPSEC */
+ if (error == 0) {
+ if ((packetchain != 0) && (pktcnt > 0)) {
+ panic("%s: mix of packet in packetlist is "
+ "wrong=%p", __func__, packetlist);
+ /* NOTREACHED */
+ }
+ if (ro->ro_rt != NULL && nstat_collect) {
+ nstat_route_tx(ro->ro_rt, 1,
+ m->m_pkthdr.len, 0);
+ }
+ error = dlil_output(ifp, PF_INET, m, ro->ro_rt,
+ SA(dst), 0, adv);
+ if (dlil_verbose && error) {
+ printf("dlil_output error on interface %s: %d\n",
+ ifp->if_xname, error);
+ }
+ } else {
+ m_freem(m);
+ }
+ }
+
+ if (error == 0) {
+ OSAddAtomic(1, &ipstat.ips_fragmented);
+ }
+
+done:
+ if (ia != NULL) {
+ IFA_REMREF(&ia->ia_ifa);
+ ia = NULL;
+ }
+#if IPSEC
+ ROUTE_RELEASE(&ipsec_state.ro);
+ if (sp != NULL) {
+ KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
+ printf("DP ip_output call free SP:%x\n", sp));
+ key_freesp(sp, KEY_SADB_UNLOCKED);
+ }
+#endif /* IPSEC */
+#if NECP
+ ROUTE_RELEASE(&necp_route);
+#endif /* NECP */
+#if DUMMYNET
+ ROUTE_RELEASE(&saved_route);
+#endif /* DUMMYNET */
+#if IPFIREWALL_FORWARD
+ ROUTE_RELEASE(&sro_fwd);
+#endif /* IPFIREWALL_FORWARD */
+
+ KERNEL_DEBUG(DBG_FNC_IP_OUTPUT | DBG_FUNC_END, error, 0, 0, 0, 0);
+ if (ip_output_measure) {
+ net_perf_measure_time(&net_perf, &start_tv, packets_processed);
+ net_perf_histogram(&net_perf, packets_processed);
+ }
+ return error;
+bad:
+ if (pktcnt > 0) {
+ m0 = packetlist;
+ }
+ m_freem_list(m0);
+ goto done;
+
+#undef ipsec_state
+#undef args
+#undef sro_fwd
+#undef saved_route
+#undef ipf_pktopts
+#undef IP_CHECK_RESTRICTIONS
+}
+
+int
+ip_fragment(struct mbuf *m, struct ifnet *ifp, unsigned long mtu, int sw_csum)
+{
+ struct ip *ip, *mhip;
+ int len, hlen, mhlen, firstlen, off, error = 0;
+ struct mbuf **mnext = &m->m_nextpkt, *m0;
+ int nfrags = 1;
+
+ ip = mtod(m, struct ip *);
+#ifdef _IP_VHL
+ hlen = IP_VHL_HL(ip->ip_vhl) << 2;
+#else /* !_IP_VHL */
+ hlen = ip->ip_hl << 2;
+#endif /* !_IP_VHL */
+
+#ifdef INET6
+ /*
+ * We need to adjust the fragment sizes to account
+ * for IPv6 fragment header if it needs to be translated
+ * from IPv4 to IPv6.
+ */
+ if (IS_INTF_CLAT46(ifp)) {
+ mtu -= sizeof(struct ip6_frag);
+ }
+
+#endif
+ firstlen = len = (mtu - hlen) & ~7;
+ if (len < 8) {
+ m_freem(m);
+ return EMSGSIZE;
+ }
+
+ /*
+ * if the interface will not calculate checksums on
+ * fragmented packets, then do it here.
+ */
+ if ((m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) &&
+ !(ifp->if_hwassist & CSUM_IP_FRAGS)) {
+ in_delayed_cksum(m);
+ }
+
+ /*
+ * Loop through length of segment after first fragment,
+ * make new header and copy data of each part and link onto chain.
+ */
+ m0 = m;
+ mhlen = sizeof(struct ip);
+ for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
+ MGETHDR(m, M_DONTWAIT, MT_HEADER); /* MAC-OK */
+ if (m == NULL) {
+ error = ENOBUFS;
+ OSAddAtomic(1, &ipstat.ips_odropped);
+ goto sendorfree;
+ }
+ m->m_flags |= (m0->m_flags & M_MCAST) | M_FRAG;
+ m->m_data += max_linkhdr;
+ mhip = mtod(m, struct ip *);
+ *mhip = *ip;
+ if (hlen > sizeof(struct ip)) {
+ mhlen = ip_optcopy(ip, mhip) + sizeof(struct ip);
+ mhip->ip_vhl = IP_MAKE_VHL(IPVERSION, mhlen >> 2);
+ }
+ m->m_len = mhlen;
+ mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
+ if (ip->ip_off & IP_MF) {
+ mhip->ip_off |= IP_MF;
+ }
+ if (off + len >= (u_short)ip->ip_len) {