18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Copyright (C) 2007-2008 The Android Open Source Project
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This software is licensed under the terms of the GNU General Public
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** License version 2, as published by the Free Software Foundation, and
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** may be copied, distributed, and modified under those terms.
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This program is distributed in the hope that it will be useful,
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** but WITHOUT ANY WARRANTY; without even the implied warranty of
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** GNU General Public License for more details.
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project*/
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "shaper.h"
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-common.h"
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-timer.h"
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <stdlib.h>
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  SHAPER_CLOCK        rt_clock
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  SHAPER_CLOCK_UNIT   1000.
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project_packet_is_internal( const uint8_t*  data, size_t  size )
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const uint8_t*  end = data + size;
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* must have room for Mac + IP header */
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (data + 40 > end)
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (data[12] != 0x08 || data[13] != 0x00 )
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* must have valid IP header */
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    data += 14;
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if ((data[0] >> 4) != 4 || (data[0] & 15) < 5)
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* internal if both source and dest addresses are in 10.x.x.x */
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ( data[12] == 10 && data[16] == 10);
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* here's how we implement network shaping. we want to limit the network
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * rate to a given constant MAX_RATE expressed as bits/second. this means
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * that it takes 1/MAX_RATE seconds to send a single bit, and count*8/MAX_RATE
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * seconds to send 'count' bytes.
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * we're going to implement a scheme where, when we send a packet of
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 'count' bytes, no other packet will go through in the same direction for
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * at least 'count*8/MAX_RATE' seconds. any successive packet that is "sent"
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * in this interval is placed in a queue, associated to a timer
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * there are different (queue/timer/rate) values for the input and output
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * direction of the user vlan.
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct QueuedPacketRec_ {
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int64_t                    expiration;
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct QueuedPacketRec_*   next;
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size_t                     size;
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    void*                      opaque;
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    void*                      data;
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} QueuedPacketRec, *QueuedPacket;
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic QueuedPacket
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectqueued_packet_create( const void*   data,
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                      size_t        size,
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                      void*         opaque,
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                      int           do_copy )
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QueuedPacket   packet;
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size_t         packet_size = sizeof(*packet);
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (do_copy)
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        packet_size += size;
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    packet = qemu_malloc(packet_size);
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    packet->next       = NULL;
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    packet->expiration = 0;
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    packet->size       = (size_t)size;
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    packet->opaque     = opaque;
808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (do_copy) {
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        packet->data = (void*)(packet+1);
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        memcpy( (char*)packet->data, (char*)data, packet->size );
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        packet->data = (void*)data;
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return packet;
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectqueued_packet_free( QueuedPacket  packet )
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (packet) {
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_free( packet );
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct NetShaperRec_ {
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QueuedPacket   packets;   /* list of queued packets, ordered by expiration date */
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int            num_packets;
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int            active;    /* is this shaper active ? */
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int64_t        block_until;
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    double         max_rate;  /* max rate expressed in bytes/second */
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    double         inv_rate;  /* inverse of max rate                */
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QEMUTimer*     timer;     /* QEMU timer */
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int                do_copy;
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    NetShaperSendFunc  send_func;
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} NetShaperRec;
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetshaper_destroy( NetShaper  shaper )
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (shaper) {
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        shaper->active = 0;
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        while (shaper->packets) {
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            QueuedPacket  packet = shaper->packets;
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            shaper->packets = packet->next;
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            packet->next    = NULL;
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            queued_packet_free(packet);
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_del_timer(shaper->timer);
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_free_timer(shaper->timer);
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        shaper->timer = NULL;
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_free(shaper);
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* this function is called when the shaper's timer expires */
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetshaper_expires( NetShaper  shaper )
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QueuedPacket  packet;
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while ((packet = shaper->packets) != NULL) {
1405973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner        int64_t   now = qemu_get_clock_ms( SHAPER_CLOCK );
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       if (packet->expiration > now)
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           break;
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       shaper->packets = packet->next;
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       shaper->send_func( packet->data, packet->size, packet->opaque );
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       queued_packet_free(packet);
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       shaper->num_packets--;
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   }
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   /* reprogram timer if needed */
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   if (shaper->packets) {
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       shaper->block_until = shaper->packets->expiration;
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       qemu_mod_timer( shaper->timer, shaper->block_until );
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   } else {
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       shaper->block_until = -1;
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   }
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectNetShaper
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetshaper_create( int                do_copy,
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                  NetShaperSendFunc  send_func )
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    NetShaper  shaper = qemu_malloc(sizeof(*shaper));
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    shaper->active = 0;
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    shaper->packets = NULL;
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    shaper->num_packets = 0;
1705973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    shaper->timer   = qemu_new_timer_ms( SHAPER_CLOCK,
1715973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner                                         (QEMUTimerCB*) netshaper_expires,
1725973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner                                         shaper );
1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    shaper->send_func = send_func;
1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    shaper->max_rate  = 1e6;
1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    shaper->inv_rate  = 0.;
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    shaper->block_until = -1; /* magic value, means to not block */
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return shaper;
1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetshaper_set_rate( NetShaper  shaper,
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    double     rate )
1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* send all current packets when changing the rate */
1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (shaper->packets) {
1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        QueuedPacket  packet = shaper->packets;
1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        shaper->packets = packet->next;
1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        shaper->send_func(packet->data, packet->size, packet->opaque);
1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_free(packet);
1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        shaper->num_packets = 0;
1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    shaper->max_rate = rate;
1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (rate > 1.) {
1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        shaper->inv_rate = (8.*SHAPER_CLOCK_UNIT)/rate;  /* qemu_get_clock returns time in ms */
1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        shaper->active   = 1;                            /* for the real-time clock           */
1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        shaper->active = 0;
2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    shaper->block_until = -1;
2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetshaper_send_aux( NetShaper  shaper,
2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    void*      data,
2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    size_t     size,
2108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    void*      opaque )
2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int64_t   now;
2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!shaper->active || _packet_is_internal(data, size)) {
2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        shaper->send_func( data, size, opaque );
2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2195973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    now = qemu_get_clock_ms( SHAPER_CLOCK );
2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (now >= shaper->block_until) {
2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        shaper->send_func( data, size, opaque );
2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        shaper->block_until = now + size*shaper->inv_rate;
2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        //fprintf(stderr, "NETSHAPER: block for %.2fms\n", (shaper->block_until - now)*1.0 );
2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* create new packet, add it to the queue */
2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    {
2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        QueuedPacket   packet;
2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        packet = queued_packet_create( data, size, opaque, shaper->do_copy );
2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        packet->expiration = shaper->block_until;
2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        {
2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            QueuedPacket  *pnode, node;
2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            pnode = &shaper->packets;
2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            for (;;) {
2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                node = *pnode;
2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (node == NULL || node->expiration > packet->expiration )
2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    break;
2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                pnode = &node->next;
2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            packet->next = *pnode;
2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            *pnode       = packet;
2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (packet == shaper->packets)
2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                qemu_mod_timer( shaper->timer, packet->expiration );
2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        shaper->num_packets += 1;
2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    shaper->block_until += size*shaper->inv_rate;
2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    //fprintf(stderr, "NETSHAPER: block2 for %.2fms\n", (shaper->block_until - now)*1.0 );
2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetshaper_send( NetShaper  shaper,
2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                void*      data,
2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                size_t     size )
2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    netshaper_send_aux(shaper, data, size, NULL);
2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint
2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetshaper_can_send( NetShaper  shaper )
2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int64_t  now;
2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!shaper->active || shaper->block_until < 0)
2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 1;
2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (shaper->packets)
2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2775973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    now = qemu_get_clock_ms( SHAPER_CLOCK );
2788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return (now >= shaper->block_until);
2798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* this type is used to model a session connection/state
2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * if session->packet is != NULL, then the connection is delayed
2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct SessionRec_ {
2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int64_t               expiration;
2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct SessionRec_*   next;
2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned              src_ip;
2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned              dst_ip;
2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned short        src_port;
2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned short        dst_port;
2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t               protocol;
2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QueuedPacket          packet;
2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} SessionRec, *Session;
3008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  _PROTOCOL_TCP   6
3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  _PROTOCOL_UDP   17
3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
3078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectsession_free( Session  session )
3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (session) {
3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (session->packet) {
3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            queued_packet_free(session->packet);
3128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            session->packet = NULL;
3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_free( session );
3158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if 0  /* useful for debugging */
3208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic const char*
3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectsession_to_string( Session  session )
3228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    static char  temp[256];
3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char*  format = (session->protocol == _PROTOCOL_TCP) ? "TCP" : "UDP";
3258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    sprintf( temp, "%s[%d.%d.%d.%d:%d / %d.%d.%d.%d:%d]", format,
3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project             (session->src_ip >> 24) & 255, (session->src_ip >> 16) & 255,
3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project             (session->src_ip >> 8) & 255, (session->src_ip) & 255, session->src_port,
3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project             (session->dst_ip >> 24) & 255, (session->dst_ip >> 16) & 255,
3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project             (session->dst_ip >> 8) & 255, (session->dst_ip) & 255, session->dst_port);
3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return temp;
3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* returns TRUE if this corresponds to a SYN packet */
3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint
3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project_packet_SYN_flags( const void*  _data, size_t   size, Session  info )
3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const uint8_t*  data = (const uint8_t*)_data;
3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const uint8_t*  end  = data + size;
3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* enough room for a Ethernet MAC packet ? */
3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (data + 14 > end - 4)
3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* is it an IP packet ? */
3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (data[12] != 0x8 || data[13] != 0)
3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    data += 14;
3518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    end  -= 4;
3528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (data + 20 > end)
3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* IP version must be 4, and the header length in words at least 5 */
3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if ((data[0] & 0xF) < 5 || (data[0] >> 4) != 4)
3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* time-to-live must be > 0 */
3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (data[8] == 0)
3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* must be TCP or UDP packet */
3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (data[9] != _PROTOCOL_TCP && data[9] != _PROTOCOL_UDP)
3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    info->protocol = data[9];
3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    info->src_ip   = (data[12] << 24) | (data[13] << 16) | (data[14] << 8) | data[15];
3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    info->dst_ip   = (data[16] << 24) | (data[17] << 16) | (data[18] << 8) | data[19];
3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    data += 4*(data[0] & 15);
3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (data + 20 > end)
3748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
3758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    info->src_port = (unsigned short)((data[0] << 8) | data[1]);
3778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    info->dst_port = (unsigned short)((data[2] << 8) | data[3]);
3788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return (data[13] & 0x1f);
3808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct NetDelayRec_
3848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    Session     sessions;
3868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int         num_sessions;
3878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QEMUTimer*  timer;
3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int         active;
3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int         min_ms;
3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int         max_ms;
3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    NetShaperSendFunc  send_func;
3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} NetDelayRec;
3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic Session*
3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetdelay_lookup_session( NetDelay  delay, Session  info )
3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    Session*  pnode = &delay->sessions;
4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    Session   node;
4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (;;) {
4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        node = *pnode;
4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (node == NULL)
4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (node->src_ip == info->src_ip &&
4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            node->dst_ip == info->dst_ip &&
4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            node->src_port == info->src_port &&
4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            node->dst_port == info->dst_port &&
4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            node->protocol == info->protocol )
4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        pnode = &node->next;
4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return pnode;
4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* called by the delay's timer on expiration */
4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetdelay_expires( NetDelay  delay )
4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    Session  session;
4275973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    int64_t  now = qemu_get_clock_ms( SHAPER_CLOCK );
4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int      rearm = 0;
4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int64_t  rearm_time = 0;
4308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (session = delay->sessions; session != NULL; session = session->next)
4328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    {
4338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        QueuedPacket  packet = session->packet;
4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (packet == NULL)
4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            continue;
4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (session->expiration <= now) {
4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* send the SYN packet now */
4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    //fprintf(stderr, "NetDelay:RST: sending creation for %s\n", session_to_string(session) );
4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            delay->send_func( packet->data, packet->size, packet->opaque );
4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            session->packet = NULL;
4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            queued_packet_free( packet );
4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (!rearm) {
4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                rearm      = 1;
4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                rearm_time = session->expiration;
4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            else if ( session->expiration < rearm_time )
4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                rearm_time = session->expiration;
4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (rearm)
4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_mod_timer( delay->timer, rearm_time );
4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectNetDelay
4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetdelay_create( NetShaperSendFunc  send_func )
4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    NetDelay  delay = qemu_malloc(sizeof(*delay));
4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    delay->sessions     = NULL;
4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    delay->num_sessions = 0;
4665973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    delay->timer        = qemu_new_timer_ms( SHAPER_CLOCK,
4675973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner                                             (QEMUTimerCB*) netdelay_expires,
4685973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner                                             delay );
4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    delay->active = 0;
4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    delay->min_ms = 0;
4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    delay->max_ms = 0;
4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    delay->send_func = send_func;
4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return delay;
4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
4808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetdelay_set_latency( NetDelay  delay, int  min_ms, int  max_ms )
4818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* when changing the latency, accept all sessions */
4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (delay->sessions) {
4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        Session  session = delay->sessions;
4858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        delay->sessions = session->next;
4868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        session->next = NULL;
4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (session->packet) {
4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            QueuedPacket  packet = session->packet;
4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            delay->send_func( packet->data, packet->size, packet->opaque );
4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        session_free(session);
4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        delay->num_sessions--;
4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    delay->min_ms = min_ms;
4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    delay->max_ms = max_ms;
4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    delay->active = (min_ms <= max_ms) && min_ms > 0;
4988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetdelay_send( NetDelay  delay, const void*  data, size_t  size )
5028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    netdelay_send_aux(delay, data, size, NULL);
5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetdelay_send_aux( NetDelay  delay, const void*  data, size_t  size, void* opaque )
5098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (delay->active && !_packet_is_internal(data, size)) {
5118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        SessionRec  info[1];
5128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int         flags;
5138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        flags = _packet_SYN_flags( data, size, info );
5158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if ((flags & 0x05) != 0)
5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        {  /* FIN or RST: drop connection */
5178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            Session*  lookup  = netdelay_lookup_session( delay, info );
5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            Session   session = *lookup;
5198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (session != NULL) {
5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                //fprintf(stderr, "NetDelay:RST: dropping %s\n", session_to_string(info) );
5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                *lookup = session->next;
5238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                session_free( session );
5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                delay->num_sessions -= 1;
5258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
5278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else if ((flags & 0x12) == 0x02)
5288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        {
5298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* SYN: create connection */
5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            Session*  lookup  = netdelay_lookup_session( delay, info );
5318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            Session   session = *lookup;
5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (session != NULL) {
5348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (session->packet != NULL) {
5358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                   /* this is a SYN re-transmission, since we didn't
5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    * send the original SYN packet yet, just eat this one
5378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    */
5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    //fprintf(stderr, "NetDelay:RST: swallow SYN re-send for %s\n", session_to_string(info) );
5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    return;
5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                }
5418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            } else {
5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                /* establish a new session slightly in the future */
5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                int   latency = delay->min_ms;
5448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                int   range   = delay->max_ms - delay->min_ms;
5458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                 if (range > 0)
5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    latency += rand() % range;
5488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    //fprintf(stderr, "NetDelay:RST: delay creation for %s\n", session_to_string(info) );
5508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                session = qemu_malloc( sizeof(*session) );
5518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                session->next        = delay->sessions;
5538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                delay->sessions      = session;
5548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                delay->num_sessions += 1;
5558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5565973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner                session->expiration = qemu_get_clock_ms( SHAPER_CLOCK ) + latency;
5578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                session->src_ip   = info->src_ip;
5598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                session->dst_ip   = info->dst_ip;
5608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                session->src_port = info->src_port;
5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                session->dst_port = info->dst_port;
5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                session->protocol = info->protocol;
5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                session->packet = queued_packet_create( data, size, opaque, 1 );
5658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                netdelay_expires(delay);
5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                return;
5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
5698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
5708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    delay->send_func( (void*)data, size, opaque );
5738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
5778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnetdelay_destroy( NetDelay  delay )
5788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (delay) {
5808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        while (delay->sessions) {
5818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            Session  session = delay->sessions;
5828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            delay->sessions = session->next;
5838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            session_free(session);
5848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            delay->num_sessions -= 1;
5858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
5868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        delay->active = 0;
5878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_free( delay );
5888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
591