Esempio n. 1
0
int
ip6_pcbbind( struct inpcb *inp, struct mbuf *nam)
{
   struct socket *so =  inp->inp_socket;
   struct inpcb  *head  =  inp->inp_head;
   struct sockaddr_in6 *sin;
   u_short  lport = 0;

   /* require that we not be bound already */
   if ((inp->inp_lport) || (!IN6_IS_ADDR_UNSPECIFIED(&inp->ip6_laddr)))
   {
      return (0);
   }

   if (nam)
   {
      sin = mtod(nam, struct sockaddr_in6 *);
      if (IP6EQ(&sin->sin6_addr, &in6addr_any) == FALSE)  /* not a wildcard? */
      {
         /* make sure caller gave us a valid local address */
         if (ip6_lookup(&sin->sin6_addr, NULL) == NULL)
            return (EADDRNOTAVAIL);
      }
      lport = sin->sin6_port;
      if (lport != 0) 
      {
         int wild = 0;

         if ((so->so_options & SO_REUSEADDR) == 0 &&
             ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
             (so->so_options & SO_ACCEPTCONN) == 0))
         {
            wild = INPLOOKUP_WILDCARD;
         }
         if (ip6_pcblookup(head, NULL, 0, &sin->sin6_addr, lport, wild))
         {
            return (EADDRINUSE);
         }
      }
      IP6CPY(&inp->ip6_laddr, &sin->sin6_addr);
   }

   /* if local port is unspecified, then find an unused value for it. */
   if (lport == 0)
   {
      do 
      {
         if ((head->inp_lport++ < IPPORT_RESERVED) ||
            (head->inp_lport > IPPORT_USERRESERVED))
         {
            head->inp_lport = IPPORT_RESERVED;
         }
         lport = htons(head->inp_lport);
      } while (ip6_pcblookup(head, NULL, 0, &inp->ip6_laddr, lport, 0));
   }
   inp->inp_lport = lport;

   return (0);
}
Esempio n. 2
0
File: packets6.c Progetto: GNS3/vpcs
int findmtu6(pcs *pc, ip6 *src)
{
	int i;
	
	for (i = 0; i < POOL_SIZE; i++) {
		if (time_tick - pc->ip6mtu[i].timeout > POOL_TIMEOUT)
			continue;
		if (IP6EQ(src, &pc->ip6mtu[i].ip))
			return pc->ip6mtu[i].mtu;
	}
	return pc->mtu;
}
Esempio n. 3
0
struct in_multi *
v6_lookup_mcast(ip6_addr * ipp, NET netp)
{
   struct in_multi * imp;

   for (imp = netp->mc_list; imp; imp = imp->inm_next)
   {
      if(IP6EQ(&imp->ip6addr, ipp))
         return imp;
   }
   return NULL;   /* addr not found in mcast list */

}
Esempio n. 4
0
File: packets6.c Progetto: GNS3/vpcs
void save_mtu6(pcs *pc, struct packet *m)
{
	icmp6hdr *icmp;
	ip6hdr *ip = NULL, *ip0 = NULL;
	int i, n;

	ip = (ip6hdr *)(m->data + sizeof(ethdr));
	if ((ip->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)
		return;

	n = ip6ehdr(ip, m->len - sizeof(ethdr), IPPROTO_ICMPV6);
	if (n == 0)
		return;

	icmp = (icmp6hdr *)((char *)ip + n);
	if (icmp->type != ICMP6_PACKET_TOO_BIG)
		return;

	ip0 = (ip6hdr *)(m->data + sizeof(ethdr) + 
	    sizeof(ip6hdr) + sizeof(icmp6hdr));
	
	for (i = 0, n = -1; i < POOL_SIZE; i++) {
		if (IP6EQ(&ip0->dst, &pc->ip6mtu[i].ip)) {
			pc->ip6mtu[i].mtu = ntohl(icmp->icmp6_mtu);
			pc->ip6mtu[i].timeout = time_tick;
			return;
		}
		if ((n < 0) && 
		    (time_tick - pc->ip6mtu[i].timeout > POOL_TIMEOUT))
			n = i;
	}

	if (n >= 0) {
		pc->ip6mtu[n].mtu = ntohl(icmp->icmp6_mtu);
		pc->ip6mtu[n].timeout = time_tick;
		memcpy(pc->ip6mtu[n].ip.addr8, ip0->dst.addr8, 16);
	}
}
Esempio n. 5
0
int
tcp_output(struct tcpcb * tp)
{
   struct socket *   so =  tp->t_inpcb->inp_socket;
   int   len;
   long  win;
   int   off,  flags,   error;
   struct mbuf *  m;
   struct tcpiphdr * ti;
   unsigned optlen = 0;
   int   idle, sendalot;
   struct mbuf *  sendm;   /* mbuf which contains data to send */
   struct mbuf * tcp_mbuf; /* mbuf containing TCP header */
   int   bufoff;           /* offset of data in sendm->m_data */

#ifdef TCP_SACK
   int   sack_resend;
   int   sack_hole = 0;    /* next sack hole to fill */

   if(tp->t_flags & TF_SACKREPLY)
   {
      /* we are resending based on a received SACK header */
      sack_resend = TRUE;
      tp->t_flags &= ~TF_SACKREPLY;    /* clear flag */
   }
   else
      sack_resend = FALSE;
#endif /* TCP_SACK */
   
   /*
    * Determine length of data that should be transmitted,
    * and flags that will be used.
    * If there is some data or critical controls (SYN, RST)
    * to send, then transmit; otherwise, investigate further.
    */
   idle = (tp->snd_max == tp->snd_una);

again:
   sendalot = 0;
   off = (int)(tp->snd_nxt - tp->snd_una);
   win = (long)tp->snd_wnd;   /* set basic send window */
   if (win > (long)tp->snd_cwnd) /* see if we need congestion control */
   {
      win = (int)(tp->snd_cwnd & ~(ALIGN_TYPE-1)); /* keep data aligned */
   }

   /*
    * If in persist timeout with window of 0, send 1 byte.
    * Otherwise, if window is small but nonzero
    * and timer expired, we will send what we can
    * and go to transmit state.
    */
   if (tp->t_force) 
   {
      if (win == 0)
         win = 1;
      else 
      {
         tp->t_timer[TCPT_PERSIST] = 0;
         tp->t_rxtshift = 0;
      }
   }

#ifdef TCP_SACK
   /* See if we need to adjust the offset for a sack resend */
   if(sack_resend)
   {
      off = (int)(tp->sack_hole_start[sack_hole] - tp->snd_una);
      /* if this hole's already been acked then punt and move to next hole */
      if(off < 0)
      {
         /* clear out the acked hole */
         tp->sack_hole_start[sack_hole] = tp->sack_hole_end[sack_hole] = 0;
         /* see if we're done with SACK hole list (2 tests) */
         if(++sack_hole >= SACK_BLOCKS)
            return 0;
         if(tp->sack_hole_start[sack_hole] == tp->sack_hole_end[sack_hole])
            return 0;
         goto again;
      }
      tp->snd_nxt = tp->sack_hole_start[sack_hole];
      len = (int)(tp->sack_hole_end[sack_hole] - tp->sack_hole_start[sack_hole]);
      len = (int)MIN(len, (int)win);
   }
   else
#endif /* TCP_SACK */
   {
      /* set length of packets which are not sack resends */
      len = (int)MIN(so->so_snd.sb_cc, (unsigned)win) - off;
   }

   flags = tcp_outflags[tp->t_state];


   /* See if we need to build TCP options field. This test should be fast. */

#if (defined(TCP_TIMESTAMP) | defined(TCP_SACK))	   
   if((flags & TH_SYN) ||
/*   !!!???   (so->so_options & SO_TIMESTAMP) ||  */
	  (tp->t_flags & TF_SACKNOW)
	 )
   {
      optlen = bld_options(tp, &tcp_optionbuf[optlen], flags, so);
   }
#else
   /* If other options not defined this build then don't bother to call bld_options() except 
    * on SYN packets
    */
   if(flags & TH_SYN)
   {
      optlen = bld_options(tp, &tcp_optionbuf[optlen], flags, so);
   }
#endif

   if (len < 0)
   {
      /*
       * If FIN has been sent but not acked,
       * but we haven't been called to retransmit,
       * len will be -1.  Otherwise, window shrank
       * after we sent into it.  If window shrank to 0,
       * cancel pending retransmit and pull snd_nxt
       * back to (closed) window.  We will enter persist
       * state below.  If the window didn't close completely,
       * just wait for an ACK.
       */
      len = 0;
      if (win == 0) 
      {
         tp->t_timer[TCPT_REXMT] = 0;
         tp->snd_nxt = tp->snd_una;
      }
   }

   if (len > (int)tp->t_maxseg)
   {
      len = tp->t_maxseg;
      sendalot = 1;
   }

#ifdef IP_V4
#ifdef IP_PMTU
   {
      int pmtu = tp->t_inpcb->inp_pmtu - 40;

      if (len > pmtu)
      {
         len = pmtu - 40;
         sendalot = 1;
      }
   }
#endif /* IP_PMTU */
   /* We don't need a pmtu test for IPv6. V6 code limits t_maxseg to
    * the Path MTU, so the test above the v4 ifdef above covers us.
    */
#endif /* IP_V4 */

   if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
      flags &= ~TH_FIN;
   win = (long)(sbspace(&so->so_rcv));

   /*
    * If our state indicates that FIN should be sent
    * and we have not yet done so, or we're retransmitting the FIN,
    * then we need to send.
    */
   if ((flags & TH_FIN) &&
       (so->so_snd.sb_cc == 0) &&
       ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una))
   {
      goto send;
   }
   /*
    * Send if we owe peer an ACK.
    */
   if (tp->t_flags & TF_ACKNOW)
      goto send;
   if (flags & (TH_SYN|TH_RST))
      goto send;
   if (SEQ_GT(tp->snd_up, tp->snd_una))
      goto send;

   /*
    * Sender silly window avoidance.  If connection is idle
    * and can send all data, a maximum segment,
    * at least a maximum default-size segment do it,
    * or are forced, do it; otherwise don't bother.
    * If peer's buffer is tiny, then send
    * when window is at least half open.
    * If retransmitting (possibly after persist timer forced us
    * to send into a small window), then must resend.
    */
   if (len)
   {
      if (len == (int)tp->t_maxseg)
         goto send;
      if ((idle || tp->t_flags & TF_NODELAY) &&
          len + off >= (int)so->so_snd.sb_cc)
      {
         goto send;
      }
      if (tp->t_force)
         goto send;
      if (len >= (int)(tp->max_sndwnd / 2))
         goto send;
      if (SEQ_LT(tp->snd_nxt, tp->snd_max))
         goto send;
   }

   /*
    * Compare available window to amount of window
    * known to peer (as advertised window less
    * next expected input).  If the difference is at least two
    * max size segments or at least 35% of the maximum possible
    * window, then want to send a window update to peer.
    */
   if (win > 0)
   {
      int   adv   =  (int)win -  (int)(tp->rcv_adv -  tp->rcv_nxt);

      if (so->so_rcv.sb_cc == 0 && adv >= (int)(tp->t_maxseg * 2))
         goto send;
      if (100 * (u_int)adv / so->so_rcv.sb_hiwat >= 35)
         goto send;
   }

   /*
    * TCP window updates are not reliable, rather a polling protocol
    * using ``persist'' packets is used to insure receipt of window
    * updates.  The three ``states'' for the output side are:
    *   idle         not doing retransmits or persists
    *   persisting      to move a small or zero window
    *   (re)transmitting   and thereby not persisting
    *
    * tp->t_timer[TCPT_PERSIST]
    *   is set when we are in persist state.
    * tp->t_force
    *   is set when we are called to send a persist packet.
    * tp->t_timer[TCPT_REXMT]
    *   is set when we are retransmitting
    * The output side is idle when both timers are zero.
    *
    * If send window is too small, there is data to transmit, and no
    * retransmit or persist is pending, then go to persist state.
    * If nothing happens soon, send when timer expires:
    * if window is nonzero, transmit what we can,
    * otherwise force out a byte.
    */
   if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 &&
       tp->t_timer[TCPT_PERSIST] == 0) 
   {
      tp->t_rxtshift = 0;
      tcp_setpersist(tp);
   }

   /*
    * No reason to send a segment, just return.
    */
   return (0);

send:
   ENTER_CRIT_SECTION(tp);

   /* Limit send length to the current buffer so as to
    * avoid doing the "mbuf shuffle" in m_copy().
    */
   bufoff = off;
   sendm = so->so_snd.sb_mb;
   if (len)
   {
      /* find mbuf containing data to send (at "off") */
      while (sendm)  /* loop through socket send list */
      {
         bufoff -= sendm->m_len;
         if (bufoff < 0)   /* if off is in this buffer, break */
            break;
         sendm = sendm->m_next;
      }
      if (!sendm) { dtrap();  /* shouldn't happen */ }
      bufoff += sendm->m_len; /* index to next data to send in msend */

      /* if socket has multiple unsent mbufs, set flag for send to loop */
      if ((sendm->m_next) && (len > (int)sendm->m_len))
      {
         flags &= ~TH_FIN; /* don't FIN on segment prior to last */
         sendalot = 1;     /* set to send more segments */
      }
      if((flags & TH_FIN) && (so->so_snd.sb_cc > (unsigned)len))
      {
         /* This can happen on slow links (PPP) which retry the last 
          * segment - the one with the FIN bit attached to data.
          */
         flags &= ~TH_FIN; /* don't FIN on segment prior to last */
      }

      /* only send the rest of msend */
      len = min(len, (int)sendm->m_len);

      /* if we're not sending starting at sendm->m_data (in which 
       * case bufoff != 0), then we will copy the data; else we would 
       * write IP/TCP headers over sent but un-ack'ed data in sendm. 
       * Similarly, if sendm->m_data is not aligned with respect to 
       * sendm->m_base and ALIGN_TYPE, we will copy the data to 
       * ensure that it (and the then-prepended IP/TCP headers) will 
       * be aligned according to ALIGN_TYPE. 
       */
      if ((bufoff != 0) ||       /* data not front aligned in send mbuf? */
          (((sendm->m_data - sendm->m_base) & (ALIGN_TYPE - 1)) != 0))
      {
         len = min(len, (int)(sendm->m_len - bufoff));   /* limit len again */

         /* One more test - if this data is not aligned with the front
          * of the m_data buffer then we can't use it in place, else we
          * might write the IP/TCP header over data that has not yet
          * been acked. In this case we must make sure our send
          * fits into a little buffer and send what we can.
          */
         if ((len > (int)(lilbufsiz - HDRSLEN)) && /* length is bigger the small buffer? */
             (bigfreeq.q_len < 2))      /* and we are low on big buffers */
         {
            len = lilbufsiz - HDRSLEN;
         }
      }
   }

   /* if send data is sufficiently aligned in packet, prepend TCP/IP header
    * in the space provided. 
    */
   if (len && (bufoff == 0) && 
       (sendm->pkt->inuse == 1) &&
       (((sendm->m_data - sendm->m_base) & (ALIGN_TYPE - 1)) == 0) && 
       (optlen == 0))
   {
      /* get an empty mbuf to "clone" the data */
      m = m_getnbuf(MT_TXDATA, 0);
      if (!m)
      {
         EXIT_CRIT_SECTION(tp);
         return (ENOBUFS);
      }
      m->pkt = sendm->pkt; /* copy packet location in new mbuf */
      m->pkt->inuse++;     /* bump packet's use count */
      m->m_base = sendm->m_base; /* clone mbuf members */
      m->m_memsz = sendm->m_memsz;
      m->m_len = len + TCPIPHDRSZ;  /* adjust clone for header */
      m->m_data = sendm->m_data - TCPIPHDRSZ;
   }
   else  /* either no data or data is not front aligned in mbuf */
   {
      /* Grab a header mbuf, attaching a copy of data to be 
       * transmitted, and initialize the header from 
       * the template for sends on this connection.
       */
      m = m_getwithdata (MT_HEADER, IFNETHDR_SIZE + TCPIPHDRSZ);
      if (m ==(struct mbuf *)NULL)
      {
         EXIT_CRIT_SECTION(tp);
         return ENOBUFS;
      }

      m->m_len = TCPIPHDRSZ;
      m->m_data += IFNETHDR_SIZE;/* Move this to sizeof tcpip hdr leave*/
      /* 14 bytes for ethernet header      */

      if (len) /* attach any data to send */
      {
         m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len);
         if (m->m_next == 0)
         {
            m_freem(m);
            EXIT_CRIT_SECTION(tp);
            return ENOBUFS;
         }
      }
   }
   EXIT_CRIT_SECTION(tp);

   if (len) 
   {
      if (tp->t_force && len == 1)
         tcpstat.tcps_sndprobe++;
      else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) 
      {
         tcpstat.tcps_sndrexmitpack++;
         tcpstat.tcps_sndrexmitbyte += len;
#ifdef TCP_SACK
      if(sack_resend)
         tcpstat.tcps_sackresend++;
#endif
      } 
      else 
      {
         tcpstat.tcps_sndpack++;
         tcpstat.tcps_sndbyte += len;
      }
   }
   else if (tp->t_flags & TF_ACKNOW)
   {
      tcpstat.tcps_sndacks++;
   }
   else if (flags & (TH_SYN|TH_FIN|TH_RST))
      tcpstat.tcps_sndctrl++;
   else if (SEQ_GT(tp->snd_up, tp->snd_una))
      tcpstat.tcps_sndurg++;
   else
      tcpstat.tcps_sndwinup++;

   ti = (struct tcpiphdr *)(m->m_data+sizeof(struct ip)-sizeof(struct ipovly));
   if ((char *)ti < m->pkt->nb_buff)
   {
      panic("tcp_out- packet ptr underflow\n");
   }
   tcp_mbuf = m;        /* flag TCP header mbuf */

#ifdef IP_V6  /* Dual mode code */
   if(so->so_domain == AF_INET6)
   {
      m = mbuf_prepend(m, sizeof(struct ipv6));
      if(m == NULL)
      {
         /* this can happen when we run out of mbufs or pkt buffers
          * That is, mfreeq is empty or (lilfreeq, bigfreeq) are empty.
          * One solution is to find out which one is getting full and
          * then increase them.
          */
         dtrap();             /* This is really rare... */
         m_freem(tcp_mbuf);   /* Free TCP/data chain */
         return ENOBUFS;
      }

      /* strip overlay from front of TCP header */
      tcp_mbuf->m_data += sizeof(struct ipovly);
      tcp_mbuf->m_len -= sizeof(struct ipovly);
   }
#endif   /* end IP_V6 */

   if (tp->t_template == 0)
      panic("tcp_output");

   MEMCPY((char*)ti, (char*)tp->t_template, sizeof(struct tcpiphdr));

   /*
    * Fill in fields, remembering maximum advertised
    * window for use in delaying messages about window sizes.
    * If resending a FIN, be sure not to use a new sequence number.
    */
   if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && 
       tp->snd_nxt == tp->snd_max)
   {
      tp->snd_nxt--;
   }

   ti->ti_seq = htonl(tp->snd_nxt);
   ti->ti_ack = htonl(tp->rcv_nxt);

   /*
    * If we're sending a SYN, check the IP address of the interface
    * that we will (likely) use to send the IP datagram -- if it's
    * changed from what is in the template (as it might if this is
    * a retransmission, and the original SYN caused PPP to start
    * bringing the interface up, and PPP has got a new IP address
    * via IPCP), update the template and the inpcb with the new 
    * address.
    */
   if (flags & TH_SYN)
   {
      struct inpcb * inp;
      inp = (struct inpcb *)so->so_pcb;

      switch(so->so_domain)
      {
#ifdef IP_V4
      case AF_INET:
      {
         ip_addr src;

#ifdef INCLUDE_PPP

         if(((flags & TH_ACK) == 0) && /* SYN only, not SYN/ACK */
            (inp->ifp) &&              /* Make sure we have iface */
            (inp->ifp->mib.ifType == PPP))   /* only PPP type */
         {
            dtrap(); /* remove after confirmed to work in PPP */ 
            src = ip_mymach(ti->ti_dst.s_addr);

         if (src != ti->ti_src.s_addr)
         {
            ti->ti_src.s_addr = src;
            tp->t_template->ti_src.s_addr = src;
            tp->t_inpcb->inp_laddr.s_addr = src;
         }
         }
#endif   /* INCLUDE_PPP */

         /* If this is a SYN (not a SYN/ACK) then set the pmtu */
         if((flags & TH_ACK) == 0)
         {
#ifdef IP_PMTU
            inp->inp_pmtu = pmtucache_get(inp->inp_faddr.s_addr);
#else    /* not compiled for pathmtu, guess based on iface */
            {
               NET ifp;
               /* find iface for route. Pass "src" as nexthop return */
               ifp = iproute(ti->ti_dst.s_addr, &src);
               if(ifp)
                  inp->inp_pmtu = ifp->n_mtu - (ifp->n_lnh + 40);
               else
                  inp->inp_pmtu = 580;  /* Ugh. */
            }
#endif   /* IP_PMTU */
         }
         break;
      }
#endif   /* IP_V4 */

#ifdef IP_V6
      case AF_INET6:
      {
         struct ip6_inaddr * local;
         
         local = ip6_myaddr(&tp->t_inpcb->ip6_faddr, inp->ifp);

         /* If we got a local address & it's not the one in the pcb, then
          * we assume it changed at the iface and fix it in the pcb. Unlike 
          * v4, we don't have an IP header yet, not do we have a template 
          * to worry about.
          */
         if((local) && 
            (!IP6EQ(&local->addr, &tp->t_inpcb->ip6_laddr)))
         {
            IP6CPY(&tp->t_inpcb->ip6_laddr, &local->addr);
         }
         /* If this is a SYN (not a SYN/ACK) then set the pmtu */
         if((flags & TH_ACK) == 0)
         {
            inp->inp_pmtu = ip6_pmtulookup(&inp->ip6_laddr, inp->ifp);
         }
         break;
      }
#endif   /* IP_V6 */
      default:
         dtrap();    /* bad domain setting */
      }
   }

   /* fill in options if any are set */
   if (optlen)
   {
      struct mbuf * mopt;

      mopt = m_getwithdata(MT_TXDATA, MAXOPTLEN);
      if (mopt == NULL) 
      {
         m_freem(m);
         return (ENOBUFS);
      }

      /* insert options mbuf after after tmp_mbuf */
      mopt->m_next = tcp_mbuf->m_next;
      tcp_mbuf->m_next = mopt;

      /* extend options to aligned address */
      while(optlen & 0x03)
         tcp_optionbuf[optlen++] = TCPOPT_EOL;

      MEMCPY(mtod(mopt, char *), tcp_optionbuf, optlen);
      mopt->m_len = optlen;
      /* use portable macro to set tcp data offset bits */
      SET_TH_OFF(ti->ti_t, ((sizeof (struct tcphdr) + optlen) >> 2));
   }

   ti->ti_flags = (u_char)flags;
   /*
    * Calculate receive window. Don't shrink window,
    * but avoid silly window syndrome.
    */
   if (win < (long)(so->so_rcv.sb_hiwat / 4) && win < (long)tp->t_maxseg)
      win = 0;
   if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
      win = (long)(tp->rcv_adv - tp->rcv_nxt);

   /* do check for Iniche buffer limits -JB- */
   if (bigfreeq.q_len == 0)   /* If queue length is 0, set window to 0 */
   {
      win = 0;
   }
   else if(win > (((long)bigfreeq.q_len - 1) * (long)bigbufsiz))
   {
      win = ((long)bigfreeq.q_len - 1) * bigbufsiz;
   }

#ifdef TCP_WIN_SCALE
   if(tp->t_flags & TF_WINSCALE)
   {
      ti->ti_win = htons((u_short)(win >> tp->rcv_wind_scale)); /* apply scale */
   }
Esempio n. 6
0
File: packets6.c Progetto: GNS3/vpcs
int save_nb_adv(pcs *pc, struct packet *m)
{
	ethdr *eh;
	ip6hdr *ip;
	ndhdr *nshdr;
	ndopt *nsopt;
	int i;

	eh = (ethdr *)(m->data);
	
	if (eh->type != htons(ETHERTYPE_IPV6))
		return -1;

	if (memcmp(eh->dst, pc->ip4.mac, ETH_ALEN))
		return -1;

	ip = (ip6hdr *)(eh + 1);

	if ((!IP6EQ(&(pc->ip6.ip), &(ip->dst)) && 
	    !IP6EQ(&(pc->link6.ip), &(ip->dst))) || IP6EQ(&ip->dst, &ip->src))
		return -1;

	nshdr = (ndhdr *)(ip + 1);
	nsopt = (ndopt *)(nshdr + 1);
	
	if (nshdr->hdr.type != ND_NEIGHBOR_ADVERT)
		return -1;

	/* shoule check sum field
	 * ...
	 */

	/* not Target Link-Layer Address */
	if (nsopt->type != 2)
		return -1;

	i = 0;
	while (i < POOL_SIZE) {
		if (IP6EQ(&pc->ipmac6[i].ip, &ip->src) &&
		    (time_tick - pc->ipmac6[i].timeout <= 120))
			break;

		if (pc->ipmac6[i].timeout == 0 || 
		    (time_tick - pc->ipmac6[i].timeout > 120)) {
			memcpy(pc->ipmac6[i].mac, nsopt->mac, ETH_ALEN);
			memcpy(pc->ipmac6[i].ip.addr8, ip->src.addr8, 
			    sizeof(ip->src.addr8));
			
			pc->ipmac6[i].timeout = time_tick;
			pc->ipmac6[i].cidr = 128;
			break;
		}
		i++;
	}

	if (i == POOL_SIZE) {
		i = 0;
		memcpy(pc->ipmac6[i].mac, nsopt->mac, ETH_ALEN);
		memcpy(pc->ipmac6[i].ip.addr8, ip->src.addr8, 16);
		pc->ipmac6[i].timeout = time_tick;
	}

	return i;
}
Esempio n. 7
0
File: packets6.c Progetto: GNS3/vpcs
int response6(struct packet *m, sesscb *sesscb)
{
	ethdr *eh;
	ip6hdr *ip;

	eh = (ethdr *)(m->data);
	ip = (ip6hdr *)(eh + 1);
	
	if (ip->ip6_nxt == IPPROTO_ICMPV6) {
		icmp6hdr *icmp = (icmp6hdr *)(ip + 1);
		if (icmp->type == ICMP6_DST_UNREACH || 
		    icmp->type == ICMP6_TIME_EXCEEDED || 
		    icmp->type == ICMP6_DST_UNREACH_NOPORT ||
		    icmp->type == ICMP6_PACKET_TOO_BIG) {
			
			if (icmp->type == ICMP6_PACKET_TOO_BIG)
				sesscb->mtu = ntohl(icmp->icmp6_mtu);
			sesscb->icmptype = icmp->type;
			sesscb->icmpcode = icmp->code;
			sesscb->rttl = ip->ip6_hlim;
			memcpy(sesscb->rdip6.addr8, ip->src.addr8, 16);
			
			return IPPROTO_ICMPV6;
		}
	}
	
	if (!IP6EQ(&(sesscb->dip6), &(ip->src)))
		return 0;
			
	if (ip->ip6_nxt == IPPROTO_ICMPV6 && sesscb->proto == IPPROTO_ICMPV6) {
		icmp6hdr *icmp = (icmp6hdr *)(ip + 1);
		
		sesscb->icmptype = icmp->type;
		sesscb->icmpcode = icmp->code;
		
		sesscb->rttl = ip->ip6_hlim;
		memcpy(sesscb->rdip6.addr8, ip->src.addr8, 16);
		
		if (ntohs(icmp->icmp6_seq) == sesscb->sn) {
			return IPPROTO_ICMPV6;
		}

		return 0;
	} 
	
	if (ip->ip6_nxt == IPPROTO_UDP) {
		udphdr *ui = (udphdr *)(ip + 1);
		char *data = ((char*)(ui + 1));
	
		if (memcmp(data, eh->dst, 6) == 0) {
			sesscb->rttl = ip->ip6_hlim;
			return IPPROTO_UDP;
		}
		return 0;
	}
	if (ip->ip6_nxt == IPPROTO_TCP) {
		struct tcphdr *th = (struct tcphdr *)(ip + 1);
		char *data = ((char*)(th + 1));
		
		sesscb->rseq = ntohl(th->th_seq);
		sesscb->rack = ntohl(th->th_ack);
		sesscb->rflags = th->th_flags;
		sesscb->rttl = ip->ip6_hlim;
		sesscb->rdsize = ntohs(ip->ip6_plen) - sizeof(iphdr) - (th->th_off << 2);
		sesscb->data = NULL;

		/* try to get MSS from options */
		if (sesscb->flags == TH_SYN && sesscb->rdsize > 0 &&
		    sesscb->rflags == (TH_SYN | TH_ACK)) {
			int i = 0;

			while (data[i] == 0x1 && i < sesscb->rdsize) i++;
			
			for (;i < sesscb->rdsize;) {
				if (data[i] == TCPOPT_MAXSEG && 
				    data[i + 1] == TCPOLEN_MAXSEG) {
					sesscb->rmss = (data[i + 2] << 8) + data[i + 3];
					break;
				}
				i += data[i + 1];
			}
		} else {
			sesscb->data = ((char*)(ip + 1)) + (th->th_off << 2);
		}
		
		return IPPROTO_TCP;
	}
	
	return 0;
}
Esempio n. 8
0
struct inpcb *
ip6_pcblookup(struct inpcb *head,
              ip6_addr *faddr,
              unshort xfport,
              ip6_addr *laddr,
              unshort xlport,
              int   flags)
{
   struct inpcb *inp;
   struct inpcb *match = NULL;
   unshort  fport =  xfport; 
   unshort  lport =  xlport;
   int   matchwild   =  3;
   int   wildcard;

   for (inp = head->inp_next; inp != head; inp = inp->inp_next) 
   {
      if (inp->inp_lport != lport)
         continue;

      /* Skip non IPv6 sockets */
      if (inp->inp_socket->so_domain != AF_INET6)
         continue;

      /* optimize this to catch exact matches ASAP */
      if ((inp->inp_fport == fport) &&
         (IP6EQ(&inp->ip6_laddr, laddr)) &&
         (IP6EQ(&inp->ip6_faddr, faddr)))
      {
         match = inp;
         goto ipl6_cacheit;
      }

      wildcard = 0;
      if (IP6EQ(&inp->ip6_laddr, &in6addr_any) == FALSE)
      {
         if (IP6EQ(laddr, &in6addr_any))
            wildcard++;
          else if (IP6EQ(&inp->ip6_laddr, laddr) == FALSE)
            continue;
      }
      else 
      {
         if (IP6EQ(laddr, &in6addr_any) == FALSE)
            wildcard++;
      }
      if (IP6EQ(&inp->ip6_faddr, &in6addr_any) == FALSE)
      {
         if (IP6EQ(faddr, &in6addr_any))
            wildcard++;
         else if ((IP6EQ(&inp->ip6_faddr, faddr) == FALSE) ||
                  (inp->inp_fport != fport))
         {
            continue;
         }
      }
      else 
      {
         if (IP6EQ(faddr, &in6addr_any) == FALSE)
            wildcard++;
      }
      if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
         continue;
      if (wildcard < matchwild) 
      {
         match = inp;
         matchwild = wildcard;
         if (matchwild == 0)
            break;
      }

      /* for the specific case of 
       * inp->ip6_laddr == in6addr_any &&
       * inp->ip6_faddr == in6addr_any &&
       * fport == lport
       *
       * This covers the case in multi-homed nodes,
       *   in which SYNs can come in from any of the IFs
       *   with local link addresses and only the
       *   port number to ID the accept or the
       *   waiting UDP.
       */
      if (
            (IP6EQ(&inp->ip6_laddr, &in6addr_any) == TRUE) &&
            (IP6EQ(&inp->ip6_faddr, &in6addr_any) == TRUE) &&
            (fport == lport)
         )
         return (inp);

   }
   if (match == NULL)
      return match;

ipl6_cacheit:

   if (head->inp_next == match)  /* got cache hit? */
   {
      inpcb_cachehits++;
   }
   else
   {
      inpcb_cachemiss++;
      /* "cache" the match to be first checked next time. */
      match->inp_next->inp_prev = match->inp_prev; /*unlink match */
      match->inp_prev->inp_next = match->inp_next;

      /* relink match as head->inp_next */
      match->inp_next = head->inp_next;
      head->inp_next = match;
      match->inp_prev = head;
      match->inp_next->inp_prev = match;
   }
   return (match);
}
Esempio n. 9
0
int
ip6_pcbconnect(struct inpcb *inp, struct mbuf *nam)
{
   struct sockaddr_in6 *sin;
   int  err;

   sin = mtod(nam, struct sockaddr_in6 *);

   if (sin->sin6_family != AF_INET6)
      return (EAFNOSUPPORT);

   if (sin->sin6_port == 0)
      return (EADDRNOTAVAIL);

   /* If the destination address is unspecified or multicast,
    * then blow it off.
    */
   if ((IP6EQ(&sin->sin6_addr, &in6addr_any)) || /* wildcard? */
       (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)))
   {
      return (EADDRNOTAVAIL);
   }
   if (!inp->ifp)
   {
#ifdef IP6_ROUTING
      if (inp->inp_socket && inp->inp_socket->so_optsPack) 
      {
#ifdef MULTI_HOMED
         if (inp->inp_socket->so_optsPack->ip_scopeid == 0)
         {
            gio_printf(NULL, "*** ip6_pcbconnect, no IPv6 IF.\n");
            return ENP_LOGIC;
         } 
#endif
         inp->ifp = nets[inp->inp_socket->so_optsPack->ip_scopeid - 1];
      }
      else
      {
         /* try to find an IPv6 IF */
         inp->ifp = ip6_findIF();
         if (inp->ifp == NULL)
         {
            gio_printf(NULL, "*** ip6_pcbconnect, no IPv6 IF.\n");
            return ENP_LOGIC;
         }   
      }
#else
       /* just use nd0 */
	   inp->ifp = nets[0];    
#endif  
   }
   inp->inp_flags |= INPF_ROUTESET;

   /* Make sure this is not a duplicate of an existing connection */
   if (ip6_pcblookup(inp->inp_head,
                     &sin->sin6_addr, sin->sin6_port,
                     &inp->ip6_laddr, inp->inp_lport,
                     0))
   {
      return (EADDRINUSE);
   }

   if (IP6EQ(&inp->ip6_laddr, &in6addr_any))
   {
      if ((err = ip6_pcbbind(inp, (struct mbuf *)NULL)) != 0)
      {
         dprintf("*** ip6_pcbconnect - ip6_pcbbind err = %d", err);
         panic("***");
      }
   }
   IP6CPY(&inp->ip6_faddr, &sin->sin6_addr);

   inp->inp_fport = sin->sin6_port;
   return (0);
}
Esempio n. 10
0
/* ping host , char *cmdstr*/
int run_ping6(int argc, char **argv)
{
	pcs *pc = &vpc[pcid];
	struct in6_addr ipaddr;
	struct packet *m = NULL;
	int i;
	char *p;
	char proto_seq[16];
	int count = 5;

	printf("\n");
	
	i = 2;
	for (i = 2; i < argc; i++) {
		if (!strcmp(argv[i], "-c")) {
			if ((i + 1) < argc && digitstring(argv[i + 1]))
				count = atoi(argv[i + 1]);
			break;
		}
	}
	
	if (vinet_pton6(AF_INET6, argv[1], &ipaddr) != 1) {
		printf("Invalid address: %s\n", argv[1]);
		return 0;
	}
	
	memcpy(pc->mscb.dip6.addr8, ipaddr.s6_addr, 16);
	if (pc->mscb.dip6.addr16[0] != IPV6_ADDR_INT16_ULL)
		memcpy(pc->mscb.sip6.addr8, pc->ip6.ip.addr8, 16);
	else
		memcpy(pc->mscb.sip6.addr8, pc->link6.ip.addr8, 16);
		
	/* ping self, discard options */	
	if (IP6EQ(&pc->mscb.sip6, &pc->mscb.dip6)) {
		i = 1;
		while (i < 6) {
			printf("%s icmp_seq=%d ttl=%d time=0.001 ms\n", 
			    argv[1], i++, pc->mscb.ttl);
			delay_ms(1);
		}
		return 1;
	}
	
	/* find destination */
	p = (char*)nbDiscovery(pc, &pc->mscb.dip6);	
	if (p == NULL) {
		printf("host (%s) not reachable\n", argv[1]);
		return 0;
	}
	memcpy(pc->mscb.dmac, p, 6);
	
	if (pc->mscb.proto == IPPROTO_ICMP) {
		pc->mscb.proto = IPPROTO_ICMPV6;
		strcpy(proto_seq, "icmp6_seq");
	} else if (pc->mscb.proto == IPPROTO_TCP) {
		strcpy(proto_seq, "tcp6_seq");
	} else if (pc->mscb.proto == IPPROTO_UDP) {
		strcpy(proto_seq, "udp6_seq");
	}	

	if (pc->mscb.proto == IPPROTO_TCP && pc->mscb.flags == 0) {	
		i = 0;
		while ((i++ < count || count == -1) && !ctrl_c) {
			struct timeval ts0, ts;
			u_int usec;
			int k;
			int dsize = pc->mscb.dsize;
			int traveltime = 1;
			
			if (i > 1)
				delay_ms(pc->mscb.waittime);
				
			/* clear the input queue */
			while ((m = deq(&pc->iq)) != NULL);
			/* connect the remote */
			gettimeofday(&(ts), (void*)0);
			k = tcp_open(IPV6_VERSION);
			
			/* restore data size */
			pc->mscb.dsize = dsize;
			
			gettimeofday(&(ts0), (void*)0);
			usec = (ts0.tv_sec - ts.tv_sec) * 1000000 + ts0.tv_usec - ts.tv_usec;
			if (k == 0) {
				printf("Connect   %d@%s timeout\n", pc->mscb.dport, argv[1]);
				continue;
			} else if (k == 2) {
				char buf[INET6_ADDRSTRLEN + 1];
				
				memset(buf, 0, sizeof(buf));
				vinet_ntop6(AF_INET6, &pc->mscb.rdip6, buf, INET6_ADDRSTRLEN + 1);
				
				printf("*%s %s=%d ttl=%d time=%.3f ms", 
				    buf, proto_seq, i++, pc->mscb.rttl, usec / 1000.0);
						
				
				printf(" (ICMP type:%d, code:%d, %s)\n", 
				    pc->mscb.icmptype, pc->mscb.icmpcode,
				    icmpTypeCode2String(6, pc->mscb.icmptype, pc->mscb.icmpcode));

				continue;
			} else if (k == 3) {
				printf("Connect   %d@%s RST returned\n", pc->mscb.dport, argv[1]);
				continue;	
			}
			
			printf("Connect   %d@%s seq=%d ttl=%d time=%.3f ms\n", 
			    pc->mscb.dport, argv[1], i, pc->mscb.rttl, usec / 1000.0);
			
			traveltime = 0.6 * usec / 1000;
			/* send data */
			delay_ms(traveltime);		
			gettimeofday(&(ts), (void*)0);
			k = tcp_send(IPV6_VERSION);
			if (k == 0) {
				printf("SendData  %d@%s timeout\n", pc->mscb.dport, argv[1]);
				continue;
			}
			
			gettimeofday(&(ts0), (void*)0);
			usec = (ts0.tv_sec - ts.tv_sec) * 1000000 + ts0.tv_usec - ts.tv_usec;
			printf("SendData  %d@%s seq=%d ttl=%d time=%.3f ms\n", 
			    pc->mscb.dport, argv[1], i, pc->mscb.rttl, usec / 1000.0);
			
			/* close */
			if (k != 2)
				delay_ms(traveltime);
			
			gettimeofday(&(ts), (void*)0);
			k = tcp_close(IPV6_VERSION);
			if (k == 0) {
				printf("Close     %d@%s timeout\n", pc->mscb.dport, argv[1]);
				continue;
			}
			
			gettimeofday(&(ts0), (void*)0);
			usec = (ts0.tv_sec - ts.tv_sec) * 1000000 + ts0.tv_usec - ts.tv_usec;
			printf("Close     %d@%s seq=%d ttl=%d time=%.3f ms\n", 
			    pc->mscb.dport, argv[1], i, pc->mscb.rttl, usec / 1000.0);

		}
	} else {
		i = 1;
		while ((i <= count || count == -1) && !ctrl_c) {
			struct packet *p;
			struct timeval tv;
			u_int usec;
    			int respok = 0;
    		
			pc->mscb.sn = i;
			pc->mscb.timeout = time_tick;
				
			m = packet6(&pc->mscb);
			
			if (m == NULL) {
				printf("out of memory\n");
				return false;
			}
			
			gettimeofday(&(tv), (void*)0);
			enq(&pc->oq, m);
		
			while (!timeout(tv, pc->mscb.waittime) && !ctrl_c) {
				delay_ms(1);
				respok = 0;	
				
				while ((p = deq(&pc->iq)) != NULL && !respok && 
				    !timeout(tv, pc->mscb.waittime) && !ctrl_c) {
					
					pc->mscb.icmptype = pc->mscb.icmpcode = 0; 
					respok = response6(p, &pc->mscb);
					usec = (p->ts.tv_sec - tv.tv_sec) * 1000000 +
					    p->ts.tv_usec - tv.tv_usec;
										
					del_pkt(p);
					
					if (respok == 0)
						continue;
					
					tv.tv_sec = 0;

					if ((pc->mscb.proto == IPPROTO_ICMPV6 && 
					    pc->mscb.icmptype == ICMP6_ECHO_REPLY) ||
					    (pc->mscb.proto == IPPROTO_UDP && respok == IPPROTO_UDP)||
					    (pc->mscb.proto == IPPROTO_TCP && respok == IPPROTO_TCP)) {
						printf("%s %s=%d ttl=%d time=%.3f ms\n", argv[1], 
						    proto_seq, i++, pc->mscb.rttl, usec / 1000.0);
						break;
					}
						
					if (respok == IPPROTO_ICMPV6) {
						char buf[INET6_ADDRSTRLEN + 1];
						
						memset(buf, 0, sizeof(buf));
						vinet_ntop6(AF_INET6, &pc->mscb.rdip6, buf, 
						    INET6_ADDRSTRLEN + 1);

						printf("*%s %s=%d ttl=%d time=%.3f ms", 
						    buf, proto_seq, i++, pc->mscb.rttl, usec / 1000.0);
						
						
						printf(" (ICMP type:%d, code:%d, %s)\n", 
						    pc->mscb.icmptype, pc->mscb.icmpcode,
						    icmpTypeCode2String(6, pc->mscb.icmptype, pc->mscb.icmpcode));
						break;
					}
				}
			}
			if (!respok && !ctrl_c)
				printf("%s %s=%d timeout\n", argv[1], proto_seq, i++);
		} 
	}
	return 1;
}
Esempio n. 11
0
int run_tracert6(int argc, char **argv)
{
	int i, j;
	struct packet *m;
	pcs *pc = &vpc[pcid];
	u_char *dmac;
	int ok = 0;
	struct in6_addr ipaddr;
	ip6 ip;
	int pktnum = 3;
	int count = 99;
	
	printf("\n");

	if (argc < 2) {
		printf("incompleted command.\n");
		return 0;
	}
	
	i = 2;
	for (i = 2; i < argc; i++) {
		if (!strcmp(argv[i], "-c")) {
			if ((i + 1) < argc && digitstring(argv[i + 1]))
				count = atoi(argv[i + 1]);
			break;
		}
	}
	if (count == 99 && digitstring(argv[argc - 1]))
		count = atoi(argv[argc - 1]);
				
	if (optind < argc && digitstring(argv[optind]))
		count = atoi(argv[optind]);
		
	if (count < 1 || count > 64)
		count = 64;
	
			
	if (vinet_pton6(AF_INET6, argv[1], &ipaddr) != 1) {
		printf("Invalid address: %s\n", argv[1]);
		return 0;
	}
	
	memcpy(pc->mscb.dip6.addr8, ipaddr.s6_addr, 16);
	if (pc->mscb.dip6.addr16[0] != IPV6_ADDR_INT16_ULL)
		memcpy(pc->mscb.sip6.addr8, pc->ip6.ip.addr8, 16);
	else
		memcpy(pc->mscb.sip6.addr8, pc->link6.ip.addr8, 16);
		
	dmac = nbDiscovery(pc, &ip);	
	if (dmac == NULL) {
		printf("host (%s) not reachable\n", argv[1]);
		return 0;
	}
	memcpy(pc->mscb.dmac, dmac, 6);
	printf("trace to %s, %d hops max\n", argv[1], count);
	
	/* send the udp packets */
	i = 1;
	while (i <= count && !ctrl_c) {
		struct packet *p;
		struct timeval tv;
		u_int usec;
		int k;
		
		printf("%2d ", i);
		for (j = 0; j < pktnum && !ctrl_c; j++) {			
			
			pc->mscb.ttl = i;
			m = packet6(&pc->mscb);

			if (m == NULL) {
				printf("out of memory\n");
				return 0;
			}

			gettimeofday(&(tv), (void*)0);
			enq(&pc->oq, m);
			
			k = 0;
			
			while (!timeout(tv, pc->mscb.waittime) && !ctrl_c) {
				delay_ms(1);
				ok = 0;	

				while ((p = deq(&pc->iq)) != NULL && !ok &&
				    !timeout(tv, pc->mscb.waittime) && !ctrl_c) {
					ok = response6(p, &pc->mscb);
					usec = (p->ts.tv_sec - tv.tv_sec) * 1000000 + 
					    p->ts.tv_usec - tv.tv_usec;
						
					del_pkt(p);
					
					if (pc->mscb.icmptype == ICMP6_TIME_EXCEEDED || 
					    IP6EQ(&(pc->mscb.dip6), &(pc->mscb.rdip6))) {
						if (j == 0) {
							char buf[128];
						
							memcpy(ipaddr.s6_addr, pc->mscb.rdip6.addr8, 16);
							memset(buf, 0, 128);
							vinet_ntop6(AF_INET6, &ipaddr, buf, 
							    INET6_ADDRSTRLEN + 1);
							printf("%s ", buf);
						}
							
						printf("  %.3f ms", usec / 1000.0);fflush(stdout);
						
						tv.tv_sec = 0;

						break;
					} else if (pc->mscb.icmptype == ICMP6_DST_UNREACH || 
					    pc->mscb.icmptype == ICMP6_DST_UNREACH_NOPORT) {
						if (j == 0) {
							char buf[128];
						
							memcpy(ipaddr.s6_addr, pc->mscb.rdip6.addr8, 16);
							memset(buf, 0, 128);
							vinet_ntop6(AF_INET6, &ipaddr, buf, INET6_ADDRSTRLEN + 1);
							printf("*%s   %.3f ms (ICMP type:%d, code:%d, %s)\n", buf,
							    usec / 1000.0, pc->mscb.icmptype, pc->mscb.icmpcode,
							    icmpTypeCode2String(6, pc->mscb.icmptype, pc->mscb.icmpcode));
						}

						tv.tv_sec = 0;

						return 1;
					}
				}
				k++;
			}
			if (!ok && !ctrl_c)
				printf("  *");
		}
		printf("\n");
		i++;
		if (pc->mscb.icmptype  == ICMP6_DST_UNREACH)
			break;
	}

	return 1;
}
Esempio n. 12
0
int
ping6_send(struct ping6 *ping)
{
   PACKET   pkt;
   struct icmp6req *pinghdr;
   char     addrbuf[40];   /* for printf()ing */
   int      plen = sizeof(struct icmp6req) + ping->length;
   int      err = 0;
   int      sendflags;
   int      bytesleft;
   int      offset;
   /* try for a pkt chain */
   LOCK_NET_RESOURCE(FREEQ_RESID);
   PK_ALLOC(pkt, plen + MaxLnh + sizeof(struct ipv6));
   UNLOCK_NET_RESOURCE(FREEQ_RESID); 

   if (pkt == NULL)
   {
      ping->count = 0;     /* mark session for deletion */
      return (ENP_NOBUFFER);
   }
   pkt->flags = 0;

   /* prepare for cb_read */
   pkt->nb_prot = pkt->nb_buff + MaxLnh + sizeof(struct ipv6);
 
   /* got chain? */
   if (pkt->pk_next == NULL)
      pkt->nb_plen = plen;       /* no */
   else
      pkt->nb_plen = pkt->nb_blen - MaxLnh - sizeof(struct ipv6);   /* yes */   

   /* Advance to point where we write the data */
   offset = sizeof(struct icmp6req);
   pkt->nb_tlen = offset;
   bytesleft = ping->length;
 
   while (bytesleft > PINGSTRSIZE)
   {
      err = cb_read(pkt, offset, (uint8_t *)pingdata6, PINGSTRSIZE);
      if (err < 0)
         break;
      offset += err;
      bytesleft -= err;
   }
   if (bytesleft && (err >= 0))
      err = cb_read(pkt, offset, (uint8_t *)pingdata6, bytesleft);
   /* read in data - user or standard? */
      
   /* got err? */
   if (err <= 0)
   {
      LOCK_NET_RESOURCE(FREEQ_RESID);  
      PK_FREE(pkt);
      UNLOCK_NET_RESOURCE(FREEQ_RESID);    
      ping->count = 0;     /* mark session for deletion */
      return (ENP_NOBUFFER);
   }    

#ifdef IP6_ROUTING
   /* Put scopeID in pkt */
   pkt->soxopts = npalloc(sizeof(struct ip_socopts));
   if (pkt->soxopts == NULL)
   {
      LOCK_NET_RESOURCE(FREEQ_RESID);
      pk_free(pkt);
      UNLOCK_NET_RESOURCE(FREEQ_RESID);      
      ping->count = 0;     /* mark session for deletion */
      return (ENP_NOBUFFER);
   }
   pkt->soxopts->ip_scopeid = ping->scopeID;
#endif

   pinghdr = (struct icmp6req *)pkt->nb_prot;
   pinghdr->code = 0;
   pinghdr->type = ICMP6_ECHOREQ;
   pinghdr->id = ping->sess_id;
   pinghdr->sequence = (htons((unshort)ping->sent));
   ping->sent++;
   pkt->net = ping->net;

   pkt->type = htons(0x86dd);

   /* multicast ping? */
   if (ping->fhost.addr[0] == 0xFF)
   {
      pkt->flags |= PKF_MCAST;  /* send mac multicast */
      sendflags = 0; /* no routing */
   }
   else
   {
      pkt->flags &= ~PKF_MCAST;  /* send mac unicast */
      /* see if we can skip the routing step */
      if(pkt->net && (!IP6EQ(&ping->nexthop, &ip6unspecified)))
      {
        pkt->nexthop = &ping->nexthop;   /* set next hop */
        sendflags = IP6F_NOROUTE;
      }
      else
        sendflags = IP6F_ALL;
   }
   /* is the scope global? */
   if ( (ping->fhost.addr[0] == 0xFF) && ((ping->fhost.addr[1] & 0xF) == 0xE) )
      {
         /* yup - it's a global ping */         
        pkt->flags |= PKF_IPV6_GBL_PING;  /* global ping */        
      }

   /* loopback? */
   if (IN6_IS_ADDR_LOOPBACK((struct in6_addr *)&(ping->fhost.addr)))
      IP6CPY((struct in6_addr *)&(ping->lhost.addr), 
             (struct in6_addr *)&(ping->fhost.addr));   /* both are loopback */

   /* put prot at IPv6 hdr */
   pkt->nb_prot -= sizeof(struct ipv6);
   pkt->nb_plen += sizeof(struct ipv6);
   pkt->nb_tlen += sizeof(struct ipv6);
  
   /* set time for next ping */
   ping->nextping = TIME_ADD(CTICKS, ping->ping6_interval); 
 
   err = icmp6_send(pkt, &ping->lhost, &ping->fhost, sendflags);
   pkt->net->icmp6_ifmib.OutEchos++;
   
   if (err < 0)
   {
      /* Don't record gio error, since we're going to kill this
       * ping session anyway.
       */
      gio_printf(ping->gio, "error %d sending ping; sess %d, seq:%d\n",
                 err, ntohs(ping->sess_id), ping->sent);
      ping->count = 0;     /* mark session for deletion by timer */
   }
   else if ((err == 1) || (err == 0))
   {
      err = gio_printf(ping->gio, "Sent ping; sess: %d, Seq: %d to %s\n",
                       ntohs(ping->sess_id), ping->sent,
                       print_ip6(&ping->fhost, addrbuf));
   }
   return (0);
}