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