check for null mbuf ptr before freeing (4.3BSD/sys/{130,131,133})
[unix-history] / usr / src / sys / netinet / ip_output.c
CommitLineData
5afc289d 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
5afc289d
MK
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
85b035eb 6 * @(#)ip_output.c 7.6 (Berkeley) %G%
5afc289d 7 */
6e8b2eca 8
20666ad3
JB
9#include "param.h"
10#include "mbuf.h"
11#include "errno.h"
53ba4464 12#include "protosw.h"
20666ad3
JB
13#include "socket.h"
14#include "socketvar.h"
f4d55810
SL
15
16#include "../net/if.h"
17#include "../net/route.h"
18
20666ad3 19#include "in.h"
53ba4464 20#include "in_pcb.h"
20666ad3 21#include "in_systm.h"
dfce8240 22#include "in_var.h"
20666ad3
JB
23#include "ip.h"
24#include "ip_var.h"
f4d55810 25
b152d3c4 26#ifdef vax
f112c673 27#include "../machine/mtpr.h"
b152d3c4 28#endif
ac904f92 29
53ba4464
MK
30struct mbuf *ip_insertoptions();
31
32/*
33 * IP output. The packet in mbuf chain m contains a skeletal IP
99fe25ae
MK
34 * header (with len, off, ttl, proto, tos, src, dst).
35 * The mbuf chain containing the packet will be freed.
36 * The mbuf opt, if present, will not be freed.
53ba4464 37 */
0e3f761f 38ip_output(m, opt, ro, flags)
2b4b57cd 39 struct mbuf *m;
8a13b737 40 struct mbuf *opt;
ee787340 41 struct route *ro;
0e3f761f 42 int flags;
ac904f92 43{
53ba4464 44 register struct ip *ip;
8a13b737 45 register struct ifnet *ifp;
8a2f82db 46 int len, hlen = sizeof (struct ip), off, error = 0;
ee787340 47 struct route iproute;
a8671e7e 48 struct sockaddr_in *dst;
ac904f92 49
53ba4464
MK
50 if (opt)
51 m = ip_insertoptions(m, opt, &hlen);
52 ip = mtod(m, struct ip *);
e8d11875 53 /*
2b4b57cd 54 * Fill in IP header.
e8d11875 55 */
0e3f761f
SL
56 if ((flags & IP_FORWARDING) == 0) {
57 ip->ip_v = IPVERSION;
58 ip->ip_off &= IP_DF;
59 ip->ip_id = htons(ip_id++);
4adcd589 60 ip->ip_hl = hlen >> 2;
53ba4464
MK
61 } else
62 hlen = ip->ip_hl << 2;
8a13b737
BJ
63
64 /*
a13c006d 65 * Route packet.
8a13b737 66 */
ee787340
SL
67 if (ro == 0) {
68 ro = &iproute;
69 bzero((caddr_t)ro, sizeof (*ro));
70 }
a8671e7e 71 dst = (struct sockaddr_in *)&ro->ro_dst;
ccb87262
MK
72 /*
73 * If there is a cached route,
74 * check that it is to the same destination
75 * and is still up. If not, free it and try again.
76 */
77 if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
78 dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
79 RTFREE(ro->ro_rt);
80 ro->ro_rt = (struct rtentry *)0;
81 }
ee787340 82 if (ro->ro_rt == 0) {
a8671e7e
SL
83 dst->sin_family = AF_INET;
84 dst->sin_addr = ip->ip_dst;
d55475b1
MK
85 }
86 /*
87 * If routing to interface only,
88 * short circuit routing lookup.
89 */
90 if (flags & IP_ROUTETOIF) {
91 struct in_ifaddr *ia;
52c6a991 92
4a9e3e93 93 ia = (struct in_ifaddr *)ifa_ifwithdstaddr(dst);
52c6a991
MK
94 if (ia == 0)
95 ia = in_iaonnetof(in_netof(ip->ip_dst));
d55475b1
MK
96 if (ia == 0) {
97 error = ENETUNREACH;
98 goto bad;
a13c006d 99 }
d55475b1
MK
100 ifp = ia->ia_ifp;
101 } else {
d55475b1
MK
102 if (ro->ro_rt == 0)
103 rtalloc(ro);
104 if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
6d22aa47
MK
105 if (in_localaddr(ip->ip_dst))
106 error = EHOSTUNREACH;
107 else
108 error = ENETUNREACH;
d55475b1
MK
109 goto bad;
110 }
111 ro->ro_rt->rt_use++;
39e4cc50 112 if (ro->ro_rt->rt_flags & RTF_GATEWAY)
d55475b1 113 dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway;
0e3f761f 114 }
5afc289d
MK
115#ifndef notdef
116 /*
117 * If source address not specified yet, use address
118 * of outgoing interface.
119 */
120 if (ip->ip_src.s_addr == INADDR_ANY) {
121 register struct in_ifaddr *ia;
122
123 for (ia = in_ifaddr; ia; ia = ia->ia_next)
124 if (ia->ia_ifp == ifp) {
125 ip->ip_src = IA_SIN(ia)->sin_addr;
126 break;
127 }
128 }
129#endif
a13c006d 130 /*
af099287
SL
131 * Look for broadcast address and
132 * and verify user is allowed to send
19f96414 133 * such a packet.
a13c006d 134 */
dfce8240 135 if (in_broadcast(dst->sin_addr)) {
19f96414
SL
136 if ((ifp->if_flags & IFF_BROADCAST) == 0) {
137 error = EADDRNOTAVAIL;
138 goto bad;
139 }
0e3f761f 140 if ((flags & IP_ALLOWBROADCAST) == 0) {
a13c006d 141 error = EACCES;
ee787340 142 goto bad;
8a2f82db 143 }
19f96414
SL
144 /* don't allow broadcast messages to be fragmented */
145 if (ip->ip_len > ifp->if_mtu) {
146 error = EMSGSIZE;
147 goto bad;
148 }
ee787340 149 }
ac904f92 150
2b4b57cd
BJ
151 /*
152 * If small enough for interface, can just send directly.
153 */
8a13b737
BJ
154 if (ip->ip_len <= ifp->if_mtu) {
155 ip->ip_len = htons((u_short)ip->ip_len);
156 ip->ip_off = htons((u_short)ip->ip_off);
157 ip->ip_sum = 0;
158 ip->ip_sum = in_cksum(m, hlen);
a8671e7e 159 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
a13c006d 160 goto done;
cdad2eb1 161 }
2b4b57cd
BJ
162
163 /*
164 * Too large for interface; fragment if possible.
165 * Must be able to put at least 8 bytes per fragment.
166 */
8a2f82db
SL
167 if (ip->ip_off & IP_DF) {
168 error = EMSGSIZE;
2b4b57cd 169 goto bad;
8a2f82db 170 }
8a13b737 171 len = (ifp->if_mtu - hlen) &~ 7;
8a2f82db
SL
172 if (len < 8) {
173 error = EMSGSIZE;
2b4b57cd 174 goto bad;
8a2f82db 175 }
2b4b57cd
BJ
176
177 /*
178 * Discard IP header from logical mbuf for m_copy's sake.
179 * Loop through length of segment, make a copy of each
180 * part and output.
181 */
182 m->m_len -= sizeof (struct ip);
183 m->m_off += sizeof (struct ip);
0b49870f 184 for (off = 0; off < ip->ip_len-hlen; off += len) {
22bd8cdc 185 struct mbuf *mh = m_get(M_DONTWAIT, MT_HEADER);
2b4b57cd
BJ
186 struct ip *mhip;
187
8a2f82db
SL
188 if (mh == 0) {
189 error = ENOBUFS;
2b4b57cd 190 goto bad;
8a2f82db 191 }
2b4b57cd
BJ
192 mh->m_off = MMAXOFF - hlen;
193 mhip = mtod(mh, struct ip *);
194 *mhip = *ip;
4ad99bae 195 if (hlen > sizeof (struct ip)) {
2b4b57cd
BJ
196 int olen = ip_optcopy(ip, mhip, off);
197 mh->m_len = sizeof (struct ip) + olen;
198 } else
199 mh->m_len = sizeof (struct ip);
2e7801e0 200 mhip->ip_off = (off >> 3) + (ip->ip_off & ~IP_MF);
4adcd589
MK
201 if (ip->ip_off & IP_MF)
202 mhip->ip_off |= IP_MF;
0b49870f
BJ
203 if (off + len >= ip->ip_len-hlen)
204 len = mhip->ip_len = ip->ip_len - hlen - off;
2b4b57cd
BJ
205 else {
206 mhip->ip_len = len;
207 mhip->ip_off |= IP_MF;
98444525 208 }
e8f40dc9 209 mhip->ip_len += sizeof (struct ip);
e8f40dc9 210 mhip->ip_len = htons((u_short)mhip->ip_len);
2b4b57cd
BJ
211 mh->m_next = m_copy(m, off, len);
212 if (mh->m_next == 0) {
2752c877 213 (void) m_free(mh);
8a2f82db 214 error = ENOBUFS; /* ??? */
2b4b57cd 215 goto bad;
98444525 216 }
0b49870f 217 mhip->ip_off = htons((u_short)mhip->ip_off);
0b49870f
BJ
218 mhip->ip_sum = 0;
219 mhip->ip_sum = in_cksum(mh, hlen);
a8671e7e 220 if (error = (*ifp->if_output)(ifp, mh, (struct sockaddr *)dst))
8a2f82db 221 break;
2b4b57cd
BJ
222 }
223bad:
224 m_freem(m);
a13c006d 225done:
0e3f761f 226 if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
a13c006d 227 RTFREE(ro->ro_rt);
8a2f82db 228 return (error);
2b4b57cd
BJ
229}
230
53ba4464
MK
231/*
232 * Insert IP options into preformed packet.
233 * Adjust IP destination as required for IP source routing,
234 * as indicated by a non-zero in_addr at the start of the options.
235 */
236struct mbuf *
237ip_insertoptions(m, opt, phlen)
238 register struct mbuf *m;
239 struct mbuf *opt;
240 int *phlen;
241{
242 register struct ipoption *p = mtod(opt, struct ipoption *);
243 struct mbuf *n;
244 register struct ip *ip = mtod(m, struct ip *);
8011f5df 245 unsigned optlen;
53ba4464
MK
246
247 optlen = opt->m_len - sizeof(p->ipopt_dst);
248 if (p->ipopt_dst.s_addr)
249 ip->ip_dst = p->ipopt_dst;
250 if (m->m_off >= MMAXOFF || MMINOFF + optlen > m->m_off) {
251 MGET(n, M_DONTWAIT, MT_HEADER);
252 if (n == 0)
253 return (m);
254 m->m_len -= sizeof(struct ip);
255 m->m_off += sizeof(struct ip);
256 n->m_next = m;
257 m = n;
258 m->m_off = MMAXOFF - sizeof(struct ip) - optlen;
259 m->m_len = optlen + sizeof(struct ip);
260 bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
261 } else {
262 m->m_off -= optlen;
263 m->m_len += optlen;
264 ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
265 }
266 ip = mtod(m, struct ip *);
8011f5df 267 bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);
53ba4464
MK
268 *phlen = sizeof(struct ip) + optlen;
269 ip->ip_len += optlen;
270 return (m);
271}
272
2b4b57cd
BJ
273/*
274 * Copy options from ip to jp.
4ad99bae 275 * If off is 0 all options are copied
2b4b57cd
BJ
276 * otherwise copy selectively.
277 */
278ip_optcopy(ip, jp, off)
279 struct ip *ip, *jp;
280 int off;
281{
282 register u_char *cp, *dp;
283 int opt, optlen, cnt;
284
285 cp = (u_char *)(ip + 1);
286 dp = (u_char *)(jp + 1);
287 cnt = (ip->ip_hl << 2) - sizeof (struct ip);
288 for (; cnt > 0; cnt -= optlen, cp += optlen) {
289 opt = cp[0];
290 if (opt == IPOPT_EOL)
291 break;
292 if (opt == IPOPT_NOP)
293 optlen = 1;
294 else
53ba4464 295 optlen = cp[IPOPT_OLEN];
2b4b57cd
BJ
296 if (optlen > cnt) /* XXX */
297 optlen = cnt; /* XXX */
298 if (off == 0 || IPOPT_COPIED(opt)) {
4ad99bae 299 bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
2b4b57cd 300 dp += optlen;
ac904f92 301 }
e8d11875 302 }
2b4b57cd
BJ
303 for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
304 *dp++ = IPOPT_EOL;
305 return (optlen);
ac904f92 306}
53ba4464
MK
307
308/*
309 * IP socket option processing.
310 */
311ip_ctloutput(op, so, level, optname, m)
312 int op;
313 struct socket *so;
314 int level, optname;
315 struct mbuf **m;
316{
317 int error = 0;
318 struct inpcb *inp = sotoinpcb(so);
319
320 if (level != IPPROTO_IP)
321 error = EINVAL;
322 else switch (op) {
323
324 case PRCO_SETOPT:
325 switch (optname) {
326 case IP_OPTIONS:
0c3fb1b4 327 return (ip_pcbopts(&inp->inp_options, *m));
53ba4464
MK
328
329 default:
330 error = EINVAL;
331 break;
332 }
333 break;
334
335 case PRCO_GETOPT:
336 switch (optname) {
337 case IP_OPTIONS:
338 *m = m_get(M_WAIT, MT_SOOPTS);
339 if (inp->inp_options) {
340 (*m)->m_off = inp->inp_options->m_off;
341 (*m)->m_len = inp->inp_options->m_len;
342 bcopy(mtod(inp->inp_options, caddr_t),
8011f5df 343 mtod(*m, caddr_t), (unsigned)(*m)->m_len);
53ba4464
MK
344 } else
345 (*m)->m_len = 0;
346 break;
347 default:
348 error = EINVAL;
349 break;
350 }
351 break;
352 }
85b035eb 353 if (op == PRCO_SETOPT && *m)
8011f5df 354 (void)m_free(*m);
53ba4464
MK
355 return (error);
356}
357
358/*
0c3fb1b4
MK
359 * Set up IP options in pcb for insertion in output packets.
360 * Store in mbuf with pointer in pcbopt, adding pseudo-option
361 * with destination address if source routed.
53ba4464 362 */
0c3fb1b4
MK
363ip_pcbopts(pcbopt, m)
364 struct mbuf **pcbopt;
365 register struct mbuf *m;
53ba4464
MK
366{
367 register cnt, optlen;
368 register u_char *cp;
369 u_char opt;
370
371 /* turn off any old options */
0c3fb1b4 372 if (*pcbopt)
8011f5df 373 (void)m_free(*pcbopt);
0c3fb1b4 374 *pcbopt = 0;
53ba4464
MK
375 if (m == (struct mbuf *)0 || m->m_len == 0) {
376 /*
377 * Only turning off any previous options.
378 */
379 if (m)
8011f5df 380 (void)m_free(m);
53ba4464
MK
381 return (0);
382 }
383
384#ifndef vax
385 if (m->m_len % sizeof(long))
386 goto bad;
387#endif
388 /*
389 * IP first-hop destination address will be stored before
390 * actual options; move other options back
391 * and clear it when none present.
392 */
393#if MAX_IPOPTLEN >= MMAXOFF - MMINOFF
394 if (m->m_off + m->m_len + sizeof(struct in_addr) > MAX_IPOPTLEN)
395 goto bad;
396#else
397 if (m->m_off + m->m_len + sizeof(struct in_addr) > MMAXOFF)
398 goto bad;
399#endif
400 cnt = m->m_len;
401 m->m_len += sizeof(struct in_addr);
402 cp = mtod(m, u_char *) + sizeof(struct in_addr);
8011f5df 403 ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
53ba4464
MK
404 bzero(mtod(m, caddr_t), sizeof(struct in_addr));
405
406 for (; cnt > 0; cnt -= optlen, cp += optlen) {
407 opt = cp[IPOPT_OPTVAL];
408 if (opt == IPOPT_EOL)
409 break;
410 if (opt == IPOPT_NOP)
411 optlen = 1;
412 else {
413 optlen = cp[IPOPT_OLEN];
414 if (optlen <= IPOPT_OLEN || optlen > cnt)
415 goto bad;
416 }
417 switch (opt) {
418
419 default:
420 break;
421
422 case IPOPT_LSRR:
423 case IPOPT_SSRR:
424 /*
425 * user process specifies route as:
426 * ->A->B->C->D
427 * D must be our final destination (but we can't
428 * check that since we may not have connected yet).
429 * A is first hop destination, which doesn't appear in
430 * actual IP option, but is stored before the options.
431 */
432 if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
433 goto bad;
434 m->m_len -= sizeof(struct in_addr);
435 cnt -= sizeof(struct in_addr);
436 optlen -= sizeof(struct in_addr);
437 cp[IPOPT_OLEN] = optlen;
438 /*
439 * Move first hop before start of options.
440 */
8011f5df 441 bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
53ba4464
MK
442 sizeof(struct in_addr));
443 /*
444 * Then copy rest of options back
445 * to close up the deleted entry.
446 */
8011f5df
MK
447 ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
448 sizeof(struct in_addr)),
449 (caddr_t)&cp[IPOPT_OFFSET+1],
450 (unsigned)cnt + sizeof(struct in_addr));
53ba4464
MK
451 break;
452 }
453 }
0c3fb1b4 454 *pcbopt = m;
53ba4464
MK
455 return (0);
456
457bad:
8011f5df 458 (void)m_free(m);
53ba4464
MK
459 return (EINVAL);
460}