Home | History | Annotate | Download | only in android-clat
      1 /*
      2  * Copyright 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  *
     16  * ring.c - packet ring buffer functions
     17  */
     18 
     19 #include <errno.h>
     20 #include <string.h>
     21 #include <arpa/inet.h>
     22 #include <sys/socket.h>
     23 #include <sys/mman.h>
     24 #include <linux/if.h>
     25 #include <linux/if_packet.h>
     26 
     27 #include "logging.h"
     28 #include "ring.h"
     29 #include "translate.h"
     30 #include "tun.h"
     31 
     32 int ring_create(struct tun_data *tunnel) {
     33   int packetsock = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
     34   if (packetsock < 0) {
     35     logmsg(ANDROID_LOG_FATAL, "packet socket failed: %s", strerror(errno));
     36     return -1;
     37   }
     38 
     39   int ver = TPACKET_V2;
     40   if (setsockopt(packetsock, SOL_PACKET, PACKET_VERSION, (void *) &ver, sizeof(ver))) {
     41     logmsg(ANDROID_LOG_FATAL, "setsockopt(PACKET_VERSION, %d) failed: %s", ver, strerror(errno));
     42     return -1;
     43   }
     44 
     45   int on = 1;
     46   if (setsockopt(packetsock, SOL_PACKET, PACKET_LOSS, (void *) &on, sizeof(on))) {
     47     logmsg(ANDROID_LOG_WARN, "PACKET_LOSS failed: %s", strerror(errno));
     48   }
     49 
     50   struct packet_ring *ring = &tunnel->ring;
     51   ring->numblocks = TP_NUM_BLOCKS;
     52 
     53   int total_frames = TP_FRAMES * ring->numblocks;
     54 
     55   struct tpacket_req req = {
     56       .tp_frame_size = TP_FRAME_SIZE,  // Frame size.
     57       .tp_block_size = TP_BLOCK_SIZE,  // Frames per block.
     58       .tp_block_nr = ring->numblocks,  // Number of blocks.
     59       .tp_frame_nr = total_frames,     // Total frames.
     60   };
     61 
     62   if (setsockopt(packetsock, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)) < 0) {
     63     logmsg(ANDROID_LOG_FATAL, "PACKET_RX_RING failed: %s", strerror(errno));
     64     return -1;
     65   }
     66 
     67   size_t buflen = TP_BLOCK_SIZE * ring->numblocks;
     68   ring->base = mmap(NULL, buflen, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED|MAP_POPULATE,
     69                     packetsock, 0);
     70   if (ring->base == MAP_FAILED) {
     71     logmsg(ANDROID_LOG_FATAL, "mmap %lu failed: %s", buflen, strerror(errno));
     72     return -1;
     73   }
     74 
     75   ring->block = 0;
     76   ring->slot = 0;
     77   ring->numslots = TP_BLOCK_SIZE / TP_FRAME_SIZE;
     78   ring->next = (struct tpacket2_hdr *) ring->base;
     79 
     80   logmsg(ANDROID_LOG_INFO, "Using ring buffer with %d frames (%d bytes) at %p",
     81          total_frames, buflen, ring->base);
     82 
     83   return packetsock;
     84 }
     85 
     86 /* function: ring_advance
     87  * advances to the next position in the packet ring
     88  * ring - packet ring buffer
     89  */
     90 static struct tpacket2_hdr* ring_advance(struct packet_ring *ring) {
     91   uint8_t *next = (uint8_t *) ring->next;
     92 
     93   ring->slot++;
     94   next += TP_FRAME_SIZE;
     95 
     96   if (ring->slot == ring->numslots) {
     97     ring->slot = 0;
     98     ring->block++;
     99 
    100     if (ring->block < ring->numblocks) {
    101       next += TP_FRAME_GAP;
    102     } else {
    103       ring->block = 0;
    104       next = (uint8_t *) ring->base;
    105     }
    106   }
    107 
    108   ring->next = (struct tpacket2_hdr *) next;
    109   return ring->next;
    110 }
    111 
    112 /* function: ring_read
    113  * reads a packet from the ring buffer and translates it
    114  * read_fd  - file descriptor to read original packet from
    115  * write_fd - file descriptor to write translated packet to
    116  * to_ipv6  - whether the packet is to be translated to ipv6 or ipv4
    117  */
    118 void ring_read(struct packet_ring *ring, int write_fd, int to_ipv6) {
    119   struct tpacket2_hdr *tp = ring->next;
    120   if (tp->tp_status & TP_STATUS_USER) {
    121     uint8_t *packet = ((uint8_t *) tp) + tp->tp_net;
    122     translate_packet(write_fd, to_ipv6, packet, tp->tp_len);
    123     tp->tp_status = TP_STATUS_KERNEL;
    124     tp = ring_advance(ring);
    125   }
    126 }
    127