ip_output.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:43k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* ip_output.c - internet output routines */
  2. /* Copyright 1984 - 2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5.  * Copyright (c) 1982, 1986, 1988, 1990, 1993
  6.  * The Regents of the University of California.  All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  * This product includes software developed by the University of
  19.  * California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  *
  36.  * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
  37.  */
  38. /*
  39. modification history
  40. --------------------
  41. 01t,22mar02,wap  export ip_mloopback() so that ipOutput() can use it (SPR
  42.                  #72246)
  43. 01s,29oct01,wap  Fixed mbuf leak in ip_output() (SPR #67966)
  44. 01r,12oct01,rae  merge from truestack ver 01w, base 01o (SPR #69683 etc.)
  45. 01q,07dec00,rae  Add IPsec output hook
  46. 01p,17nov00,rae  allow IP_DROP_MEMBERSHIP with INADDR_ANY (SPR# 33093)
  47. 01o,03sep98,n_s  fixed fragmentation problem for mcast and bcast. spr #21071.
  48. 01n,26aug98,n_s  added return val check for mBufClGet in ip_ctloutput and
  49.                  ip_getmoptions. spr #22238.
  50. 01m,09jan98,vin  changed IP_CKSUM_SEND_MASK to IP_DO_CHECKSUM_SND
  51. 01l,08dec97,vin  fixed ip_freemoptions() SPR 9970. 
  52. 01k,19nov97,vin  changed extern declaration of _ipCfgFlags to int from UCHAR.
  53. 01j,13nov97,vin  provided an additional flag for sending large BCAST pkts.
  54. 01i,05oct97,vin  added fast multicasting.
  55. 01h,15jul97,spm  made IP checksum calculation configurable (SPR #7836)
  56. 01g,08mar97,vin  added mCastRouteFwdHook to access mcast routing code.
  57. 01f,24mar97,vin  bug fixed in ip_mloopback() ip hdr being shared, SPR8252
  58. 01e,13feb97,rjc  fixed bad parameter to TOS_SET
  59. 01d,05feb97,rjc  changes for tos routing and fix for multicast bug.
  60. 01c,05dec96,vin  changed malloc(..) to MALLOC(..) to use only network buffers,
  61.  changed free(..) to FREE(..).
  62. 01b,22nov96,vin  added cluster support replaced m_get(..) with mBufClGet(..)
  63.  replaced m_gethdr with mHdrClGet(..)
  64. 01a,03mar96,vin  created from BSD4.4 stuff,integrated with 02n of ip_output.c
  65. */
  66. #include "vxWorks.h"
  67. #include "netLib.h"
  68. #include "net/mbuf.h"
  69. #include "errno.h"
  70. #include "net/protosw.h"
  71. #include "sys/socket.h"
  72. #include "sys/ioctl.h"
  73. #include "net/socketvar.h"
  74. #include "net/if.h"
  75. #include "net/if_types.h"
  76. #include "net/route.h"
  77. #include "netinet/in.h"
  78. #include "netinet/in_pcb.h"
  79. #include "netinet/in_systm.h"
  80. #include "netinet/in_var.h"
  81. #include "netinet/ip.h"
  82. #include "netinet/ip_var.h"
  83. #include "net/systm.h"
  84. #ifdef WV_INSTRUMENTATION
  85. #ifdef INCLUDE_WVNET
  86. #include "wvNetLib.h"
  87. #endif
  88. #endif
  89. /*IPsec output hook defined in /target/src/wrn/ipsec/ipsec_io.c */
  90. typedef int (*IPSEC_OUTPUT_FUNCPTR) (struct mbuf** m0,
  91.                                      struct mbuf* opt,
  92.                                      struct route* ro, int flags,
  93.                                      struct ip_moptions* imo,struct sockaddr_in* dst,
  94.                                      struct in_ifaddr* ia);
  95. IPSEC_OUTPUT_FUNCPTR    _func_ipsecOutput;
  96. #ifdef VIRTUAL_STACK
  97. #include "netinet/vsLib.h"
  98. #include "netinet/vsMcast.h"
  99. #endif
  100. /* externs */
  101. #ifndef VIRTUAL_STACK
  102. IMPORT int  _ipCfgFlags;  /* Calculate IP checksum? */
  103. extern FUNCPTR _mCastRouteFwdHook; /* WRS mcast forward command hook */
  104. #endif /* VIRTUAL_STACK */
  105. extern int looutput();
  106. static struct mbuf *ip_insertoptions (struct mbuf *, struct mbuf *, int *);
  107. void ip_mloopback (struct ifnet *, struct mbuf *, struct sockaddr_in *,
  108.                    struct rtentry *rt);
  109. static int  ip_setmoptions (int, struct inpcb *, struct mbuf *);
  110. /* locals */
  111. #ifdef WV_INSTRUMENTATION
  112. #ifdef INCLUDE_WVNET
  113.     /* Set common fields of event identifiers for this module. */
  114. LOCAL UCHAR wvNetModuleId = WV_NET_IPOUTPUT_MODULE; /* Value for ip_output.c */
  115. LOCAL UCHAR wvNetLocalFilter = WV_NET_NONE;     /* Available event filter */
  116. LOCAL ULONG wvNetEventId;       /* Event identifier: see wvNetLib.h */
  117. #endif    /* INCLUDE_WVNET */
  118. #endif
  119. /*
  120.  * IP output.  The packet in mbuf chain m contains a skeletal IP
  121.  * header (with len, off, ttl, proto, tos, src, dst).
  122.  * The mbuf chain containing the packet will be freed.
  123.  * The mbuf opt, if present, will not be freed.
  124.  */
  125. int
  126. ip_output(m0, opt, ro, flags, imo)
  127. struct mbuf *m0;
  128. struct mbuf *opt;
  129. struct route *ro;
  130. int flags;
  131. struct ip_moptions *imo;
  132. {
  133. register struct ip *ip, *mhip;
  134. register struct ifnet *ifp = NULL;
  135. register struct mbuf *m = m0;
  136. register int hlen = sizeof (struct ip);
  137. int len, off, error = 0;
  138. struct route iproute;
  139. struct sockaddr_in *dst;
  140.         MTU_QUERY mtuQuery;
  141.         int mtu = 0;
  142. struct in_ifaddr *ia = NULL;
  143. #ifdef WV_INSTRUMENTATION
  144. #ifdef INCLUDE_WVNET
  145.         u_long srcAddr; /* Source IP address, unavailable when finished */
  146.         u_long dstAddr; /* Dest. IP address, unavailable when finished */
  147. #endif
  148. #endif
  149. #ifdef DIAGNOSTIC
  150. if ((m->m_flags & M_PKTHDR) == 0)
  151. panic("ip_output no HDR");
  152. #endif
  153. if (opt) {
  154. m = ip_insertoptions(m, opt, &len);
  155. hlen = len;
  156. }
  157. ip = mtod(m, struct ip *);
  158. /*
  159.  * Fill in IP header.
  160.  */
  161. if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
  162. ip->ip_v = IPVERSION;
  163. ip->ip_off &= IP_DF;
  164. #ifdef VIRTUAL_STACK
  165. ip->ip_id = htons(_ip_id++);
  166. #else
  167. ip->ip_id = htons(ip_id++);
  168. #endif /* VIRTUAL_STACK */
  169. ip->ip_hl = hlen >> 2;
  170. #ifdef VIRTUAL_STACK
  171. _ipstat.ips_localout++;
  172. #else
  173. ipstat.ips_localout++;
  174. #endif /* VIRTUAL_STACK */
  175. } else {
  176. hlen = ip->ip_hl << 2;
  177. }
  178. #ifdef WV_INSTRUMENTATION
  179. #ifdef INCLUDE_WVNET
  180.         /*
  181.          * Save the source and destination address from the original packet,
  182.          * since they will be unavailable at the "done:" label.
  183.          */
  184.         srcAddr = ip->ip_src.s_addr;
  185.         dstAddr = ip->ip_dst.s_addr;
  186. #endif
  187. #endif
  188. /*
  189.  * Route packet.
  190.  */
  191. if (ro == 0) {
  192. ro = &iproute;
  193. bzero((caddr_t)ro, sizeof (*ro));
  194. }
  195. dst = (struct sockaddr_in *)&ro->ro_dst;
  196. /*
  197.  * If there is a cached route,
  198.  * check that it is to the same destination
  199.  * and is still up.  If not, free it and try again.
  200.  */
  201. if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
  202.    dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
  203. #ifdef WV_INSTRUMENTATION
  204. #ifdef INCLUDE_WVNET    /* WV_NET_VERBOSE event */
  205.         WV_NET_DSTADDROUT_EVENT_2 (NET_CORE_EVENT, WV_NET_VERBOSE, 57, 8,
  206.                                    ip->ip_dst.s_addr,
  207.                                    WV_NETEVENT_IPOUT_CACHEMISS, WV_NET_SEND,
  208.                                    ip->ip_dst.s_addr, dst->sin_addr.s_addr)
  209. #endif  /* INCLUDE_WVNET */
  210. #endif
  211. RTFREE(ro->ro_rt);
  212. ro->ro_rt = (struct rtentry *)0;
  213. }
  214. if (ro->ro_rt == 0) {
  215. dst->sin_family = AF_INET;
  216. dst->sin_len = sizeof(*dst);
  217. dst->sin_addr = ip->ip_dst;
  218. TOS_SET (dst, ip->ip_tos);
  219. }
  220. /*
  221.  * If routing to interface only,
  222.  * short circuit routing lookup.
  223.  */
  224. #define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
  225. #define sintosa(sin) ((struct sockaddr *)(sin))
  226. if (flags & IP_ROUTETOIF ) {
  227. if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
  228.     (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
  229. #ifdef WV_INSTRUMENTATION
  230. #ifdef INCLUDE_WVNET    /* WV_NET_CRITICAL event */
  231.         WV_NET_DSTADDROUT_EVENT_1 (NET_CORE_EVENT, WV_NET_CRITICAL, 20, 1,
  232.                                    ip->ip_dst.s_addr,
  233.                                    WV_NETEVENT_IPOUT_BADADDR, WV_NET_SEND,
  234.                                    dst->sin_addr.s_addr)
  235. #endif  /* INCLUDE_WVNET */
  236. #endif
  237. #ifdef VIRTUAL_STACK
  238. _ipstat.ips_noroute++;
  239. #else
  240. ipstat.ips_noroute++;
  241. #endif /* VIRTUAL_STACK */
  242. error = ENETUNREACH;
  243. goto bad;
  244. }
  245. ifp = ia->ia_ifp;
  246. ip->ip_ttl = 1;
  247. } else if (! (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) && imo &&
  248.               ((imo->imo_multicast_ifp != NULL)))) {
  249. if (ro->ro_rt == 0)
  250. rtalloc(ro);
  251. if (ro->ro_rt == 0) {
  252. #ifdef WV_INSTRUMENTATION
  253. #ifdef INCLUDE_WVNET    /* WV_NET_CRITICAL event */
  254.         WV_NET_DSTADDROUT_EVENT_1 (NET_CORE_EVENT, WV_NET_CRITICAL, 20, 1,
  255.                                    ip->ip_dst.s_addr,
  256.                                    WV_NETEVENT_IPOUT_BADADDR, WV_NET_SEND,
  257.                                    dst->sin_addr.s_addr)
  258. #endif  /* INCLUDE_WVNET */
  259. #endif
  260. #ifdef VIRTUAL_STACK
  261. _ipstat.ips_noroute++;
  262. #else
  263. ipstat.ips_noroute++;
  264. #endif /* VIRTUAL_STACK */
  265. error = EHOSTUNREACH;
  266. goto bad;
  267. }
  268. ia = ifatoia(ro->ro_rt->rt_ifa);
  269. ifp = ro->ro_rt->rt_ifp;
  270. ro->ro_rt->rt_use++;
  271. if (ro->ro_rt->rt_flags & RTF_GATEWAY)
  272. dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
  273. }
  274. if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
  275. struct in_multi *inm;
  276. #ifndef VIRTUAL_STACK
  277. extern struct ifnet loif[];
  278. #endif /* VIRTUAL_STACK */
  279. m->m_flags |= M_MCAST;
  280. /*
  281.  * IP destination address is multicast.  Make sure "dst"
  282.  * still points to the address in "ro".  (It may have been
  283.  * changed to point to a gateway address, above.)
  284.  */
  285. dst = (struct sockaddr_in *)&ro->ro_dst;
  286.                if (imo && imo->imo_multicast_ifp != NULL) 
  287.                    {
  288.                    register struct in_ifaddr *ia;
  289. #ifdef VIRTUAL_STACK
  290.                    for (ia = _in_ifaddr; ia; ia = ia->ia_next)
  291. #else
  292.                    for (ia = in_ifaddr; ia; ia = ia->ia_next)
  293. #endif /* VIRTUAL_STACK */
  294.                        if (ia->ia_ifp == ifp) 
  295.                            {
  296.            dst->sin_addr.s_addr = IA_SIN(ia)->sin_addr.s_addr;
  297.                    break;
  298.    }
  299.                    if (ro->ro_rt)
  300.                        {
  301.                        RTFREE(ro->ro_rt);
  302.                        ro->ro_rt = (struct rtentry *)0;
  303.                        }
  304.                    }
  305. /*
  306.  * See if the caller provided any multicast options
  307.  */
  308. if (imo != NULL) {
  309. ip->ip_ttl = imo->imo_multicast_ttl;
  310. if (imo->imo_multicast_ifp != NULL)
  311. ifp = imo->imo_multicast_ifp;
  312. } else
  313. ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
  314. /*
  315.  * Confirm that the outgoing interface supports multicast.
  316.  */
  317. if ((ifp->if_flags & IFF_MULTICAST) == 0) {
  318. #ifdef WV_INSTRUMENTATION
  319. #ifdef INCLUDE_WVNET    /* WV_NET_CRITICAL event */
  320.         WV_NET_DSTADDROUT_EVENT_2 (NET_CORE_EVENT, WV_NET_CRITICAL, 21, 2,
  321.                                    ip->ip_dst.s_addr,
  322.                                    WV_NETEVENT_IPOUT_BADFLAGS, WV_NET_SEND,
  323.                                    dst->sin_addr.s_addr, ifp)
  324. #endif  /* INCLUDE_WVNET */
  325. #endif
  326. #ifdef VIRTUAL_STACK
  327. _ipstat.ips_noroute++;
  328. #else
  329. ipstat.ips_noroute++;
  330. #endif /* VIRTUAL_STACK */
  331. error = ENETUNREACH;
  332. goto bad;
  333. }
  334. /*
  335.  * If source address not specified yet, use address
  336.  * of outgoing interface.
  337.  */
  338. if (ip->ip_src.s_addr == INADDR_ANY) {
  339. register struct in_ifaddr *ia;
  340. #ifdef VIRTUAL_STACK
  341. for (ia = _in_ifaddr; ia; ia = ia->ia_next)
  342. #else
  343. for (ia = in_ifaddr; ia; ia = ia->ia_next)
  344. #endif /* VIRTUAL_STACK */
  345. if (ia->ia_ifp == ifp) {
  346. ip->ip_src = IA_SIN(ia)->sin_addr;
  347. break;
  348. }
  349. #ifdef WV_INSTRUMENTATION
  350. #ifdef INCLUDE_WVNET
  351.         /*
  352.          * Update the source destination address if not previously
  353.          * specified, since it will be unavailable at the "done:" label.
  354.          */
  355.         srcAddr = ip->ip_src.s_addr;
  356. #endif
  357. #endif
  358. }
  359. IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
  360. if (inm != NULL &&
  361.    (imo == NULL || imo->imo_multicast_loop)) {
  362. /*
  363.  * If we belong to the destination multicast group
  364.  * on the outgoing interface, and the caller did not
  365.  * forbid loopback, loop back a copy.
  366.  */
  367. ip_mloopback(ifp, m, dst, NULL);
  368. }
  369. else {
  370. /*
  371.  * If we are acting as a multicast router, perform
  372.  * multicast forwarding as if the packet had just
  373.  * arrived on the interface to which we are about
  374.  * to send.  The multicast forwarding function
  375.  * recursively calls this function, using the
  376.  * IP_FORWARDING flag to prevent infinite recursion.
  377.  *
  378.  * Multicasts that are looped back by ip_mloopback(),
  379.  * above, will be forwarded by the ip_input() routine,
  380.  * if necessary.
  381.  */
  382.                  if ((_mCastRouteFwdHook != NULL) &&
  383.                             ((flags & IP_FORWARDING) == 0)) {
  384. if ((*_mCastRouteFwdHook)(m, ifp, ip, NULL) != 0) {
  385. m_freem(m);
  386. goto done;
  387. }
  388. }
  389. }
  390. /*
  391.  * Multicasts with a time-to-live of zero may be looped-
  392.  * back, above, but must not be transmitted on a network.
  393.  * Also, multicasts addressed to the loopback interface
  394.  * are not sent -- the above call to ip_mloopback() will
  395.  * loop back a copy if this host actually belongs to the
  396.  * destination group on the loopback interface.
  397.  */
  398. if (ip->ip_ttl == 0 || ifp == loif) {
  399. m_freem(m);
  400. goto done;
  401. }
  402.                 /*
  403.                  * Use the predefined MTU size for outgoing packets. The
  404.                  * point-to-multipoint devices which permit a different
  405.                  * value do not support multicast addresses.
  406.                  */
  407.                 mtu = ifp->if_mtu;
  408. goto sendit;
  409. }
  410. #ifndef notdef
  411. /*
  412.  * If source address not specified yet, use address
  413.  * of outgoing interface.
  414.  */
  415. if (ip->ip_src.s_addr == INADDR_ANY)
  416. ip->ip_src = IA_SIN(ia)->sin_addr;
  417. #ifdef WV_INSTRUMENTATION
  418. #ifdef INCLUDE_WVNET
  419.         /*
  420.          * Update the source destination address if not previously 
  421.          * specified, since it will be unavailable at the "done:" label.
  422.          */
  423.         srcAddr = ip->ip_src.s_addr;
  424. #endif
  425. #endif
  426. #endif
  427.         /*
  428.          * Get the MTU size. Point-to-multipoint devices allow a separate
  429.          * MTU for each destination address. All other devices use a
  430.          * predefined size.
  431.          */
  432.         if (ifp->if_type == IFT_PMP)
  433.             {
  434.             /*
  435.              * The SIOCGMTU operation reads the address from the
  436.              * argument and returns the corresponding MTU size.
  437.              */
  438.             mtuQuery.family = AF_INET;
  439.             mtuQuery.dstIpAddr = dst->sin_addr.s_addr;
  440.             error = ifp->if_ioctl (ifp, SIOCGMTU, (caddr_t)&mtuQuery);
  441.             if (error)
  442.                 {
  443.                 error = EHOSTUNREACH;
  444.                 goto bad;
  445.                 }
  446.             mtu = mtuQuery.mtu;
  447.             }
  448.         else
  449.             mtu = ifp->if_mtu;
  450. /*
  451.  * Look for broadcast address and
  452.  * and verify user is allowed to send
  453.  * such a packet.
  454.  */
  455. if (in_broadcast(dst->sin_addr, ifp)) {
  456. if ((ifp->if_flags & IFF_BROADCAST) == 0) {
  457. #ifdef WV_INSTRUMENTATION
  458. #ifdef INCLUDE_WVNET    /* WV_NET_CRITICAL event */
  459.             WV_NET_ADDROUT_EVENT_2 (NET_CORE_EVENT, WV_NET_CRITICAL, 21, 2,
  460.                                     ip->ip_src.s_addr, ip->ip_dst.s_addr,
  461.                                     WV_NETEVENT_IPOUT_BADFLAGS, WV_NET_SEND,
  462.                                     dst->sin_addr.s_addr, ifp)
  463. #endif  /* INCLUDE_WVNET */
  464. #endif
  465. error = EADDRNOTAVAIL;
  466. goto bad;
  467. }
  468. if ((flags & IP_ALLOWBROADCAST) == 0) {
  469. #ifdef WV_INSTRUMENTATION
  470. #ifdef INCLUDE_WVNET    /* WV_NET_CRITICAL event */
  471.             WV_NET_ADDROUT_EVENT_2 (NET_CORE_EVENT, WV_NET_CRITICAL, 21, 2,
  472.                                     ip->ip_src.s_addr, ip->ip_dst.s_addr,
  473.                                     WV_NETEVENT_IPOUT_BADFLAGS, WV_NET_SEND,
  474.                                     dst->sin_addr.s_addr, 0)
  475. #endif  /* INCLUDE_WVNET */
  476. #endif
  477. error = EACCES;
  478. goto bad;
  479. }
  480. /* allow broadcast messages to be fragmented if flag set */
  481. if (((u_short)ip->ip_len > mtu) &&
  482.                     !(_ipCfgFlags & IP_DO_LARGE_BCAST)) {
  483. #ifdef WV_INSTRUMENTATION
  484. #ifdef INCLUDE_WVNET    /* WV_NET_CRITICAL event */
  485.             WV_NET_ADDROUT_EVENT_2 (NET_CORE_EVENT, WV_NET_CRITICAL, 22, 3,
  486.                                     ip->ip_src.s_addr, ip->ip_dst.s_addr,
  487.                                     WV_NETEVENT_IPOUT_CANTFRAG, WV_NET_SEND,
  488.                                     dst->sin_addr.s_addr, ifp)
  489. #endif  /* INCLUDE_WVNET */
  490. #endif
  491. error = EMSGSIZE;
  492. goto bad;
  493. }
  494. m->m_flags |= M_BCAST;
  495. } else
  496. m->m_flags &= ~M_BCAST;
  497. sendit:
  498.         if (_func_ipsecOutput != NULL)
  499.             {
  500.             /* Deliver the packet to ipsec for further processing/filtering. */
  501.             error = _func_ipsecOutput (&m0, opt, ro, flags, imo, dst, ia);
  502.             m = m0;
  503.             ip = mtod(m, struct ip *);
  504.             if (error != 0)
  505.                 {
  506.                 /* If there is an error we should have already freed the packet */
  507.                 if (error == ERROR)
  508.                     {
  509.                     /* Unless the error is very specific we do not propagate the error; so we reset it */
  510.                     error = OK;
  511.                     }
  512.                 goto done;
  513.                 }
  514.             }
  515. /*
  516.  * If small enough for interface, can just send directly.
  517.  */
  518. if ((u_short)ip->ip_len <= mtu) {
  519. #ifdef WV_INSTRUMENTATION
  520. #ifdef INCLUDE_WVNET    /* WV_NET_INFO event */
  521.             WV_NET_ADDROUT_EVENT_4 (NET_CORE_EVENT, WV_NET_INFO, 54, 10,
  522.                                     ip->ip_src.s_addr, ip->ip_dst.s_addr,
  523.                                     WV_NETEVENT_IPOUT_SENDALL, WV_NET_SEND,
  524.                                     ip->ip_src.s_addr, ip->ip_dst.s_addr,
  525.                                     (u_long)ip->ip_len, mtu)
  526. #endif  /* INCLUDE_WVNET */
  527. #endif
  528. ip->ip_len = htons((u_short)ip->ip_len);
  529. ip->ip_off = htons((u_short)ip->ip_off);
  530. ip->ip_sum = 0;
  531.                 if (_ipCfgFlags & IP_DO_CHECKSUM_SND)
  532.                     ip->ip_sum = in_cksum(m, hlen);
  533. error = (*ifp->if_output)(ifp, m,
  534. (struct sockaddr *)dst, ro->ro_rt);
  535. goto done;
  536. }
  537. /*
  538.  * Too large for interface; fragment if possible.
  539.  * Must be able to put at least 8 bytes per fragment.
  540.  */
  541. if (ip->ip_off & IP_DF) {
  542. #ifdef WV_INSTRUMENTATION
  543. #ifdef INCLUDE_WVNET    /* WV_NET_CRITICAL event */
  544.             WV_NET_ADDROUT_EVENT_2 (NET_CORE_EVENT, WV_NET_CRITICAL, 22, 3,
  545.                                     ip->ip_src.s_addr, ip->ip_dst.s_addr,
  546.                                     WV_NETEVENT_IPOUT_CANTFRAG, WV_NET_SEND,
  547.                                     dst->sin_addr.s_addr, ifp)
  548. #endif  /* INCLUDE_WVNET */
  549. #endif
  550. error = EMSGSIZE;
  551.             /*
  552.              * If the interface is using a new (smaller) MTU size than
  553.              * originally assigned, update the current path MTU estimate
  554.              * (if any) to the new (largest possible) value.
  555.              */
  556.             if (ro->ro_rt && (ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST))
  557.                 && !(ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU)
  558.                 && (ro->ro_rt->rt_rmx.rmx_mtu > mtu))
  559.                 {
  560.                 ro->ro_rt->rt_rmx.rmx_mtu = mtu;
  561.                 }
  562. #ifdef VIRTUAL_STACK
  563. _ipstat.ips_cantfrag++;
  564. #else
  565. ipstat.ips_cantfrag++;
  566. #endif /* VIRTUAL_STACK */
  567. goto bad;
  568. }
  569. len = (mtu - hlen) &~ 7;
  570. if (len < 8) {
  571. #ifdef WV_INSTRUMENTATION
  572. #ifdef INCLUDE_WVNET    /* WV_NET_CRITICAL event */
  573.             WV_NET_ADDROUT_EVENT_2 (NET_CORE_EVENT, WV_NET_CRITICAL, 23, 4,
  574.                                     ip->ip_src.s_addr, ip->ip_dst.s_addr,
  575.                                     WV_NETEVENT_IPOUT_SHORTMSG, WV_NET_SEND,
  576.                                     dst->sin_addr.s_addr, ifp)
  577. #endif  /* INCLUDE_WVNET */
  578. #endif
  579. error = EMSGSIZE;
  580. goto bad;
  581. }
  582.     {
  583. int mhlen, firstlen = len;
  584. struct mbuf **mnext = &m->m_nextpkt;
  585. #ifdef WV_INSTRUMENTATION
  586. #ifdef INCLUDE_WVNET    /* WV_NET_INFO event */
  587.         WV_NET_ADDROUT_EVENT_4 (NET_CORE_EVENT, WV_NET_INFO, 55, 11,
  588.                                 ip->ip_src.s_addr, ip->ip_dst.s_addr,
  589.                                 WV_NETEVENT_IPOUT_SENDFRAG, WV_NET_SEND,
  590.                                 dst->sin_addr.s_addr, (u_long)ip->ip_len,
  591.                                 hlen, mtu);
  592. #endif  /* INCLUDE_WVNET */
  593. #endif
  594. /*
  595.  * Loop through length of segment after first fragment,
  596.  * make new header and copy data of each part and link onto chain.
  597.  */
  598. m0 = m;
  599. mhlen = sizeof (struct ip);
  600. for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
  601. m= mHdrClGet(M_DONTWAIT, MT_HEADER, CL_SIZE_128, TRUE);
  602. if (m == 0) {
  603. error = ENOBUFS;
  604. #ifdef VIRTUAL_STACK
  605. _ipstat.ips_odropped++;
  606. #else
  607. ipstat.ips_odropped++;
  608. #endif /* VIRTUAL_STACK */
  609. goto sendorfree;
  610. }
  611. m->m_flags = m0->m_flags;
  612. m->m_data += max_linkhdr;
  613. mhip = mtod(m, struct ip *);
  614. *mhip = *ip;
  615. if (hlen > sizeof (struct ip)) {
  616. mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
  617. mhip->ip_hl = mhlen >> 2;
  618. }
  619. m->m_len = mhlen;
  620. mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
  621. if (ip->ip_off & IP_MF)
  622. mhip->ip_off |= IP_MF;
  623. if (off + len >= (u_short)ip->ip_len)
  624. len = (u_short)ip->ip_len - off;
  625. else
  626. mhip->ip_off |= IP_MF;
  627. mhip->ip_len = htons((u_short)(len + mhlen));
  628. m->m_next = m_copy(m0, off, len);
  629. if (m->m_next == 0) {
  630. (void) m_free(m);
  631. error = ENOBUFS; /* ??? */
  632. #ifdef VIRTUAL_STACK
  633. _ipstat.ips_odropped++;
  634. #else
  635. ipstat.ips_odropped++;
  636. #endif /* VIRTUAL_STACK */
  637. goto sendorfree;
  638. }
  639. m->m_pkthdr.len = mhlen + len;
  640. m->m_pkthdr.rcvif = (struct ifnet *)0;
  641. mhip->ip_off = htons((u_short)mhip->ip_off);
  642.                 mhip->ip_sum = 0;
  643.                 if (_ipCfgFlags & IP_DO_CHECKSUM_SND)
  644.                     mhip->ip_sum = in_cksum(m, mhlen);
  645. *mnext = m;
  646. mnext = &m->m_nextpkt;
  647. #ifdef VIRTUAL_STACK
  648. _ipstat.ips_ofragments++;
  649. #else
  650. ipstat.ips_ofragments++;
  651. #endif /* VIRTUAL_STACK */
  652. }
  653. /*
  654.  * Update first fragment by trimming what's been copied out
  655.  * and updating header, then send each fragment (in order).
  656.  */
  657. m = m0;
  658. m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
  659. m->m_pkthdr.len = hlen + firstlen;
  660. ip->ip_len = htons((u_short)m->m_pkthdr.len);
  661. ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
  662.         ip->ip_sum = 0;
  663.         if (_ipCfgFlags & IP_DO_CHECKSUM_SND)
  664.             ip->ip_sum = in_cksum(m, hlen);
  665. sendorfree:
  666. for (m = m0; m; m = m0) {
  667. m0 = m->m_nextpkt;
  668. m->m_nextpkt = 0;
  669. if (error == 0)
  670. error = (*ifp->if_output)(ifp, m,
  671.     (struct sockaddr *)dst, ro->ro_rt);
  672. else
  673. m_freem(m);
  674. }
  675. if (error == 0)
  676. #ifdef VIRTUAL_STACK
  677. _ipstat.ips_fragmented++;
  678. #else
  679. ipstat.ips_fragmented++;
  680. #endif /* VIRTUAL_STACK */
  681.     }
  682. done:
  683. #ifdef WV_INSTRUMENTATION
  684. #ifdef INCLUDE_WVNET    /* WV_NET_ERROR event */
  685.     WV_NET_ADDROUT_EVENT_4 (NET_CORE_EVENT, WV_NET_ERROR, 31, 9,
  686.                             srcAddr, dstAddr,
  687.                             WV_NETEVENT_IPOUT_FINISH, WV_NET_SEND,
  688.                             error, ifp, srcAddr, dstAddr)
  689. #endif  /* INCLUDE_WVNET */
  690. #endif
  691. if ((ro == &iproute) && ((flags & IP_ROUTETOIF) == 0) && ro->ro_rt) {
  692. RTFREE(ro->ro_rt);
  693. }
  694. return (error);
  695. bad:
  696. m_freem(m);
  697. goto done;
  698. }
  699. /*
  700.  * Insert IP options into preformed packet.
  701.  * Adjust IP destination as required for IP source routing,
  702.  * as indicated by a non-zero in_addr at the start of the options.
  703.  */
  704. static struct mbuf *
  705. ip_insertoptions(m, opt, phlen)
  706. register struct mbuf *m;
  707. struct mbuf *opt;
  708. int *phlen;
  709. {
  710. register struct ipoption *p = mtod(opt, struct ipoption *);
  711. struct mbuf *n;
  712. register struct ip *ip = mtod(m, struct ip *);
  713. unsigned optlen;
  714. optlen = opt->m_len - sizeof(p->ipopt_dst);
  715. if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
  716. return (m); /* XXX should fail */
  717. if (p->ipopt_dst.s_addr)
  718. ip->ip_dst = p->ipopt_dst;
  719. #if 0 /* XXX changed for default cluster support vinai
  720.          * The reason why always new clusters are allocted,
  721.          * is that, data could be overwritten since clusters are shared.
  722.          */
  723. if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
  724. #endif
  725. n = mHdrClGet(M_DONTWAIT, MT_HEADER, CL_SIZE_128, TRUE);
  726. if (n == 0)
  727. return (m);
  728. n->m_pkthdr.len = m->m_pkthdr.len + optlen;
  729. m->m_len -= sizeof(struct ip);
  730. m->m_data += sizeof(struct ip);
  731. n->m_next = m;
  732. m = n;
  733. m->m_len = optlen + sizeof(struct ip);
  734. m->m_data += max_linkhdr;
  735. bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
  736. #if 0  /* XXX changed for default cluster support vinai */               
  737. } else {
  738. m->m_data -= optlen;
  739. m->m_len += optlen;
  740. m->m_pkthdr.len += optlen;
  741. ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
  742. }
  743. #endif        
  744. ip = mtod(m, struct ip *);
  745. bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);
  746. *phlen = sizeof(struct ip) + optlen;
  747. ip->ip_len += optlen;
  748. return (m);
  749. }
  750. /*
  751.  * Copy options from ip to jp,
  752.  * omitting those not copied during fragmentation.
  753.  */
  754. int
  755. ip_optcopy(ip, jp)
  756. struct ip *ip, *jp;
  757. {
  758. register u_char *cp, *dp;
  759. int opt, optlen, cnt;
  760. cp = (u_char *)(ip + 1);
  761. dp = (u_char *)(jp + 1);
  762. cnt = (ip->ip_hl << 2) - sizeof (struct ip);
  763. for (; cnt > 0; cnt -= optlen, cp += optlen) {
  764. opt = cp[0];
  765. if (opt == IPOPT_EOL)
  766. break;
  767. if (opt == IPOPT_NOP) {
  768. /* Preserve for IP mcast tunnel's LSRR alignment. */
  769. *dp++ = IPOPT_NOP;
  770. optlen = 1;
  771. continue;
  772. } else
  773. optlen = cp[IPOPT_OLEN];
  774. /* bogus lengths should have been caught by ip_dooptions */
  775. if (optlen > cnt)
  776. optlen = cnt;
  777. if (IPOPT_COPIED(opt)) {
  778. bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
  779. dp += optlen;
  780. }
  781. }
  782. for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
  783. *dp++ = IPOPT_EOL;
  784. return (optlen);
  785. }
  786. /*
  787.  * IP socket option processing.
  788.  */
  789. int
  790. ip_ctloutput(op, so, level, optname, mp)
  791. int op;
  792. struct socket *so;
  793. int level, optname;
  794. struct mbuf **mp;
  795. {
  796. register struct inpcb *inp = sotoinpcb(so);
  797. register struct mbuf *m = *mp;
  798. register int optval = 0;
  799. int error = 0;
  800. #ifdef WV_INSTRUMENTATION
  801. #ifdef INCLUDE_WVNET    /* WV_NET_INFO event */
  802.     WV_NET_MARKER_4 (NET_AUX_EVENT, WV_NET_INFO, 11, 6,
  803.                      WV_NETEVENT_IPOUTCTRL_START,
  804.                      so->so_fd, op, level, optname)
  805. #endif  /* INCLUDE_WVNET */
  806. #endif
  807. if (level != IPPROTO_IP) {
  808. error = EINVAL;
  809. if (op == PRCO_SETOPT && *mp)
  810. (void) m_free(*mp);
  811. } else switch (op) {
  812. case PRCO_SETOPT:
  813. switch (optname) {
  814. case IP_OPTIONS:
  815. #ifdef notyet
  816. case IP_RETOPTS:
  817. return (ip_pcbopts(optname, &inp->inp_options, m));
  818. #else
  819. return (ip_pcbopts(&inp->inp_options, m));
  820. #endif
  821. case IP_TOS:
  822. case IP_TTL:
  823. case IP_RECVOPTS:
  824. case IP_RECVRETOPTS:
  825. case IP_RECVDSTADDR:
  826. if (m->m_len != sizeof(int))
  827. error = EINVAL;
  828. else {
  829. optval = *mtod(m, int *);
  830. switch (optname) {
  831. case IP_TOS:
  832. inp->inp_ip.ip_tos = optval;
  833. break;
  834. case IP_TTL:
  835. inp->inp_ip.ip_ttl = optval;
  836. break;
  837. #define OPTSET(bit) 
  838. if (optval) 
  839. inp->inp_flags |= bit; 
  840. else 
  841. inp->inp_flags &= ~bit;
  842. case IP_RECVOPTS:
  843. OPTSET(INP_RECVOPTS);
  844. break;
  845. case IP_RECVRETOPTS:
  846. OPTSET(INP_RECVRETOPTS);
  847. break;
  848. case IP_RECVDSTADDR:
  849. OPTSET(INP_RECVDSTADDR);
  850. break;
  851. }
  852. }
  853. break;
  854. #undef OPTSET
  855. case IP_MULTICAST_IF:
  856. case IP_MULTICAST_TTL:
  857. case IP_MULTICAST_LOOP:
  858. case IP_ADD_MEMBERSHIP:
  859. case IP_DROP_MEMBERSHIP:
  860. error = ip_setmoptions(optname, inp, m);
  861. break;
  862. default:
  863. #ifdef WV_INSTRUMENTATION
  864. #ifdef INCLUDE_WVNET    /* WV_NET_ERROR event */
  865.                     WV_NET_MARKER_4 (NET_AUX_EVENT, WV_NET_ERROR, 30, 5,
  866.                                      WV_NETEVENT_IPOUTCTRL_BADCMD,
  867.                                      so->so_fd, op, level, optname)
  868. #endif  /* INCLUDE_WVNET */
  869. #endif
  870. error = ENOPROTOOPT;
  871. break;
  872. }
  873. if (m)
  874. (void)m_free(m);
  875. break;
  876. case PRCO_GETOPT:
  877. switch (optname) {
  878. case IP_OPTIONS:
  879. case IP_RETOPTS:
  880. *mp = m = mBufClGet(M_WAIT, MT_SOOPTS, CL_SIZE_128,
  881.     TRUE);
  882. if (m == NULL)
  883.     {
  884.     error = ENOBUFS;
  885.     break;
  886.     }
  887. if (inp->inp_options) {
  888. m->m_len = inp->inp_options->m_len;
  889. bcopy(mtod(inp->inp_options, caddr_t),
  890.     mtod(m, caddr_t), (unsigned)m->m_len);
  891. } else
  892. m->m_len = 0;
  893. break;
  894. case IP_TOS:
  895. case IP_TTL:
  896. case IP_RECVOPTS:
  897. case IP_RECVRETOPTS:
  898. case IP_RECVDSTADDR:
  899. *mp = m = mBufClGet(M_WAIT, MT_SOOPTS, CL_SIZE_128,
  900.     TRUE);
  901. if (m == NULL)
  902.     {
  903.     error = ENOBUFS;
  904.     break;
  905.     }
  906. m->m_len = sizeof(int);
  907. switch (optname) {
  908. case IP_TOS:
  909. optval = inp->inp_ip.ip_tos;
  910. break;
  911. case IP_TTL:
  912. optval = inp->inp_ip.ip_ttl;
  913. break;
  914. #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0)
  915. case IP_RECVOPTS:
  916. optval = OPTBIT(INP_RECVOPTS);
  917. break;
  918. case IP_RECVRETOPTS:
  919. optval = OPTBIT(INP_RECVRETOPTS);
  920. break;
  921. case IP_RECVDSTADDR:
  922. optval = OPTBIT(INP_RECVDSTADDR);
  923. break;
  924. }
  925. *mtod(m, int *) = optval;
  926. break;
  927. case IP_MULTICAST_IF:
  928. case IP_MULTICAST_TTL:
  929. case IP_MULTICAST_LOOP:
  930. case IP_ADD_MEMBERSHIP:
  931. case IP_DROP_MEMBERSHIP:
  932. error = ip_getmoptions(optname, inp->inp_moptions, mp);
  933. break;
  934. default:
  935. #ifdef WV_INSTRUMENTATION
  936. #ifdef INCLUDE_WVNET    /* WV_NET_ERROR event */
  937.                     WV_NET_MARKER_4 (NET_AUX_EVENT, WV_NET_ERROR, 30, 5,
  938.                                      WV_NETEVENT_IPOUTCTRL_BADCMD,
  939.                                      so->so_fd, op, level, optname)
  940. #endif  /* INCLUDE_WVNET */
  941. #endif
  942. error = ENOPROTOOPT;
  943. break;
  944. }
  945. break;
  946. }
  947. return (error);
  948. }
  949. /*
  950.  * Set up IP options in pcb for insertion in output packets.
  951.  * Store in mbuf with pointer in pcbopt, adding pseudo-option
  952.  * with destination address if source routed.
  953.  */
  954. int
  955. #ifdef notyet
  956. ip_pcbopts(optname, pcbopt, m)
  957. int optname;
  958. #else
  959. ip_pcbopts(pcbopt, m)
  960. #endif
  961. struct mbuf **pcbopt;
  962. register struct mbuf *m;
  963. {
  964. register int cnt, optlen;
  965. register u_char *cp;
  966. u_char opt;
  967. /* turn off any old options */
  968. if (*pcbopt)
  969. (void)m_free(*pcbopt);
  970. *pcbopt = 0;
  971. if (m == (struct mbuf *)0 || m->m_len == 0) {
  972. /*
  973.  * Only turning off any previous options.
  974.  */
  975. if (m)
  976. (void)m_free(m);
  977. return (0);
  978. }
  979. #ifndef vax
  980. if (m->m_len % sizeof(long))
  981. goto bad;
  982. #endif
  983. /*
  984.  * IP first-hop destination address will be stored before
  985.  * actual options; move other options back
  986.  * and clear it when none present.
  987.  */
  988. #if 0 /*XXX changed for default cluster support vinai*/
  989. if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
  990. goto bad;
  991. #else
  992. if (m->m_data + m->m_len + sizeof(struct in_addr) >= 
  993.     (m->m_extBuf + m->m_extSize))
  994. goto bad;
  995. #endif
  996. cnt = m->m_len;
  997. m->m_len += sizeof(struct in_addr);
  998. cp = mtod(m, u_char *) + sizeof(struct in_addr);
  999. ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
  1000. bzero(mtod(m, caddr_t), sizeof(struct in_addr));
  1001. for (; cnt > 0; cnt -= optlen, cp += optlen) {
  1002. opt = cp[IPOPT_OPTVAL];
  1003. if (opt == IPOPT_EOL)
  1004. break;
  1005. if (opt == IPOPT_NOP)
  1006. optlen = 1;
  1007. else {
  1008. optlen = cp[IPOPT_OLEN];
  1009. if (optlen <= IPOPT_OLEN || optlen > cnt)
  1010. goto bad;
  1011. }
  1012. switch (opt) {
  1013. default:
  1014. break;
  1015. case IPOPT_LSRR:
  1016. case IPOPT_SSRR:
  1017. /*
  1018.  * user process specifies route as:
  1019.  * ->A->B->C->D
  1020.  * D must be our final destination (but we can't
  1021.  * check that since we may not have connected yet).
  1022.  * A is first hop destination, which doesn't appear in
  1023.  * actual IP option, but is stored before the options.
  1024.  */
  1025. if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
  1026. goto bad;
  1027. m->m_len -= sizeof(struct in_addr);
  1028. cnt -= sizeof(struct in_addr);
  1029. optlen -= sizeof(struct in_addr);
  1030. cp[IPOPT_OLEN] = optlen;
  1031. /*
  1032.  * Move first hop before start of options.
  1033.  */
  1034. bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
  1035.     sizeof(struct in_addr));
  1036. /*
  1037.  * Then copy rest of options back
  1038.  * to close up the deleted entry.
  1039.  */
  1040. ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
  1041.     sizeof(struct in_addr)),
  1042.     (caddr_t)&cp[IPOPT_OFFSET+1],
  1043.     (unsigned)cnt + sizeof(struct in_addr));
  1044. break;
  1045. }
  1046. }
  1047. if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
  1048. goto bad;
  1049. *pcbopt = m;
  1050. return (0);
  1051. bad:
  1052. (void)m_free(m);
  1053. return (EINVAL);
  1054. }
  1055. /*
  1056.  * Set the IP multicast options in response to user setsockopt().
  1057.  */
  1058. static int ip_setmoptions
  1059.     (
  1060.     int optname,
  1061.     struct inpcb *  pInPcb,
  1062.     struct mbuf * m
  1063.     )
  1064. {
  1065. register int error = 0;
  1066. u_char loop;
  1067. struct in_addr addr;
  1068. register struct ip_mreq *mreq;
  1069. register struct ifnet *ifp;
  1070.         register struct ip_moptions ** imop = &pInPcb->inp_moptions;
  1071. register struct ip_moptions *imo = *imop;
  1072. struct route ro;
  1073. register struct sockaddr_in *dst;
  1074.         struct in_multi *  pInMulti;
  1075.         M_BLK_ID  pInmMblk = NULL;
  1076.         M_BLK ** ppMblk;
  1077. if (imo == NULL) {
  1078. /*
  1079.  * No multicast option buffer attached to the pcb;
  1080.  * allocate one and initialize to default values.
  1081.  */
  1082. MALLOC(imo,struct ip_moptions *, sizeof (*imo),
  1083.        MT_IPMOPTS, M_WAIT);
  1084. if (imo == NULL)
  1085. return (ENOBUFS);
  1086. *imop = imo;
  1087. imo->imo_multicast_ifp = NULL;
  1088. imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
  1089. imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
  1090. imo->imo_num_memberships = 0;
  1091.                 imo->pInmMblk = NULL; 
  1092. }
  1093. switch (optname) {
  1094. case IP_MULTICAST_IF:
  1095. /*
  1096.  * Select the interface for outgoing multicast packets.
  1097.  */
  1098. if (m == NULL || m->m_len != sizeof(struct in_addr)) {
  1099. error = EINVAL;
  1100. break;
  1101. }
  1102. addr = *(mtod(m, struct in_addr *));
  1103. /*
  1104.  * INADDR_ANY is used to remove a previous selection.
  1105.  * When no interface is selected, a default one is
  1106.  * chosen every time a multicast packet is sent.
  1107.  */
  1108. if (addr.s_addr == INADDR_ANY) {
  1109. imo->imo_multicast_ifp = NULL;
  1110. break;
  1111. }
  1112. /*
  1113.  * The selected interface is identified by its local
  1114.  * IP address.  Find the interface and confirm that
  1115.  * it supports multicasting.
  1116.  */
  1117. INADDR_TO_IFP(addr, ifp);
  1118. if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
  1119. error = EADDRNOTAVAIL;
  1120. break;
  1121. }
  1122. imo->imo_multicast_ifp = ifp;
  1123. break;
  1124. case IP_MULTICAST_TTL:
  1125. /*
  1126.  * Set the IP time-to-live for outgoing multicast packets.
  1127.  */
  1128. if (m == NULL || m->m_len != 1) {
  1129. error = EINVAL;
  1130. break;
  1131. }
  1132. imo->imo_multicast_ttl = *(mtod(m, u_char *));
  1133. break;
  1134. case IP_MULTICAST_LOOP:
  1135. /*
  1136.  * Set the loopback flag for outgoing multicast packets.
  1137.  * Must be zero or one.
  1138.  */
  1139. if (m == NULL || m->m_len != 1 ||
  1140.    (loop = *(mtod(m, u_char *))) > 1) {
  1141. error = EINVAL;
  1142. break;
  1143. }
  1144. imo->imo_multicast_loop = loop;
  1145. break;
  1146. case IP_ADD_MEMBERSHIP:
  1147. /*
  1148.  * Add a multicast group membership.
  1149.  * Group must be a valid IP multicast address.
  1150.  */
  1151. if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
  1152. error = EINVAL;
  1153. break;
  1154. }
  1155. mreq = mtod(m, struct ip_mreq *);
  1156. if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
  1157. error = EINVAL;
  1158. break;
  1159. }
  1160. /*
  1161.  * If no interface address was provided, use the interface of
  1162.  * the route to the given multicast address.
  1163.  */
  1164. if (mreq->imr_interface.s_addr == INADDR_ANY) {
  1165. ro.ro_rt = NULL;
  1166. dst = (struct sockaddr_in *)&ro.ro_dst;
  1167. dst->sin_len = sizeof(*dst);
  1168. dst->sin_family = AF_INET;
  1169. dst->sin_addr = mreq->imr_multiaddr;
  1170. rtalloc(&ro);
  1171. if (ro.ro_rt == NULL) {
  1172. error = EADDRNOTAVAIL;
  1173. break;
  1174. }
  1175. ifp = ro.ro_rt->rt_ifp;
  1176. rtfree(ro.ro_rt);
  1177. }
  1178. else {
  1179. INADDR_TO_IFP(mreq->imr_interface, ifp);
  1180. }
  1181. /*
  1182.  * See if we found an interface, and confirm that it
  1183.  * supports multicast.
  1184.  */
  1185. if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
  1186. error = EADDRNOTAVAIL;
  1187. break;
  1188. }
  1189.                 ppMblk = &imo->pInmMblk;
  1190.                 while (*ppMblk)
  1191.                     {
  1192.                     pInMulti = mtod (*ppMblk, struct in_multi*);
  1193.                     if ((pInMulti->inm_ifp == ifp) &&
  1194.                         (pInMulti->inm_addr.s_addr ==
  1195.                          mreq->imr_multiaddr.s_addr))
  1196.                         break; /* jump out of the while loop */
  1197.                     ppMblk = &(*ppMblk)->mBlkHdr.mNext;
  1198.                     }
  1199.                 if (*ppMblk == NULL)
  1200.                     {
  1201.                     if ((pInmMblk = in_addmulti (&mreq->imr_multiaddr,
  1202.                                                  ifp, pInPcb)) == NULL)
  1203.                         {
  1204. error = ENOBUFS;
  1205.                         break;
  1206.                         }
  1207.                     *ppMblk = pInmMblk; /* add to the list */
  1208.                     ++imo->imo_num_memberships;
  1209.                     }
  1210.                 else
  1211.                     error = EADDRINUSE;
  1212.                 break;
  1213. case IP_DROP_MEMBERSHIP:
  1214. /*
  1215.  * Drop a multicast group membership.
  1216.  * Group must be a valid IP multicast address.
  1217.  */
  1218. if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
  1219. error = EINVAL;
  1220. break;
  1221. }
  1222. mreq = mtod(m, struct ip_mreq *);
  1223. if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
  1224. error = EINVAL;
  1225. break;
  1226. }
  1227. /*
  1228.  * If an interface address was specified, get a pointer
  1229.  * to its ifnet structure.
  1230.  */
  1231. if (mreq->imr_interface.s_addr == INADDR_ANY)
  1232. ifp = NULL;
  1233. else {
  1234. INADDR_TO_IFP(mreq->imr_interface, ifp);
  1235. if (ifp == NULL) {
  1236. error = EADDRNOTAVAIL;
  1237. break;
  1238. }
  1239. }
  1240.                 {
  1241.                 ppMblk = &imo->pInmMblk;
  1242.                 while (*ppMblk)
  1243.                     {
  1244.                     pInMulti = mtod (*ppMblk, struct in_multi*);
  1245.                     if ((ifp == NULL || pInMulti->inm_ifp == ifp) &&
  1246.                         (pInMulti->inm_addr.s_addr ==
  1247.                          mreq->imr_multiaddr.s_addr))
  1248.                         {
  1249.                         pInmMblk = *ppMblk;
  1250.                         /* delete from the list */
  1251.                         *ppMblk = (*ppMblk)->mBlkHdr.mNext; 
  1252.                         break; /* jump out of the while loop */
  1253.                         }
  1254.                     ppMblk = &(*ppMblk)->mBlkHdr.mNext;
  1255.                     }
  1256.                 if (pInmMblk == NULL)
  1257.                     {
  1258.                     error = EADDRNOTAVAIL;
  1259.                     break;
  1260.                     }
  1261.                 
  1262. /*
  1263.  * Give up the multicast address record to which the
  1264.  * membership points.
  1265.  */
  1266. in_delmulti (pInmMblk, pInPcb);
  1267. --imo->imo_num_memberships;
  1268.                 
  1269. break;
  1270.                 }
  1271. default:
  1272. error = EOPNOTSUPP;
  1273. break;
  1274. }
  1275. /*
  1276.  * If all options have default values, no need to keep the mbuf.
  1277.  */
  1278. if (imo->imo_multicast_ifp == NULL &&
  1279.     imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
  1280.     imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
  1281.     imo->imo_num_memberships == 0) {
  1282.  FREE(*imop, MT_IPMOPTS);
  1283. *imop = NULL;
  1284. }
  1285. return (error);
  1286. }
  1287. /*
  1288.  * Return the IP multicast options in response to user getsockopt().
  1289.  */
  1290. int
  1291. ip_getmoptions(optname, imo, mp)
  1292. int optname;
  1293. register struct ip_moptions *imo;
  1294. register struct mbuf **mp;
  1295. {
  1296. u_char *ttl;
  1297. u_char *loop;
  1298. struct in_addr *addr;
  1299. struct in_ifaddr *ia;
  1300. *mp = mBufClGet(M_WAIT, MT_SOOPTS, CL_SIZE_128, TRUE);
  1301. if (*mp == NULL)
  1302.     return (ENOBUFS);
  1303.     
  1304. switch (optname) {
  1305. case IP_MULTICAST_IF:
  1306. addr = mtod(*mp, struct in_addr *);
  1307. (*mp)->m_len = sizeof(struct in_addr);
  1308. if (imo == NULL || imo->imo_multicast_ifp == NULL)
  1309. addr->s_addr = INADDR_ANY;
  1310. else {
  1311. IFP_TO_IA(imo->imo_multicast_ifp, ia);
  1312. addr->s_addr = (ia == NULL) ? INADDR_ANY
  1313. : IA_SIN(ia)->sin_addr.s_addr;
  1314. }
  1315. return (0);
  1316. case IP_MULTICAST_TTL:
  1317. ttl = mtod(*mp, u_char *);
  1318. (*mp)->m_len = 1;
  1319. *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL
  1320.      : imo->imo_multicast_ttl;
  1321. return (0);
  1322. case IP_MULTICAST_LOOP:
  1323. loop = mtod(*mp, u_char *);
  1324. (*mp)->m_len = 1;
  1325. *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP
  1326.       : imo->imo_multicast_loop;
  1327. return (0);
  1328. default:
  1329. return (EOPNOTSUPP);
  1330. }
  1331. }
  1332. /*
  1333.  * Discard the IP multicast options.
  1334.  */
  1335. void
  1336. ip_freemoptions(imo, pInPcb)
  1337. register struct ip_moptions *imo;
  1338. struct inpcb *  pInPcb;
  1339.         
  1340. {
  1341.         M_BLK_ID pInmMblk;
  1342.         M_BLK_ID pInmMblkNext;
  1343. if (imo != NULL) {
  1344.                 pInmMblk = imo->pInmMblk;
  1345.                 pInmMblkNext = imo->pInmMblk;
  1346.          while ((pInmMblk = pInmMblkNext) != NULL)
  1347.                     {
  1348.                     pInmMblkNext = pInmMblk->mBlkHdr.mNext; 
  1349.                     in_delmulti (pInmMblk, pInPcb);
  1350.                     }
  1351. FREE(imo, MT_IPMOPTS);
  1352. }
  1353. }
  1354. /*
  1355.  * Routine called from ip_output() to loop back a copy of an IP multicast
  1356.  * packet to the input queue of a specified interface.  Note that this
  1357.  * calls the output routine of the loopback "driver", but with an interface
  1358.  * pointer that might NOT be &loif -- easier than replicating that code here.
  1359.  */
  1360. void
  1361. ip_mloopback(ifp, m, dst, rt)
  1362. struct ifnet *ifp;
  1363. register struct mbuf *m;
  1364. register struct sockaddr_in *dst;
  1365. struct rtentry *rt;
  1366. {
  1367. register struct ip *ip;
  1368. struct mbuf *copym;
  1369.         struct mbuf * pMbuf;
  1370. #ifdef WV_INSTRUMENTATION
  1371. #ifdef INCLUDE_WVNET    /* WV_NET_INFO event */
  1372.     WV_NET_EVENT_0 (NET_AUX_EVENT, WV_NET_INFO, 12, 7,
  1373.                     WV_NETEVENT_IPMLOOP_START, WV_NET_RECV)
  1374. #endif  /* INCLUDE_WVNET */
  1375. #endif
  1376. copym = m_copy(m, 0, M_COPYALL);
  1377. if (copym != NULL) {
  1378. /*
  1379.  * We don't bother to fragment if the IP length is greater
  1380.  * than the interface's MTU.  Can this possibly matter?
  1381.  */
  1382. ip = mtod(copym, struct ip *);
  1383.                 /*
  1384.                  * This copying of ip header is done because the same
  1385.                  * ip header is shared by looutput and the code under the
  1386.                  * the label sendit: in ip_output. so a fresh mbuf has to be
  1387.                  * linked to the data.
  1388.                  */
  1389.                 if ((pMbuf = mBufClGet (M_DONTWAIT, MT_DATA, sizeof(struct ip),
  1390.                                    TRUE)) == NULL)
  1391.                     {
  1392.                     m_freem (copym); 
  1393.                     return;
  1394.                     }
  1395.                 /* copy the ip header */
  1396.                 bcopy ((char *)ip , (char *)(mtod(pMbuf, char *)),
  1397.                        sizeof(struct ip));
  1398.                 pMbuf->m_len   = sizeof (struct ip); 
  1399.                 pMbuf->m_flags = copym->m_flags; /* copy the flags */
  1400.                 pMbuf->m_pkthdr = copym->m_pkthdr; /* copy the pkt hdr */
  1401.                 pMbuf->m_next = copym;
  1402.                 
  1403.                 copym->m_flags &= ~M_PKTHDR;
  1404.                 copym->m_len -= sizeof(struct ip);
  1405.                 copym->m_data += sizeof(struct ip);
  1406. ip = mtod(pMbuf, struct ip *);
  1407.                 copym = pMbuf; 
  1408. ip->ip_len = htons((u_short)ip->ip_len);
  1409. ip->ip_off = htons((u_short)ip->ip_off);
  1410.                 ip->ip_sum = 0;
  1411.                 if (_ipCfgFlags & IP_DO_CHECKSUM_SND)
  1412.                     ip->ip_sum = in_cksum(copym, ip->ip_hl << 2);
  1413. (void) looutput(ifp, copym, (struct sockaddr *)dst, rt);
  1414. }
  1415. }