xref: /csrg-svn/sys/netinet/ip_output.c (revision 4967)
1 /*	ip_output.c	1.16	81/11/20	*/
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/inet.h"
9 #include "../net/inet_systm.h"
10 #include "../net/imp.h"
11 #include "../net/ip.h"
12 #include "../net/ip_var.h"
13 
14 ip_output(m)
15 	struct mbuf *m;
16 {
17 	register struct ip *ip = mtod(m, struct ip *);
18 	int len, hlen = ip->ip_hl << 2, off;
19 
20 COUNT(IP_OUTPUT);
21 	/*
22 	 * Fill in IP header.
23 	 */
24 	ip->ip_v = IPVERSION;
25 	ip->ip_hl = hlen >> 2;
26 	ip->ip_off &= IP_DF;
27 	ip->ip_ttl = MAXTTL;
28 	ip->ip_id = ip_id++;
29 
30 	/*
31 	 * If small enough for interface, can just send directly.
32 	 */
33 	if (ip->ip_len <= MTU) {
34 		ip_send(ip);
35 		return;
36 	}
37 
38 	/*
39 	 * Too large for interface; fragment if possible.
40 	 * Must be able to put at least 8 bytes per fragment.
41 	 */
42 	if (ip->ip_off & IP_DF)
43 		goto bad;
44 	len = (MTU-hlen) &~ 7;
45 	if (len < 8)
46 		goto bad;
47 
48 	/*
49 	 * Discard IP header from logical mbuf for m_copy's sake.
50 	 * Loop through length of segment, make a copy of each
51 	 * part and output.
52 	 */
53 	m->m_len -= sizeof (struct ip);
54 	m->m_off += sizeof (struct ip);
55 	for (off = 0; off < ip->ip_len; off += len) {
56 		struct mbuf *mh = m_get(0);
57 		struct ip *mhip;
58 
59 		if (mh == 0)
60 			goto bad;
61 		mh->m_off = MMAXOFF - hlen;
62 		mhip = mtod(mh, struct ip *);
63 		*mhip = *ip;
64 		if (hlen > sizeof (struct ip)) {
65 			int olen = ip_optcopy(ip, mhip, off);
66 			mh->m_len = sizeof (struct ip) + olen;
67 		} else
68 			mh->m_len = sizeof (struct ip);
69 		mhip->ip_off = off;
70 		if (off + len >= ip->ip_len)
71 			mhip->ip_len = ip->ip_len - off;
72 		else {
73 			mhip->ip_len = len;
74 			mhip->ip_off |= IP_MF;
75 		}
76 		mh->m_next = m_copy(m, off, len);
77 		if (mh->m_next == 0) {
78 			(void) m_free(mh);
79 			goto bad;
80 		}
81 		ip_send(mhip);
82 	}
83 bad:
84 	m_freem(m);
85 }
86 
87 /*
88  * Copy options from ip to jp.
89  * If off is 0 all options are copied
90  * otherwise copy selectively.
91  */
92 ip_optcopy(ip, jp, off)
93 	struct ip *ip, *jp;
94 	int off;
95 {
96 	register u_char *cp, *dp;
97 	int opt, optlen, cnt;
98 
99 COUNT(IP_OPTCOPY);
100 	cp = (u_char *)(ip + 1);
101 	dp = (u_char *)(jp + 1);
102 	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
103 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
104 		opt = cp[0];
105 		if (opt == IPOPT_EOL)
106 			break;
107 		if (opt == IPOPT_NOP)
108 			optlen = 1;
109 		else
110 			optlen = cp[1];
111 		if (optlen > cnt)			/* XXX */
112 			optlen = cnt;			/* XXX */
113 		if (off == 0 || IPOPT_COPIED(opt)) {
114 			bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
115 			dp += optlen;
116 		}
117 	}
118 	for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
119 		*dp++ = IPOPT_EOL;
120 	return (optlen);
121 }
122 
123 /* REST OF CODE HERE IS GARBAGE */
124 
125 ip_send(ip)
126 	register struct ip *ip;
127 {
128 	register struct mbuf *m;
129 	register struct imp *l;
130 	int hlen = ip->ip_hl << 2;
131 	int s;
132 COUNT(IP_SEND);
133 
134 	m = dtom(ip);
135 	l = (struct imp *)(mtod(m, caddr_t) - L1822);
136 	l->i_shost = ip->ip_src.s_host;
137 	l->i_dhost = ip->ip_dst.s_host;
138 	l->i_type = IPTYPE;
139 	ip->ip_sum = 0;
140 	ip->ip_len = htons((u_short)ip->ip_len);
141 	ip->ip_id = htons(ip->ip_id);
142 	ip->ip_off = htons((u_short)ip->ip_off);
143 	ip->ip_sum = inet_cksum(m, hlen);
144 	m->m_off -= L1822;
145 	m->m_len += L1822;
146 	m->m_act = NULL;
147 #ifndef IMPLOOP
148 	s = splimp();
149 	if (imp_stat.outq_head != NULL)
150 		imp_stat.outq_tail->m_act = m;
151 	else
152 		imp_stat.outq_head = m;
153 	imp_stat.outq_tail = m;
154 	splx(s);
155 	if (!imp_stat.outactive)
156 		enstart(0);
157 #else
158 	if (imp_stat.inq_head != NULL)
159 		imp_stat.inq_tail->m_act = m;
160 	else
161 		imp_stat.inq_head = m;
162 	imp_stat.inq_tail = m;
163 	setsoftnet();
164 #endif IMPLOOP
165 }
166 
167 /* END GARBAGE */
168