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