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