예제 #1
0
struct iob_s *ieee80211_encrypt(struct ieee80211_s *ic, struct iob_s *iob0,
                                struct ieee80211_key *k)
{
  switch (k->k_cipher)
    {
    case IEEE80211_CIPHER_WEP40:
    case IEEE80211_CIPHER_WEP104:
      iob0 = ieee80211_wep_encrypt(ic, iob0, k);
      break;
    case IEEE80211_CIPHER_TKIP:
      iob0 = ieee80211_tkip_encrypt(ic, iob0, k);
      break;
    case IEEE80211_CIPHER_CCMP:
      iob0 = ieee80211_ccmp_encrypt(ic, iob0, k);
      break;
    case IEEE80211_CIPHER_BIP:
      iob0 = ieee80211_bip_encap(ic, iob0, k);
      break;
    default:
      /* Should not get there */

      iob_free_chain(iob0);
      iob0 = NULL;
    }

  return iob0;
}
예제 #2
0
uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer,
                         uint16_t buflen)
{
  FAR struct iob_s *iob;
  int ret;

  /* Try to allocate on I/O buffer to start the chain without waiting (and
   * throttling as necessary).  If we would have to wait, then drop the
   * packet.
   */

  iob = iob_tryalloc(true);
  if (iob == NULL)
    {
      nlldbg("ERROR: Failed to create new I/O buffer chain\n");
      return 0;
    }

  /* Copy the new appdata into the I/O buffer chain (without waiting) */

  ret = iob_trycopyin(iob, buffer, buflen, 0, true);
  if (ret < 0)
    {
      /* On a failure, iob_copyin return a negated error value but does
       * not free any I/O buffers.
       */

      nlldbg("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
      (void)iob_free_chain(iob);
      return 0;
    }

  /* Add the new I/O buffer chain to the tail of the read-ahead queue (again
   * without waiting).
   */

  ret = iob_tryadd_queue(iob, &conn->readahead);
  if (ret < 0)
    {
      nlldbg("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
      (void)iob_free_chain(iob);
      return 0;
    }

  nllvdbg("Buffered %d bytes\n", buflen);
  return buflen;
}
예제 #3
0
void tcp_wrbuffer_release(FAR struct tcp_wrbuffer_s *wrb)
{
  DEBUGASSERT(wrb && wrb->wb_iob);

  /* To avoid deadlocks, we must following this ordering:  Release the I/O
   * buffer chain first, then the write buffer structure.
   */

  iob_free_chain(wrb->wb_iob);

  /* Then free the write buffer structure */

  sq_addlast(&wrb->wb_node, &g_wrbuffer.freebuffers);
  sem_post(&g_wrbuffer.sem);
}
예제 #4
0
struct iob_s *ieee80211_decrypt(FAR struct ieee80211_s *ic,
                                FAR struct iob_s *iob0,
                                struct ieee80211_node *ni)
{
  FAR struct ieee80211_frame *wh;
  FAR struct ieee80211_key *k;
  FAR uint8_t *ivp;
  FAR uint8_t *mmie;
  uint16_t kid;
  int hdrlen;

  /* Find key for decryption */

  wh = (FAR struct ieee80211_frame *)IOB_DATA(iob0);
  if ((ic->ic_flags & IEEE80211_F_RSNON) &&
      !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
      ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP)
    {
      k = &ni->ni_pairwise_key;

    }
  else if (!IEEE80211_IS_MULTICAST(wh->i_addr1) ||
           (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
    {
      /* Retrieve group data key id from IV field */

      hdrlen = ieee80211_get_hdrlen(wh);

      /* Check that IV field is present */

      if (iob0->io_len < hdrlen + 4)
        {
          iob_free_chain(iob0);
          return NULL;
        }

      ivp = (uint8_t *) wh + hdrlen;
      kid = ivp[3] >> 6;
      k = &ic->ic_nw_keys[kid];
    }
예제 #5
0
int ieee80211_output(FAR struct ieee80211_s *ic, FAR struct iob_s *iob,
                     FAR struct sockaddr *dst, uint8_t flags)
{
  FAR struct uip_driver_s *dev;
  FAR struct ieee80211_frame *wh;
  FAR struct m_tag *mtag;
  uip_lock_t flags;
  int error = 0;

  /* Get the driver structure */

  dev = netdev_findbyaddr(ic->ic_ifname);
  if (!dev)
    {
      error = -ENODEV;
      goto bad;
    }

  /* Interface has to be up and running */

  if ((dev->d_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
    {
      error = -ENETDOWN;
      goto bad;
    }

  /* Try to get the DLT from a buffer tag */

  if ((mtag = m_tag_find(iob, PACKET_TAG_DLT, NULL)) != NULL)
    {
      unsigned int dlt = *(unsigned int *)(mtag + 1);

      /* Fallback to Ethernet for non-802.11 linktypes */

      if (!(dlt == DLT_IEEE802_11 || dlt == DLT_IEEE802_11_RADIO))
        {
          goto fallback;
        }

      if (iob->io_pktlen < sizeof(struct ieee80211_frame_min))
        {
          return -EINVAL;
        }

      wh = (FAR struct ieee80211_frame *)IOB_DATA(iob);
      if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != IEEE80211_FC0_VERSION_0)
        {
          return -EINVAL;
        }

      if (!(ic->ic_caps & IEEE80211_C_RAWCTL) &&
          (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
        {
          return -EINVAL;
        }

      /* Queue message on interface without adding any further headers, and
       * start output if interface not yet active.
       */

      flags = uip_lock();
      error = ieee80211_ifsend(ic, iob, flags);
      if (error)
        {
          /* buffer is already freed */

          uip_unlock(flags);
          ndbg("ERROR: %s: failed to queue raw tx frame\n", ic->ic_ifname);
          return error;
        }

      uip_unlock(flags);
      return error;
    }

fallback:
  return ether_output(ic, iob, dst);

bad:
  if (iob)
    {
      iob_free_chain(iob);
    }

  return error;
}
예제 #6
0
파일: udp_callback.c 프로젝트: dagar/NuttX
static uint16_t udp_datahandler(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn,
                                FAR uint8_t *buffer, uint16_t buflen)
{
  FAR struct iob_s *iob;
  int ret;
#ifdef CONFIG_NET_IPv6
  FAR struct sockaddr_in6 src_addr6;
#endif
#ifdef CONFIG_NET_IPv4
  FAR struct sockaddr_in src_addr4;
#endif
  FAR void  *src_addr;
  uint8_t src_addr_size;

  /* Allocate on I/O buffer to start the chain (throttling as necessary).
   * We will not wait for an I/O buffer to become available in this context.
   */

  iob = iob_tryalloc(true);
  if (iob == NULL)
    {
      nerr("ERROR: Failed to create new I/O buffer chain\n");
      return 0;
    }

#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
  if (IFF_IS_IPv6(dev->d_flags))
#endif
    {
      FAR struct udp_hdr_s *udp   = UDPIPv6BUF;
      FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;

      src_addr6.sin6_family = AF_INET6;
      src_addr6.sin6_port   = udp->srcport;

      net_ipv6addr_copy(src_addr6.sin6_addr.s6_addr, ipv6->srcipaddr);

      src_addr_size = sizeof(src_addr6);
      src_addr = &src_addr6;
    }
#endif /* CONFIG_NET_IPv6 */

#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
  else
#endif
    {
#ifdef CONFIG_NET_IPv6
      /* Hybrid dual-stack IPv6/IPv4 implementations recognize a special
       * class of addresses, the IPv4-mapped IPv6 addresses.
       */

      if (conn->domain == PF_INET6)
        {
          FAR struct udp_hdr_s *udp   = UDPIPv6BUF;
          FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
          in_addr_t ipv4addr;

          /* Encode the IPv4 address as an IPv-mapped IPv6 address */

          src_addr6.sin6_family = AF_INET6;
          src_addr6.sin6_port = udp->srcport;

          ipv4addr = net_ip4addr_conv32(ipv6->srcipaddr);
          ip6_map_ipv4addr(ipv4addr, src_addr6.sin6_addr.s6_addr16);

          src_addr_size = sizeof(src_addr6);
          src_addr = &src_addr6;
        }
      else
#endif
        {
          FAR struct udp_hdr_s *udp   = UDPIPv4BUF;
          FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;

          src_addr4.sin_family = AF_INET;
          src_addr4.sin_port   = udp->srcport;

          net_ipv4addr_copy(src_addr4.sin_addr.s_addr,
                            net_ip4addr_conv32(ipv4->srcipaddr));

          src_addr_size = sizeof(src_addr4);
          src_addr = &src_addr4;
        }
    }
#endif /* CONFIG_NET_IPv4 */

  /* Copy the src address info into the I/O buffer chain.  We will not wait
   * for an I/O buffer to become available in this context.  It there is
   * any failure to allocated, the entire I/O buffer chain will be discarded.
   */

  ret = iob_trycopyin(iob, (FAR const uint8_t *)&src_addr_size,
                      sizeof(uint8_t), 0, true);
  if (ret < 0)
    {
      /* On a failure, iob_trycopyin return a negated error value but does
       * not free any I/O buffers.
       */

      nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
      (void)iob_free_chain(iob);
      return 0;
    }

  ret = iob_trycopyin(iob, (FAR const uint8_t *)src_addr, src_addr_size,
                      sizeof(uint8_t), true);
  if (ret < 0)
    {
      /* On a failure, iob_trycopyin return a negated error value but does
       * not free any I/O buffers.
       */

      nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
      (void)iob_free_chain(iob);
      return 0;
    }

  if (buflen > 0)
    {
      /* Copy the new appdata into the I/O buffer chain */

      ret = iob_trycopyin(iob, buffer, buflen,
                          src_addr_size + sizeof(uint8_t), true);
      if (ret < 0)
        {
          /* On a failure, iob_trycopyin return a negated error value but
           * does not free any I/O buffers.
           */

          nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n",
               ret);
          (void)iob_free_chain(iob);
          return 0;
        }
    }

  /* Add the new I/O buffer chain to the tail of the read-ahead queue */

  ret = iob_tryadd_queue(iob, &conn->readahead);
  if (ret < 0)
    {
      nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
      (void)iob_free_chain(iob);
      return 0;
    }

#ifdef CONFIG_UDP_READAHEAD_NOTIFIER
  /* Provided notification(s) that additional UDP read-ahead data is
   * available.
   */

  udp_notifier_signal(conn);
#endif

  ninfo("Buffered %d bytes\n", buflen);
  return buflen;
}
예제 #7
0
struct iob_s *ieee80211_ccmp_decrypt(struct ieee80211_s *ic, struct iob_s *iob0,
                                     struct ieee80211_key *k)
{
  struct ieee80211_ccmp_ctx *ctx = k->k_priv;
  struct ieee80211_frame *wh;
  uint64_t pn, *prsc;
  const uint8_t *ivp;
  const uint8_t *src;
  uint8_t *dst;
  uint8_t mic0[IEEE80211_CCMP_MICLEN];
  uint8_t a[16];
  uint8_t b[16];
  uint8_t s0[16];
  uint8_t s[16];
  struct iob_s *next0;
  struct iob_s *iob;
  struct iob_s *next;
  int hdrlen;
  int left;
  int moff;
  int noff;
  int len;
  uint16_t ctr;
  int i;
  int j;

  wh = (FAR struct ieee80211_frame *)IOB_DATA(iob0);
  hdrlen = ieee80211_get_hdrlen(wh);
  ivp = (uint8_t *) wh + hdrlen;

  if (iob0->io_pktlen < hdrlen + IEEE80211_CCMP_HDRLEN + IEEE80211_CCMP_MICLEN)
    {
      iob_free_chain(iob0);
      return NULL;
    }

  /* Check that ExtIV bit is set */

  if (!(ivp[3] & IEEE80211_WEP_EXTIV))
    {
      iob_free_chain(iob0);
      return NULL;
    }

  /* Retrieve last seen packet number for this frame type/priority */

  if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA)
    {
      uint8_t tid =
        ieee80211_has_qos(wh) ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
      prsc = &k->k_rsc[tid];
    }
  else
    {
      /* 11w: management frames have their own counters */

      prsc = &k->k_mgmt_rsc;
    }

  /* Extract the 48-bit PN from the CCMP header */

  pn = (uint64_t) ivp[0] |
    (uint64_t) ivp[1] << 8 |
    (uint64_t) ivp[4] << 16 |
    (uint64_t) ivp[5] << 24 | (uint64_t) ivp[6] << 32 | (uint64_t) ivp[7] << 40;

  if (pn <= *prsc)
    {
      /* Replayed frame, discard */

      iob_free_chain(iob0);
      return NULL;
    }

  next0 = iob_alloc(false);
  if (next0 == NULL)
    {
      goto nospace;
    }

  if (iob_clone(next0, iob0) < 0)
    {
      goto nospace;
    }

  next0->io_pktlen -= IEEE80211_CCMP_HDRLEN + IEEE80211_CCMP_MICLEN;
  next0->io_len = CONFIG_IEEE80211_BUFSIZE;
  if (next0->io_len > next0->io_pktlen)
    {
      next0->io_len = next0->io_pktlen;
    }

  /* Construct initial B, A and S_0 blocks */

  ieee80211_ccmp_phase1(&ctx->rijndael, wh, pn,
                        next0->io_pktlen - hdrlen, b, a, s0);

  /* Copy 802.11 header and clear protected bit */

  memcpy(IOB_DATA(next0), wh, hdrlen);
  wh = (FAR struct ieee80211_frame *)IOB_DATA(next0);
  wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;

  /* construct S_1 */
  ctr = 1;
  a[14] = ctr >> 8;
  a[15] = ctr & 0xff;
  rijndael_encrypt(&ctx->rijndael, a, s);

  /* decrypt frame body and compute MIC */
  j = 0;
  iob = iob0;
  next = next0;
  moff = hdrlen + IEEE80211_CCMP_HDRLEN;
  noff = hdrlen;
  left = next0->io_pktlen - noff;
  while (left > 0)
    {
      if (moff == iob->io_len)
        {
          /* Nothing left to copy from iob */

          iob = iob->io_flink;
          moff = 0;
        }

      if (noff == next->io_len)
        {
          struct iob_s *newbuf;

          /* next is full and there's more data to copy */

          newbuf = iob_alloc(false);
          if (newbuf == NULL)
            {
              goto nospace;
            }

          next->io_flink = newbuf;
          next = newbuf;
          next->io_len = 0;

          if (next->io_len > left)
            {
              next->io_len = left;
            }

          noff = 0;
        }

      len = MIN(iob->io_len - moff, next->io_len - noff);

      src = (FAR uint8_t *) IOB_DATA(iob) + moff;
      dst = (FAR uint8_t *) IOB_DATA(next) + noff;

      for (i = 0; i < len; i++)
        {
          /* decrypt message */

          dst[i] = src[i] ^ s[j];

          /* update MIC with clear text */

          b[j] ^= dst[i];
          if (++j < 16)
            continue;
          /* we have a full block, encrypt MIC */

          rijndael_encrypt(&ctx->rijndael, b, b);

          /* construct a new S_ctr block */

          ctr++;
          a[14] = ctr >> 8;
          a[15] = ctr & 0xff;
          rijndael_encrypt(&ctx->rijndael, a, s);
          j = 0;
        }

      moff += len;
      noff += len;
      left -= len;
    }

  if (j != 0)
    {
      /* Partial block, encrypt MIC */

      rijndael_encrypt(&ctx->rijndael, b, b);
    }

  /* Finalize MIC, U := T XOR first-M-bytes( S_0 ) */

  for (i = 0; i < IEEE80211_CCMP_MICLEN; i++)
    b[i] ^= s0[i];

  /* Check that it matches the MIC in received frame */

  iob_copyout(mic0, iob, moff, IEEE80211_CCMP_MICLEN);
  if (memcmp(mic0, b, IEEE80211_CCMP_MICLEN) != 0)
    {
      iob_free_chain(iob0);
      iob_free_chain(next0);
      return NULL;
    }

  /* update last seen packet number (MIC is validated) */
  *prsc = pn;

  iob_free_chain(iob0);
  return next0;

nospace:
  iob_free_chain(iob0);
  if (next0 != NULL)
    {
      iob_free_chain(next0);
    }

  return NULL;
}
예제 #8
0
struct iob_s *ieee80211_ccmp_encrypt(struct ieee80211_s *ic, struct iob_s *iob0,
                                     struct ieee80211_key *k)
{
  struct ieee80211_ccmp_ctx *ctx = k->k_priv;
  const struct ieee80211_frame *wh;
  const uint8_t *src;
  uint8_t *ivp, *mic, *dst;
  uint8_t a[16], b[16], s0[16], s[16];
  struct iob_s *next0, *iob, *next;
  int hdrlen, left, moff, noff, len;
  uint16_t ctr;
  int i, j;

  next0 = iob_alloc(false);
  if (next0 == NULL)
    {
      goto nospace;
    }

  if (iob_clone(next0, iob0) < 0)
    {
      goto nospace;
    }

  next0->io_pktlen += IEEE80211_CCMP_HDRLEN;
  next0->io_len = CONFIG_IEEE80211_BUFSIZE;

  if (next0->io_len > next0->io_pktlen)
    {
      next0->io_len = next0->io_pktlen;
    }

  /* Copy 802.11 header */

  wh = (FAR struct ieee80211_frame *)IOB_DATA(iob0);
  hdrlen = ieee80211_get_hdrlen(wh);
  memcpy(IOB_DATA(next0), wh, hdrlen);

  k->k_tsc++;                   /* increment the 48-bit PN */

  /* construct CCMP header */

  ivp = (FAR uint8_t *) IOB_DATA(next0) + hdrlen;
  ivp[0] = k->k_tsc;            /* PN0 */
  ivp[1] = k->k_tsc >> 8;       /* PN1 */
  ivp[2] = 0;                   /* Rsvd */
  ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV;  /* KeyID | ExtIV */
  ivp[4] = k->k_tsc >> 16;      /* PN2 */
  ivp[5] = k->k_tsc >> 24;      /* PN3 */
  ivp[6] = k->k_tsc >> 32;      /* PN4 */
  ivp[7] = k->k_tsc >> 40;      /* PN5 */

  /* construct initial B, A and S_0 blocks */
  ieee80211_ccmp_phase1(&ctx->rijndael, wh, k->k_tsc,
                        iob0->io_pktlen - hdrlen, b, a, s0);

  /* construct S_1 */
  ctr = 1;
  a[14] = ctr >> 8;
  a[15] = ctr & 0xff;
  rijndael_encrypt(&ctx->rijndael, a, s);

  /* encrypt frame body and compute MIC */
  j = 0;
  iob = iob0;
  next = next0;
  moff = hdrlen;
  noff = hdrlen + IEEE80211_CCMP_HDRLEN;
  left = iob0->io_pktlen - moff;
  while (left > 0)
    {
      if (moff == iob->io_len)
        {
          /* Nothing left to copy from iob */

          iob = iob->io_flink;
          moff = 0;
        }

      if (noff == next->io_len)
        {
          struct iob_s *newbuf;

          /* next is full and there's more data to copy */

          newbuf = iob_alloc(false);
          if (newbuf == NULL)
            {
              goto nospace;
            }

          next->io_flink = newbuf;
          next = newbuf;
          next->io_len = 0;

          if (next->io_len > left)
            {
              next->io_len = left;
            }

          noff = 0;
        }

      len = MIN(iob->io_len - moff, next->io_len - noff);

      src = (FAR uint8_t *) IOB_DATA(iob) + moff;
      dst = (FAR uint8_t *) IOB_DATA(next) + noff;

      for (i = 0; i < len; i++)
        {
          /* update MIC with clear text */
          b[j] ^= src[i];

          /* encrypt message */
          dst[i] = src[i] ^ s[j];
          if (++j < 16)
            continue;

          /* we have a full block, encrypt MIC */
          rijndael_encrypt(&ctx->rijndael, b, b);

          /* construct a new S_ctr block */
          ctr++;
          a[14] = ctr >> 8;
          a[15] = ctr & 0xff;
          rijndael_encrypt(&ctx->rijndael, a, s);
          j = 0;
        }

      moff += len;
      noff += len;
      left -= len;
    }
  if (j != 0)                   /* partial block, encrypt MIC */
    rijndael_encrypt(&ctx->rijndael, b, b);

  /* Reserve trailing space for MIC */

  if (IOB_FREESPACE(next) < IEEE80211_CCMP_MICLEN)
    {
      struct iob_s *newbuf;

      newbuf = iob_alloc(false);
      if (newbuf == NULL)
        {
          goto nospace;
        }

      next->io_flink = newbuf;
      next = newbuf;
      next->io_len = 0;
    }

  /* Finalize MIC, U := T XOR first-M-bytes( S_0 ) */

  mic = (FAR uint8_t *) IOB_DATA(next) + next->io_len;
  for (i = 0; i < IEEE80211_CCMP_MICLEN; i++)
    {
      mic[i] = b[i] ^ s0[i];
    }

  next->io_len += IEEE80211_CCMP_MICLEN;
  next0->io_pktlen += IEEE80211_CCMP_MICLEN;

  iob_free_chain(iob0);
  return next0;

nospace:
  iob_free_chain(iob0);
  if (next0 != NULL)
    {
      iob_free_chain(next0);
    }

  return NULL;
}