xref: /csrg-svn/sys/netinet/ip_output.c (revision 4662)
1 /* ip_output.c 1.5 81/10/29 */
2 
3 #include "../h/param.h"
4 #include "../h/mbuf.h"
5 #include "../h/socket.h"
6 #include "../inet/inet.h"
7 #include "../inet/inet_systm.h"
8 #include "../inet/imp.h"
9 #include "../inet/inet_host.h"
10 #include "../inet/ip.h"
11 #include "../inet/tcp.h"
12 
13 ip_output(mp)
14 	struct mbuf *mp;
15 {
16 	register i, rnd;
17 	register struct mbuf *m, *n;
18 	register struct ip *p;
19 	struct mbuf *mm;
20 	int hlen, adj, max, len, off;
21 
22 COUNT(IP_OUTPUT);
23 	p = (struct ip *)((int)mp + mp->m_off); /* -> ip header */
24 	hlen = sizeof (struct ip);               /* header length */
25 
26 	/*
27 	 * Fill in and byte swap ip header.
28 	 */
29 	p->ip_v = IPVERSION;
30 	p->ip_hl = hlen >> 2;
31 	p->ip_off = 0 | (p->ip_off & IP_DF);
32 	p->ip_ttl = MAXTTL;
33 	p->ip_id = ip_id++;
34 
35 	if (p->ip_len > MTU) {          /* must fragment */
36 		if (p->ip_off & IP_DF)
37 			return (0);
38 		max = MTU - hlen;       /* maximum data length in fragment */
39 		len = p->ip_len - hlen; /* data length */
40 		off = 0;                /* fragment offset */
41 		m = mp;
42 
43 		while (len > 0) {
44 
45 			/* correct the header */
46 
47 			p->ip_off |= off >> 3;
48 
49 			/* find the end of the fragment */
50 
51 			i = -hlen;
52 			while (m != NULL) {
53 				i += m->m_len;
54 				if (i > max)
55 					break;
56 				n = m;
57 				m = m->m_next;
58 			}
59 
60 			if (i < max || m == NULL) {     /* last fragment */
61 				p->ip_off = p->ip_off &~ IP_MF;
62 				p->ip_len = i + hlen;
63 				break;
64 
65 			} else {                        /* more fragments */
66 
67 				/* allocate header mbuf for next fragment */
68 
69 				if ((mm = m_get(1)) == NULL)    /* no more bufs */
70 					return(0);
71 
72 				p->ip_off |= IP_MF;
73 
74 				/* terminate fragment at 8 byte boundary (round down) */
75 
76 				i -= m->m_len;
77         			rnd = i & ~7;           /* fragment length */
78 				adj = i - rnd;          /* leftover in mbuf */
79 				p->ip_len = rnd + hlen;
80 
81 				/* setup header for next fragment and
82 				   append remaining fragment data */
83 
84 				n->m_next = NULL;
85 				mm->m_next = m;
86 				m = mm;
87 				m->m_off = MMAXOFF - hlen - adj;
88 				m->m_len = hlen + adj;
89 
90 				/* copy old header to new */
91 
92 				bcopy(p, (caddr_t)((int)m + m->m_off), hlen);
93 
94 				/* copy leftover data from previous frag */
95 
96 				if (adj) {
97 					n->m_len -= adj;
98 					bcopy((caddr_t)((int)n + n->m_len + n->m_off),
99 					      (caddr_t)((int)m + m->m_off + hlen), adj);
100 				}
101 			}
102 
103 			ip_send(p);             /* pass frag to local net level */
104 
105 			p = (struct ip *)((int)m + m->m_off);   /* -> new hdr */
106 			len -= rnd;
107 			off += rnd;
108 		}
109 	}
110 
111 	return(ip_send(p));     /* pass datagram to local net level */
112 }
113 
114 ip_send(p)      /* format header and send message to 1822 level */
115 struct ip *p;
116 {
117 	register struct mbuf *m;
118 	register struct imp *l;
119 	int s;
120 COUNT(IP_SEND);
121 
122 	m = dtom(p);                    /* ->header mbuf */
123 
124 	/* set up 1822 leader fields for transmit */
125 
126 	l = (struct imp *)((int)m + m->m_off - L1822);
127 /*
128 	l->i_hst = p->ip_dst.s_host;
129 	l->i_impno = p->ip_dst.s_imp;
130 	l->i_mlen = p->ip_len + L1822;
131 	l->i_link = IPLINK;
132 	l->i_type = 0;
133 	l->i_htype = 0;
134 	l->i_stype = 0;
135 */
136 	if ((l->i_shost = p->ip_src.s_host) == 0)
137 		l->i_shost = 253;
138 	if ((l->i_dhost = p->ip_dst.s_host) == 0)
139 		l->i_dhost = 253;
140 	l->i_type = IPTYPE;
141 
142 	/* finish ip leader by calculating checksum and doing
143 	   necessary byte-swapping  */
144 
145 	p->ip_sum = 0;
146 	p->ip_len = htons(p->ip_len);
147 	p->ip_id = htons(p->ip_id);
148 	p->ip_off = htons(p->ip_off);
149 	p->ip_sum = cksum(m, sizeof(struct ip));
150 
151 	m->m_off -= L1822;              /* -> 1822 leader */
152 	m->m_len += L1822;
153 
154 	m->m_act = NULL;
155 
156 #ifndef IMPLOOP
157 
158 	/* put output message on queue */
159 
160 	s = splimp();
161 	if (imp_stat.outq_head != NULL)
162 		imp_stat.outq_tail->m_act = m;
163 	else
164 		imp_stat.outq_head = m;
165 	imp_stat.outq_tail = m;
166 	splx(s);
167 
168 	/* if no outstanding output, start some */
169 
170 	if (!imp_stat.outactive)
171 		imp_output(0);
172 
173 #else
174 	/* software looping: put msg chain on input queue */
175 
176 	if (imp_stat.inq_head != NULL)
177 		imp_stat.inq_tail->m_act = m;
178 	else
179 		imp_stat.inq_head = m;
180 	imp_stat.inq_tail = m;
181 
182 #endif IMPLOOP
183 	return (1);
184 }
185 
186 ip_setup(up, m, len)            /* setup an ip header for raw write */
187 register struct ucb *up;
188 register struct mbuf *m;
189 int len;
190 {
191 	register struct ip *ip;
192 COUNT(IP_SETUP);
193 
194 	m->m_off = MMAXOFF - sizeof(struct ip);
195 	m->m_len = sizeof(struct ip);
196 
197 	ip = (struct ip *)((int)m + m->m_off);
198 
199 	ip->ip_tos = 0;
200 	ip->ip_id = 0;
201 	ip->ip_off = 0;
202 	ip->ip_p = up->uc_lolink;
203 	ip->ip_len = len + sizeof(struct ip);
204 
205 	ip->ip_src.s_addr = n_lhost.s_addr;
206         ip->ip_dst.s_addr = up->uc_host->h_addr.s_addr;
207 }
208