Exemplo n.º 1
0
void igmp_send (u_char type, struct in_multi * inm)
{
    PACKET p;
    struct igmp * igmp;
    struct ip_moptions * imop;
    struct ip_moptions simo;
    struct ip * pip;
    int i;
    u_char * tmpp;
    u_char opts [2] = {IP_RTR_ALERT_OPT, EOL_OPT};
    u_char * optp;
    u_char reqd_len;

    /* compute length of buffer required for outgoing packet.
     * also account for the length of the IP Router Alert
     * option, if required. */
    reqd_len = MaxLnh + sizeof (struct ip) + sizeof (struct igmp);
    if ((type == IGMPv2_LEAVE_GROUP) ||
            (type == IGMPv2_MEMBERSHIP_REPORT))
    {
        reqd_len += IP_RTR_ALERT_OPT_SIZE;
    }

    /* obtain a packet to send the IGMP message */
    LOCK_NET_RESOURCE (FREEQ_RESID);
    p = pk_alloc (reqd_len);
    UNLOCK_NET_RESOURCE (FREEQ_RESID);

    /* log an error and return if the allocation fails */
    if (!p)
    {
        ++igmpstats.igmp_pkt_alloc_fail;
        return;
    }

    /* Need to fill in the source and destination ip addresses */
    pip = (struct ip *) p->nb_prot;
    pip->ip_src = inm->inm_netp->n_ipaddr;
    /* Leave Group messages are sent to the all-routers multicast group */
    if (type == IGMPv2_LEAVE_GROUP)
    {
        /* igmp_all_rtrs_group is already in network byte order */
        pip->ip_dest = igmp_all_rtrs_group;
    }
    else
        pip->ip_dest = inm->inm_addr;

    p->fhost = pip->ip_dest;

    tmpp = (((u_char *) p->nb_prot) + sizeof (struct ip));

    /* when transmitting an IGMP packet, our IGMP module will insert
     * data for the Router Alert option in the following types of
     * packets: Version 2 Membership Report (0x16) and Leave Group
     * (0x17) */
    if ((type == IGMPv2_LEAVE_GROUP) ||
            (type == IGMPv2_MEMBERSHIP_REPORT))
    {
        /* provide space for ip_write2 () to write option-related data */
        tmpp += IP_RTR_ALERT_OPT_SIZE;
        optp = &(opts [0]); /* one option (IP Router Alert) */
    }
    /* outgoing packet does not require any options */
    else
        optp = &(opts [1]);
    /* point to the start of the IGMP header */
    igmp = (struct igmp *) tmpp;

    igmp->igmp_type = type;
    igmp->igmp_code = 0;

    /* all messages (Report or Leave) have Group Address field
     * set to the group being reported or left */
    igmp->igmp_group = inm->inm_addr;
    igmp->igmp_cksum = 0;
    igmp->igmp_cksum = ~cksum((void*)igmp, IGMP_MINLEN>>1);

    imop = &simo;
    MEMSET(imop, 0, sizeof(simo));
    imop->imo_multicast_netp = inm->inm_netp;
    imop->imo_multicast_ttl = 1;
    /* we do not want our own reports to be looped back */
    imop->imo_multicast_loop = 0;

    /* set nb_prot to point to the beginning of the IGMP data,
     * and nb_plen to the length of the IGMP data, and attach
     * the multicast options structure to the outgoing packet */
    p->nb_prot = (char *) tmpp;
    p->nb_plen = sizeof(struct igmp);
    p->imo = imop;

    i = ip_write2 (IGMP_PROT, p, optp);

    if (type == IGMPv2_LEAVE_GROUP)
        ++igmpstats.igmpv2mode_v2_leave_msgs_sent;
    else if (type == IGMPv2_MEMBERSHIP_REPORT)
        ++igmpstats.igmpv2mode_v2_reports_sent;
    else if (type == IGMP_HOST_MEMBERSHIP_REPORT)
        ++igmpstats.igmp_v1_reports_sent;
}
Exemplo n.º 2
0
int
icmpEcho(ip_addr host,  /* host to ping - 32 bit, network-endian */
   char *   data,       /* ping data, NULL if don't care */
   unsigned datalen,     /* length of data to attach to ping request */
   unshort  pingseq)    /* ping sequence number */
{
   PACKET   p;
   int      ip_err;
   struct ping *  e;
   struct ip *    pip;

   LOCK_NET_RESOURCE(FREEQ_RESID);
   p = pk_alloc(PINGHDRSLEN + datalen);
   UNLOCK_NET_RESOURCE(FREEQ_RESID);
   if (!p)
   {
#ifdef   NPDEBUG
      if (NDEBUG & IPTRACE)
         dprintf("icmp: can't alloc packet\n");
#endif
      return(ENP_NOBUFFER);
   }

   p->nb_prot = p->nb_buff + PINGHDRSLEN;
   p->nb_plen = datalen;
   p->fhost = host;

   if(host == 0xFFFFFFFF)  /* broadcast? */
      p->net = nets[0];    /* then use first iface */

   /* copy in data field */
   if (data)
   {
      MEMCPY(p->nb_prot, data, datalen);
   }
   else  /* caller didn't specify data */
   {
      unsigned   donedata;
      strcpy(p->nb_prot, pingdata);
      donedata = (unsigned)strlen(pingdata);
      while (donedata < datalen)
      {
         *(p->nb_prot + donedata) = (char)((donedata) & 0x00FF);
         donedata++;
      }
   }

   /* adjust packet pointers to icmp ping header */
   p->nb_prot -= sizeof(struct ping);
   p->nb_plen += sizeof(struct ping);

   /* fill in icmp ping header */
   e = (struct ping *)p->nb_prot;
   e->ptype = ECHOREQ;
   e->pcode = 0;
   e->pid = 0;
   e->pseq = pingseq;

   /* Calculate the checksum */
   e->pchksum = 0;
   if (datalen & 1)  /* if data size is odd, pad with a zero */
      *((char*)(e+1) + datalen) = 0;

   e->pchksum = ~cksum(e, (ICMPSIZE+datalen+1)>>1);

   /* need to fill in IP addresses at this layer too */
   pip = (struct ip *)(p->nb_prot - sizeof(struct ip));
   pip->ip_src = ip_mymach(host);
   pip->ip_dest = host;

   LOCK_NET_RESOURCE(NET_RESID);
   ip_err = ip_write(ICMP_PROT, p);    /* send down to IP layer */
   UNLOCK_NET_RESOURCE(NET_RESID);

   /* Errors are negative. A zero means send was OK. a positive number
    * usually means we had to ARP. Assume this will work and count a send.
    */
   if(ip_err < 0)
   {
#ifdef   NPDEBUG
      if (NDEBUG & NETERR)
         dprintf("icmp: can't send echo request\n");
#endif
      /* rfc 1156 seems to say not to count these. (pg 48) -JB- */
      /* LOCK_NET_RESOURCE(FREEQ_RESID); */
      /* pk_free(p); */
      /* UNLOCK_NET_RESOURCE(FREEQ_RESID); */
      return(ip_err);
   }
   /* fall to here if we sent echo request OK */
   icmp_mib.icmpOutMsgs++;
   icmp_mib.icmpOutEchos++;

   return(0);
}
Exemplo n.º 3
0
void igmp_fasttimo (void)
{
    struct in_multi * inm;
    NET ifp;

    LOCK_NET_RESOURCE (NET_RESID);

    /*
     * Quick check to see if any work needs to be done, in order
     * to minimize the overhead of fasttimo processing.
     */
    if (!igmp_timers_are_running)
    {
        UNLOCK_NET_RESOURCE (NET_RESID);
        return;
    }

    for (ifp = (NET)(netlist.q_head); ifp; ifp = ifp->n_next)
    {
        for (inm = ifp->mc_list; inm; inm = inm->inm_next)
        {
            /* skip IPv6 entries */
            if (inm->inm_addr == 0)
                continue;

            if (inm->inm_timer == 0)   /* timer not set */
            {
                /* do nothing */
            }
            else if (--inm->inm_timer == 0)  /* timer expired */
            {
                /* send membership report in appropriate format */
                if (ifp->igmpv1_rtr_present)
                {
                    /* always true for IGMPv1, may be true for IGMPv2 */
                    igmp_send (IGMP_HOST_MEMBERSHIP_REPORT, inm);
                }
                else
                {
                    igmp_send (IGMPv2_MEMBERSHIP_REPORT, inm);
                }

                /* for IGMPv2, indicate that we were the last to send
                 * a Report for this multicast group (relevant for
                 * IGMPv2 only).  also check to see if we should mark
                 * the IGMPv1 router as "absent". */
                if (ifp->igmp_oper_mode == IGMP_MODE_V2)
                {
                    inm->last2send_report = IGMP_TRUE;

                    if (ifp->igmpv1_rtr_present)
                    {
                        if (cticks > (ifp->igmpv1_query_rcvd_time + (IGMPv1_RTR_PRESENT_TMO * TPS)))
                        {
                            /* we haven't heard from the IGMPv1 router for a duration
                             * greater than or equal to Version 1 Router Present Timeout
                             * (400 seconds), and will now update the igmpv1_rtr_present
                             * variable to reflect that.
                             */
                            ifp->igmpv1_rtr_present = IGMP_FALSE;
                            ifp->igmpv1_query_rcvd_time = 0;
                        }
                    }
                }

                /* decrement the count of running IGMP timers */
                --igmp_timers_are_running;
            }
            else
            {
                /* timer is still counting down */
            }
        }
    }

    /* Setup time for the next call into igmp_fasttimo ()
     * (200 ms later). */
    igmp_cticks = cticks + TPS/PR_FASTHZ;

    UNLOCK_NET_RESOURCE (NET_RESID);

    return;
}
Exemplo n.º 4
0
void pk_free_heapbuf (PACKET pkt)
{
   u_char start_offset;
   u_char num_guard_bytes;
   char * bufp;
#ifdef HEAPBUFS_DEBUG
   PHLEP phlep;
#endif
   u_long len;
   u_long decrement;

#ifdef NPDEBUG
   start_offset = ALIGN_TYPE;
   num_guard_bytes = ALIGN_TYPE + 1;
#else
   start_offset = num_guard_bytes = 0;
#endif

   bufp = pkt->nb_buff - start_offset;
   len = pkt->nb_blen + num_guard_bytes;
#ifdef HEAPBUFS_DEBUG
   /* update private heapbuf list - remove element */
   ENTER_CRIT_SECTION(&phlq);
   for (phlep=(PHLEP)phlq.q_head; phlep; phlep = phlep->next)
   { 
      if ((phlep->netbufp == pkt) && (phlep->databufp == bufp))
      {
         /* found a matching entry; remove it... */
         break;
      }
   }
   EXIT_CRIT_SECTION(&phlq);

   /* did we find the private heapbuf list entry corresponding to this allocation? */
   if (phlep == 0)
   {
      /* No; we were able to validate this PACKET earlier, 
       * but the corresponding PHL entry has now disappeared! */
      INCR_SHARED_VAR (hbufstats, NO_PHLE_ERR, 1);
      return;
   }
   else
   {
      /* delete PHLE entry from its queue.  This deletion is protected via 
       * ENTER_CRIT_SECTION () and EXIT_CRIT_SECTION () macros. */
      qdel(&phlq, phlep);
   }
#endif /* HEAPBUFS_DEBUG */

   if (heap_type == HEAP_ACCESS_BLOCKING) UNLOCK_NET_RESOURCE (FREEQ_RESID);
   
   HB_FREE (pkt);
   HB_FREE (bufp);
#ifdef HEAPBUFS_DEBUG
   HB_FREE (phlep);
#endif /* HEAPBUFS_DEBUG */
   
   if (heap_type == HEAP_ACCESS_BLOCKING) LOCK_NET_RESOURCE (FREEQ_RESID);
   /* decrement the global counter that is used to keep track of the total
    * heap allocation */
   decrement = sizeof (struct netbuf) + len;
#ifdef HEAPBUFS_DEBUG
   /* also account for the size of the debug structure if HEAPBUFS_DEBUG
    * is enabled */
   decrement += sizeof (PHLE);
#endif
   DECR_SHARED_VAR (heap_curr_mem, decrement);

   return;
}
Exemplo n.º 5
0
int
lb_raw_send(struct net * netp, char * buffer, unsigned length)
{
   struct ethhdr *   eth;
   IFMIB mib;
   PACKET pkt;

#ifdef NPDEBUG
   /* Sanity check interface pointer */
   if(netp->raw_send != lb_raw_send)
   {
      dprintf("macloop: bad net\n");
      dtrap();
   }
#endif

   /* Don't send if iface is logically down */
   if(netp->n_mib->ifAdminStatus != NI_UP)
   {
      netp->n_mib->ifOutDiscards++; /* bump mib counter for these */
      return ENP_LOGIC;    /* right thing to do? */
   }

   /* maintain mib xmit stats */
   mib = netp->n_mib;
   if (*buffer & 0x01)  /* see if multicast bit is on */
      mib->ifOutNUcastPkts++;
   else
      mib->ifOutUcastPkts++;
   mib->ifOutOctets += length;

   /* at this point we make the logical switch from sending to receiving */

   /* fill in a packet for the "received" buffer */
   LOCK_NET_RESOURCE(FREEQ_RESID);
   pkt = pk_alloc(length);
   UNLOCK_NET_RESOURCE(FREEQ_RESID);
   if (!pkt)
   {
      mib->ifInDiscards++;
      return ENP_RESOURCE;
   }
   MEMCPY(pkt->nb_buff, buffer, length);
   pkt->nb_prot = pkt->nb_buff + ETHHDR_SIZE;   /* point to IP header */
   pkt->nb_plen = length - ETHHDR_SIZE;   /* IP length */
   pkt->net = netp;
   eth = (struct ethhdr *)(pkt->nb_buff + ETHHDR_BIAS);
   MEMCPY(eth->e_dst, (void *)lpbhaddr, 6);
   MEMCPY(eth->e_src, (void *)lpbhaddr, 6);
   pkt->type = eth->e_type;

   mib->ifInOctets += length;

   /* queue the packet in rcvdq */
   putq(&rcvdq, (q_elt)pkt);

   /* Most ports should now wake the packet demuxer task */
   SignalPktDemux();

   return 0;   /* OK return */
}
Exemplo n.º 6
0
int igmpv1_input(PACKET p)
{
   u_char igmp_type;
   ip_addr igmp_group;
   struct in_multi * inm;
   NET netp  = p->net;
   int rc;

   /* extract IGMP type from received packet */
   rc = cb_write(p, 0, (uint8_t *) &igmp_type, sizeof(igmp_type));
   if (rc != sizeof(igmp_type))
   {
      LOCK_NET_RESOURCE(FREEQ_RESID);
      PK_FREE(p);
      UNLOCK_NET_RESOURCE(FREEQ_RESID);
      return (IGMP_ERR);
   }

   switch (igmp_type) 
   {
   case IGMP_HOST_MEMBERSHIP_QUERY:
      ++igmpstats.igmpv1mode_v1_queries_rcvd;
      /*
       * Start the timers in all of our membership records for
       * the interface on which the query arrived, except those
       * that are already running and those that belong to the
       * "all-hosts" group.
       */
      for (inm = netp->mc_list; inm; inm = inm->inm_next)
      {
         /* skip all IPv6 entries - they are indicated by 
          * an IPv4 address field of 0 */
         if (inm->inm_addr == 0)
            continue;
         /* skip IPv4 multicast address of 224.0.0.1 (note that
          * the IPv4 address stored in inm_addr is in network 
          * byte order */
         if (inm->inm_addr != igmp_all_hosts_group)
         {
            if (inm->inm_timer == 0)
            {
               inm->inm_timer = (unsigned) IGMP_RANDOM_DELAY(inm->inm_addr);
               /* increment the count of running timers */
               ++igmp_timers_are_running;            
            }   
         }
      }
      rc = IGMP_OK;
      break;

   case IGMP_HOST_MEMBERSHIP_REPORT:
      ++igmpstats.igmpv1mode_v1_reports_rcvd;
      /*
       * If we belong to the group being reported and have a 
       * running timer for that group, stop our timer for that 
       * group.
       */
      /* extract IGMP group from received packet */
      rc = cb_write(p, IGMP_GRP_OFFSET, (uint8_t *) &igmp_group, sizeof(igmp_group));
      if (rc != sizeof(igmp_group))
      {
         rc = IGMP_ERR;
         break;
      }
      inm = lookup_mcast(igmp_group, netp);
      if (inm != NULL) 
      {
         if (inm->inm_timer > 0)
         {
            inm->inm_timer = 0;
            /* decrement the count of running timers */
            --igmp_timers_are_running;
            ++igmpstats.igmpv1mode_v1_reports_rcvd_canceled_timer;
         }
      }
      rc = IGMP_OK;
      break;
      
   default:
      ++igmpstats.igmpv1mode_unknown_pkttype;
      rc = IGMP_ERR;
      break;   
   }

   /* we're done with the received packet; return packet buffer back 
    * to free pool */
   LOCK_NET_RESOURCE(FREEQ_RESID);
   PK_FREE(p);
   UNLOCK_NET_RESOURCE(FREEQ_RESID);
      
   return rc;
}
Exemplo n.º 7
0
int
ip2mac(PACKET pkt,         /* the packet itself, all set but for dest MAC address */
   ip_addr  dest_ip)    /* the IP host or gateway to get MAC addr for */
{
   IFMIB ifmib = pkt->net->n_mib;   /* mib info for this interface */

#ifdef  LOSSY_IO
   if(NDEBUG & LOSSY_TX)
   {
      if(myloss())
      {		  
		  LOCK_NET_RESOURCE(FREEQ_RESID);
         pk_free(pkt);                 /* punt packet */
         UNLOCK_NET_RESOURCE(FREEQ_RESID);
         in_lastloss = (int)(cticks & 0x07) - 4;  /* pseudo random reset */
         return 0;                     /* act as if we sent OK */
      }
   }
#endif   /* LOSSY_IO */

   /* Always punt if iface ifAdminStatus is DOWN. ifOperStatus may 
    * be down too, but our packet may be the event required to bring 
    * it up - so don't worry about ifOperStatus here.
    */
   if(ifmib->ifAdminStatus == NI_DOWN)
   {
      LOCK_NET_RESOURCE(FREEQ_RESID);
      pk_free(pkt);
      UNLOCK_NET_RESOURCE(FREEQ_RESID);
      return(ENP_NO_ROUTE);
   }

#ifdef LINKED_PKTS
   /* If packet gather is not supported by the driver, then collect the
    * fragments into one big buffer. Caller should have checked that buffer
    * is smaller than driver's MTU.
    */
   if (((pkt->net->n_flags & NF_GATHER) == 0) &&   /* no gather flag, and... */
       (pkt->pk_next))                             /* ...packet is scattered. */
   {
      pkt = pk_gather(pkt, pkt->net->n_lnh);
      if (!pkt)
         return ENP_NOBUFFER;
   }
#endif   /* LINKED_PKTS */

   /* some interfaces (ie SLIP) just get the raw IP frame - no ARP needed */
   if ((pkt->net->n_lnh == 0) ||    /* no MAC header */
       (ifmib->ifType == PPP) ||     /* or PPP or SLIP... */
       (ifmib->ifType == SLIP))
   {
      ifmib->ifOutUcastPkts++;   /* maintain MIB counters */
      ifmib->ifOutOctets += pkt->nb_plen;

      /* send packet on media */
      if (pkt->net->pkt_send) /* favor using packet send */
         pkt->net->pkt_send(pkt);   /* pkt will be freed by MAC code */
      else  /* no packet send; try raw send */
      {
         pkt->net->raw_send(pkt->net, pkt->nb_prot, pkt->nb_plen);
         LOCK_NET_RESOURCE(FREEQ_RESID);
         pk_free(pkt);
         UNLOCK_NET_RESOURCE(FREEQ_RESID);
      }
      return(SUCCESS);
   }

   /* don't allow unicast sends if NIC iface has no IP address. This
    * is to prevent DHCP clients from sending prior to assignment.
    */
   if (pkt->net->n_ipaddr == 0L)
   {
      if (pkt->fhost != 0xFFFFFFFF) /* check for broadcast packet */
      {
         LOCK_NET_RESOURCE(FREEQ_RESID);
         pk_free(pkt);
         UNLOCK_NET_RESOURCE(FREEQ_RESID);
         return ENP_SENDERR;
      }
   }

#ifdef INCLUDE_ARP   /* must be ethernet or token ring */
   return(send_via_arp(pkt, dest_ip));
#else
   dtrap();    /* Bad option combination? */
   return ENP_NO_IFACE; /* sent to unknown interface type */
#endif   /* INCLUDE_ARP */
}
Exemplo n.º 8
0
int
ping6_recv(PACKET pkt)
{
   struct ipv6 *pip;
   struct ping6 *ping;
   struct icmp6req *pinghdr;
   char   msg[50];
   int    offset;
   int    bytesleft;
   int    err = 0;
   int    len;
   char  *datap;
   int    i;
   PACKET p;

   pip = pkt->ip6_hdr;
   pinghdr = (struct icmp6req *)pkt->nb_prot;

   /* find the session the callback is for */
   for (ping = ping6q; ping; ping = ping->next)
   {
      if (pinghdr->id == ping->sess_id)
         break;
   }
   if (!ping)
   {
      dprintf("Ping response from unknown host=%lx\n", pkt->fhost);
      LOCK_NET_RESOURCE(FREEQ_RESID);
      PK_FREE(pkt);
      UNLOCK_NET_RESOURCE(FREEQ_RESID);
      return (0);
   }
  /* the upcalled packet included the ICMP header. Strip this off
    * for the purposes of reporting data size
    */
   if (ping->totread == 0)
   {
      bytesleft = pkt->nb_plen -= sizeof(struct icmp6req);
      datap = pkt->nb_prot + sizeof(struct icmp6req);
   }
   else
   {
      bytesleft = pkt->nb_plen;
      datap = pkt->nb_prot;
   }
   /* Verify that the data matches our default data */
   p = pkt;
   while (p)
   {
      offset = ping->totread ? ping->totread % PINGSTRSIZE : 0;
      while (bytesleft)
      {
         len = MIN(bytesleft, PINGSTRSIZE);
         for (i = offset; i < len; i++) 
         {
            if (*datap++ != *(pingdata6 + i))
            {
               dprintf("ping data mismatch at byte %u\n", 
                       i + ping->totread + sizeof(struct icmp6req));
               err = -1;
               break;
            }
         }
         if (err)
            break;
         offset = 0;   /* Back to beginning of pingdata */
         bytesleft -= len;
         ping->totread += len;
      }
      p = p->pk_next;
      if (p)
      {
         bytesleft = p->nb_plen;
         datap = p->nb_prot;
      }
   }
   LOCK_NET_RESOURCE(FREEQ_RESID);
   PK_FREE(pkt);
   UNLOCK_NET_RESOURCE(FREEQ_RESID);
   if ((ping->totread != ping->length) && (ping->replies == 0))
      gio_printf(ping->gio, "Reply truncated to %d bytes\n", ping->totread);
   if (++ping->replies == ping->count)
      ping6_done(ping);
   else
   {
      gio_printf(ping->gio, "ping6 reply: len=%d session %d (seq: %d) [%s]\n",
                 ping->totread,
                 htons(pinghdr->id), 
                 htons(pinghdr->sequence), 
                 print_ip6(&pip->ip_src, msg));
      ping->totread = 0;
      ping->last = CTICKS;
   }
   return 0;
}
Exemplo n.º 9
0
void
so_icmpdu(PACKET p, struct destun * pdp)
{
   ip_addr lhost;    /* IP address of originator (our iface) */
   ip_addr fhost;    /* IP address we sent to */
   unshort  fport;   /* TCP/UDP port we sent to */
   unshort  lport;   /* TCP/UDP port we sent from */
   struct inpcb * inp;
   struct socket *   so;
   struct tcpcb * tp;

   /* extract information about packet which generated DU */
   fhost = htonl(pdp->dip.ip_dest);
   lhost = htonl(pdp->dip.ip_src);
   lport = htons(*(unshort*)(&pdp->ddata[0]));
   fport = htons(*(unshort*)(&pdp->ddata[2]));

#ifndef IP_PMTU
   /* if it's a datagram-too-big message, ignore it -- As the
    * build isn't using PMTU Discovery this packet is most 
    * probably a Denial of Service Attack.
    */
    if(pdp->dcode == DSTFRAG)
    {
       goto done;
    }
#endif   /* IP_PMTU */

   /* if it's a TCP connection, clean it up */
   if (pdp->dip.ip_prot == TCPTP)
   {
      /* find associated data structs and socket */
      inp = in_pcblookup(&tcb, fhost, fport, lhost, lport, INPLOOKUP_WILDCARD);
      if (inp == 0)
         goto done;
      so = inp->inp_socket;
      if (so == 0)
         goto done;
      tp = intotcpcb(inp);
      if (tp)
      {
         if (tp->t_state <= TCPS_LISTEN)
         {
            goto done;
         }

#ifdef ICMP_TCP_DOS
         {
         struct ip * pip;
         struct tcpiphdr * ti;

         pip = ip_head(p);  /* find IP header */
         ti = (struct tcpiphdr *)p->nb_prot;

         if(!((tp->snd_una <=  ti->ti_seq) && (ti->ti_seq <= tp->snd_nxt)))
            goto done;

         /* If we get an ICMP Type 3 (Destination Unreachable) - Code 2
          * (Protocol Unreachable) message and during the life of a TCP
          * connection, then its most probably a Denial of Service Attack.
          * As the only other interpretation would be that the support for
          * the transport protocol has been removed from the host sending
          * the error message during the life of the corresponding 
          * connection. As in common practice this is higly unlikely in most
          * cases, we will treat this message as a DOS attack.
          */
         if(pdp->dcode == DSTPROT)
         {
            if((tp->t_state >= TCPS_ESTABLISHED) && (tp->t_state <= TCPS_TIME_WAIT))
               goto done;
         }

        /* Note some ICMP error messages generated by intermediate routers,
         * include more than the recommended 64 bits of the IP Data. If the
         * TCP ACK number happens to be present then use it in detecting a
         * Denial of Service attack.
         *
         * This way we can ensure that the TCP Acknowledgement number should
         * correspond to data that have already been acknowledged. This way
         * we can further reduce the possiblity of considering a spoofed ICMP
         * packet by a factor of 2.
         */
        if(pip->ip_len >= 32)
        {
            if(!(ti->ti_seq <= tp->rcv_nxt))
               goto done;
        }
   }
#endif

         tcp_close(tp);
      }
      so->so_error = ECONNREFUSED;  /* set error for socket owner */
   }   
#ifdef UDP_SOCKETS   /* this sockets layer supports UDP too */
   else if(pdp->dip.ip_prot == UDP_PROT)
   {
      UDPCONN tmp;
      /* search udp table (which keeps hosts in net endian) */
      for (tmp = firstudp; tmp; tmp = tmp->u_next)
         if ((tmp->u_fport == fport || tmp->u_fport == 0) &&
             (tmp->u_fhost == htonl(fhost)) &&
             (tmp->u_lport == lport))
         {
            break;   /* found our UDP table entry */
         }
      if (!tmp) 
         goto done;
      so = (struct socket *)tmp->u_data;
      /* May be non-socket (lightweight) UDP connection. */
      if (so->so_type != SOCK_DGRAM)
         goto done;
      so->so_error = ECONNREFUSED;  /* set error for socket owner */
      /* do a select() notify on socket here */
      sorwakeup(so);
      sowwakeup(so);
   }
#endif   /* UDP_SOCKETS */
   else
      goto done;

#ifdef IP_PMTU
   /* if this is a datagram-too-big message, update the Path MTU cache */
   if (pdp->dcode == DSTFRAG)
      pmtucache_set(pdp->dip.ip_dest, htons(pdp->dno2));
#endif   /* IP_PMTU */

done:
   LOCK_NET_RESOURCE(FREEQ_RESID);
   pk_free(p); /* done with original packet */
   UNLOCK_NET_RESOURCE(FREEQ_RESID);
   return;
}
Exemplo n.º 10
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);
}
Exemplo n.º 11
0
int
ping6_start(GIO *gio, ip6_addr *addr, int scopeID, long count, 
            int dataLen, char *data, int delay, int *live)
{
   struct ping6 *ping;
   NET           ifp;
   int   i;


   *live = 0; /* init to bad */
   
   /* sanity check parameters */
   if ((addr == NULL) || (count < 1))   
   {
      gio_printf(gio, "*** ping6 ENP_PARAM.\n");
      return (0);               
   }
   /* alloc ping */
   ping = (struct ping6 *)PING6_ALLOC(sizeof(struct ping6));
   if (!ping)
   {
      gio_printf(gio, "*** ping6 ENP_NOMEM.\n");
      return (0);               
   }      
   if ((ifp = nets[scopeID - 1]) == (NET)NULL)
   {
      gio_printf(gio, "*** ping6 bad scope id.\n");
      return (0);               
   }   
   /* MCAST? */
   if (addr->addr[0] != 0xff)
   {
      /* no */
      ping->net = ifp;
      IP6CPY(&ping->nexthop, addr);

      /* is dest GLOBAL? */
      if (IN6_IS_ADDR_GLOBAL(addr) && (ifp->v6addrs[IPA_GLOBAL] != 0))
         IP6CPY(&ping->lhost, &(ifp->v6addrs[IPA_GLOBAL]->addr));
      else
         IP6CPY(&ping->lhost, &(ifp->v6addrs[IPA_LINK]->addr));
   }
   else
   {
      /* yes - set src addr. */
      if (!ifp || (ifp->v6addrs[IPA_LINK] == 0))
      {
         gio_printf(gio, "*** ping6 ENP_NO_ROUTE.\n");
         return (0);               
      }  
      IP6CPY(&ping->lhost, &ifp->v6addrs[IPA_LINK]->addr);
      ping->net = ifp;
   }
   IP6CPY(&ping->fhost, addr);
   ping->count = count;
   ping->gio = gio;
   ping->ping6_interval = delay;
   ping->wait_time = delay + GIVE_UP_INTERVAL;
   ping->length = dataLen;
   ping->data = data;
   ping->sess_id = htons(ping6ids);
   ping6ids++;    
   ping->net = ifp;
   ping->scopeID = scopeID;
   *live = 1;
   ping->last = CTICKS;
   LOCK_NET_RESOURCE(NET_RESID); /* protect list */
   ping->next = ping6q;          /* enque in master ping list */
   ping6q = ping;
   UNLOCK_NET_RESOURCE(NET_RESID);

   /* set the ping callback function */
   ping6_callback = ping6_recv;

   /* go do first send */
   if ((i = ping6_send(ping)) != 0)
   {
      /* nope */
      gio_printf(gio, "*** ping6_send error = %d.\n", i);
   }  
   return(0);
}
Exemplo n.º 12
0
STATIC int
ping_debug(CLI_CTX ctx)
{
   GIO *gio = ctx->gio;
   uint32_t count = 1;              /* Default count */
   char *data = NULL; 
   int datalen;
   int ret;
   u_long ipadd = 0;
   struct cli_addr *cliaddr = NULL;
#ifdef IP_V6
   ip6_addr fhost6;                 /* v6 target to ping */
   int  scopeID = 1;                /* Default scope ID  */
   int  prefixLen = 64;
   int *ping6Live = (int *)NULL;
#endif   /* IP_V6 */
   int delay = TPS;                 /* Default delay  */
   int set_datalen = 0;
   
   if (CLI_HELP(ctx))
      return (0);
  
   if ((!CLI_DEFINED(ctx, 'a') && !CLI_DEFINED(ctx, 'h')) ||
       (CLI_DEFINED(ctx, 'a') && CLI_DEFINED(ctx, 'h')))
   {
      gio_printf(gio, "One of: -a <addr> or -h <name> is required\n");
      return (CLI_ERR_PARAM);
   }
   if (CLI_DEFINED(ctx, 'a'))
   {
      cliaddr = (struct cli_addr *)CLI_VALUE(ctx, 'a');
      if ((cliaddr->type != CLI_IPV4) && (cliaddr->type != CLI_IPV6))
         return (CLI_ERR_PARAM);
#ifdef IP_V4     
      if (cliaddr->type == CLI_IPV4) 
         ipadd = *((ip_addr *)&cliaddr->addr[0]);   /* IPv4 address? */
#endif /* IP_V4 */
#ifdef IP_V6    
      if (cliaddr->type == CLI_IPV6) 
      {
         IP6CPY(&fhost6, ((ip6_addr *)&cliaddr->addr[0]));  /* IPv6 address? */
         scopeID = cliaddr->scopeID;
         if (cliaddr->prefixLen != 0)
            prefixLen = cliaddr->prefixLen;
      }
#endif /* IP_V6 */  
   }
   else
   {
      char *hdata = (char *)CLI_VALUE(ctx, 'h');
      ip_addr fhost4 = 0L;
         
#ifdef IP_V6
      ret = in_reshost(hdata, &fhost4, &fhost6, RH_VERBOSE | RH_BLOCK);
#else         
      ret = in_reshost(hdata, &fhost4, NULL, RH_VERBOSE | RH_BLOCK);
#endif /* IP_V6 or not */
      if (ret != 0)
      {
         gio_printf(gio, "Unable to resolve ping host \"%s\"\n", hdata);
         return (CLI_ERR_PARAM);
      }      
      if (fhost4 != 0L)
         ipadd = (u_long)fhost4;
   }
   /* length? */
   if (CLI_DEFINED(ctx, 'l'))
   {
      datalen = (int)CLI_VALUE(ctx, 'l');
      
      set_datalen = 1;
      
      if (datalen < 0)
      {
         gio_printf(gio, "length < 0\n");
         return (CLI_ERR_PARAM);
      }
   }   
   /* delay between pings? */
   if (CLI_DEFINED(ctx, 't'))
   {
      delay = (int)CLI_VALUE(ctx, 't');
      if (delay <= 0)
      {
         gio_printf(gio, "delay <= 0\n");
         return (CLI_ERR_PARAM);
      }   
   }
   /* Number of pings  */
   if (CLI_DEFINED(ctx, 'n'))
   {
      count = (int)CLI_VALUE(ctx, 'n');
      if (count < 1)
      {
         gio_printf(gio, "ping count <= 0\n");
         return (CLI_ERR_PARAM);
      }
   }
   if (count > 5)
      gio_printf(gio, "Type 'k' (Kill) for early termination\n");
 
#ifdef IP_V6
   /* ipadd is now used as a flag to indicate IPv4 or not */
   if (ipadd == 0) 
   {
      char wrkBuf[40];

      if (!set_datalen)
         datalen = strlen(pingdata6);  /* Default length */
         
      ping6Live = &ping6LiveSig;
      gio_printf(gio, "ping IPv6 addr: %s\n", print_ip6(&fhost6, wrkBuf));
      ping6_start(gio, &fhost6, scopeID, count, datalen, data,  delay, ping6Live);
         
      /* bad start? */
      if (ping6LiveSig == 0)
      {
         gio_printf(gio, "Bad ping6 initialization\n");
         return (0);  /* yes */
      }
   }
#endif    /* IP_V6  */

#ifdef IP_V4
   /* ipadd is now used as a flag to indicate IPv4 or not */
   if (ipadd != 0) 
   {
      ping4ID++;  /* bump to next ping ID */
      
      if (!set_datalen)
         datalen = strlen(pingdata);  /* Default length */
         
#ifndef OS_PREEMPTIVE
     start_ping_req(gio, ipadd, count, datalen, data, delay);
#else
      msgp = (struct pingtask_msg *) PING_ALLOC (sizeof (struct pingtask_msg));
      if (!msgp)
      {
         ++ping_err.alloc_fail;
         return (PING_ST_ALLOC_ERR);
      }
         
      /* send message for PING client task */
      msgp->type = PING_CNTRL_START_PING;
      msgp->ipadd = (u_long) ipadd;
      msgp->times = count;
      msgp->gio = gio;
      msgp->data = data; 
      msgp->length = dataLen;
      msgp->delay = delay;
         
      LOCK_NET_RESOURCE (PINGQ_RESID);
      putq(&pingRcvq, (q_elt)msgp);
      UNLOCK_NET_RESOURCE (PINGQ_RESID);
      
      TK_SIGNAL(to_diagcheck, NULL);
#endif   /* OS_PREEMPTIVE  */
   }
#endif  /* IP_V4 */
      
   /* wait for console input or ping end */
   for (;;)
   {
      int  ret;
      char buff[3];
      int flags;
      
      buff[0] = NUL;

      /* Check if ping is still running */
#if defined(IP_V4) && defined(PING_APP)
      if ((ipadd != 0) && !ping_search(gio))
         break;    /* No */
#endif  /* IP_V4 && PING_APP */
#ifdef IP_V6
      if ((ipadd == 0) && !ping6q)
         break;    /* No  */
#endif   /* IP_V6  */

      /* read a char - set GIO non-blocking read */
      flags = gio->flags;
      gio->flags &= ~GIO_F_BIN;
      ret = gio_in(gio, buff, 1);
      gio->flags = flags;

      /* Console routine puts char in buff[0]; telnet's puts it in ret */
      if ((ret > 0) && ((buff[0] == 'k') || (ret == 'k')))
      {
#if defined(IP_V4) && defined(PING_APP)
         if (ipadd != 0)
         {
            PING_INFO p;

            if ((p = ping_search(gio)) != NULL)
               ping_cmd_end(p);
            break;  /* already done */
         }
         else
#endif  /* IP_V4 && PING_APP */
#ifdef IP_V6
            ping6_done(ping6q);
#endif   /* IP_V6  */

         gio_printf(gio, "Ping canceled by console\n");
         break;
      }     
      TK_YIELD();
   }  
   return (0);
}
Exemplo n.º 13
0
int
arp_flood (void * pio)
{
   PACKET arppkt;
   struct ethhdr *   ethhdr;
   struct arp_hdr *  arphdr;
   NET net;
   long  i;
   int   e;
   ip_addr ipaddr;

#ifdef MULTI_HOMED
   ip_addr phost;    /* phoney host for pass to iproute */
   net = iproute(activehost, &phost);
#else
   net = nets[0];
#endif

   if (!net)
   {
      ns_printf(pio, "ARP flood: no route");
      return -1;
   }

   ns_printf(pio, "sending ARP flood of %ld pkts to %u.%u.%u.%u..", 
    pktcount, PUSH_IPADDR(activehost) );


   for (i = 0; i < pktcount; i++)
   {
      if (pktwait("ARP", pio))
         return -1;

      /******** code cribbed from et_arp.c: ********/
      LOCK_NET_RESOURCE(FREEQ_RESID);
      arppkt = pk_alloc(arpsize);
      UNLOCK_NET_RESOURCE(FREEQ_RESID);
      if (!arppkt)
         return ENP_RESOURCE;
      arppkt->nb_prot = arppkt->nb_buff;
      arppkt->nb_plen = arpsize;
      arppkt->net = net;

      /* build arp request packet */
      ethhdr = (struct ethhdr *)(arppkt->nb_buff + ETHHDR_BIAS);     /* ethernet header at start of buffer */
      arphdr = (struct arp_hdr *)(arppkt->nb_buff + ETHHDR_SIZE); /* arp header follows */
      arphdr->ar_hd = ARPHW;     /* net endian arp hardware type (ethernet) */
      arphdr->ar_pro = ARPIP;
      arphdr->ar_hln = 6;
      arphdr->ar_pln = 4;
      arphdr->ar_op = ARREQ;
      arphdr->ar_tpa = activehost;        /* target's IP address */

      /* FLOOD TEST MOD: just for grins, rotate our IP address so we 
       * flood everybody's arp tables. Remember that we store IP 
       * addresses 
       */
      ipaddr = i & (0x00FFFFFE & htonl(~net->snmask));   /* make host portion */
      arphdr->ar_spa = (net->n_ipaddr | htonl(ipaddr));  /* add net portion */

      MEMCPY(arphdr->ar_sha, net->n_mib->ifPhysAddress, 6);
      MEMSET(&(ethhdr->e_dst[0]), 0xFF, 6);     /* destination to broadcast (all FFs) */
      MEMCPY(ethhdr->e_src, net->n_mib->ifPhysAddress, 6);
      ethhdr->e_type = ET_ARP;   /* 0x0806 - ARP type on ethernet */

#ifdef NO_CC_PACKING    /* move ARP fields to proper network boundaries */
      {
         struct arp_wire * arwp  =  (struct  arp_wire *)arphdr;
         MEMMOVE(&arwp->data[AR_SHA], arphdr->ar_sha, 6);
         MEMMOVE(&arwp->data[AR_SPA], &arphdr->ar_spa, 4);
         MEMMOVE(&arwp->data[AR_THA], arphdr->ar_tha, 6);
         MEMMOVE(&arwp->data[AR_TPA], &arphdr->ar_tpa, 4);
      }
#endif   /* NO_CC_PACKING */

      /* send arp request - if a packet oriented send exists, use it: */
      if (net->pkt_send)
         e = net->pkt_send(arppkt);    /* driver should free arppkt later */
      else  /* use old raw send */
      {
         e = net->raw_send(arppkt->net, arppkt->nb_buff, arpsize);
         LOCK_NET_RESOURCE(FREEQ_RESID);
         pk_free(arppkt);
         UNLOCK_NET_RESOURCE(FREEQ_RESID);
      }

      arpReqsOut++;
      /******** end of code cribbed from et_arp.c: ********/

      if (e < 0)
      {
         ns_printf(pio, "ARP flood send error %d on pkt %ld\n",e,i);
         return -1;
      }
      if ((i & 0x0f) == 0x0f)
         ns_printf(pio, ".");
   }

   return 0;
}
Exemplo n.º 14
0
int
Netinit()
{
   int   i; /* general counter variable */
   int   e; /* error holder */

#ifndef MULTI_HOMED
   ifNumber = 1;     /* prevents weird behavior below... */
#endif

   /* set our largest header size and frames size */
   for (i = 0; i < (int)ifNumber; i++)
   {
      /* sanity check on mtu, et.al. We added this because earlier 
       * drivers were sloppy about setting them, but new
       * logic depends on these sizes.
       */
      if (nets[i]->n_mib->ifType == ETHERNET)   /* ethernet? */
      {
         if (nets[i]->n_mtu == 0)   /* let device code override */
            nets[i]->n_mtu = 1514;

         if (nets[i]->n_lnh == 0)
         {
#ifdef IEEE_802_3
            nets[i]->n_lnh = ETHHDR_SIZE + sizeof(struct snap_hdr);
#else
            nets[i]->n_lnh = ETHHDR_SIZE;
#endif
         }
      }
#ifdef IP_V6
      /* Ignore IPv6 tunnels for lnh and mtu values */
      if((nets[i]->n_mib->ifType == IP6GIF) ||
         (nets[i]->n_mib->ifType == IP6TO4))
      {
         continue;
      }
#endif   /* IP_V6 */

      MaxLnh = max(MaxLnh, nets[i]->n_lnh);
      MaxMtu = max(MaxMtu, nets[i]->n_mtu);
   }

   /* set up the received packet queue */
   rcvdq.q_head = rcvdq.q_tail = NULL;
   rcvdq.q_max = rcvdq.q_min = rcvdq.q_len = 0;

   /* initialize freeq */
   LOCK_NET_RESOURCE(FREEQ_RESID);
   e = pk_init();
   UNLOCK_NET_RESOURCE(FREEQ_RESID);
   if (e)   /* report error (memory ran out?) */
      return e;

   /* packet buffers in freeq are now all set. */
   exit_hook(netclose);       /* Clean up nets when we are unloaded */

   /* now do the per-IP interface initializations */
   for (i = 0; i < (int)ifNumber; i++)
   {
      if (nets[i]->n_init != NULL)  /* If iface has init routine... */
      {
         if ((e = (*nets[i]->n_init)(i)) != 0)  /* call init routine */
         {
            dprintf("init error %d on net[%d]\n", e, i);
            nets[i]->n_mib->ifOperStatus = NI_DOWN;
            continue;   /* ignore ifaces which fail */
         }
         /* If interface is ethernet, set bcast flag bit. This
          * should really be done by the init routine, but we handle it
          * here to support MAC drivers which predate the flags field.
          */
         if(nets[i]->n_mib->ifType == ETHERNET)
            nets[i]->n_flags |= NF_BCAST;

         /* set ifAdminStatus in case init() routine forgot to. IfOperStatus
          * is not nessecarily up at this point, as in the case of a modem which
          * is now in autoanswer mode.
          */
         nets[i]->n_mib->ifAdminStatus = NI_UP;

         /* assign default names to unnamed ifaces */
         if(nets[i]->name[0] == 0)     /* no name set by prep or init */
         {
            if(nets[i]->n_mib->ifType == ETHERNET)
            {
               nets[i]->name[0] = 'e';    /* "et1", "et2", etc. */
               nets[i]->name[1] = 't';
            }
            else
            {
               nets[i]->name[0] = 'i';    /* "if1", "if2", etc. */
               nets[i]->name[1] = 'f';
            }
            nets[i]->name[2] = (char)(i + '1');
            nets[i]->name[3] = '\0';
         }
      }
      /* check on subnet routing - if no mask then make one */
      fixup_subnet_mask(i);      /* make mask for this net */

      /* build broadcast addresses */
      if(nets[i]->n_ipaddr != 0)
      {
         nets[i]->n_netbr = nets[i]->n_ipaddr | ~nets[i]->snmask;
         nets[i]->n_netbr42 = nets[i]->n_ipaddr & nets[i]->snmask;
         nets[i]->n_subnetbr = nets[i]->n_ipaddr | ~nets[i]->snmask;
      }
   }

#if defined(DYNAMIC_IFACES) && defined(IN_MENUS)
   /* Install dynamic iface menu */
   install_menu(&dynif_menu[0]);
#endif /* DYNAMIC_IFACES && IN_MENUS */

   return(0);
}
Exemplo n.º 15
0
int
rawip_usrreq(struct socket * so, 
   struct mbuf *  m,
   struct mbuf *  nam)
{
   int   e;    /* error from IP stack */
   PACKET pkt; /* packet for sending */
   struct sockaddr_in * sin;
   struct ipraw_ep * ep;
   ip_addr fhost; /* host to send to/recv from (network byte order) */
   ip_addr lhost; /* local IP address to bind to (network byte order) */
   u_char prot;
   struct ip * pip;
   int   req;
   NET   ifp;     /* ptr to network interface structure */

   req = so->so_req;    /* get request from socket struct */

   switch (req) 
   {
   case PRU_ATTACH:
      /* fake small windows so sockets asks us to move data */
      so->so_rcv.sb_hiwat = so->so_snd.sb_hiwat = 
         ip_raw_maxalloc(so->so_options & SO_HDRINCL);
      /* make a raw IP endpoint */
      prot = (u_char)(MBUF2LONG(nam));
      /* unlock the net resource; IP will immediatly re-lock it */
      UNLOCK_NET_RESOURCE(NET_RESID);
      ep = ip_raw_open(prot, 0L, 0L, rawip_soinput, so);
      LOCK_NET_RESOURCE(NET_RESID);
      if (!ep)
         return(EINVAL);
      return 0;
   case PRU_DETACH:
      /* delete the raw IP endpoint */
      ep = rawip_lookup(so);
      if (!ep)
         return(EINVAL);
      /* unlock the net resource; IP will immediatly re-lock it */
      UNLOCK_NET_RESOURCE(NET_RESID);
      ip_raw_close(ep);
      LOCK_NET_RESOURCE(NET_RESID);
      return 0;
   case PRU_CONNECT:
      /* "connect" the raw IP endpoint to a peer IP address:
       * this sets a filter for received IP datagrams and sets
       * a default address for sending
       */
      /* fall through to shared bind logic */
   case PRU_BIND:
      /* do bind parameters lookups and tests */
      if (nam == NULL)
         return(EINVAL);
      sin = mtod(nam, struct sockaddr_in *);
      if (sin == NULL)
         return(EINVAL);
      if (nam->m_len != sizeof (*sin))
         return(EINVAL);
      ep = rawip_lookup(so);
      if (!ep)
         return(EINVAL);
      if (req == PRU_BIND)
      {
         /* bind the socket to a local interface IP address.
          *
          * if the caller-supplied address is INADDR_ANY,
          * don't bind to a specific address; else, 
          * make sure the caller-supplied address is
          * an interface IP address and if so, bind to that
          */
         if (sin->sin_addr.s_addr == INADDR_ANY)
         {
            lhost = 0L;
         }
         else
         {
            lhost = sin->sin_addr.s_addr;
            /* verify that lhost is a local interface address */
            for (ifp = (NET)(netlist.q_head); ifp; ifp = ifp->n_next)
               if (ifp->n_ipaddr == lhost)
                  break;
            if (ifp == NULL)
               return(EADDRNOTAVAIL);
         }

         /* bind the endpoint */
         ep->ipr_laddr = lhost;
      }
      else /* PRU_CONNECT */
      {
         /* connect the socket to a remote IP address.
          *
          * if the caller-supplied address is INADDR_ANY,
          * use the wildcard address; else, use the caller-
          * supplied address
          */
         if (sin->sin_addr.s_addr == INADDR_ANY)
            fhost = 0L;
         else
            fhost = sin->sin_addr.s_addr;
         /* connect the IP endpoint */
         ep->ipr_faddr = fhost;
         /* mark the socket as connected or disconnected, as appropriate */
         if (fhost != 0L) {
            so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING);
            so->so_state |= SS_ISCONNECTED;
         }
         else
         {
            so->so_state &= ~SS_ISCONNECTED;
         }
         /* since socket was in listen state, packets may be queued */
         sbflush(&so->so_rcv);   /* dump these now */
      }
      return 0;
   case PRU_SEND:
      /* do parameter lookups and tests */
      if (!m)  /* no data passed? */
         return(EINVAL);

      ep = rawip_lookup(so);
      if (!ep)
      {
         m_free(m);
         /* may be bogus socket, but more likely the connection may 
         have closed due to ICMP dest unreachable from other side. */
         return(ECONNREFUSED);
      }

      if (nam == NULL)  /* no sendto() info passed, must be send() */
      {
         if (!(so->so_state & SS_ISCONNECTED))
            return (ENOTCONN);
         fhost = ep->ipr_faddr;
      }
      else 
      {
         if (so->so_state & SS_ISCONNECTED)
            return (EISCONN);
         if (nam->m_len != sizeof (*sin))
         {
            dtrap();
            return (EINVAL);
         }
         sin = mtod(nam, struct sockaddr_in *);
         fhost = sin->sin_addr.s_addr;
      }

      /* since our pkt->nb_buff size is tied to max packet size, we 
       * assume our raw IP datagrams are always in one mbuf and that the 
       * mbuf -- but check anyway
       */
      if (m->m_len > (unsigned)ip_raw_maxalloc(so->so_options & SO_HDRINCL))
      {
         dtrap(); /* should never happen */
         return EMSGSIZE;  /* try to recover */
      }
      /* get a packet buffer for send */
      pkt = ip_raw_alloc(m->m_len, so->so_options & SO_HDRINCL);
      if (!pkt)
      {
         m_free(m);
         return ENOBUFS;   /* report buffer shortages */
      }
      MEMCPY(pkt->nb_prot, m->m_data, m->m_len);
      pkt->nb_plen = m->m_len;
      /* finished with mbuf, free it now */
      m_free(m);
      pkt->fhost = fhost;

      /* if we're being asked to send to 255.255.255.255 (a local-net
       * broadcast), figure out which interface to send the broadcast
       * on, based on the IP address that the socket is bound to: if
       * it has been bound to an interface address, we should send the
       * broadcast on that interface; else, we look for the first
       * interface that can support broadcasts and is up; if we still
       * don't have an interface we look for the first interface that
       * is up; if (after all that) we don't have an interface then we
       * fail with error EADDRNOTAVAIL; and finally, if we're built
       * for a single-homed configuration where there's only one
       * interface, we might as well use it, so we do.  
       */
      if (fhost == 0xffffffff)
      {
#ifdef MULTI_HOMED
         if (ep->ipr_laddr != 0L)
         {
            for (ifp = (NET)(netlist.q_head); ifp; ifp = ifp->n_next)
               if (ifp->n_ipaddr == ep->ipr_laddr)
                  break;
         }
         else {
            for (ifp = (NET)(netlist.q_head); ifp; ifp = ifp->n_next)
               if ((ifp->n_flags & NF_BCAST) &&
                   (ifp->n_mib) && (ifp->n_mib->ifAdminStatus == NI_UP))
                  break;
         }
         if (ifp == NULL)
         {
            for (ifp = (NET)(netlist.q_head); ifp; ifp = ifp->n_next)
               if ((ifp->n_mib) && (ifp->n_mib->ifAdminStatus == NI_UP))
                  break;
            if (ifp == NULL)
               return(EADDRNOTAVAIL);
         }
         pkt->net = ifp;
#else  /* single-homed */
         pkt->net = (NET)(netlist.q_head);
#endif /* MULTI_HOMED */
      }

#ifdef IP_MULTICAST

      /* If the socket has an IP moptions structure for multicast options,
       * place a pointer to this structure in the PACKET structure.
       */
      if (so->inp_moptions)
         pkt->imo = so->inp_moptions;

#endif   /* IP_MULTICAST */

      if (so->so_options & SO_HDRINCL)
      {
         UNLOCK_NET_RESOURCE(NET_RESID);
         e = ip_raw_write(pkt);
         LOCK_NET_RESOURCE(NET_RESID);
      }
      else
      {
         pip = (struct ip *)(pkt->nb_prot - IPHSIZ);
         if (ep->ipr_laddr)
            pip->ip_src = ep->ipr_laddr;
         else
         {
            if (fhost == 0xffffffff)
               pip->ip_src = pkt->net->n_ipaddr;
            else
               pip->ip_src = ip_mymach(fhost);
         }
         pip->ip_dest = fhost;
         UNLOCK_NET_RESOURCE(NET_RESID);
         e = ip_write(ep->ipr_prot, pkt);
         LOCK_NET_RESOURCE(NET_RESID);
      }         
      if (e < 0) 
         return(e);
      return 0;
   case PRU_SOCKADDR:
      /* fall through to share PRU_PEERADDR prefix */
   case PRU_PEERADDR:
      if (nam == NULL)
         return(EINVAL);
      sin = mtod(nam, struct sockaddr_in *);
      if (sin == NULL)
         return(EINVAL);
      ep = rawip_lookup(so);
      if (!ep)
         return(EINVAL);
      sin->sin_port = 0;
      nam->m_len = sizeof(*sin);
      if (req == PRU_SOCKADDR)
      {
         sin->sin_addr.s_addr = ep->ipr_laddr;
      }
      else /* PRU_PEERADDR */
      {
         sin->sin_addr.s_addr = ep->ipr_faddr;
      }
      return 0;
   case PRU_DISCONNECT:
   case PRU_RCVD:
      dtrap();
      return 0;
   case PRU_LISTEN:     /* don't support these for raw IP */
   case PRU_ACCEPT:
   default:
      return EOPNOTSUPP;
   }
}
Exemplo n.º 16
0
int
ip_output(struct mbuf * data, struct   ip_socopts * so_optsPack) /* mbuf chain with data to send */
{
   struct ip * bip;
   struct tcphdr *   tcpp;
   PACKET pkt;
   struct mbuf *  m1, * m2, * mtmp; /* temp mbuf pointers */
   int   e;    /* error holder */
   int   total;

   /* reassemble mbufs into a contiguous packet. Do this with as 
    * little copying as possible. Typically the mbufs will be either 
    * 1) a single mbuf with iptcp header info only (e.g.tcp ACK 
    * packet), or 2) iptcp header with data mbuf chained to it, or 3) 
    * #2) with a tiny option data mbuf between header and data. 
    */
   if ((data->m_next))
   {
      m1 = data;
      m2 = data->m_next;

      /* If m2 is small (e.g. options), copy it to m1 and free it */
      while (m2 && (m2->m_len < 10))
      {
         pkt = m1->pkt;
         if ((pkt->nb_buff + pkt->nb_blen) > /* make sure m2 will fit in m1 */
             (m1->m_data + m1->m_len + m2->m_len))
         {
            MEMCPY((m1->m_data + m1->m_len), m2->m_data, m2->m_len);
            m1->m_len += m2->m_len;
            m1->m_next = m2->m_next;
            m_free(m2);    /* free this m2.... */
            m2 = m1->m_next;  /* ...and thread the next one */
            tcpstat.tcps_oappends++;
         }
         else     /* if won't fit, fall to next copy */
            break;
      }

      while (m2)  /* If we still have two or more buffers, more copying: */
      {
         /* try prepending m1 to m2, first see if it fits: */
         e = m2->m_data - m2->pkt->nb_buff;  /* e is prepend space */
         if (e < MaxLnh)
         { 
#ifdef NPDEBUG
            dprintf("nptcp: MaxLnh:%d, e:%d\n", MaxLnh, e);
#endif
            panic("tcp_out:mbuf-nbuf");   /* sanity check */
         }

         if ((m1->m_len < (unsigned)(e - MaxLnh))  /* leave room for MAC */
             && ((m1->m_len & (ALIGN_TYPE - 1)) == 0)  /* and stay aligned */
             && ((m2->m_data - m2->pkt->nb_buff) == HDRSLEN))   /* be at start */
         {
            MEMCPY((m2->m_data - m1->m_len), m1->m_data, m1->m_len);
            m2->m_data -= m1->m_len;   /* fix target to reflect prepend */
            m2->m_len += m1->m_len;
            m_free(m1);    /* free head (copied) mbuf */
            data = m1 = m2;   /* move other mbufs up the chain */
            m2 = m2->m_next;  /* loop to while(m2) test */
            tcpstat.tcps_oprepends++;
         }
         else     /* if won't fit, fall to next copy */
            break;
      }

      if (m2)  /* If all else fails, brute force copy: */
      {
         total = 0;
         for (mtmp = m1; mtmp; mtmp = mtmp->m_next)
            total += mtmp->m_len;
         LOCK_NET_RESOURCE(FREEQ_RESID);
         pkt = pk_alloc(total + HDRSLEN);
         UNLOCK_NET_RESOURCE(FREEQ_RESID);
         if (!pkt)
            return ENOBUFS;
         pkt->nb_prot = pkt->nb_buff + MaxLnh;

         mtmp = m1;
         while (mtmp)
         {
            MEMCPY(pkt->nb_prot, mtmp->m_data, mtmp->m_len);
            pkt->nb_prot += mtmp->m_len;
            pkt->nb_plen += mtmp->m_len;
            m2 = mtmp;
            mtmp = mtmp->m_next;
            if (m2 != data)   /* save original head */
               m_free(m2);
            tcpstat.tcps_ocopies++;
         }
         pkt->nb_prot -= total;     /* fix data pointer */

         /* release the original mbufs packet install the new one */
         LOCK_NET_RESOURCE(FREEQ_RESID);
         pk_free(data->pkt);
         UNLOCK_NET_RESOURCE(FREEQ_RESID);
         data->pkt = pkt;
         data->m_len = pkt->nb_plen;
         data->m_next = NULL;
         data->m_data = pkt->nb_prot;
         data->m_len = total;
      }
   }

   if ((data->m_data < (data->pkt->nb_buff + MaxLnh)))
      panic("ip_output: overflow");

   pkt = data->pkt;

   /* do we have options? */
   if (so_optsPack)
	   pkt->soxopts = so_optsPack;   /* yup */
#ifdef IP6_ROUTING
   else
   {
      panic("ip_output: no so_optsPack for the IPv6 scope");     
   }
#endif

   /* fill in dest host for IP layer */
   bip = (struct ip *)data->m_data;
   pkt->fhost = bip->ip_dest;

   /* make enough IP header for cksum calculation */
   bip->ip_ver_ihl = 0x45;
   bip->ip_len = htons(bip->ip_len);   /* make net endian for calculation */
   tcpp = (struct tcphdr *)ip_data(bip);
#ifdef CSUM_DEMO
   if (!(tcpp->th_flags & TH_SYN))
   tcpp->th_flags |= TH_PUSH;     /* force the PSH flag in TCP hdr */
#endif
   tcpp->th_sum = tcp_cksum(bip);

   pkt->nb_prot = (char*)(bip + 1);    /* point past IP header */
   pkt->nb_plen = data->m_len - sizeof(struct ip);

   e = ip_write(IPPROTO_TCP, pkt);

   /* ip_write() is now responsable for data->pkt, so... */
   data->pkt = NULL;
   m_freem(data);

   if (e < 0)
   {
      /* don't report dropped sends, it causes socket applications to 
      bail when a TCP retry will fix the problem */
      if (e == SEND_DROPPED)
         return 0;
      return e;
   }
   else
      return 0;
}
Exemplo n.º 17
0
int
rawip_soinput(PACKET pkt, void * so_ptr)
{
   struct mbuf *  m_in;    /* packet/data mbuf */
   struct socket *   so =  (struct  socket *)so_ptr;
   struct sockaddr_in   sin;

   LOCK_NET_RESOURCE(NET_RESID); 

   /* make sure we're not flooding input buffers */
   if ((so->so_rcv.sb_cc + pkt->nb_plen) >= so->so_rcv.sb_hiwat)
   {
      UNLOCK_NET_RESOURCE(NET_RESID);
      return ENOBUFS;
   }

   /* alloc mbuf for received data */
   m_in = m_getnbuf(MT_RXDATA, 0);
   if (!m_in)
   {
      UNLOCK_NET_RESOURCE(NET_RESID);
      return ENOBUFS;
   }

   /* set data mbuf to point to start of IP header */
   m_in->pkt = pkt;
   m_in->m_base = pkt->nb_buff;
   m_in->m_memsz = pkt->nb_blen;
   m_in->m_data = pkt->nb_prot;
   m_in->m_len = pkt->nb_plen;

   /* if this socket doesn't have IP_HDRINCL set, adjust the
    * mbuf to skip past the IP header
    */
   if (!(so->so_options & SO_HDRINCL))
   {
      unsigned int ihl = 
         (((struct ip *)(pkt->nb_prot))->ip_ver_ihl & 0x0f) << 2;
      m_in->m_data += ihl;
      m_in->m_len -= ihl;
   }

   /* fill in net address info for pass to socket append()ers */
   sin.sin_addr.s_addr = pkt->fhost;
   sin.sin_port = 0;
   sin.sin_family = AF_INET;

   /* attempt to append address information to mbuf */
   if (!sbappendaddr(&so->so_rcv, (struct sockaddr *)&sin, m_in))
   {
      /* set the pkt field in the mbuf to NULL so m_free() below wont 
       * free the packet buffer, because that is left to the 
       * underlying stack
       */
      m_in->pkt = NULL;
      /* free only the mbuf itself */
      m_free(m_in);
      /* return error condition so caller can free the packet buffer */
      UNLOCK_NET_RESOURCE(NET_RESID);
      return ENOBUFS;
   }

   tcp_wakeup(&so->so_rcv);   /* wake anyone waiting for this */

   sorwakeup(so);    /* wake up selects too */

   UNLOCK_NET_RESOURCE(NET_RESID);
   return 0;
}
Exemplo n.º 18
0
PACKET pk_alloc_heapbuf (unsigned len)
{
   u_long increment;
   u_char limit_exceeded = PKTALLOC_FALSE;
   PACKET p;
   u_char num_guard_bytes;
#ifdef HEAPBUFS_DEBUG
   PHLEP phlep;
#endif
#ifdef NPDEBUG
   u_char i;
   char * bufp;
#endif

   /* check to see if the caller is requesting more than the maximum 
    * allowed individual allocation */
   if (len > MAX_INDIVIDUAL_HEAP_ALLOC)
   {
      INCR_SHARED_VAR (hbufstats, TOOBIG_ALLOC_ERR, 1);
      return(NULL);
   }

#ifdef NPDEBUG
   num_guard_bytes = ALIGN_TYPE + 1;
#else
   num_guard_bytes = 0;
#endif

   /* check to make sure that this allocation will not cause us to
    * exceed the maximum total allocation allowed from the heap.  First
    * compute the increment. */
   increment = sizeof (struct netbuf) + (len + num_guard_bytes);
#ifdef HEAPBUFS_DEBUG
   /* also account for the size of the debug structure if HEAPBUFS_DEBUG
    * is enabled */
   increment += sizeof (PHLE);
#endif
   ENTER_CRIT_SECTION(&heap_curr_mem);
   heap_curr_mem += increment;
   if (heap_curr_mem > MAX_TOTAL_HEAP_ALLOC)
   {
      limit_exceeded = PKTALLOC_TRUE;
   }
   EXIT_CRIT_SECTION(&heap_curr_mem);
   if (limit_exceeded)
   {
      INCR_SHARED_VAR (hbufstats, LIMIT_EXCEEDED_ERR, 1);
      DECR_SHARED_VAR (heap_curr_mem, increment);
      return(NULL);
   }

   if (heap_type == HEAP_ACCESS_BLOCKING) UNLOCK_NET_RESOURCE (FREEQ_RESID);
      
   /* attempt to allocate a buffer for struct netbuf from the heap */
   if ((p = ((struct netbuf *) HB_ALLOC (sizeof (struct netbuf)))) == 0)
   {
      /* restore state that existed prior to call into pk_alloc () */
      if (heap_type == HEAP_ACCESS_BLOCKING) LOCK_NET_RESOURCE (FREEQ_RESID);
      INCR_SHARED_VAR (hbufstats, NB_ALLOCFAIL_ERR, 1);
      DECR_SHARED_VAR (heap_curr_mem, increment);
      return(NULL);
   }
   /* attempt to allocate data buffer from heap */
   if ((p->nb_buff = HB_ALLOC (len + num_guard_bytes)) == 0)
   {
      HB_FREE (p);
      if (heap_type == HEAP_ACCESS_BLOCKING) LOCK_NET_RESOURCE (FREEQ_RESID);
      INCR_SHARED_VAR (hbufstats, DB_ALLOCFAIL_ERR, 1);
      DECR_SHARED_VAR (heap_curr_mem, increment);
      return(NULL);
   }
#ifdef HEAPBUFS_DEBUG
   /* obtain storage for private heapbuf list element to help keep track of the heapbuf allocation */
   if ((phlep = ((PHLEP) HB_ALLOC (sizeof(PHLE)))) == 0)
   {
      HB_FREE (p->nb_buff);
      HB_FREE (p);
      if (heap_type == HEAP_ACCESS_BLOCKING) LOCK_NET_RESOURCE (FREEQ_RESID);
      INCR_SHARED_VAR (hbufstats, PHLEB_ALLOCFAIL_ERR, 1);
      DECR_SHARED_VAR (heap_curr_mem, increment);
      return(NULL);
   }
   else
   {
      phlep->netbufp = p;
      phlep->databufp = p->nb_buff;
      phlep->length = len + num_guard_bytes;
   }
#endif

   p->next = 0;
   p->nb_tstamp = 0L;
   /* mark buffer as being from heap and not interrupt-safe */
   p->flags = (PKF_HEAPBUF | PKF_INTRUNSAFE);
#ifdef NPDEBUG
   /* Add memory markers at start and end of block (to help detect memory corruption) */
   bufp = p->nb_buff;
   for (i = 0; i < ALIGN_TYPE; i++)
       *(bufp + i) = 'M';
   *(bufp + len + ALIGN_TYPE) = 'M';
   p->nb_buff += ALIGN_TYPE;   /* increment buffer's start pointer past guard band */
#endif
   p->nb_blen = len;

   if (heap_type == HEAP_ACCESS_BLOCKING) LOCK_NET_RESOURCE (FREEQ_RESID);
#ifdef HEAPBUFS_DEBUG
   /* add element describing current allocation into the private heapbuf list.  This
    * manipulation is already protected via ENTER_CRIT_SECTION () and EXIT_CRIT_SECTION
    * macros. */
   q_add(&phlq, (qp)phlep);
#endif
   /* increment the count of successfull allocations */
   INCR_SHARED_VAR (hbufstats, HB_ALLOC_SUCC, 1);

   /* update the high watermark if appropriate */
   ENTER_CRIT_SECTION(&heap_curr_mem);
   if (heap_curr_mem > heap_curr_mem_hi_watermark)
   {
      heap_curr_mem_hi_watermark = heap_curr_mem;
   }
   EXIT_CRIT_SECTION(&heap_curr_mem);

   return p;
}
Exemplo n.º 19
0
long
t_accept(long s, 
   struct sockaddr * addr,
   int * addrlen)
{
#ifdef SOCKDEBUG
   char logbuf[10];
#endif
   struct socket *   so;
   struct mbuf *  nam;

   so = LONG2SO(s);
   SOC_CHECK(so);
   DOMAIN_CHECK(so, *addrlen);

   so->so_error = 0;
   INET_TRACE (INETM_SOCKET,
      ("INET:accept:so %x so_qlen %d so_state %x\n", so, so->so_qlen, so->so_state));
   if ((so->so_options & SO_ACCEPTCONN) == 0)
   {
      so->so_error = EINVAL;
#ifdef SOCKDEBUG
      sprintf(logbuf, "t_accept[%d]: %d", __LINE__, so->so_error);
      glog_with_type(LOG_TYPE_DEBUG, logbuf, 1);
#endif
      return SOCKET_ERROR;
   }
   if ((so->so_state & SS_NBIO) && so->so_qlen == 0)
   {
      so->so_error = EWOULDBLOCK;
#ifdef SOCKDEBUG
      sprintf(logbuf, "t_accept[%d]: %d", __LINE__, so->so_error);
      glog_with_type(LOG_TYPE_DEBUG, logbuf, 1);
#endif
      return SOCKET_ERROR;
   }
   LOCK_NET_RESOURCE(NET_RESID);
   while (so->so_qlen == 0 && so->so_error == 0)
   {
      if (so->so_state & SS_CANTRCVMORE)
      {
         so->so_error = ECONNABORTED;
         UNLOCK_NET_RESOURCE(NET_RESID);
         return SOCKET_ERROR;
      }
      tcp_sleep ((char *)&so->so_timeo);
   }
   if (so->so_error)
   {
#ifdef SOCKDEBUG
      sprintf(logbuf, "t_accept[%d]: %d", __LINE__, so->so_error);
      glog_with_type(LOG_TYPE_DEBUG, logbuf, 1);
#endif
      UNLOCK_NET_RESOURCE(NET_RESID);
      return SOCKET_ERROR;
   }
   nam = m_getwithdata (MT_SONAME, sizeof (struct sockaddr));
   if (nam == NULL) 
   {
      UNLOCK_NET_RESOURCE(NET_RESID);
      so->so_error = ENOMEM;
#ifdef SOCKDEBUG
      sprintf(logbuf, "t_accept[%d]: %d", __LINE__, so->so_error);
      glog_with_type(LOG_TYPE_DEBUG, logbuf, 1);
#endif
      return SOCKET_ERROR;
   }
   { 
      struct socket *aso = so->so_q;
      if (soqremque (aso, 1) == 0)
         panic("accept");
      so = aso;
   }
   (void)soaccept (so, nam);
#ifdef TRACE_DEBUG
   { struct sockaddr_in *sin;
      sin = mtod(nam, struct sockaddr_in *);
      INET_TRACE (INETM_SOCKET, ("INET:accept:done so %lx port %d addr %lx\n",
       so, sin->sin_port, sin->sin_addr.s_addr));
   }
#endif   /* TRACE_INET */
   /* return the addressing info in the passed structure */
   if (addr != NULL)
      MEMCPY(addr, nam->m_data, *addrlen);
   m_freem (nam);
   UNLOCK_NET_RESOURCE(NET_RESID);
   SOC_RANGE(so);
   return SO2LONG(so);
}
Exemplo n.º 20
0
void
pktdemux()
{
   PACKET   pkt;
   NET      ifc;                /* interface packet came from */
   IFMIB    mib;
   int      pkts;
   char *   eth;

   pkts = 0;   /* packets per loop */

   while (rcvdq.q_len)
   {
      /* If we are low on free packets, don't hog CPU cycles */
      if (pkts++ > bigfreeq.q_len)
      {
#ifdef SUPERLOOP
         return;        /* don't hog stack on superloop */
#else    /* SUPERLOOP */
         tk_yield(); /* let application tasks process received packets */
         pkts = 0;   /* reset counter */
#endif   /* SUPERLOOP else */
      }

      /* If we get receive interupt from the net during this
      lock, the MAC driver needs to wait or reschedule */
      LOCK_NET_RESOURCE(RXQ_RESID);
      pkt = (PACKET)q_deq(&rcvdq);
      UNLOCK_NET_RESOURCE(RXQ_RESID);
      if (!pkt) panic("pktdemux: got null pkt");
      ifc = pkt->net;

      mib = ifc->n_mib;
      /* maintain mib stats for unicast and broadcast */
      if (isbcast(ifc, (u_char*)pkt->nb_buff + ETHHDR_BIAS))
         mib->ifInNUcastPkts++;
      else
         mib->ifInUcastPkts++;

      if(mib->ifAdminStatus == NI_DOWN)
      {
         LOCK_NET_RESOURCE(FREEQ_RESID);
         pk_free(pkt);  /* dump packet from downed interface */
         UNLOCK_NET_RESOURCE(FREEQ_RESID);
         mib->ifInDiscards++;
         continue;      /* next packet */
      }

#ifdef NPDEBUG
      if (*(pkt->nb_buff - ALIGN_TYPE) != 'M' ||
          *(pkt->nb_buff + pkt->nb_blen) != 'M')
      {
         dtrap();
         panic("pktdemux: corrupt pkt");
      }
#endif   /* NPDEBUG */

#ifdef  LOSSY_IO
      if(NDEBUG & LOSSY_RX)
      {
         if(myloss())  
         {
            LOCK_NET_RESOURCE(FREEQ_RESID);
            pk_free(pkt);        /* punt packet */
            UNLOCK_NET_RESOURCE(FREEQ_RESID);
            in_lastloss = (int)(cticks & 0x07) - 4;  /* pseudo random reset */
            continue;            /* act as if we sent OK */
         }
      }
#endif   /* LOSSY_IO */

      /* see if driver set pkt->nb_prot and pkt->type */
      if((ifc->n_flags & NF_NBPROT) == 0)
      {
         /* Set pkt->type and pkt->nb_prot based based on media type.
          * Some device drivers pass nb_plen as the total length of the
          * packet, while others subtract the MAC header. The latter is
          * probably the right thing to do, but because of this historic
          * inconsistency we don't try to fix it here - the longer size
          * turns out to be harmless since the IP layer fixes the size
          * based on the IP header length field.
          */
         switch(ifc->n_mib->ifType)
         {
         case ETHERNET:
            /* get pointer to ethernet header */
            eth = (pkt->nb_buff + ETHHDR_BIAS);
#ifdef IEEE_802_3
            /* see if it's got snap baggage */
            if (ET_TYPE_GET(eth) <= 0x0600)
            {
               struct snap_hdr *snap;
               snap = (struct snap_hdr *)(pkt->nb_buff + ETHHDR_SIZE);
               pkt->type = (unshort)(snap->type);
               pkt->nb_prot = pkt->nb_buff + pkt->net->n_lnh;
            }
            else
            {
               pkt->type = htons((unshort)ET_TYPE_GET(eth));
               pkt->nb_prot = pkt->nb_buff + ETHHDR_SIZE;
            }
#else
            pkt->type = htons((unshort)ET_TYPE_GET(eth));
            pkt->nb_prot = pkt->nb_buff + pkt->net->n_lnh;
#endif   /* IEEE_802_3 */
            break;
#if defined(USE_PPP) || defined(USE_SLIP) || defined(PROTOCOL_LIBS)
         case PPP:   /* PPP or SLIP over a UART */
         case SLIP:
            pkt->nb_prot = pkt->nb_buff + MaxLnh;
            pkt->type = IPTP;    /* only type our PPP supports */
            break;
#endif  /* USE_PPP || USE_SLIP */
#ifdef USE_PPPOE
         case PPPOE:
            /* do not change type yet, for PPPoE */
            break;
#endif   /* USE_PPPOE */
         default:    /* driver bug? */
            dprintf("pktdemux: bad Iface type %ld\n",ifc->n_mib->ifType);
            LOCK_NET_RESOURCE(FREEQ_RESID);
            pk_free(pkt);
            UNLOCK_NET_RESOURCE(FREEQ_RESID);
            continue;
         }
      }

      /* pkt->nb_prot and pkt->type are now set. pass pkt to upper layer */
      switch(pkt->type)
      {
      case IPTP:     /* IP type */
         LOCK_NET_RESOURCE(NET_RESID);
#ifdef SHARED_IPADDRS
         add_share_route(pkt);
#endif /* SHARED_IPADDRS */
#ifdef IP_V4
         ip_rcv(pkt);
#else
            /* don't care, it's IPv4 */
            LOCK_NET_RESOURCE(FREEQ_RESID);
            pk_free(pkt);
            UNLOCK_NET_RESOURCE(FREEQ_RESID);
#endif
		UNLOCK_NET_RESOURCE(NET_RESID);
         break;
#ifdef INCLUDE_ARP
      case ARPTP:       /* ARP type */
         LOCK_NET_RESOURCE(NET_RESID);
         arprcv(pkt);
         UNLOCK_NET_RESOURCE(NET_RESID);
         break;
#endif   /* INCLUDE_ARP */
#ifdef USE_PPPOE
      case  htons(0x8863):
      case  htons(0x8864):
         LOCK_NET_RESOURCE(NET_RESID);
         poe_rcv(pkt);
         UNLOCK_NET_RESOURCE(NET_RESID);
         break;
#endif   /* USE_PPPOE */
#ifdef IP_V6
      case  htons(0x86DD):
         /* Each received v6 pkt goes thru here exactly once, so set the
          * outer (first, and usually only) ipv6 header pointer. Tunneled headers
          * may exist further into the packet.
          */
         pkt->ip6_hdr = (struct ipv6 *)pkt->nb_prot;
         LOCK_NET_RESOURCE(NET_RESID);
         ip6_rcv(pkt);
         UNLOCK_NET_RESOURCE(NET_RESID);
         break;
#endif
      default:
#ifdef NPDEBUG
         if (NDEBUG & UPCTRACE)
            dprintf("pktdemux: bad pkt type 0x%04x\n", ntohs(pkt->type));
#endif   /* NPDEBUG */
         ifc->n_mib->ifInUnknownProtos++;
         LOCK_NET_RESOURCE(FREEQ_RESID);
         pk_free(pkt);           /* return to free buffer */
         UNLOCK_NET_RESOURCE(FREEQ_RESID);
         break;
      }
      continue;
   }
}