xref: /csrg-svn/sys/netinet/ip_output.c (revision 4924)
1*4924Swnj /*	ip_output.c	1.14	81/11/18	*/
24571Swnj 
34496Swnj #include "../h/param.h"
44662Swnj #include "../h/mbuf.h"
54724Swnj #include "../h/mtpr.h"
64662Swnj #include "../h/socket.h"
7*4924Swnj #include "../h/socketvar.h"
84802Swnj #include "../net/inet.h"
94802Swnj #include "../net/inet_systm.h"
104802Swnj #include "../net/imp.h"
114802Swnj #include "../net/inet_host.h"
124802Swnj #include "../net/ip.h"
134899Swnj #include "../net/ip_var.h"
144496Swnj 
15*4924Swnj ip_output(m)
16*4924Swnj 	struct mbuf *m;
174496Swnj {
18*4924Swnj 	register struct ip *ip = mtod(m, struct ip *);
19*4924Swnj 	int len, hlen = ip->ip_hl << 2, off;
204496Swnj 
214496Swnj COUNT(IP_OUTPUT);
22*4924Swnj 	/*
23*4924Swnj 	 * Fill in IP header.
24*4924Swnj 	 */
25*4924Swnj 	ip->ip_v = IPVERSION;
26*4924Swnj 	ip->ip_hl = hlen >> 2;
27*4924Swnj 	ip->ip_off &= IP_DF;
28*4924Swnj 	ip->ip_ttl = MAXTTL;
29*4924Swnj 	ip->ip_id = ip_id++;
304496Swnj 
314545Swnj 	/*
32*4924Swnj 	 * If small enough for interface, can just send directly.
334545Swnj 	 */
34*4924Swnj 	if (ip->ip_len <= MTU) {
35*4924Swnj 		ip_send(ip);
364908Swnj 		return;
374908Swnj 	}
38*4924Swnj 
39*4924Swnj 	/*
40*4924Swnj 	 * Too large for interface; fragment if possible.
41*4924Swnj 	 * Must be able to put at least 8 bytes per fragment.
42*4924Swnj 	 */
43*4924Swnj 	if (ip->ip_off & IP_DF)
44*4924Swnj 		goto bad;
45*4924Swnj 	len = (MTU-hlen) &~ 7;
46*4924Swnj 	if (len < 8)
47*4924Swnj 		goto bad;
48*4924Swnj 
49*4924Swnj 	/*
50*4924Swnj 	 * Discard IP header from logical mbuf for m_copy's sake.
51*4924Swnj 	 * Loop through length of segment, make a copy of each
52*4924Swnj 	 * part and output.
53*4924Swnj 	 */
54*4924Swnj 	m->m_len -= sizeof (struct ip);
55*4924Swnj 	m->m_off += sizeof (struct ip);
56*4924Swnj 	for (off = 0; off < ip->ip_len; off += len) {
57*4924Swnj 		struct mbuf *mh = m_get(0);
58*4924Swnj 		struct ip *mhip;
59*4924Swnj 
60*4924Swnj 		if (mh == 0)
61*4924Swnj 			goto bad;
62*4924Swnj 		mh->m_off = MMAXOFF - hlen;
63*4924Swnj 		mhip = mtod(mh, struct ip *);
64*4924Swnj 		*mhip = *ip;
65*4924Swnj 		if (ip->ip_hl > sizeof (struct ip) >> 2) {
66*4924Swnj 			int olen = ip_optcopy(ip, mhip, off);
67*4924Swnj 			mh->m_len = sizeof (struct ip) + olen;
68*4924Swnj 		} else
69*4924Swnj 			mh->m_len = sizeof (struct ip);
70*4924Swnj 		mhip->ip_off = off;
71*4924Swnj 		if (off + len >= ip->ip_len)
72*4924Swnj 			mhip->ip_len = ip->ip_len - off;
73*4924Swnj 		else {
74*4924Swnj 			mhip->ip_len = len;
75*4924Swnj 			mhip->ip_off |= IP_MF;
764496Swnj 		}
77*4924Swnj 		mh->m_next = m_copy(m, off, len);
78*4924Swnj 		if (mh->m_next == 0) {
79*4924Swnj 			m_free(mh);
80*4924Swnj 			goto bad;
814674Swnj 		}
82*4924Swnj 		ip_send(mh);
83*4924Swnj 	}
84*4924Swnj bad:
85*4924Swnj 	m_freem(m);
86*4924Swnj }
87*4924Swnj 
88*4924Swnj /*
89*4924Swnj  * Copy options from ip to jp.
90*4924Swnj  * If off is 0 all options are copies
91*4924Swnj  * otherwise copy selectively.
92*4924Swnj  */
93*4924Swnj ip_optcopy(ip, jp, off)
94*4924Swnj 	struct ip *ip, *jp;
95*4924Swnj 	int off;
96*4924Swnj {
97*4924Swnj 	register u_char *cp, *dp;
98*4924Swnj 	int opt, optlen, cnt;
99*4924Swnj 
100*4924Swnj 	cp = (u_char *)(ip + 1);
101*4924Swnj 	dp = (u_char *)(jp + 1);
102*4924Swnj 	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
103*4924Swnj 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
104*4924Swnj 		opt = cp[0];
105*4924Swnj 		if (opt == IPOPT_EOL)
106*4924Swnj 			break;
107*4924Swnj 		if (opt == IPOPT_NOP)
108*4924Swnj 			optlen = 1;
109*4924Swnj 		else
110*4924Swnj 			optlen = cp[1];
111*4924Swnj 		if (optlen > cnt)			/* XXX */
112*4924Swnj 			optlen = cnt;			/* XXX */
113*4924Swnj 		if (off == 0 || IPOPT_COPIED(opt)) {
114*4924Swnj 			bcopy(cp, dp, optlen);
115*4924Swnj 			dp += optlen;
1164674Swnj 		}
1174545Swnj 	}
118*4924Swnj 	for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
119*4924Swnj 		*dp++ = IPOPT_EOL;
120*4924Swnj 	return (optlen);
1214496Swnj }
1224496Swnj 
1234693Swnj ip_send(ip)
124*4924Swnj 	register struct ip *ip;
1254496Swnj {
1264496Swnj 	register struct mbuf *m;
1274496Swnj 	register struct imp *l;
128*4924Swnj 	int hlen = ip->ip_hl << 2;
1294545Swnj 	int s;
1304496Swnj COUNT(IP_SEND);
1314496Swnj 
1324693Swnj 	m = dtom(ip);
1334908Swnj 	l = (struct imp *)(mtod(m, caddr_t) - L1822);
1344693Swnj 	l->i_shost = ip->ip_src.s_host;
1354693Swnj 	l->i_dhost = ip->ip_dst.s_host;
1364496Swnj 	l->i_type = IPTYPE;
1374693Swnj 	ip->ip_sum = 0;
1384908Swnj 	ip->ip_len = htons((u_short)ip->ip_len);
1394693Swnj 	ip->ip_id = htons(ip->ip_id);
1404908Swnj 	ip->ip_off = htons((u_short)ip->ip_off);
141*4924Swnj 	ip->ip_sum = inet_cksum(m, hlen);
1424693Swnj 	m->m_off -= L1822;
1434496Swnj 	m->m_len += L1822;
1444545Swnj 	m->m_act = NULL;
1454545Swnj #ifndef IMPLOOP
1464662Swnj 	s = splimp();
1474545Swnj 	if (imp_stat.outq_head != NULL)
1484545Swnj 		imp_stat.outq_tail->m_act = m;
1494545Swnj 	else
1504545Swnj 		imp_stat.outq_head = m;
1514545Swnj 	imp_stat.outq_tail = m;
1524545Swnj 	splx(s);
1534545Swnj 	if (!imp_stat.outactive)
1544688Swnj 		enstart(0);
1554545Swnj #else
1564545Swnj 	if (imp_stat.inq_head != NULL)
1574545Swnj 		imp_stat.inq_tail->m_act = m;
1584545Swnj 	else
1594545Swnj 		imp_stat.inq_head = m;
1604545Swnj 	imp_stat.inq_tail = m;
1614724Swnj 	setsoftnet();
1624545Swnj #endif IMPLOOP
1634496Swnj }
164