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: }

Defined functions

ip_ctloutput defined in line 340; never used
ip_insertoptions defined in line 266; used 2 times
ip_optcopy defined in line 307; used 1 times
ip_output defined in line 46; never used
ip_pcbopts defined in line 392; used 1 times

Defined macros

ovbcopy defined in line 37; used 3 times
Last modified: 1988-04-29
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4445
Valid CSS Valid XHTML 1.0 Strict