19353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti/*
29353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * Copyright 2014 The Android Open Source Project
39353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti *
49353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * Licensed under the Apache License, Version 2.0 (the "License");
59353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * you may not use this file except in compliance with the License.
69353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * You may obtain a copy of the License at
79353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti *
89353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * http://www.apache.org/licenses/LICENSE-2.0
99353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti *
109353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * Unless required by applicable law or agreed to in writing, software
119353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * distributed under the License is distributed on an "AS IS" BASIS,
129353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * See the License for the specific language governing permissions and
149353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * limitations under the License.
159353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti *
169353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * ring.c - packet ring buffer functions
179353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti */
189353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
199353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti#include <errno.h>
209353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti#include <string.h>
219353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti#include <arpa/inet.h>
229353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti#include <sys/socket.h>
239353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti#include <sys/mman.h>
249353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti#include <linux/if.h>
259353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti#include <linux/if_packet.h>
269353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
279353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti#include "logging.h"
289353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti#include "ring.h"
299353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti#include "translate.h"
309353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti#include "tun.h"
319353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
329353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colittiint ring_create(struct tun_data *tunnel) {
339353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  int packetsock = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
349353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  if (packetsock < 0) {
359353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    logmsg(ANDROID_LOG_FATAL, "packet socket failed: %s", strerror(errno));
369353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    return -1;
379353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  }
389353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
399353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  int ver = TPACKET_V2;
409353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  if (setsockopt(packetsock, SOL_PACKET, PACKET_VERSION, (void *) &ver, sizeof(ver))) {
419353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    logmsg(ANDROID_LOG_FATAL, "setsockopt(PACKET_VERSION, %d) failed: %s", ver, strerror(errno));
429353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    return -1;
439353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  }
449353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
459353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  int on = 1;
469353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  if (setsockopt(packetsock, SOL_PACKET, PACKET_LOSS, (void *) &on, sizeof(on))) {
479353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    logmsg(ANDROID_LOG_WARN, "PACKET_LOSS failed: %s", strerror(errno));
489353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  }
499353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
509353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  struct packet_ring *ring = &tunnel->ring;
519353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  ring->numblocks = TP_NUM_BLOCKS;
529353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
539353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  int total_frames = TP_FRAMES * ring->numblocks;
549353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
559353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  struct tpacket_req req = {
569353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti      .tp_frame_size = TP_FRAME_SIZE,  // Frame size.
579353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti      .tp_block_size = TP_BLOCK_SIZE,  // Frames per block.
589353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti      .tp_block_nr = ring->numblocks,  // Number of blocks.
599353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti      .tp_frame_nr = total_frames,     // Total frames.
609353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  };
619353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
629353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  if (setsockopt(packetsock, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)) < 0) {
639353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    logmsg(ANDROID_LOG_FATAL, "PACKET_RX_RING failed: %s", strerror(errno));
649353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    return -1;
659353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  }
669353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
679353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  size_t buflen = TP_BLOCK_SIZE * ring->numblocks;
689353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  ring->base = mmap(NULL, buflen, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED|MAP_POPULATE,
699353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti                    packetsock, 0);
709353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  if (ring->base == MAP_FAILED) {
719353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    logmsg(ANDROID_LOG_FATAL, "mmap %lu failed: %s", buflen, strerror(errno));
729353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    return -1;
739353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  }
749353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
759353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  ring->block = 0;
769353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  ring->slot = 0;
779353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  ring->numslots = TP_BLOCK_SIZE / TP_FRAME_SIZE;
789353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  ring->next = (struct tpacket2_hdr *) ring->base;
799353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
809353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  logmsg(ANDROID_LOG_INFO, "Using ring buffer with %d frames (%d bytes) at %p",
819353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti         total_frames, buflen, ring->base);
829353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
839353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  return packetsock;
849353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti}
859353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
869353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti/* function: ring_advance
879353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * advances to the next position in the packet ring
889353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * ring - packet ring buffer
899353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti */
909353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colittistatic struct tpacket2_hdr* ring_advance(struct packet_ring *ring) {
919353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  uint8_t *next = (uint8_t *) ring->next;
929353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
939353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  ring->slot++;
949353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  next += TP_FRAME_SIZE;
959353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
969353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  if (ring->slot == ring->numslots) {
979353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    ring->slot = 0;
989353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    ring->block++;
999353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
1009353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    if (ring->block < ring->numblocks) {
1019353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti      next += TP_FRAME_GAP;
1029353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    } else {
1039353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti      ring->block = 0;
1049353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti      next = (uint8_t *) ring->base;
1059353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    }
1069353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  }
1079353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
1089353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  ring->next = (struct tpacket2_hdr *) next;
1099353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  return ring->next;
1109353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti}
1119353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti
1129353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti/* function: ring_read
1139353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * reads a packet from the ring buffer and translates it
1149353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * read_fd  - file descriptor to read original packet from
1159353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * write_fd - file descriptor to write translated packet to
1169353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti * to_ipv6  - whether the packet is to be translated to ipv6 or ipv4
1179353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti */
1189353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colittivoid ring_read(struct packet_ring *ring, int write_fd, int to_ipv6) {
1199353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  struct tpacket2_hdr *tp = ring->next;
1209353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  if (tp->tp_status & TP_STATUS_USER) {
1219353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    uint8_t *packet = ((uint8_t *) tp) + tp->tp_net;
1229353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    translate_packet(write_fd, to_ipv6, packet, tp->tp_len);
1239353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    tp->tp_status = TP_STATUS_KERNEL;
1249353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti    tp = ring_advance(ring);
1259353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti  }
1269353be2a5f1b4fd00b04e4c826f7f3c3ec6c5d46Lorenzo Colitti}
127