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