|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution is only permitted until one year after the first shipment
6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7: * binary forms are permitted provided that: (1) source distributions retain
8: * this entire copyright notice and comment, and (2) distributions including
9: * binaries display the following acknowledgement: This product includes
10: * software developed by the University of California, Berkeley and its
11: * contributors'' in the documentation or other materials provided with the
12: * distribution and in all advertising materials mentioning features or use
13: * of this software. Neither the name of the University nor the names of
14: * its contributors may be used to endorse or promote products derived from
15: * this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)ip_output.c 7.22 (Berkeley) 7/28/90
21: */
22:
23: #include "param.h"
24: #include "malloc.h"
25: #include "mbuf.h"
26: #include "errno.h"
27: #include "protosw.h"
28: #include "socket.h"
29: #include "socketvar.h"
30:
31: #include "../net/if.h"
32: #include "../net/route.h"
33:
34: #include "in.h"
35: #include "in_systm.h"
36: #include "ip.h"
37: #include "in_pcb.h"
38: #include "in_var.h"
39: #include "ip_var.h"
40:
41: #ifdef vax
42: #include "machine/mtpr.h"
43: #endif
44:
45: struct mbuf *ip_insertoptions();
46:
47: /*
48: * IP output. The packet in mbuf chain m contains a skeletal IP
49: * header (with len, off, ttl, proto, tos, src, dst).
50: * The mbuf chain containing the packet will be freed.
51: * The mbuf opt, if present, will not be freed.
52: */
53: ip_output(m0, opt, ro, flags)
54: struct mbuf *m0;
55: struct mbuf *opt;
56: struct route *ro;
57: int flags;
58: {
59: register struct ip *ip, *mhip;
60: register struct ifnet *ifp;
61: register struct mbuf *m = m0;
62: register int hlen = sizeof (struct ip);
63: int len, off, error = 0;
64: struct route iproute;
65: struct sockaddr_in *dst;
66: struct in_ifaddr *ia;
67:
68: #ifdef DIAGNOSTIC
69: if ((m->m_flags & M_PKTHDR) == 0)
70: panic("ip_output no HDR");
71: #endif
72: if (opt) {
73: m = ip_insertoptions(m, opt, &len);
74: hlen = len;
75: }
76: ip = mtod(m, struct ip *);
77: /*
78: * Fill in IP header.
79: */
80: if ((flags & IP_FORWARDING) == 0) {
81: ip->ip_v = IPVERSION;
82: ip->ip_off &= IP_DF;
83: ip->ip_id = htons(ip_id++);
84: ip->ip_hl = hlen >> 2;
85: } else {
86: hlen = ip->ip_hl << 2;
87: ipstat.ips_localout++;
88: }
89: /*
90: * Route packet.
91: */
92: if (ro == 0) {
93: ro = &iproute;
94: bzero((caddr_t)ro, sizeof (*ro));
95: }
96: dst = (struct sockaddr_in *)&ro->ro_dst;
97: /*
98: * If there is a cached route,
99: * check that it is to the same destination
100: * and is still up. If not, free it and try again.
101: */
102: if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
103: dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
104: RTFREE(ro->ro_rt);
105: ro->ro_rt = (struct rtentry *)0;
106: }
107: if (ro->ro_rt == 0) {
108: dst->sin_family = AF_INET;
109: dst->sin_len = sizeof(*dst);
110: dst->sin_addr = ip->ip_dst;
111: }
112: /*
113: * If routing to interface only,
114: * short circuit routing lookup.
115: */
116: if (flags & IP_ROUTETOIF) {
117:
118: ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst);
119: if (ia == 0)
120: ia = in_iaonnetof(in_netof(ip->ip_dst));
121: if (ia == 0) {
122: error = ENETUNREACH;
123: goto bad;
124: }
125: ifp = ia->ia_ifp;
126: } else {
127: if (ro->ro_rt == 0)
128: rtalloc(ro);
129: if (ro->ro_rt == 0) {
130: error = EHOSTUNREACH;
131: goto bad;
132: }
133: ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa;
134: ifp = ro->ro_rt->rt_ifp;
135: ro->ro_rt->rt_use++;
136: if (ro->ro_rt->rt_flags & RTF_GATEWAY)
137: dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
138: }
139: #ifndef notdef
140: /*
141: * If source address not specified yet, use address
142: * of outgoing interface.
143: */
144: if (ip->ip_src.s_addr == INADDR_ANY)
145: ip->ip_src = IA_SIN(ia)->sin_addr;
146: #endif
147: /*
148: * Look for broadcast address and
149: * and verify user is allowed to send
150: * such a packet.
151: */
152: if (in_broadcast(dst->sin_addr)) {
153: if ((ifp->if_flags & IFF_BROADCAST) == 0) {
154: error = EADDRNOTAVAIL;
155: goto bad;
156: }
157: if ((flags & IP_ALLOWBROADCAST) == 0) {
158: error = EACCES;
159: goto bad;
160: }
161: /* don't allow broadcast messages to be fragmented */
162: if ((u_short)ip->ip_len > ifp->if_mtu) {
163: error = EMSGSIZE;
164: goto bad;
165: }
166: m->m_flags |= M_BCAST;
167: }
168:
169: /*
170: * If small enough for interface, can just send directly.
171: */
172: if ((u_short)ip->ip_len <= ifp->if_mtu) {
173: ip->ip_len = htons((u_short)ip->ip_len);
174: ip->ip_off = htons((u_short)ip->ip_off);
175: ip->ip_sum = 0;
176: ip->ip_sum = in_cksum(m, hlen);
177: error = (*ifp->if_output)(ifp, m,
178: (struct sockaddr *)dst, ro->ro_rt);
179: goto done;
180: }
181: ipstat.ips_fragmented++;
182: /*
183: * Too large for interface; fragment if possible.
184: * Must be able to put at least 8 bytes per fragment.
185: */
186: if (ip->ip_off & IP_DF) {
187: error = EMSGSIZE;
188: goto bad;
189: }
190: len = (ifp->if_mtu - hlen) &~ 7;
191: if (len < 8) {
192: error = EMSGSIZE;
193: goto bad;
194: }
195:
196: {
197: int mhlen, firstlen = len;
198: struct mbuf **mnext = &m->m_nextpkt;
199:
200: /*
201: * Loop through length of segment after first fragment,
202: * make new header and copy data of each part and link onto chain.
203: */
204: m0 = m;
205: mhlen = sizeof (struct ip);
206: for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
207: MGETHDR(m, M_DONTWAIT, MT_HEADER);
208: if (m == 0) {
209: error = ENOBUFS;
210: goto sendorfree;
211: }
212: m->m_data += max_linkhdr;
213: mhip = mtod(m, struct ip *);
214: *mhip = *ip;
215: if (hlen > sizeof (struct ip)) {
216: mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
217: mhip->ip_hl = mhlen >> 2;
218: }
219: m->m_len = mhlen;
220: mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
221: if (ip->ip_off & IP_MF)
222: mhip->ip_off |= IP_MF;
223: if (off + len >= (u_short)ip->ip_len)
224: len = (u_short)ip->ip_len - off;
225: else
226: mhip->ip_off |= IP_MF;
227: mhip->ip_len = htons((u_short)(len + mhlen));
228: m->m_next = m_copy(m0, off, len);
229: if (m->m_next == 0) {
230: error = ENOBUFS; /* ??? */
231: goto sendorfree;
232: }
233: m->m_pkthdr.len = mhlen + len;
234: m->m_pkthdr.rcvif = (struct ifnet *)0;
235: mhip->ip_off = htons((u_short)mhip->ip_off);
236: mhip->ip_sum = 0;
237: mhip->ip_sum = in_cksum(m, mhlen);
238: *mnext = m;
239: mnext = &m->m_nextpkt;
240: ipstat.ips_ofragments++;
241: }
242: /*
243: * Update first fragment by trimming what's been copied out
244: * and updating header, then send each fragment (in order).
245: */
246: m = m0;
247: m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
248: m->m_pkthdr.len = hlen + firstlen;
249: ip->ip_len = htons((u_short)m->m_pkthdr.len);
250: ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
251: ip->ip_sum = 0;
252: ip->ip_sum = in_cksum(m, hlen);
253: sendorfree:
254: for (m = m0; m; m = m0) {
255: m0 = m->m_nextpkt;
256: m->m_nextpkt = 0;
257: if (error == 0)
258: error = (*ifp->if_output)(ifp, m,
259: (struct sockaddr *)dst, ro->ro_rt);
260: else
261: m_freem(m);
262: }
263: }
264: done:
265: if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
266: RTFREE(ro->ro_rt);
267: return (error);
268: bad:
269: m_freem(m0);
270: goto done;
271: }
272:
273: /*
274: * Insert IP options into preformed packet.
275: * Adjust IP destination as required for IP source routing,
276: * as indicated by a non-zero in_addr at the start of the options.
277: */
278: struct mbuf *
279: ip_insertoptions(m, opt, phlen)
280: register struct mbuf *m;
281: struct mbuf *opt;
282: int *phlen;
283: {
284: register struct ipoption *p = mtod(opt, struct ipoption *);
285: struct mbuf *n;
286: register struct ip *ip = mtod(m, struct ip *);
287: unsigned optlen;
288:
289: optlen = opt->m_len - sizeof(p->ipopt_dst);
290: if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
291: return (m); /* XXX should fail */
292: if (p->ipopt_dst.s_addr)
293: ip->ip_dst = p->ipopt_dst;
294: if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
295: MGETHDR(n, M_DONTWAIT, MT_HEADER);
296: if (n == 0)
297: return (m);
298: n->m_pkthdr.len = m->m_pkthdr.len + optlen;
299: m->m_len -= sizeof(struct ip);
300: m->m_data += sizeof(struct ip);
301: n->m_next = m;
302: m = n;
303: m->m_len = optlen + sizeof(struct ip);
304: m->m_data += max_linkhdr;
305: bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
306: } else {
307: m->m_data -= optlen;
308: m->m_len += optlen;
309: m->m_pkthdr.len += optlen;
310: ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
311: }
312: ip = mtod(m, struct ip *);
313: bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);
314: *phlen = sizeof(struct ip) + optlen;
315: ip->ip_len += optlen;
316: return (m);
317: }
318:
319: /*
320: * Copy options from ip to jp,
321: * omitting those not copied during fragmentation.
322: */
323: ip_optcopy(ip, jp)
324: struct ip *ip, *jp;
325: {
326: register u_char *cp, *dp;
327: int opt, optlen, cnt;
328:
329: cp = (u_char *)(ip + 1);
330: dp = (u_char *)(jp + 1);
331: cnt = (ip->ip_hl << 2) - sizeof (struct ip);
332: for (; cnt > 0; cnt -= optlen, cp += optlen) {
333: opt = cp[0];
334: if (opt == IPOPT_EOL)
335: break;
336: if (opt == IPOPT_NOP)
337: optlen = 1;
338: else
339: optlen = cp[IPOPT_OLEN];
340: /* bogus lengths should have been caught by ip_dooptions */
341: if (optlen > cnt)
342: optlen = cnt;
343: if (IPOPT_COPIED(opt)) {
344: bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
345: dp += optlen;
346: }
347: }
348: for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
349: *dp++ = IPOPT_EOL;
350: return (optlen);
351: }
352:
353: /*
354: * IP socket option processing.
355: */
356: ip_ctloutput(op, so, level, optname, mp)
357: int op;
358: struct socket *so;
359: int level, optname;
360: struct mbuf **mp;
361: {
362: register struct inpcb *inp = sotoinpcb(so);
363: register struct mbuf *m = *mp;
364: register int optval;
365: int error = 0;
366:
367: if (level != IPPROTO_IP)
368: error = EINVAL;
369: else switch (op) {
370:
371: case PRCO_SETOPT:
372: switch (optname) {
373: case IP_OPTIONS:
374: #ifdef notyet
375: case IP_RETOPTS:
376: return (ip_pcbopts(optname, &inp->inp_options, m));
377: #else
378: return (ip_pcbopts(&inp->inp_options, m));
379: #endif
380:
381: case IP_TOS:
382: case IP_TTL:
383: case IP_RECVOPTS:
384: case IP_RECVRETOPTS:
385: case IP_RECVDSTADDR:
386: if (m->m_len != sizeof(int))
387: error = EINVAL;
388: else {
389: optval = *mtod(m, int *);
390: switch (optname) {
391:
392: case IP_TOS:
393: inp->inp_ip.ip_tos = optval;
394: break;
395:
396: case IP_TTL:
397: inp->inp_ip.ip_tos = optval;
398: break;
399: #define OPTSET(bit) \
400: if (optval) \
401: inp->inp_flags |= bit; \
402: else \
403: inp->inp_flags &= ~bit;
404:
405: case IP_RECVOPTS:
406: OPTSET(INP_RECVOPTS);
407: break;
408:
409: case IP_RECVRETOPTS:
410: OPTSET(INP_RECVRETOPTS);
411: break;
412:
413: case IP_RECVDSTADDR:
414: OPTSET(INP_RECVDSTADDR);
415: break;
416: }
417: }
418: break;
419: #undef OPTSET
420:
421: default:
422: error = EINVAL;
423: break;
424: }
425: if (m)
426: (void)m_free(m);
427: break;
428:
429: case PRCO_GETOPT:
430: switch (optname) {
431: case IP_OPTIONS:
432: case IP_RETOPTS:
433: *mp = m = m_get(M_WAIT, MT_SOOPTS);
434: if (inp->inp_options) {
435: m->m_len = inp->inp_options->m_len;
436: bcopy(mtod(inp->inp_options, caddr_t),
437: mtod(m, caddr_t), (unsigned)m->m_len);
438: } else
439: m->m_len = 0;
440: break;
441:
442: case IP_TOS:
443: case IP_TTL:
444: case IP_RECVOPTS:
445: case IP_RECVRETOPTS:
446: case IP_RECVDSTADDR:
447: *mp = m = m_get(M_WAIT, MT_SOOPTS);
448: m->m_len = sizeof(int);
449: switch (optname) {
450:
451: case IP_TOS:
452: optval = inp->inp_ip.ip_tos;
453: break;
454:
455: case IP_TTL:
456: optval = inp->inp_ip.ip_tos;
457: break;
458:
459: #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0)
460:
461: case IP_RECVOPTS:
462: optval = OPTBIT(INP_RECVOPTS);
463: break;
464:
465: case IP_RECVRETOPTS:
466: optval = OPTBIT(INP_RECVRETOPTS);
467: break;
468:
469: case IP_RECVDSTADDR:
470: optval = OPTBIT(INP_RECVDSTADDR);
471: break;
472: }
473: *mtod(m, int *) = optval;
474: break;
475:
476: default:
477: error = EINVAL;
478: break;
479: }
480: break;
481: }
482: return (error);
483: }
484:
485: /*
486: * Set up IP options in pcb for insertion in output packets.
487: * Store in mbuf with pointer in pcbopt, adding pseudo-option
488: * with destination address if source routed.
489: */
490: #ifdef notyet
491: ip_pcbopts(optname, pcbopt, m)
492: int optname;
493: #else
494: ip_pcbopts(pcbopt, m)
495: #endif
496: struct mbuf **pcbopt;
497: register struct mbuf *m;
498: {
499: register cnt, optlen;
500: register u_char *cp;
501: u_char opt;
502:
503: /* turn off any old options */
504: if (*pcbopt)
505: (void)m_free(*pcbopt);
506: *pcbopt = 0;
507: if (m == (struct mbuf *)0 || m->m_len == 0) {
508: /*
509: * Only turning off any previous options.
510: */
511: if (m)
512: (void)m_free(m);
513: return (0);
514: }
515:
516: #ifndef vax
517: if (m->m_len % sizeof(long))
518: goto bad;
519: #endif
520: /*
521: * IP first-hop destination address will be stored before
522: * actual options; move other options back
523: * and clear it when none present.
524: */
525: if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
526: goto bad;
527: cnt = m->m_len;
528: m->m_len += sizeof(struct in_addr);
529: cp = mtod(m, u_char *) + sizeof(struct in_addr);
530: ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
531: bzero(mtod(m, caddr_t), sizeof(struct in_addr));
532:
533: for (; cnt > 0; cnt -= optlen, cp += optlen) {
534: opt = cp[IPOPT_OPTVAL];
535: if (opt == IPOPT_EOL)
536: break;
537: if (opt == IPOPT_NOP)
538: optlen = 1;
539: else {
540: optlen = cp[IPOPT_OLEN];
541: if (optlen <= IPOPT_OLEN || optlen > cnt)
542: goto bad;
543: }
544: switch (opt) {
545:
546: default:
547: break;
548:
549: case IPOPT_LSRR:
550: case IPOPT_SSRR:
551: /*
552: * user process specifies route as:
553: * ->A->B->C->D
554: * D must be our final destination (but we can't
555: * check that since we may not have connected yet).
556: * A is first hop destination, which doesn't appear in
557: * actual IP option, but is stored before the options.
558: */
559: if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
560: goto bad;
561: m->m_len -= sizeof(struct in_addr);
562: cnt -= sizeof(struct in_addr);
563: optlen -= sizeof(struct in_addr);
564: cp[IPOPT_OLEN] = optlen;
565: /*
566: * Move first hop before start of options.
567: */
568: bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
569: sizeof(struct in_addr));
570: /*
571: * Then copy rest of options back
572: * to close up the deleted entry.
573: */
574: ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
575: sizeof(struct in_addr)),
576: (caddr_t)&cp[IPOPT_OFFSET+1],
577: (unsigned)cnt + sizeof(struct in_addr));
578: break;
579: }
580: }
581: if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
582: goto bad;
583: *pcbopt = m;
584: return (0);
585:
586: bad:
587: (void)m_free(m);
588: return (EINVAL);
589: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.