xref: /csrg-svn/sys/netinet/ip_output.c (revision 6412)
1 /*	ip_output.c	1.31	82/03/31	*/
2 
3 #include "../h/param.h"
4 #include "../h/mbuf.h"
5 #include "../h/mtpr.h"
6 #include "../h/socket.h"
7 #include "../h/socketvar.h"
8 #include "../net/in.h"
9 #include "../net/in_systm.h"
10 #include "../net/if.h"
11 #include "../net/ip.h"
12 #include "../net/ip_var.h"
13 #include "../net/route.h"
14 
15 ip_output(m, opt, ro, allowbroadcast)
16 	struct mbuf *m;
17 	struct mbuf *opt;
18 	struct route *ro;
19 	int allowbroadcast;
20 {
21 	register struct ip *ip = mtod(m, struct ip *);
22 	register struct ifnet *ifp;
23 	int len, hlen = sizeof (struct ip), off;
24 	struct route iproute;
25 	struct sockaddr *dst;
26 
27 COUNT(IP_OUTPUT);
28 	if (opt)				/* XXX */
29 		(void) m_free(opt);		/* XXX */
30 	/*
31 	 * Fill in IP header.
32 	 */
33 	ip->ip_v = IPVERSION;
34 	ip->ip_hl = hlen >> 2;
35 	ip->ip_off &= IP_DF;
36 	ip->ip_id = htons(ip_id++);
37 
38 	/*
39 	 * Find interface for this packet in the routing
40 	 * table.  Note each interface has placed itself
41 	 * in there at boot time, so calls to rtalloc
42 	 * degenerate to if_ifonnetof(ip->ip_dst.s_net).
43 	 */
44 	if (ro == 0) {
45 		ro = &iproute;
46 		bzero((caddr_t)ro, sizeof (*ro));
47 	}
48 	if (ro->ro_rt == 0) {
49 		ro->ro_dst.sa_family = AF_INET;
50 		((struct sockaddr_in *)&ro->ro_dst)->sin_addr = ip->ip_dst;
51 		rtalloc(ro);
52 	}
53 	if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
54 		printf("no route to %x (from %x, len %d)\n",
55 		    ip->ip_dst.s_addr, ip->ip_src.s_addr, ip->ip_len);
56 		goto bad;
57 	}
58 	dst = ro->ro_rt->rt_flags&RTF_DIRECT ?
59 	    (struct sockaddr *)&ro->ro_dst : &ro->ro_rt->rt_gateway;
60 	if (ro == &iproute)
61 		RTFREE(ro->ro_rt);
62 	if (!allowbroadcast && (ifp->if_flags & IFF_BROADCAST)) {
63 		struct sockaddr_in *sin;
64 
65 		sin = (struct sockaddr_in *)&ifp->if_broadaddr;
66 		if (sin->sin_addr.s_addr == ip->ip_dst.s_addr)
67 			goto bad;
68 	}
69 
70 	/*
71 	 * If small enough for interface, can just send directly.
72 	 */
73 	if (ip->ip_len <= ifp->if_mtu) {
74 #if vax
75 		ip->ip_len = htons((u_short)ip->ip_len);
76 		ip->ip_off = htons((u_short)ip->ip_off);
77 #endif
78 		ip->ip_sum = 0;
79 		ip->ip_sum = in_cksum(m, hlen);
80 		ro->ro_rt->rt_use++;
81 		return ((*ifp->if_output)(ifp, m, dst));
82 	}
83 
84 	/*
85 	 * Too large for interface; fragment if possible.
86 	 * Must be able to put at least 8 bytes per fragment.
87 	 */
88 	if (ip->ip_off & IP_DF)
89 		goto bad;
90 	len = (ifp->if_mtu - hlen) &~ 7;
91 	if (len < 8)
92 		goto bad;
93 
94 	/*
95 	 * Discard IP header from logical mbuf for m_copy's sake.
96 	 * Loop through length of segment, make a copy of each
97 	 * part and output.
98 	 */
99 	m->m_len -= sizeof (struct ip);
100 	m->m_off += sizeof (struct ip);
101 	for (off = 0; off < ip->ip_len-hlen; off += len) {
102 		struct mbuf *mh = m_get(M_DONTWAIT);
103 		struct ip *mhip;
104 
105 		if (mh == 0)
106 			goto bad;
107 		mh->m_off = MMAXOFF - hlen;
108 		mhip = mtod(mh, struct ip *);
109 		*mhip = *ip;
110 		if (hlen > sizeof (struct ip)) {
111 			int olen = ip_optcopy(ip, mhip, off);
112 			mh->m_len = sizeof (struct ip) + olen;
113 		} else
114 			mh->m_len = sizeof (struct ip);
115 		mhip->ip_off = off >> 3;
116 		if (off + len >= ip->ip_len-hlen)
117 			len = mhip->ip_len = ip->ip_len - hlen - off;
118 		else {
119 			mhip->ip_len = len;
120 			mhip->ip_off |= IP_MF;
121 		}
122 		mhip->ip_len += sizeof (struct ip);
123 #if vax
124 		mhip->ip_len = htons((u_short)mhip->ip_len);
125 #endif
126 		mh->m_next = m_copy(m, off, len);
127 		if (mh->m_next == 0) {
128 			(void) m_free(mh);
129 			goto bad;
130 		}
131 #if vax
132 		mhip->ip_off = htons((u_short)mhip->ip_off);
133 #endif
134 		mhip->ip_sum = 0;
135 		mhip->ip_sum = in_cksum(mh, hlen);
136 		ro->ro_rt->rt_use++;
137 		if ((*ifp->if_output)(ifp, mh, dst) == 0)
138 			goto bad;
139 	}
140 	m_freem(m);
141 	return (1);
142 bad:
143 	m_freem(m);
144 	return (0);
145 }
146 
147 /*
148  * Copy options from ip to jp.
149  * If off is 0 all options are copied
150  * otherwise copy selectively.
151  */
152 ip_optcopy(ip, jp, off)
153 	struct ip *ip, *jp;
154 	int off;
155 {
156 	register u_char *cp, *dp;
157 	int opt, optlen, cnt;
158 
159 COUNT(IP_OPTCOPY);
160 	cp = (u_char *)(ip + 1);
161 	dp = (u_char *)(jp + 1);
162 	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
163 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
164 		opt = cp[0];
165 		if (opt == IPOPT_EOL)
166 			break;
167 		if (opt == IPOPT_NOP)
168 			optlen = 1;
169 		else
170 			optlen = cp[1];
171 		if (optlen > cnt)			/* XXX */
172 			optlen = cnt;			/* XXX */
173 		if (off == 0 || IPOPT_COPIED(opt)) {
174 			bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
175 			dp += optlen;
176 		}
177 	}
178 	for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
179 		*dp++ = IPOPT_EOL;
180 	return (optlen);
181 }
182