Example #1
0
File: inLib.c Project: phoboz/vmx
int in_control(struct socket *so,
               unsigned long cmd,
               void *data,
               struct ifnet *ifp)
{
  struct ifreq *ifr;
  struct in_ifaddr *ia, *oia;
  struct ifaddr *ifa;
  struct in_aliasreq *ifra;
  struct sockaddr_in oldaddr;
  int err, newroute, newmask, newhost;
  unsigned long i;

  /* Initialize local */
  ifr = (struct ifreq *) data;
  ia = NULL;
  ifra = (struct in_aliasreq *) data;
  err = 0;
  newroute = 0;

  /* If interface argument sent */
  if (ifp != NULL) {
 
    /* For all interfaces */
    for (ia = in_ifaddr; ia != NULL; ia = ia->ia_next)
      if (ia->ia_ifp == ifp)
        break;

  } /* End if interface argument sent */

  /******************************************/
  /* Select command part1 - Initialize data */
  /******************************************/
  switch(cmd) {

    case SIOCAIFADDR:

      if (ia == NULL)
        newroute = 1;

      /* FALL TRU */

    case SIOCDIFADDR:

      /* If internet family */
      if (ifra->ifra_addr.sin_family == AF_INET) {

        /* For all interface addresses */
        for (oia = ia; ia != NULL; ia = ia->ia_next) {

          if ((ia->ia_ifp == ifp) &&
              (ia->ia_addr.sin_addr.s_addr == ifra->ifra_addr.sin_addr.s_addr))
            break;

        } /* End for all interface addresses */

      } /* End if internet family */

      if ( (cmd == SIOCDIFADDR) && (ia == NULL) )
        return EADDRNOTAVAIL;
 
      /* FALL TRU */

    case SIOCSIFADDR:
    case SIOCSIFNETMASK:
    case SIOCSIFDSTADDR:

      if ( (so->so_state & SS_PRIV) == 0 )
        return EPERM;

      if (ifp == NULL)
        panic("in control");


      /* If need to alloc */
      if (ia == NULL) {

        oia = mb_alloc(sizeof(struct in_ifaddr), MT_IFADDR, M_WAIT);
        if (oia == NULL)
          return ENOBUFS;

      } /* End if need to alloc */

      /* Clear address */
      memset(oia, 0, sizeof(struct in_ifaddr));

      /* Add address to address list */
      ia = in_ifaddr;

      /* If any addresses exists */
      if (ia != NULL) {

        /* Go to end of address list */
        for (; ia->ia_next != NULL; ia = ia->ia_next)
          continue;

        /* Set address */
        ia->ia_next = oia;

      } /* End if any addresses exists */

      /* Else no addresses exists */
      else {

        /* Set address */
        in_ifaddr = oia;

      } /* End else no addresses exists */

      /* Add address to interface address list */
      ia = oia;
      ifa = ifp->if_addrlist;

      /* If any addresses in interface address list */
      if (ifa != NULL) {

        /* Move to last address */
        for ( ; ifa->ifa_next != NULL; ifa = ifa->ifa_next)
          continue;

        /* Set address */
        ifa->ifa_next = (struct ifaddr *) ia;

      } /* End if any addresses in interface address list */

      /* Else no addresses in interface address list */
      else {

        /* Set address */
        ifp->if_addrlist = (struct ifaddr *) ia;

      } /* End else no addresses in interface address list */

      /* Setup address struct */
      ia->ia_ifa.ifa_addr = (struct sockaddr *) &ia->ia_addr;
      ia->ia_ifa.ifa_dstaddr = (struct sockaddr *) &ia->ia_dstaddr;
      ia->ia_ifa.ifa_netmask = (struct sockaddr *) &ia->ia_netmask;
      ia->ia_sockmask.sin_len = 8;

      /* If broadcast available */
      if (ifp->if_flags & IFF_BROADCAST) {

        ia->ia_broadaddr.sin_len = sizeof(struct sockaddr_in);
        ia->ia_broadaddr.sin_family = AF_INET;

      } /* End if broadcast available */

      /* Set interface point in address */
      ia->ia_ifp = ifp;

      if (ifp != loif)
        in_interfaces++;

    break;

    case SIOCSIFBRDADDR:

      if ( (so->so_state & SS_PRIV) == 0 )
        return EPERM;

      /* FALL TRU */

    case SIOCGIFADDR:
    case SIOCGIFNETMASK:
    case SIOCGIFDSTADDR:
    case SIOCGIFBRDADDR:

      if (ia == NULL)
        return EADDRNOTAVAIL;

    break;

  } /* End select command part1 - Initialize data */

  /******************************************/
  /* Select command part2 - Execute command */
  /******************************************/
  switch(cmd) {

    case SIOCGIFADDR:

      /* Get address */
      *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;

    break;

    case SIOCGIFBRDADDR:

      if ( (ifp->if_flags & IFF_BROADCAST) == 0 )
        return EINVAL;

      /* Get address */
      *((struct sockaddr_in *) &ifr->ifr_dstaddr) = ia->ia_broadaddr;

    break;

    case SIOCGIFDSTADDR:

      if ( (ifp->if_flags & IFF_POINTOPOINT) == 0 )
        return EINVAL;

      /* Get address */
      *((struct sockaddr_in *) &ifr->ifr_dstaddr) = ia->ia_dstaddr;

    break;

    case SIOCGIFNETMASK:

      /* Get mask */
      *((struct sockaddr_in *) &ifr->ifr_addr) = ia->ia_sockmask;

    break;

    case SIOCSIFDSTADDR:

      if ( (ifp->if_flags & IFF_POINTOPOINT) == 0 )
        return EINVAL;

      /* Set address */
      oldaddr = ia->ia_dstaddr;
      ia->ia_dstaddr = *(struct sockaddr_in *) &ifr->ifr_dstaddr;

      /* If interface ioctl fails */
      if ( (ifp->if_ioctl != NULL) &&
           (err = ( *ifp->if_ioctl) (ifp, SIOCSIFDSTADDR, ia)) ) {

        ia->ia_dstaddr = oldaddr;
        return err;

      } /* If interface ioctl fails */

      /* If route */
      if (ia->ia_flags & IFA_ROUTE) {

        /* Delete old route */
        ia->ia_ifa.ifa_dstaddr = (struct sockaddr *) &oldaddr;
        rtinit(&(ia->ia_ifa), RTM_DELETE, RTF_HOST);

        /* Add new route */
        ia->ia_ifa.ifa_dstaddr = (struct sockaddr *) &ia->ia_dstaddr;
        rtinit(&(ia->ia_ifa), RTM_ADD, RTF_HOST | RTF_UP);

      } /* If route */

    break;

    case SIOCSIFBRDADDR:

      if ( (ifp->if_flags & IFF_BROADCAST) == 0 )
        return EINVAL;

      /* Set address */
      ia->ia_broadaddr = *(struct sockaddr_in *) &ifr->ifr_broadaddr;

    break;

    case SIOCSIFADDR:

      return in_ifinit(ifp, ia, (struct sockaddr_in *) &ifr->ifr_addr, 1);

    case SIOCSIFNETMASK:

      i = ifra->ifra_addr.sin_addr.s_addr;
      ia->ia_sockmask.sin_addr.s_addr = i;
      ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr);
      in_socktrim(&ia->ia_sockmask);

    break;

    case SIOCAIFADDR:

      newmask = 0;
      newhost = 1;

      /* If inet family */
      if (ia->ia_addr.sin_family == AF_INET) {

        /* If zero length */
        if (ifra->ifra_addr.sin_len == 0) {

          ifra->ifra_addr = ia->ia_addr;
          newhost = 0;

        } /* End if zero length */

        /* Else if address match */
        else if (ifra->ifra_addr.sin_addr.s_addr ==
                 ia->ia_addr.sin_addr.s_addr) {

          newhost = 0;

        } /* End else if address match */

      } /* End if inet family */

      /* If mask length non-zero */
      if (ifra->ifra_mask.sin_len) {

        in_ifscrub(ifp, ia);
        ia->ia_sockmask = ifra->ifra_mask;
        ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr);
        newmask = 1;

      } /* End if mask length non-zero */

      /* If point-to-point and inet */
      if ( (ifp->if_flags & IFF_POINTOPOINT) &&
           (ifra->ifra_dstaddr.sin_family == AF_INET) ) {

        in_ifscrub(ifp, ia);
        ia->ia_dstaddr = ifra->ifra_dstaddr;
        newmask = 1;

      } /* End if point-to-point and inet */

      if ( (ifra->ifra_addr.sin_family == AF_INET) &&
           (newhost || newmask) )
        err = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);

      if ( (err == EEXIST) && !newroute)
        err = 0;

      if ( (ifp->if_flags & IFF_BROADCAST) &&
           (ifra->ifra_broadaddr.sin_family == AF_INET) &&
           (ifra->ifra_broadaddr.sin_addr.s_addr) )
        ia->ia_broadaddr = ifra->ifra_broadaddr;

      return err;

    case SIOCDIFADDR:

      in_ifscrub(ifp, ia);

      /* Get interface address list */
      ifa = ifp->if_addrlist;

      /* If the same address list */
      if (ifa == (struct ifaddr *) ia) {

        ifp->if_addrlist = ifa->ifa_next;

      } /* End if the same address list */

      /* Else not the same address list */
      else {

        /* Move until end or match */
        while ( (ifa->ifa_next != NULL) &&
                (ifa->ifa_next != (struct ifaddr *) ia) )
          ifa = ifa->ifa_next;

        if (ifa->ifa_next != NULL)
          ifa->ifa_next = ((struct ifaddr *) ia)->ifa_next;
        else
          panic("link inifaddr");

      } /* End else not the same address list */

      oia = ia;
      ia = in_ifaddr;

      /* If old is first element */
      if (oia == ia) {

        in_ifaddr = ia->ia_next;

      } /* End if old is first element */

      /* Else old is not first element */
      else {

        /* Move until end or match */
        while ( (ia->ia_next != NULL) &&
                (ia->ia_next != oia) )
          ia = ia->ia_next;

        if (ia->ia_next != NULL)
          ia->ia_next = oia->ia_next;
        else
          panic("unlink inifaddr");

      } /* End else old is not first element */

      IFAFREE(&oia->ia_ifa);

    break;

    default:

      if ( (ifp == NULL) || (ifp->if_ioctl == NULL) )
        return EOPNOTSUPP;

      return ( *ifp->if_ioctl) (ifp, cmd, data);

  } /* End select command part2 - Execute command */

  return 0;
}
Example #2
0
ROUTE_ENTRY * routeLookup
    (
    struct sockaddr * pDest, 	/* IP address reachable with matching route */
    ULONG * pMask, 		/* netmask value, in network byte order */
    int	protoId 		/* route source from m2Lib.h, or 0 for any. */
    )
    {
    struct radix_node_head * pHead = rt_tables[pDest->sa_family];

    struct radix_node * pNode;        /* radix tree entry for route */
    struct rtentry * pRoute = NULL;   /* candidate for matching route */
    ROUTE_ENTRY * pMatch = NULL;      /* matching route entry */

    struct sockaddr_in netmask;       /* netmask value, internal format */
    char * pNetmask = NULL;           /* target netmask value from tree */

    struct rtentry * pNextRoute;

    STATUS result = ERROR;            /* OK indicates a successful search */
    int  s;

    if (pHead == NULL)
        {
        /* No route table exists for the given address family. */

        return (NULL);
        }

    bzero ( (char *)&netmask, sizeof (struct sockaddr_in));

    s = splnet ();

    /*
     * If a specific netmask match is required, find the target value
     * (a pointer to the stored netmask entry) which will determine
     * whether the match exists. A mask value of zero indicates a
     * host-specific route, which does not contain a netmask entry.
     */

    if (pMask && *pMask)
        {
        /* Setup data structure to search mask's tree for given value. */

        netmask.sin_family = AF_INET;
        netmask.sin_len = sizeof (struct sockaddr_in);
        netmask.sin_addr.s_addr = *pMask;

        TOS_SET (&netmask, 0x1f);

        in_socktrim (&netmask);    /* Adjust length field for tree search. */

        /* Search for netmask from corresponding tree. */

        pNode = rn_addmask (&netmask, 1, pHead->rnh_treetop->rn_off);
        if (pNode == 0)
            {
            /* No route currently uses the specified netmask. */

#ifdef DEBUG
            logMsg ("routeLookup: requested mask does not exist.\n",
                    0, 0, 0, 0, 0, 0);
#endif
            splx(s);
            return (NULL);
            }

        pNetmask = pNode->rn_key;
        }

    pNode = pHead->rnh_matchaddr ((caddr_t)pDest, pHead);
    if (pNode && ((pNode->rn_flags & RNF_ROOT) == 0))
        {
        /* Possible match found. Save for later use. */

        pRoute = (struct rtentry *)pNode;
        }
    else
        {
        /* No route matches the given key. */

        splx (s);
        return (NULL);
        }

#ifdef DEBUG
    logMsg ("routeLookup: candidate for match at %p.\n", pNode,
            0, 0, 0, 0, 0);
#endif

    /*
     * Compare the set of routes available with the initial key
     * against the desired values. Each entry in the chain of
     * routes with duplicate keys uses a different netmask value.
     *
     * NOTE: The pNode value is not necessarily the start of the
     * chain. It is the first entry in the chain with a short
     * enough netmask to produce a match against the destination.
     */

    for ( ; pRoute != NULL; pRoute = pNextRoute)
        {
        /* Select the next route candidate in case a test fails. */

        pNextRoute = (struct rtentry *)
                           ((struct radix_node *)pRoute)->rn_dupedkey;

        if (pMask)
            {
            /*
             * Check mask of route against corresponding entry from
             * the stored netmasks (derived from the given value).
             */

#ifdef DEBUG
            logMsg ("routeLookup: checking against specific mask.\n",
                    0, 0, 0, 0, 0, 0);
#endif

            if (*pMask)
                {
                if ( ((struct radix_node *)pRoute)->rn_mask != pNetmask)
                    continue;   /* Mask values do not match. */
                }
            else if ( ( (struct sockaddr_in *)pDest)->sin_addr.s_addr)
                {
                /* Searching for a host-specific route (no netmask entry). */

                if ( ((struct radix_node *)pRoute)->rn_mask != 0)
                    continue;   /* Entry is not a host route. */
                }
            }

        /*
         * Candidate passed any mask requirements. Search for entries
         * which match the specified route source.
         */

#ifdef DEBUG
        logMsg ("routeLookup: Current mask is OK.\n", 0, 0, 0, 0, 0, 0);
#endif

        if (protoId)
            {
            /* Check source of route against specified value. */

#ifdef DEBUG
            logMsg ("routeLookup: testing protocol ID.\n",
                    0, 0, 0, 0, 0, 0);
#endif

            for (pMatch = (ROUTE_ENTRY *)pRoute; pMatch != NULL;
                   pMatch = pMatch->diffNode.pFrwd)
                {
                if (RT_PROTO_GET(ROUTE_ENTRY_KEY(pMatch)) == protoId)
                    break;
                }

            if (pMatch == NULL)   /* Route protocol values do not match. */
                continue;

#ifdef DEBUG
            logMsg ("routeLookup: Current protocol ID is OK.\n",
                    0, 0, 0, 0, 0, 0);
#endif
            }
        else
            {
            /*
             * No route source is specified. Accept the entry
             * which met any mask criteria.
             */

            pMatch = (ROUTE_ENTRY *)pRoute;
            }
 
        /* The candidate route entry met all criteria. Stop the search. */

        result = OK;
        break;
        }

    if (result == OK)
        {
        /* Increase the reference count before returning the matching entry. */

        pMatch->rtEntry.rt_refcnt++;
        }
    else
        pMatch = NULL;

    splx (s);

    return (pMatch);
    }
Example #3
0
File: inLib.c Project: phoboz/vmx
int in_ifinit(struct ifnet *ifp,
              struct in_ifaddr *ia,
              struct sockaddr_in *sin,
              int scrub)
{
  int s, flags, err;
  unsigned long i;
  struct sockaddr_in oldaddr;

  /* Initialize locals */
  err = 0;
  i = ntohl(sin->sin_addr.s_addr);
  flags = RTF_UP;

  /* Get processor level */
  s = splimp();

  /* Store old address */
  oldaddr = ia->ia_addr;

  /* Set new address */
  ia->ia_addr = *sin;

  /* If ioctl function */
  if (ifp->if_ioctl != NULL) {

    /* Initialize interface */
    err = ( *ifp->if_ioctl) (ifp, SIOCSIFADDR, ia);
    if (err) {

      splx(s);
      ia->ia_addr = oldaddr;
      return err;

    }

  } /* End if ioctl function */

  /* Restore processor level */
  splx(s);

  /* If scrub requested */
  if (scrub) {

    ia->ia_ifa.ifa_addr = (struct sockaddr *) &oldaddr;
    in_ifscrub(ifp, ia);
    ia->ia_ifa.ifa_addr = (struct sockaddr *) &ia->ia_addr;

  } /* End if scrub requested */

  /* Setup netmask */
  if ( IN_CLASSA(i) )
    ia->ia_netmask = IN_CLASSA_NET;
  else if ( IN_CLASSB(i) )
    ia->ia_netmask = IN_CLASSB_NET;
  else
    ia->ia_netmask = IN_CLASSC_NET;

  /* If subnet mask zero */
  if (ia->ia_subnetmask == 0) {

    ia->ia_subnetmask = ia->ia_netmask;
    ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);

  } /* End if subnet mask zero */

  /* Else subnet mask non-zero */
  else {

    ia->ia_netmask &= ia->ia_subnetmask;

  } /* End else subnet mask non-zero */

  /* Set net */
  ia->ia_net = i & ia->ia_netmask;
  ia->ia_subnet = i & ia->ia_subnetmask;
  in_socktrim(&ia->ia_sockmask);

  /* Add route for network */
  ia->ia_ifa.ifa_metric = ifp->if_metric;

  /* If broadcast */
  if (ifp->if_flags & IFF_BROADCAST) {

    ia->ia_broadaddr.sin_addr.s_addr =
        htonl(ia->ia_subnet | ~ia->ia_subnetmask);

    ia->ia_netbroadcast.s_addr =
        htonl(ia->ia_net | ~ia->ia_netmask);

  } /* End if broadcast */

  /* Else if loopback */
  else if (ifp->if_flags & IFF_LOOPBACK) {

    ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
    flags |= RTF_HOST;

  } /* End else if loopback */

  /* Else if pointopoint */
  else if (ifp->if_flags & IFF_POINTOPOINT) {

    if (ia->ia_dstaddr.sin_family != AF_INET)
      return 0;

    flags |= RTF_HOST;

  } /* End else if pointopoint */

  /* Initialize route */
  err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
  if (err == 0)
    ia->ia_flags |= IFA_ROUTE;

  return err;
}