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

Defined functions

ip_insertoptions defined in line 232; used 2 times
ip_optcopy defined in line 274; used 1 times
ip_pcbopts defined in line 359; used 2 times
Last modified: 1986-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1509
Valid CSS Valid XHTML 1.0 Strict