# 2.11BSD#431 - /usr/src/sys/netinet/ip_output.c

##### Functions

    ip_ctloutput      X
    ip_insertoptions  X
    ip_optcopy        X
    ip_output         X
    ip_pcbopts        X

##### Macros

    ovbcopy           X

       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

- in line 38, 61

ip_optcopy defined in line 307; used 1 times

- in line 209

ip_output defined in line 46; never used
ip_pcbopts defined in line 392; used 1 times

- in line 356

#### Defined macros

ovbcopy defined in line 37; used 3 times

- in line 294, 432, 476

Last modified: 1988-04-29 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1868 |