1/* 2 * Copyright (c) 1982, 1986, 1988, 1990, 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 --- 17 unchanged lines hidden (view full) --- 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_output.c 8.3 (Berkeley) 1/21/94 |
34 * $FreeBSD: head/sys/netinet/ip_output.c 58698 2000-03-27 19:14:27Z jlemon $ |
35 */ 36 37#define _IP_VHL 38 39#include "opt_ipfw.h" 40#include "opt_ipdn.h" 41#include "opt_ipdivert.h" 42#include "opt_ipfilter.h" --- 48 unchanged lines hidden (view full) --- 91#define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\ 92 (ntohl(a.s_addr)>>16)&0xFF,\ 93 (ntohl(a.s_addr)>>8)&0xFF,\ 94 (ntohl(a.s_addr))&0xFF); 95#endif 96 97u_short ip_id; 98 |
99static void in_delayed_cksum(struct mbuf *m); |
100static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *)); 101static void ip_mloopback 102 __P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int)); 103static int ip_getmoptions 104 __P((struct sockopt *, struct ip_moptions *)); 105static int ip_pcbopts __P((int, struct mbuf **, struct mbuf *)); 106static int ip_setmoptions 107 __P((struct sockopt *, struct ip_moptions **)); --- 20 unchanged lines hidden (view full) --- 128{ 129 struct ip *ip, *mhip; 130 struct ifnet *ifp; 131 struct mbuf *m = m0; 132 int hlen = sizeof (struct ip); 133 int len, off, error = 0; 134 struct sockaddr_in *dst; 135 struct in_ifaddr *ia; |
136 int isbroadcast, sw_csum; |
137#ifdef IPSEC 138 struct route iproute; 139 struct socket *so = NULL; 140 struct secpolicy *sp = NULL; 141#endif 142 u_int16_t divert_cookie; /* firewall cookie */ 143#ifdef IPFIREWALL_FORWARD 144 int fwd_rewrite_src = 0; --- 543 unchanged lines hidden (view full) --- 688 state.m = m; 689 if (flags & IP_ROUTETOIF) { 690 state.ro = &iproute; 691 bzero(&iproute, sizeof(iproute)); 692 } else 693 state.ro = ro; 694 state.dst = (struct sockaddr *)dst; 695 |
696 /* 697 * XXX 698 * delayed checksums are not currently compatible with IPsec 699 */ 700 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 701 in_delayed_cksum(m); 702 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 703 } 704 |
705 error = ipsec4_output(&state, sp, flags); 706 707 m = state.m; 708 if (flags & IP_ROUTETOIF) { 709 /* 710 * if we have tunnel mode SA, we may need to ignore 711 * IP_ROUTETOIF. 712 */ --- 46 unchanged lines hidden (view full) --- 759 } 760 761 /* make it flipped, again. */ 762 ip->ip_len = ntohs((u_short)ip->ip_len); 763 ip->ip_off = ntohs((u_short)ip->ip_off); 764skip_ipsec: 765#endif /*IPSEC*/ 766 |
767 sw_csum = m->m_pkthdr.csum_flags | CSUM_IP; 768 m->m_pkthdr.csum_flags = sw_csum & ifp->if_hwassist; 769 sw_csum &= ~ifp->if_hwassist; 770 if (sw_csum & CSUM_DELAY_DATA) { 771 in_delayed_cksum(m); 772 sw_csum &= ~CSUM_DELAY_DATA; 773 } 774 |
775 /* |
776 * If small enough for interface, or the interface will take 777 * care of the fragmentation for us, can just send directly. |
778 */ |
779 if ((u_short)ip->ip_len <= ifp->if_mtu || 780 ifp->if_hwassist & CSUM_FRAGMENT) { |
781 ip->ip_len = htons((u_short)ip->ip_len); 782 ip->ip_off = htons((u_short)ip->ip_off); 783 ip->ip_sum = 0; |
784 if (sw_csum & CSUM_DELAY_IP) { 785 if (ip->ip_vhl == IP_VHL_BORING) { 786 ip->ip_sum = in_cksum_hdr(ip); 787 } else { 788 ip->ip_sum = in_cksum(m, hlen); 789 } |
790 } 791 error = (*ifp->if_output)(ifp, m, 792 (struct sockaddr *)dst, ro->ro_rt); 793 goto done; 794 } 795 /* 796 * Too large for interface; fragment if possible. 797 * Must be able to put at least 8 bytes per fragment. --- 16 unchanged lines hidden (view full) --- 814 goto bad; 815 } 816 len = (ifp->if_mtu - hlen) &~ 7; 817 if (len < 8) { 818 error = EMSGSIZE; 819 goto bad; 820 } 821 |
822 /* 823 * if the interface will not calculate checksums on 824 * fragmented packets, then do it here. 825 */ 826 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA && 827 (ifp->if_hwassist & CSUM_IP_FRAGS) == 0) { 828 in_delayed_cksum(m); 829 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 830 } 831 |
832 { 833 int mhlen, firstlen = len; 834 struct mbuf **mnext = &m->m_nextpkt; |
835 int nfrags = 1; |
836 837 /* 838 * Loop through length of segment after first fragment, 839 * make new header and copy data of each part and link onto chain. 840 */ 841 m0 = m; 842 mhlen = sizeof (struct ip); 843 for (off = hlen + len; off < (u_short)ip->ip_len; off += len) { 844 MGETHDR(m, M_DONTWAIT, MT_HEADER); 845 if (m == 0) { 846 error = ENOBUFS; 847 ipstat.ips_odropped++; 848 goto sendorfree; 849 } |
850 m->m_flags |= (m0->m_flags & M_MCAST) | M_FRAG; |
851 m->m_data += max_linkhdr; 852 mhip = mtod(m, struct ip *); 853 *mhip = *ip; 854 if (hlen > sizeof (struct ip)) { 855 mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 856 mhip->ip_vhl = IP_MAKE_VHL(IPVERSION, mhlen >> 2); 857 } 858 m->m_len = mhlen; --- 9 unchanged lines hidden (view full) --- 868 if (m->m_next == 0) { 869 (void) m_free(m); 870 error = ENOBUFS; /* ??? */ 871 ipstat.ips_odropped++; 872 goto sendorfree; 873 } 874 m->m_pkthdr.len = mhlen + len; 875 m->m_pkthdr.rcvif = (struct ifnet *)0; |
876 m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags; |
877 mhip->ip_off = htons((u_short)mhip->ip_off); 878 mhip->ip_sum = 0; |
879 if (sw_csum & CSUM_DELAY_IP) { 880 if (mhip->ip_vhl == IP_VHL_BORING) { 881 mhip->ip_sum = in_cksum_hdr(mhip); 882 } else { 883 mhip->ip_sum = in_cksum(m, mhlen); 884 } |
885 } 886 *mnext = m; 887 mnext = &m->m_nextpkt; |
888 nfrags++; |
889 } |
890 ipstat.ips_ofragments += nfrags; 891 892 /* set first/last markers for fragment chain */ 893 m->m_flags |= M_LASTFRAG; 894 m0->m_flags |= M_FIRSTFRAG | M_FRAG; 895 m0->m_pkthdr.csum_data = nfrags; 896 |
897 /* 898 * Update first fragment by trimming what's been copied out 899 * and updating header, then send each fragment (in order). 900 */ 901 m = m0; 902 m_adj(m, hlen + firstlen - (u_short)ip->ip_len); 903 m->m_pkthdr.len = hlen + firstlen; 904 ip->ip_len = htons((u_short)m->m_pkthdr.len); 905 ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); 906 ip->ip_sum = 0; |
907 if (sw_csum & CSUM_DELAY_IP) { 908 if (ip->ip_vhl == IP_VHL_BORING) { 909 ip->ip_sum = in_cksum_hdr(ip); 910 } else { 911 ip->ip_sum = in_cksum(m, hlen); 912 } |
913 } 914sendorfree: 915 for (m = m0; m; m = m0) { 916 m0 = m->m_nextpkt; 917 m->m_nextpkt = 0; 918 if (error == 0) 919 error = (*ifp->if_output)(ifp, m, 920 (struct sockaddr *)dst, ro->ro_rt); --- 17 unchanged lines hidden (view full) --- 938 } 939#endif /* IPSEC */ 940 return (error); 941bad: 942 m_freem(m0); 943 goto done; 944} 945 |
946static void 947in_delayed_cksum(struct mbuf *m) 948{ 949 struct ip *ip; 950 u_short csum, offset; 951 952 ip = mtod(m, struct ip *); 953 offset = IP_VHL_HL(ip->ip_vhl) << 2 ; 954 csum = in_cksum_skip(m, ip->ip_len, offset); 955 offset += m->m_pkthdr.csum_data; /* checksum offset */ 956 957 if (offset + sizeof(u_short) > m->m_len) { 958 printf("delayed m_pullup, m->len: %d off: %d p: %d\n", 959 m->m_len, offset, ip->ip_p); 960 /* 961 * XXX 962 * this shouldn't happen, but if it does, the 963 * correct behavior may be to insert the checksum 964 * in the existing chain instead of rearranging it. 965 */ 966 m = m_pullup(m, offset + sizeof(u_short)); 967 } 968 *(u_short *)(m->m_data + offset) = csum; 969} 970 |
971/* 972 * Insert IP options into preformed packet. 973 * Adjust IP destination as required for IP source routing, 974 * as indicated by a non-zero in_addr at the start of the options. 975 * 976 * XXX This routine assumes that the packet has no options in place. 977 */ 978static struct mbuf * --- 886 unchanged lines hidden --- |