forked from acouzens/open5gs
add TFT(Packet Filter) in Create Bearer Request
This commit is contained in:
parent
d1056a06c8
commit
886ef5a747
|
@ -28,6 +28,7 @@ case $host in
|
|||
*linux*)
|
||||
OSDIR="unix"
|
||||
OSCPPFLAGS="-DLINUX=1"
|
||||
IPFW_CPPFLAGS="-DNEED_SYSCTLBYNAME -DNEED_SIN_LEN"
|
||||
;;
|
||||
*-apple-darwin*)
|
||||
OSDIR="unix"
|
||||
|
@ -39,6 +40,7 @@ case $host in
|
|||
esac
|
||||
AC_SUBST(OSCPPFLAGS)
|
||||
AC_SUBST(OSDIR)
|
||||
AC_SUBST(IPFW_CPPFLAGS)
|
||||
|
||||
AH_TOP([
|
||||
#ifndef __NEXTEPC_CONFIG_H__
|
||||
|
@ -329,6 +331,7 @@ AC_CONFIG_FILES([lib/fd/gx/Makefile])
|
|||
AC_CONFIG_FILES([lib/fd/s6a/Makefile])
|
||||
AC_CONFIG_FILES([lib/fd/Makefile])
|
||||
AC_CONFIG_FILES([lib/gtp/Makefile])
|
||||
AC_CONFIG_FILES([lib/ipfw/Makefile])
|
||||
AC_CONFIG_FILES([lib/Makefile])
|
||||
AC_CONFIG_FILES([src/mme/Makefile])
|
||||
AC_CONFIG_FILES([src/hss/Makefile])
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
SUBDIRS = core logger base s1ap nas fd gtp
|
||||
SUBDIRS = core logger base s1ap nas fd gtp ipfw
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
MOSTLYCLEANFILES = *.stackdump
|
||||
|
|
|
@ -11,14 +11,17 @@ extern "C" {
|
|||
#define MAX_NUM_OF_UE 128
|
||||
#define MAX_NUM_OF_SESS 4
|
||||
#define MAX_NUM_OF_BEARER 4
|
||||
#define MAX_NUM_OF_PF 16 /* Num of Packet Filter per Bearer */
|
||||
#define MAX_NUM_OF_GTP_NODE 8
|
||||
|
||||
#define MAX_POOL_OF_UE (MAX_NUM_OF_ENB * MAX_NUM_OF_UE)
|
||||
#define MAX_POOL_OF_SESS (MAX_POOL_OF_UE * MAX_NUM_OF_SESS)
|
||||
#define MAX_POOL_OF_BEARER (MAX_POOL_OF_SESS * MAX_NUM_OF_BEARER)
|
||||
#define MAX_POOL_OF_PF (MAX_POOL_OF_BEARER * MAX_NUM_OF_PF)
|
||||
|
||||
#define MAX_NUM_OF_PCC_RULE 8
|
||||
#define MAX_NUM_OF_FLOW 8
|
||||
#define MAX_NUM_OF_PCC_RULE 8
|
||||
#define MAX_NUM_OF_FLOW 8 /* Num of Flow per PCC Rule */
|
||||
#define MAX_NUM_OF_PACKET_FILTER 16 /* Num of Packet Filter per Bearer */
|
||||
|
||||
#define MAX_SDU_LEN 2048
|
||||
#define IPV6_LEN 16
|
||||
|
@ -147,6 +150,8 @@ typedef struct _qos_t {
|
|||
|
||||
/**********************************
|
||||
* Flow Structure */
|
||||
#define FLOW_DOWNLINK_ONLY 1
|
||||
#define FLOW_UPLINK_ONLY 2
|
||||
typedef struct _flow_t {
|
||||
c_uint8_t direction;
|
||||
c_int8_t *description;
|
||||
|
|
|
@ -97,6 +97,143 @@ c_int16_t gtp_build_bearer_qos(
|
|||
return octet->len;
|
||||
}
|
||||
|
||||
/* 8.19 EPS Bearer Level Traffic Flow Template (Bearer TFT)
|
||||
* See subclause 10.5.6.12 in 3GPP TS 24.008 [13]. */
|
||||
c_int16_t gtp_build_tft(
|
||||
tlv_octet_t *octet, gtp_tft_t *tft, void *data, int data_len)
|
||||
{
|
||||
gtp_tft_t target;
|
||||
c_uint16_t size = 0;
|
||||
int i, j;
|
||||
|
||||
d_assert(tft, return -1, "Null param");
|
||||
d_assert(octet, return -1, "Null param");
|
||||
d_assert(data, return -1, "Null param");
|
||||
d_assert(data_len >= GTP_MAX_TRAFFIC_FLOW_TEMPLATE,
|
||||
return -1, "Null param");
|
||||
|
||||
octet->data = data;
|
||||
memcpy(&target, tft, sizeof(gtp_tft_t));
|
||||
|
||||
d_assert(size + sizeof(target.flags) <= data_len,
|
||||
return -1, "encode error");
|
||||
memcpy(octet->data + size, &target.flags, sizeof(target.flags));
|
||||
size += sizeof(target.flags);
|
||||
|
||||
for (i = 0; i < target.num_of_packet_filter; i++)
|
||||
{
|
||||
d_assert(size + sizeof(target.pf[i].flags) <= data_len,
|
||||
return -1, "encode error");
|
||||
memcpy(octet->data + size, &target.pf[i].flags,
|
||||
sizeof(target.pf[i].flags));
|
||||
size += sizeof(target.pf[i].flags);
|
||||
|
||||
d_assert(size + sizeof(target.pf[i].precedence) <= data_len,
|
||||
return -1, "encode error");
|
||||
memcpy(octet->data + size, &target.pf[i].precedence,
|
||||
sizeof(target.pf[i].precedence));
|
||||
size += sizeof(target.pf[i].precedence);
|
||||
|
||||
d_assert(size + sizeof(target.pf[i].length) <= data_len,
|
||||
return -1, "encode error");
|
||||
memcpy(octet->data + size, &target.pf[i].length,
|
||||
sizeof(target.pf[i].length));
|
||||
size += sizeof(target.pf[i].length);
|
||||
|
||||
for (j = 0; j < target.pf[i].num_of_component; j++)
|
||||
{
|
||||
d_assert(size +
|
||||
sizeof(target.pf[i].component[j].type) <= data_len,
|
||||
return -1, "encode error");
|
||||
memcpy(octet->data + size, &target.pf[i].component[j].type,
|
||||
sizeof(target.pf[i].component[j].type));
|
||||
size += sizeof(target.pf[i].component[j].type);
|
||||
switch(target.pf[i].component[j].type)
|
||||
{
|
||||
case GTP_PACKET_FILTER_PROTOCOL_IDENTIFIER_NEXT_HEADER_TYPE:
|
||||
{
|
||||
d_assert(size +
|
||||
sizeof(target.pf[i].component[j].proto) <= data_len,
|
||||
return -1, "encode error");
|
||||
memcpy(octet->data + size, &target.pf[i].component[j].proto,
|
||||
sizeof(target.pf[i].component[j].proto));
|
||||
size += sizeof(target.pf[i].component[j].proto);
|
||||
break;
|
||||
}
|
||||
case GTP_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE:
|
||||
case GTP_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE:
|
||||
d_assert(size +
|
||||
sizeof(target.pf[i].component[j].ipv4.addr)
|
||||
<= data_len,
|
||||
return -1, "encode error");
|
||||
memcpy(octet->data + size,
|
||||
&target.pf[i].component[j].ipv4.addr,
|
||||
sizeof(target.pf[i].component[j].ipv4.addr));
|
||||
size += sizeof(target.pf[i].component[j].ipv4.addr);
|
||||
|
||||
d_assert(size +
|
||||
sizeof(target.pf[i].component[j].ipv4.mask)
|
||||
<= data_len,
|
||||
return -1, "encode error");
|
||||
memcpy(octet->data + size,
|
||||
&target.pf[i].component[j].ipv4.mask,
|
||||
sizeof(target.pf[i].component[j].ipv4.mask));
|
||||
size += sizeof(target.pf[i].component[j].ipv4.mask);
|
||||
break;
|
||||
|
||||
case GTP_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE:
|
||||
case GTP_PACKET_FILTER_SINGLE_REMOTE_PORT_TYPE:
|
||||
d_assert(size +
|
||||
sizeof(target.pf[i].component[j].port.low)
|
||||
<= data_len,
|
||||
return -1, "encode error");
|
||||
target.pf[i].component[j].port.low =
|
||||
htons(target.pf[i].component[j].port.low);
|
||||
memcpy(octet->data + size,
|
||||
&target.pf[i].component[j].port.low,
|
||||
sizeof(target.pf[i].component[j].port.low));
|
||||
size += sizeof(target.pf[i].component[j].port.low);
|
||||
break;
|
||||
|
||||
case GTP_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE:
|
||||
case GTP_PACKET_FILTER_REMOTE_PORT_RANGE_TYPE:
|
||||
d_assert(size +
|
||||
sizeof(target.pf[i].component[j].port.low)
|
||||
<= data_len,
|
||||
return -1, "encode error");
|
||||
target.pf[i].component[j].port.low =
|
||||
htons(target.pf[i].component[j].port.low);
|
||||
memcpy(octet->data + size,
|
||||
&target.pf[i].component[j].port.low,
|
||||
sizeof(target.pf[i].component[j].port.low));
|
||||
size += sizeof(target.pf[i].component[j].port.low);
|
||||
|
||||
d_assert(size +
|
||||
sizeof(target.pf[i].component[j].port.high)
|
||||
<= data_len,
|
||||
return -1, "encode error");
|
||||
target.pf[i].component[j].port.high =
|
||||
htons(target.pf[i].component[j].port.high);
|
||||
memcpy(octet->data + size,
|
||||
&target.pf[i].component[j].port.high,
|
||||
sizeof(target.pf[i].component[j].port.high));
|
||||
size += sizeof(target.pf[i].component[j].port.high);
|
||||
break;
|
||||
default:
|
||||
d_error("Unknown Packet Filter Type(%d)",
|
||||
target.pf[i].component[j].type);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
octet->len = size;
|
||||
|
||||
return octet->len;
|
||||
}
|
||||
|
||||
|
||||
/* 8.21 User Location Information (ULI) */
|
||||
c_int16_t gtp_parse_uli(gtp_uli_t *uli, tlv_octet_t *octet)
|
||||
{
|
||||
|
|
|
@ -185,6 +185,72 @@ CORE_DECLARE(c_int16_t) gtp_build_bearer_qos(
|
|||
#define GTP_RAT_TYPE_VIRTUAL 7
|
||||
#define GTP_RAT_TYPE_EUTRAN_NB_IOT 8
|
||||
|
||||
/* 8.19 EPS Bearer Level Traffic Flow Template (Bearer TFT)
|
||||
* See subclause 10.5.6.12 in 3GPP TS 24.008 [13]. */
|
||||
#define GTP_MAX_TRAFFIC_FLOW_TEMPLATE 255
|
||||
|
||||
#define GTP_MAX_NUM_OF_PACKET_FILTER_COMPONENT 16
|
||||
typedef struct _gtp_tft_t {
|
||||
union {
|
||||
struct {
|
||||
#define GTP_TFT_CODE_IGNORE_THIS_IE 0
|
||||
#define GTP_TFT_CODE_CREATE_NEW_TFT 1
|
||||
#define GTP_TFT_CODE_DELETE_EXISTING_TFT 2
|
||||
#define GTP_TFT_CODE_ADD_PACKET_FILTERS_TO_EXISTING_TFT 3
|
||||
#define GTP_TFT_CODE_REPLACE_PACKET_FILTERS_IN_EXISTING 4
|
||||
#define GTP_TFT_CODE_DELETE_PACKET_FILTERS_FROM_EXISTING 5
|
||||
#define GTP_TFT_CODE_NO_TFT_OPERATION 6
|
||||
ED3(c_uint8_t code:3;,
|
||||
c_uint8_t e_bit:1;,
|
||||
c_uint8_t num_of_packet_filter:4;)
|
||||
};
|
||||
c_uint8_t flags;
|
||||
};
|
||||
struct {
|
||||
union {
|
||||
struct {
|
||||
ED3(c_uint8_t spare:2;,
|
||||
c_uint8_t direction:2;,
|
||||
c_uint8_t identifier:4;)
|
||||
};
|
||||
c_uint8_t flags;
|
||||
};
|
||||
c_uint8_t precedence;
|
||||
c_uint8_t length;
|
||||
#define GTP_PACKET_FILTER_PROTOCOL_IDENTIFIER_NEXT_HEADER_TYPE 48
|
||||
#define GTP_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE 16
|
||||
#define GTP_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE 17
|
||||
#define GTP_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE 32
|
||||
#define GTP_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE 33
|
||||
#define GTP_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE 35
|
||||
#define GTP_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE 64
|
||||
#define GTP_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE 65
|
||||
#define GTP_PACKET_FILTER_SINGLE_REMOTE_PORT_TYPE 80
|
||||
#define GTP_PACKET_FILTER_REMOTE_PORT_RANGE_TYPE 81
|
||||
#define GTP_PACKET_FILTER_SECURITY_PARAMETER_INDEX_TYPE 96
|
||||
#define GTP_PACKET_FILTER_TOS_TRAFFIC_CLASS_TYPE 112
|
||||
#define GTP_PACKET_FILTER_FLOW_LABEL_TYPE 128
|
||||
struct {
|
||||
c_uint8_t type;
|
||||
union {
|
||||
c_uint8_t proto;
|
||||
struct {
|
||||
c_uint32_t addr;
|
||||
c_uint32_t mask;
|
||||
} ipv4;
|
||||
struct {
|
||||
c_uint16_t low;
|
||||
c_uint16_t high;
|
||||
} port;
|
||||
};
|
||||
} component[GTP_MAX_NUM_OF_PACKET_FILTER_COMPONENT];
|
||||
c_uint8_t num_of_component;
|
||||
} pf[MAX_NUM_OF_PACKET_FILTER];
|
||||
} gtp_tft_t;
|
||||
|
||||
CORE_DECLARE(c_int16_t) gtp_build_tft(
|
||||
tlv_octet_t *octet, gtp_tft_t *tft, void *data, int data_len);
|
||||
|
||||
/* 8.21 User Location Information (ULI) */
|
||||
#define GTP_MAX_ULI_LEN sizeof(gtp_uli_t)
|
||||
typedef struct _gtp_uli_cgi_t {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
## Process this file with automake to produce Makefile.in.
|
||||
|
||||
noinst_LTLIBRARIES = libipfw.la
|
||||
|
||||
libipfw_la_SOURCES = \
|
||||
ipfw2.h \
|
||||
ipfw2.c dummynet.c ipv6.c tables.c \
|
||||
expand_number.c humanize_number.c \
|
||||
glue.c
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/lib/ipfw/objs/include_e \
|
||||
-include glue.h \
|
||||
-DUSERSPACE -D__BSD_VISIBLE -DNEED_STRTONUM -DNEED_ROUNDUP2 \
|
||||
@IPFW_CPPFLAGS@
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall -Werror -Wno-shift-negative-value \
|
||||
-Wno-unused-but-set-variable -Wno-unknown-warning-option
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
MOSTLYCLEANFILES = core *.stackdump
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,101 @@
|
|||
/*-
|
||||
* Copyright (c) 2007 Eric Anderson <anderson@FreeBSD.org>
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: head/lib/libutil/expand_number.c 211343 2010-08-15 18:32:06Z des $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
//#include <libutil.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Convert an expression of the following forms to a uint64_t.
|
||||
* 1) A positive decimal number.
|
||||
* 2) A positive decimal number followed by a 'b' or 'B' (mult by 1).
|
||||
* 3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10).
|
||||
* 4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20).
|
||||
* 5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30).
|
||||
* 6) A positive decimal number followed by a 't' or 'T' (mult by 1 << 40).
|
||||
* 7) A positive decimal number followed by a 'p' or 'P' (mult by 1 << 50).
|
||||
* 8) A positive decimal number followed by a 'e' or 'E' (mult by 1 << 60).
|
||||
*/
|
||||
int
|
||||
expand_number(const char *buf, uint64_t *num)
|
||||
{
|
||||
uint64_t number;
|
||||
unsigned shift;
|
||||
char *endptr;
|
||||
|
||||
number = strtoumax(buf, &endptr, 0);
|
||||
|
||||
if (endptr == buf) {
|
||||
/* No valid digits. */
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
switch (tolower((unsigned char)*endptr)) {
|
||||
case 'e':
|
||||
shift = 60;
|
||||
break;
|
||||
case 'p':
|
||||
shift = 50;
|
||||
break;
|
||||
case 't':
|
||||
shift = 40;
|
||||
break;
|
||||
case 'g':
|
||||
shift = 30;
|
||||
break;
|
||||
case 'm':
|
||||
shift = 20;
|
||||
break;
|
||||
case 'k':
|
||||
shift = 10;
|
||||
break;
|
||||
case 'b':
|
||||
case '\0': /* No unit. */
|
||||
*num = number;
|
||||
return (0);
|
||||
default:
|
||||
/* Unrecognized unit. */
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((number << shift) >> shift != number) {
|
||||
/* Overflow */
|
||||
errno = ERANGE;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*num = number << shift;
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,555 @@
|
|||
/*
|
||||
* Userland functions missing in linux
|
||||
* taken from /usr/src/lib/libc/stdtime/time32.c
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h> /* sockaddr_in */
|
||||
#include <netinet/tcp.h> /* TCP_NODELAY */
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h> /* uint* types */
|
||||
#include <errno.h>
|
||||
#include <string.h> /* bzero */
|
||||
#include <arpa/inet.h> /* htonl */
|
||||
|
||||
#ifndef HAVE_NAT
|
||||
/* dummy nat functions */
|
||||
void
|
||||
ipfw_show_nat(int ac, char **av)
|
||||
{
|
||||
D("unsupported");
|
||||
}
|
||||
|
||||
void
|
||||
ipfw_config_nat(int ac, char **av)
|
||||
{
|
||||
D("unsupported");
|
||||
}
|
||||
#endif /* HAVE_NAT */
|
||||
|
||||
#ifdef NEED_STRTONUM
|
||||
/* missing in linux and windows */
|
||||
long long int
|
||||
strtonum(const char *nptr, long long minval, long long maxval,
|
||||
const char **errstr)
|
||||
{
|
||||
long long ret;
|
||||
int errno_c = errno; /* save actual errno */
|
||||
|
||||
errno = 0;
|
||||
#ifdef TCC
|
||||
ret = strtol(nptr, (char **)errstr, 0);
|
||||
#else
|
||||
ret = strtoll(nptr, (char **)errstr, 0);
|
||||
#endif
|
||||
/* We accept only a string that represent exactly a number (ie. start
|
||||
* and end with a digit).
|
||||
* FreeBSD version wants errstr==NULL if no error occurs, otherwise
|
||||
* errstr should point to an error string.
|
||||
* For our purspose, we implement only the invalid error, ranges
|
||||
* error aren't checked
|
||||
*/
|
||||
if (errno != 0 || nptr == *errstr || **errstr != '\0')
|
||||
*errstr = "invalid";
|
||||
else {
|
||||
*errstr = NULL;
|
||||
errno = errno_c;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ishexnumber(int c)
|
||||
{
|
||||
return ((c >= '0' && c <= '9') ||
|
||||
(c >= 'a' && c <= 'f') ||
|
||||
(c >= 'A' && c <= 'F') );
|
||||
}
|
||||
|
||||
#endif /* NEED_STRTONUM */
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
|
||||
int optreset; /* missing in linux */
|
||||
|
||||
/*
|
||||
* not implemented in linux.
|
||||
* taken from /usr/src/lib/libc/string/strlcpy.c
|
||||
*/
|
||||
size_t
|
||||
strlcpy(dst, src, siz)
|
||||
char *dst;
|
||||
const char *src;
|
||||
size_t siz;
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0 && --n != 0) {
|
||||
do {
|
||||
if ((*d++ = *s++) == 0)
|
||||
break;
|
||||
} while (--n != 0);
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0) {
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
}
|
||||
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
|
||||
#if defined (EMULATE_SYSCTL)
|
||||
//XXX missing prerequisites
|
||||
#include <net/if.h> //openwrt
|
||||
#include <netinet/ip.h> //openwrt
|
||||
#include <netinet/ip_fw.h>
|
||||
#include <netinet/ip_dummynet.h>
|
||||
int do_cmd(int optname, void *optval, uintptr_t optlen);
|
||||
#endif /* EMULATE_SYSCTL */
|
||||
|
||||
/*
|
||||
* set or get system information
|
||||
* XXX lock acquisition/serialize calls
|
||||
*
|
||||
* we export this as sys/module/ipfw_mod/parameters/___
|
||||
* This function get or/and set the value of the sysctl passed by
|
||||
* the name parameter. If the old value is not desired,
|
||||
* oldp and oldlenp should be set to NULL.
|
||||
*
|
||||
* XXX
|
||||
* I do not know how this works in FreeBSD in the case
|
||||
* where there are no write permission on the sysctl var.
|
||||
* We read the value and set return variables in any way
|
||||
* but returns -1 on write failures, regardless the
|
||||
* read success.
|
||||
*
|
||||
* Since there is no information on types, in the following
|
||||
* code we assume a length of 4 is a int.
|
||||
*
|
||||
* Returns 0 on success, -1 on errors.
|
||||
*/
|
||||
int
|
||||
sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
|
||||
size_t newlen)
|
||||
{
|
||||
#if defined (EMULATE_SYSCTL)
|
||||
/*
|
||||
* we embed the sysctl request in the usual sockopt mechanics.
|
||||
* the sockopt buffer il filled with a dn_id with IP_DUMMYNET3
|
||||
* command, and the special DN_SYSCTL_GET and DN_SYSCTL_SET
|
||||
* subcommands.
|
||||
* the syntax of this function is fully compatible with
|
||||
* POSIX sysctlby name:
|
||||
* if newp and newlen are != 0 => this is a set
|
||||
* else if oldp and oldlen are != 0 => this is a get
|
||||
* to avoid too much overhead in the module, the whole
|
||||
* sysctltable is returned, and the parsing is done in userland,
|
||||
* a probe request is done to retrieve the size needed to
|
||||
* transfer the table, before the real request
|
||||
* if both old and new params = 0 => this is a print
|
||||
* this is a special request, done only by main()
|
||||
* to implement the extension './ipfw sysctl',
|
||||
* a command that bypasses the normal getopt, and that
|
||||
* is available on those platforms that use this
|
||||
* sysctl emulation.
|
||||
* in this case, a negative oldlen signals that *oldp
|
||||
* is actually a FILE* to print somewhere else than stdout
|
||||
*/
|
||||
|
||||
int l;
|
||||
int ret;
|
||||
struct dn_id* oid;
|
||||
struct sysctlhead* entry;
|
||||
char* pstring;
|
||||
char* pdata;
|
||||
FILE* fp;
|
||||
|
||||
if((oldlenp != NULL) && ((int)*oldlenp < 0))
|
||||
fp = (FILE*)oldp;
|
||||
else
|
||||
fp = stdout;
|
||||
if(newp != NULL && newlen != 0)
|
||||
{
|
||||
//this is a set
|
||||
l = sizeof(struct dn_id) + sizeof(struct sysctlhead) + strlen(name)+1 + newlen;
|
||||
oid = malloc(l);
|
||||
if (oid == NULL)
|
||||
return -1;
|
||||
oid->len = l;
|
||||
oid->type = DN_SYSCTL_SET;
|
||||
oid->id = DN_API_VERSION;
|
||||
|
||||
entry = (struct sysctlhead*)(oid+1);
|
||||
pdata = (char*)(entry+1);
|
||||
pstring = pdata + newlen;
|
||||
|
||||
entry->blocklen = ((sizeof(struct sysctlhead) + strlen(name)+1 + newlen) + 3) & ~3;
|
||||
entry->namelen = strlen(name)+1;
|
||||
entry->flags = 0;
|
||||
entry->datalen = newlen;
|
||||
|
||||
bcopy(newp, pdata, newlen);
|
||||
bcopy(name, pstring, strlen(name)+1);
|
||||
|
||||
ret = do_cmd(IP_DUMMYNET3, oid, (uintptr_t)l);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//this is a get or a print
|
||||
l = sizeof(struct dn_id);
|
||||
oid = malloc(l);
|
||||
if (oid == NULL)
|
||||
return -1;
|
||||
oid->len = l;
|
||||
oid->type = DN_SYSCTL_GET;
|
||||
oid->id = DN_API_VERSION;
|
||||
|
||||
ret = do_cmd(-IP_DUMMYNET3, oid, (uintptr_t)&l);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
l=oid->id;
|
||||
free(oid);
|
||||
oid = malloc(l);
|
||||
if (oid == NULL)
|
||||
return -1;
|
||||
oid->len = l;
|
||||
oid->type = DN_SYSCTL_GET;
|
||||
oid->id = DN_API_VERSION;
|
||||
|
||||
ret = do_cmd(-IP_DUMMYNET3, oid, (uintptr_t)&l);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
entry = (struct sysctlhead*)(oid+1);
|
||||
while(entry->blocklen != 0)
|
||||
{
|
||||
pdata = (char*)(entry+1);
|
||||
pstring = pdata+entry->datalen;
|
||||
|
||||
//time to check if this is a get or a print
|
||||
if(name != NULL && oldp != NULL && *oldlenp > 0)
|
||||
{
|
||||
//this is a get
|
||||
if(strcmp(name,pstring) == 0)
|
||||
{
|
||||
//match found, sanity chech on len
|
||||
if(*oldlenp < entry->datalen)
|
||||
{
|
||||
printf("%s error: buffer too small\n",__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
*oldlenp = entry->datalen;
|
||||
bcopy(pdata, oldp, *oldlenp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//this is a print
|
||||
if( name == NULL )
|
||||
goto print;
|
||||
if ( (strncmp(pstring,name,strlen(name)) == 0) && ( pstring[strlen(name)]=='\0' || pstring[strlen(name)]=='.' ) )
|
||||
goto print;
|
||||
else
|
||||
goto skip;
|
||||
print:
|
||||
fprintf(fp, "%s: ",pstring);
|
||||
switch( entry->flags >> 2 )
|
||||
{
|
||||
case SYSCTLTYPE_LONG:
|
||||
fprintf(fp, "%li ", *(long*)(pdata));
|
||||
break;
|
||||
case SYSCTLTYPE_UINT:
|
||||
fprintf(fp, "%u ", *(unsigned int*)(pdata));
|
||||
break;
|
||||
case SYSCTLTYPE_ULONG:
|
||||
fprintf(fp, "%lu ", *(unsigned long*)(pdata));
|
||||
break;
|
||||
case SYSCTLTYPE_INT:
|
||||
default:
|
||||
fprintf(fp, "%i ", *(int*)(pdata));
|
||||
}
|
||||
if( (entry->flags & 0x00000003) == CTLFLAG_RD )
|
||||
fprintf(fp, "\t(read only)\n");
|
||||
else
|
||||
fprintf(fp, "\n");
|
||||
skip: ;
|
||||
}
|
||||
entry = (struct sysctlhead*)((unsigned char*)entry + entry->blocklen);
|
||||
}
|
||||
free(oid);
|
||||
return 0;
|
||||
}
|
||||
//fallback for invalid options
|
||||
return -1;
|
||||
|
||||
#else /* __linux__ */
|
||||
FILE *fp;
|
||||
char *basename = "/sys/module/ipfw_mod/parameters/";
|
||||
char filename[256]; /* full filename */
|
||||
char *varp;
|
||||
int ret = 0; /* return value */
|
||||
int d;
|
||||
|
||||
if (name == NULL) /* XXX set errno */
|
||||
return -1;
|
||||
|
||||
/* locate the filename */
|
||||
varp = strrchr(name, '.');
|
||||
if (varp == NULL) /* XXX set errno */
|
||||
return -1;
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s%s", basename, varp+1);
|
||||
|
||||
/*
|
||||
* XXX we could open the file here, in rw mode
|
||||
* but need to check if a file have write
|
||||
* permissions.
|
||||
*/
|
||||
|
||||
/* check parameters */
|
||||
if (oldp && oldlenp) { /* read mode */
|
||||
fp = fopen(filename, "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "%s fopen error reading filename %s\n", __FUNCTION__, filename);
|
||||
return -1;
|
||||
}
|
||||
if (*oldlenp == 4) {
|
||||
if (fscanf(fp, "%d", &d) == 1)
|
||||
memcpy(oldp, &d, *oldlenp);
|
||||
else
|
||||
ret = -1;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (newp && newlen) { /* write */
|
||||
fp = fopen(filename, "w");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "%s fopen error writing filename %s\n", __FUNCTION__, filename);
|
||||
return -1;
|
||||
}
|
||||
if (newlen == 4) {
|
||||
if (fprintf(fp, "%d", *(int*)newp) < 1)
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
/*
|
||||
* The following two functions implement getsockopt/setsockopt
|
||||
* replacements to talk over a TCP socket.
|
||||
* Because the calls are synchronous, we can run blocking code
|
||||
* and do not need to play special tricks to be selectable.
|
||||
* The wire protocol for the emulation is the following:
|
||||
* REQUEST: n32 req_size, level, optname; u8 data[req_size]
|
||||
* RESPONSE: n32 resp_size, ret_code; u8 data[resp_size]
|
||||
* data is only present if ret_code == 0
|
||||
*
|
||||
* Return 0 if the message wan sent to the remote
|
||||
* endpoint, -1 on error.
|
||||
*
|
||||
* If the required lenght is greater then the
|
||||
* available buffer size, -1 is returned and
|
||||
* optlen is the required lenght.
|
||||
*/
|
||||
enum sock_type {GET_SOCKOPT, SET_SOCKOPT};
|
||||
|
||||
struct wire_hdr {
|
||||
uint32_t optlen; /* actual data len */
|
||||
uint32_t level; /* or error */
|
||||
uint32_t optname; /* or act len */
|
||||
uint32_t dir; /* in or out */
|
||||
};
|
||||
|
||||
/* do a complete write of the buffer */
|
||||
static int
|
||||
writen(int fd, const char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (; len > 0; buf += i, len -= i) {
|
||||
i = write(fd, buf, len);
|
||||
ND("have %d wrote %d", len, i);
|
||||
if (i < 0) {
|
||||
if (errno == EAGAIN)
|
||||
continue;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do a complete read */
|
||||
static int
|
||||
readn(int fd, char *buf, int len)
|
||||
{
|
||||
int i, pos;
|
||||
|
||||
for (pos = 0; pos < len; pos += i) {
|
||||
i = read(fd, buf + pos, len - pos);
|
||||
ND("have %d want %d got %d", pos, len, i);
|
||||
if (i < 0) {
|
||||
if (errno == EAGAIN)
|
||||
continue;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ND("full read got %d", pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__sockopt2(int s, int level, int optname, void *optval, socklen_t *optlen,
|
||||
enum sopt_dir dir)
|
||||
{
|
||||
struct wire_hdr r;
|
||||
int len = optlen && optval ? *optlen : 0;
|
||||
int new_errno;
|
||||
|
||||
ND("dir %d optlen %d level %d optname %d", dir, len, level, optname);
|
||||
/* send request to the server */
|
||||
r.optlen = htonl(len);
|
||||
r.level = htonl(level);
|
||||
r.optname = htonl(optname);
|
||||
r.dir = htonl(dir);
|
||||
|
||||
if (writen(s, (const char *) &r, sizeof(r)))
|
||||
return -1; /* error writing */
|
||||
|
||||
/* send data, if present */
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "%s invalid args found\n", __FUNCTION__);
|
||||
return -1;
|
||||
} else if (len > 0) {
|
||||
if (writen(s, optval, len))
|
||||
return -1; /* error writing */
|
||||
}
|
||||
|
||||
/* read response size and error code */
|
||||
if (readn(s, (char *)&r, sizeof(r)))
|
||||
return -1; /* error reading */
|
||||
len = ntohl(r.optlen);
|
||||
ND("got header, datalen %d", len);
|
||||
if (len > 0) {
|
||||
if (readn(s, optval, len)) {
|
||||
return -1; /* error reading */
|
||||
}
|
||||
}
|
||||
if (optlen)
|
||||
*optlen = ntohl(r.optlen); /* actual len */
|
||||
new_errno = ntohl(r.level);
|
||||
if (new_errno)
|
||||
errno = new_errno;
|
||||
return (new_errno ? -1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* getsockopt() replacement.
|
||||
*/
|
||||
int
|
||||
getsockopt2(int s, int level, int optname, void *optval,
|
||||
socklen_t *optlen)
|
||||
{
|
||||
return __sockopt2(s, level, optname, optval, optlen, SOPT_GET);
|
||||
}
|
||||
|
||||
/*
|
||||
* setsockopt() replacement
|
||||
*/
|
||||
int
|
||||
setsockopt2(int s, int level, int optname, void *optval,
|
||||
socklen_t optlen)
|
||||
{
|
||||
/* optlen not changed, use the local address */
|
||||
return __sockopt2(s, level, optname, optval, &optlen, SOPT_SET);
|
||||
}
|
||||
|
||||
#ifdef socket
|
||||
#undef socket /* we want the real one */
|
||||
#endif
|
||||
/*
|
||||
* This function replaces the socket() call to connect to
|
||||
* the ipfw control socket.
|
||||
* We actually ignore the paramerers if IPFW_HOST and IPFW_PORT
|
||||
* are defined.
|
||||
*/
|
||||
int
|
||||
do_connect(const char *addr, int port)
|
||||
{
|
||||
int conn_fd;
|
||||
|
||||
/* open the socket */
|
||||
#ifdef NETLINK
|
||||
|
||||
struct rtnl_handle rth;
|
||||
|
||||
conn_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||
#else
|
||||
struct sockaddr_in server; /* server address */
|
||||
const char *s;
|
||||
|
||||
conn_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (conn_fd < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#ifndef NETLINK
|
||||
/* fill the sockaddr structure with server address */
|
||||
bzero(&server, sizeof(server));
|
||||
server.sin_family = AF_INET;
|
||||
|
||||
/* override the host if set in the environment */
|
||||
s = getenv("IPFW_HOST");
|
||||
if (s)
|
||||
addr = s;
|
||||
inet_aton(addr, &server.sin_addr);
|
||||
s = getenv("IPFW_PORT");
|
||||
if (s && atoi(s) > 0)
|
||||
port = atoi(s);
|
||||
server.sin_port = htons(port);
|
||||
|
||||
/* connect to the server */
|
||||
if (connect(conn_fd, (struct sockaddr*) &server, sizeof(server)) < 0) {
|
||||
perror("connect");
|
||||
return -1;
|
||||
}
|
||||
#ifdef setsockopt /* we want the real one here */
|
||||
#undef setsockopt
|
||||
#undef getsockopt
|
||||
#endif
|
||||
{
|
||||
int on = 1, ret;
|
||||
ret = setsockopt(conn_fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
|
||||
ND("set TCP_NODELAY %d returns %d", on, ret);
|
||||
}
|
||||
if (0)
|
||||
fprintf(stderr, "connected to %s:%d\n",
|
||||
inet_ntoa(server.sin_addr), ntohs(server.sin_port));
|
||||
#endif
|
||||
return conn_fd;
|
||||
}
|
|
@ -0,0 +1,488 @@
|
|||
/*
|
||||
* Copyright (c) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* $Id: glue.h 8327 2011-03-22 17:01:35Z marta $
|
||||
*
|
||||
* glue code to adapt the FreeBSD version to linux and windows,
|
||||
* userland and kernel.
|
||||
* This is included before any other headers, so we do not have
|
||||
* a chance to override any #define that should appear in other
|
||||
* headers.
|
||||
* First handle headers for userland and kernel. Then common code
|
||||
* (including headers that require a specific order of inclusion),
|
||||
* then the user- and kernel- specific parts.
|
||||
*/
|
||||
|
||||
#ifndef _GLUE_H
|
||||
#define _GLUE_H
|
||||
|
||||
/*
|
||||
* common definitions to allow portability
|
||||
*/
|
||||
#ifndef __FBSDID
|
||||
#define __FBSDID(x) struct __hack
|
||||
#endif /* FBSDID */
|
||||
|
||||
#include <stdint.h> /* linux needs it in addition to sys/types.h */
|
||||
#include <sys/types.h> /* for size_t */
|
||||
|
||||
#define true 1 /* stdbool */
|
||||
#ifdef _KERNEL /* prevent a warning */
|
||||
#undef _KERNEL
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h> /* we want errno */
|
||||
#define _KERNEL
|
||||
#else
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#ifndef USERSPACE
|
||||
#include <netinet/ether.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*----- */
|
||||
|
||||
/* ipfw2.c - from timeconv.h */
|
||||
static __inline time_t
|
||||
_long_to_time(long tlong)
|
||||
{
|
||||
if (sizeof(long) == sizeof(__int32_t))
|
||||
return((time_t)(__int32_t)(tlong));
|
||||
return((time_t)tlong);
|
||||
}
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b) ) // radix.c
|
||||
/*
|
||||
* debugging macros from ip_dn_private.h
|
||||
*/
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
extern char *strrchr(const char *, int);
|
||||
static inline const char *xyz(const char *s) {
|
||||
static char buf[128];
|
||||
struct timeval t;
|
||||
const char *ret = strrchr(s, '/');
|
||||
if (ret) s = ret + 1;
|
||||
gettimeofday(&t, NULL);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
snprintf(buf, sizeof(buf), "[%4d.%06d] %s",
|
||||
(int)(t.tv_sec % 1000), (int)(t.tv_usec), s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define ND(fmt, ...) do {} while (0)
|
||||
#define D1(fmt, ...) do {} while (0)
|
||||
#define D(fmt, ...) fprintf(stderr, "%s:%-10s [%d] " fmt "\n", \
|
||||
xyz(__FILE__), __FUNCTION__, __LINE__, ## __VA_ARGS__)
|
||||
|
||||
/* Rate limited version of "D", lps indicates how many per second */
|
||||
#define RD(lps, format, ...) \
|
||||
do { \
|
||||
static int t0, __cnt; \
|
||||
struct timeval __xxts; \
|
||||
gettimeofday(&__xxts, NULL); \
|
||||
if (t0 != __xxts.tv_sec) { \
|
||||
t0 = __xxts.tv_sec; \
|
||||
__cnt = 0; \
|
||||
} \
|
||||
if (__cnt++ < lps) { \
|
||||
D(format, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DX(lev, fmt, ...) do { \
|
||||
if (dn_cfg.debug > lev) D(fmt, ## __VA_ARGS__); } while (0)
|
||||
/* end debugging macros */
|
||||
|
||||
|
||||
/*
|
||||
* sbin/ipfw on non-freebsd platform
|
||||
*/
|
||||
#ifdef NEED_STRTONUM
|
||||
/* prototypes from libutil */
|
||||
/* humanize_number(3) */
|
||||
#define HN_DECIMAL 0x01
|
||||
#define HN_NOSPACE 0x02
|
||||
#define HN_B 0x04
|
||||
#define HN_DIVISOR_1000 0x08
|
||||
#define HN_IEC_PREFIXES 0x10
|
||||
|
||||
#define HN_GETSCALE 0x10
|
||||
#define HN_AUTOSCALE 0x20
|
||||
|
||||
|
||||
int humanize_number(char *_buf, size_t _len, int64_t _number,
|
||||
const char *_suffix, int _scale, int _flags);
|
||||
int expand_number(const char *buf, uint64_t *num);
|
||||
|
||||
|
||||
long long
|
||||
strtonum(const char *nptr, long long minval, long long maxval,
|
||||
const char **errstr);
|
||||
#ifndef __APPLE__
|
||||
int ishexnumber(int c);
|
||||
#endif
|
||||
#endif /* NEED_STRTONUM */
|
||||
|
||||
#ifdef NEED_SYSCTLBYNAME /* and other linux calls */
|
||||
int sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen);
|
||||
#define setprogname(x) /* not present in linux */
|
||||
|
||||
extern int optreset; /* not present in linux */
|
||||
|
||||
long long int strtonum(const char *nptr, long long minval,
|
||||
long long maxval, const char **errstr);
|
||||
|
||||
|
||||
struct ether_addr;
|
||||
struct ether_addr * ether_aton(const char *a);
|
||||
|
||||
#define ICMP6_MAXTYPE 201
|
||||
#define __u6_addr in6_u
|
||||
#define in6_u __in6_u /* missing type for ipv6 (linux 2.6.28) */
|
||||
|
||||
|
||||
#define __u6_addr32 u6_addr32
|
||||
/* on freebsd sys/socket.h pf specific */
|
||||
#define NET_RT_IFLIST 3 /* survey interface list */
|
||||
|
||||
#define RTM_VERSION 5 /* Up the ante and ignore older versions */
|
||||
|
||||
#endif // NEED_SYSCTLBYNAME
|
||||
|
||||
#ifdef NEED_SIN_LEN
|
||||
/*
|
||||
* linux at least does not have sin_len and sin6_len, so we remap
|
||||
* to some safe fields (check use of sin6_flowinfo XXX)
|
||||
*/
|
||||
#define sin_len sin_zero[0]
|
||||
#define sin6_len sin6_flowinfo
|
||||
#endif /* NEED_SIN_LEN */
|
||||
|
||||
#ifdef NEED_ROUNDUP2 /* in freensd is in sys/param.h */
|
||||
/* round up to the next power of 2 (y) */
|
||||
#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
|
||||
#endif // NEED_ROUNDUP2
|
||||
|
||||
/* possibly redundant, does not harm */
|
||||
size_t strlcpy(char * dst, const char * src, size_t siz);
|
||||
|
||||
/*
|
||||
* Part 2: common userland and kernel definitions
|
||||
*/
|
||||
|
||||
#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */
|
||||
#define ICMP6_DST_UNREACH_ADMIN 1 /* administratively prohibited */
|
||||
#define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */
|
||||
#define ICMP6_DST_UNREACH_NOPORT 4 /* port unreachable */
|
||||
|
||||
/*
|
||||
* linux: sysctl are mapped into /sys/module/ipfw_mod parameters
|
||||
* windows: they are emulated via get/setsockopt
|
||||
*/
|
||||
#define CTLFLAG_RD 1
|
||||
#define CTLFLAG_RDTUN 1
|
||||
#define CTLFLAG_RW 2
|
||||
#define CTLFLAG_SECURE3 0 /* unsupported */
|
||||
#define CTLFLAG_VNET 0 /* unsupported */
|
||||
|
||||
/* if needed, queue.h must be included here after list.h */
|
||||
|
||||
/*
|
||||
* our own struct thread
|
||||
*/
|
||||
struct thread { /* ip_fw_sockopt */
|
||||
void *sopt_td;
|
||||
void *td_ucred;
|
||||
};
|
||||
|
||||
enum sopt_dir { SOPT_GET, SOPT_SET };
|
||||
|
||||
struct sockopt {
|
||||
enum sopt_dir sopt_dir; /* is this a get or a set? */
|
||||
int sopt_level; /* second arg of [gs]etsockopt */
|
||||
int sopt_name; /* third arg of [gs]etsockopt */
|
||||
void *sopt_val; /* fourth arg of [gs]etsockopt */
|
||||
size_t sopt_valsize; /* (almost) fifth arg of [gs]etsockopt */
|
||||
struct thread *sopt_td; /* calling thread or null if kernel */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* List of values used for set/getsockopt options.
|
||||
* The base value on FreeBSD is defined as a macro,
|
||||
* if not available we will use our own enum.
|
||||
* The TABLE_BASE value is used in the kernel.
|
||||
*/
|
||||
#define _IPFW_SOCKOPT_BASE 100 /* 40 on freebsd */
|
||||
#define IP_FW_TABLE_ADD (_IPFW_SOCKOPT_BASE + 0)
|
||||
#define IP_FW_TABLE_DEL (_IPFW_SOCKOPT_BASE + 1)
|
||||
#define IP_FW_TABLE_FLUSH (_IPFW_SOCKOPT_BASE + 2)
|
||||
#define IP_FW_TABLE_GETSIZE (_IPFW_SOCKOPT_BASE + 3)
|
||||
#define IP_FW_TABLE_LIST (_IPFW_SOCKOPT_BASE + 4)
|
||||
#define IP_FW_DYN_GET (_IPFW_SOCKOPT_BASE + 5)
|
||||
|
||||
#define IP_FW3 (_IPFW_SOCKOPT_BASE + 8)
|
||||
#define IP_DUMMYNET3 (_IPFW_SOCKOPT_BASE + 9)
|
||||
|
||||
#define IP_FW_ADD (_IPFW_SOCKOPT_BASE + 10)
|
||||
#define IP_FW_DEL (_IPFW_SOCKOPT_BASE + 11)
|
||||
#define IP_FW_FLUSH (_IPFW_SOCKOPT_BASE + 12)
|
||||
#define IP_FW_ZERO (_IPFW_SOCKOPT_BASE + 13)
|
||||
#define IP_FW_GET (_IPFW_SOCKOPT_BASE + 14)
|
||||
#define IP_FW_RESETLOG (_IPFW_SOCKOPT_BASE + 15)
|
||||
|
||||
#define IP_FW_NAT_CFG (_IPFW_SOCKOPT_BASE + 16)
|
||||
#define IP_FW_NAT_DEL (_IPFW_SOCKOPT_BASE + 17)
|
||||
#define IP_FW_NAT_GET_CONFIG (_IPFW_SOCKOPT_BASE + 18)
|
||||
#define IP_FW_NAT_GET_LOG (_IPFW_SOCKOPT_BASE + 19)
|
||||
|
||||
#define IP_DUMMYNET_CONFIGURE (_IPFW_SOCKOPT_BASE + 20)
|
||||
#define IP_DUMMYNET_DEL (_IPFW_SOCKOPT_BASE + 21)
|
||||
#define IP_DUMMYNET_FLUSH (_IPFW_SOCKOPT_BASE + 22)
|
||||
/* 63 is missing */
|
||||
#define IP_DUMMYNET_GET (_IPFW_SOCKOPT_BASE + 24)
|
||||
#define _IPFW_SOCKOPT_END (_IPFW_SOCKOPT_BASE + 25)
|
||||
|
||||
/*
|
||||
* Part 3: userland stuff for linux/windows
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* now remap functions for userland or linux kernel etc.
|
||||
*/
|
||||
#ifdef USERSPACE
|
||||
/*
|
||||
* definitions used when the programs communicate through userspace.
|
||||
* We need to define the socket and addresses used to talk, and
|
||||
* the userland side must also remap socket() and [gs]etsockopt()
|
||||
* to appropriate wrappers.
|
||||
*/
|
||||
|
||||
#define LOCALADDR "127.0.0.1"
|
||||
#define IPFW_PORT 5555
|
||||
|
||||
#ifndef KERNEL_SIDE
|
||||
#ifdef _KERNEL
|
||||
#error _KERNEL defined in user space
|
||||
#endif
|
||||
int do_connect(const char *addr, int port);
|
||||
#include <sys/socket.h> /* for socklen_t */
|
||||
|
||||
#define socket(a, b, c) do_connect(LOCALADDR, IPFW_PORT)
|
||||
#define setsockopt setsockopt2
|
||||
#define getsockopt getsockopt2
|
||||
int getsockopt2(int s, int lev, int optname, void *optval, socklen_t *optlen);
|
||||
int setsockopt2(int s, int lev, int optname, void *optval, socklen_t optlen);
|
||||
#endif /* KERNEL_SIDE */
|
||||
|
||||
#endif /* USERSPACE */
|
||||
|
||||
/*
|
||||
* Part 5: windows specific stuff and sysctl emulation
|
||||
*/
|
||||
|
||||
/*******************
|
||||
* SYSCTL emulation *
|
||||
********************/
|
||||
#ifdef EMULATE_SYSCTL
|
||||
|
||||
/* this needs to be here, as it is part of the user-kernel messages */
|
||||
/* flag is set with the last 2 bits for access, as defined in glue.h
|
||||
* and the rest for type
|
||||
*/
|
||||
enum {
|
||||
SYSCTLTYPE_INT = 0,
|
||||
SYSCTLTYPE_UINT = 1,
|
||||
SYSCTLTYPE_SHORT = 2,
|
||||
SYSCTLTYPE_USHORT = 3,
|
||||
SYSCTLTYPE_LONG = 4,
|
||||
SYSCTLTYPE_ULONG = 5,
|
||||
SYSCTLTYPE_STRING = 6,
|
||||
|
||||
/* the following are SYSCTL_PROC equivalents of the above,
|
||||
* where the SYSCTLTYPE is shifted 2 bits,
|
||||
* and SYSCTLTYPE_PROC is set
|
||||
*/
|
||||
SYSCTLTYPE_PROC = 0x100,
|
||||
CTLTYPE_INT = (0x100 | (0<<2)),
|
||||
CTLTYPE_UINT = (0x100 | (1<<2)),
|
||||
CTLTYPE_LONG = (0x100 | (4<<2)),
|
||||
CTLTYPE_ULONG = (0x100 | (5<<2))
|
||||
};
|
||||
|
||||
struct sysctlhead {
|
||||
uint32_t blocklen; //total size of the entry
|
||||
uint32_t namelen; //strlen(name) + '\0'
|
||||
uint32_t flags; //type and access
|
||||
uint32_t datalen;
|
||||
};
|
||||
|
||||
|
||||
#endif /* EMULATE_SYSCTL */
|
||||
int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
|
||||
size_t newlen);
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
#define test_bit(ix, pData) ((*pData) & (1<<(ix)))
|
||||
#define __set_bit(ix, pData) (*pData) |= (1<<(ix))
|
||||
#define __clear_bit(ix, pData) (*pData) &= ~(1<<(ix))
|
||||
|
||||
static inline int fls(int _n)
|
||||
{
|
||||
unsigned int n = _n;
|
||||
int i = 0;
|
||||
for (i = 0; n > 0; n >>= 1, i++)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline unsigned long __fls(unsigned long word)
|
||||
{
|
||||
return fls(word) - 1;
|
||||
}
|
||||
|
||||
|
||||
#endif /* !FreeBSD */
|
||||
|
||||
#ifdef KERNEL_SIDE
|
||||
/* sys/counter.h , to be moved to a file */
|
||||
typedef uint64_t *counter_u64_t; // XXX kernel
|
||||
static inline void counter_u64_add(counter_u64_t c, int64_t v)
|
||||
{
|
||||
*c += v;
|
||||
}
|
||||
static inline void counter_u64_zero(counter_u64_t c)
|
||||
{
|
||||
*c = 0;
|
||||
}
|
||||
static inline uint64_t counter_u64_fetch(counter_u64_t c)
|
||||
{
|
||||
return *c;
|
||||
}
|
||||
|
||||
struct rm_priotracker {
|
||||
};
|
||||
|
||||
#define vslock(_a, _b) (0)
|
||||
#define vsunlock(_a, _b)
|
||||
|
||||
typedef uint64_t u_register_t; // XXX not on osx ?
|
||||
|
||||
typedef uintptr_t eventhandler_tag;
|
||||
#define EVENTHANDLER_REGISTER(_a, _b, ...) (uintptr_t)_b;
|
||||
#define EVENTHANDLER_DEREGISTER(_a, _b, ...) (void)_b;
|
||||
|
||||
// XXX this needs to be completed
|
||||
#define if_name(_ifp) (_ifp->if_xname)
|
||||
#define ifunit_ref(_n) NULL // XXX
|
||||
#define if_rele(_n)
|
||||
|
||||
#define rtalloc1_fib(_a, ...) NULL
|
||||
#define rt_key(_a) NULL
|
||||
#define rt_mask(_a) NULL
|
||||
#define RTFREE_LOCKED(_a) ((void)NULL)
|
||||
struct rtentry {
|
||||
};
|
||||
#define rt_tables_get_rnh(_a, _b) NULL
|
||||
|
||||
#endif /* KERNEL_SIDE */
|
||||
|
||||
#ifdef _KERNEL
|
||||
/* XXX kernel support */
|
||||
/* on freebsd net/if.h XXX used */
|
||||
#ifdef linux
|
||||
#define div64(a,b) (((int64_t)a)/((int64_t)b))
|
||||
#define LINUX_VERSION_CODE 30003
|
||||
#define KERNEL_VERSION(a,b,c) (a*10000+b*100 + c)
|
||||
#define __printflike(a,b)
|
||||
#endif /* linux */
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
#ifndef IFNAMSIZ
|
||||
#define IFNAMSIZ 16
|
||||
#endif
|
||||
#include "missing.h"
|
||||
|
||||
struct if_data {
|
||||
/* ... */
|
||||
u_long ifi_mtu; /* maximum transmission unit */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/socketvar.h> // need in kernel
|
||||
|
||||
/* needed both in kernel and userspace */
|
||||
struct if_data64 { // XXX Darwin version
|
||||
/* ... */
|
||||
u_long ifi_mtu; /* maximum transmission unit */
|
||||
};
|
||||
|
||||
struct net_event_data {
|
||||
};
|
||||
|
||||
struct in_addr;
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#define __PAST_END(v, idx) v[idx]
|
||||
|
||||
/*
|
||||
* a fast copy routine
|
||||
*/
|
||||
#include <strings.h>
|
||||
// XXX only for multiples of 64 bytes, non overlapped.
|
||||
static inline void
|
||||
_pkt_copy(const void *_src, void *_dst, int l)
|
||||
{
|
||||
const uint64_t *src = _src;
|
||||
uint64_t *dst = _dst;
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
if (unlikely(l >= 1024)) {
|
||||
bcopy(src, dst, l);
|
||||
return;
|
||||
}
|
||||
for (; l > 0; l-=64) {
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !_GLUE_H */
|
|
@ -0,0 +1,167 @@
|
|||
/* $NetBSD: humanize_number.c,v 1.14 2008/04/28 20:22:59 martin Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
|
||||
* NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: head/lib/libutil/humanize_number.c 220582 2011-04-12 22:48:03Z delphij $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
//#include <libutil.h>
|
||||
|
||||
static const int maxscale = 7;
|
||||
|
||||
int
|
||||
humanize_number(char *buf, size_t len, int64_t quotient,
|
||||
const char *suffix, int scale, int flags)
|
||||
{
|
||||
const char *prefixes, *sep;
|
||||
int i, r, remainder, s1, s2, sign;
|
||||
int64_t divisor, max;
|
||||
size_t baselen;
|
||||
|
||||
assert(buf != NULL);
|
||||
assert(suffix != NULL);
|
||||
assert(scale >= 0);
|
||||
assert(scale < maxscale || (((scale & (HN_AUTOSCALE | HN_GETSCALE)) != 0)));
|
||||
assert(!((flags & HN_DIVISOR_1000) && (flags & HN_IEC_PREFIXES)));
|
||||
|
||||
remainder = 0;
|
||||
|
||||
if (flags & HN_IEC_PREFIXES) {
|
||||
baselen = 2;
|
||||
/*
|
||||
* Use the prefixes for power of two recommended by
|
||||
* the International Electrotechnical Commission
|
||||
* (IEC) in IEC 80000-3 (i.e. Ki, Mi, Gi...).
|
||||
*
|
||||
* HN_IEC_PREFIXES implies a divisor of 1024 here
|
||||
* (use of HN_DIVISOR_1000 would have triggered
|
||||
* an assertion earlier).
|
||||
*/
|
||||
divisor = 1024;
|
||||
if (flags & HN_B)
|
||||
prefixes = "B\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei";
|
||||
else
|
||||
prefixes = "\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei";
|
||||
} else {
|
||||
baselen = 1;
|
||||
if (flags & HN_DIVISOR_1000)
|
||||
divisor = 1000;
|
||||
else
|
||||
divisor = 1024;
|
||||
|
||||
if (flags & HN_B)
|
||||
prefixes = "B\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E";
|
||||
else
|
||||
prefixes = "\0\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E";
|
||||
}
|
||||
|
||||
#define SCALE2PREFIX(scale) (&prefixes[(scale) * 3])
|
||||
|
||||
if (scale < 0 || (scale >= maxscale &&
|
||||
(scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0))
|
||||
return (-1);
|
||||
|
||||
if (buf == NULL || suffix == NULL)
|
||||
return (-1);
|
||||
|
||||
if (len > 0)
|
||||
buf[0] = '\0';
|
||||
if (quotient < 0) {
|
||||
sign = -1;
|
||||
quotient = -quotient;
|
||||
baselen += 2; /* sign, digit */
|
||||
} else {
|
||||
sign = 1;
|
||||
baselen += 1; /* digit */
|
||||
}
|
||||
if (flags & HN_NOSPACE)
|
||||
sep = "";
|
||||
else {
|
||||
sep = " ";
|
||||
baselen++;
|
||||
}
|
||||
baselen += strlen(suffix);
|
||||
|
||||
/* Check if enough room for `x y' + suffix + `\0' */
|
||||
if (len < baselen + 1)
|
||||
return (-1);
|
||||
|
||||
if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
|
||||
/* See if there is additional columns can be used. */
|
||||
for (max = 1, i = len - baselen; i-- > 0;)
|
||||
max *= 10;
|
||||
|
||||
/*
|
||||
* Divide the number until it fits the given column.
|
||||
* If there will be an overflow by the rounding below,
|
||||
* divide once more.
|
||||
*/
|
||||
for (i = 0;
|
||||
(quotient >= max || (quotient == max - 1 && remainder >= 950)) &&
|
||||
i < maxscale; i++) {
|
||||
remainder = quotient % divisor;
|
||||
quotient /= divisor;
|
||||
}
|
||||
|
||||
if (scale & HN_GETSCALE)
|
||||
return (i);
|
||||
} else {
|
||||
for (i = 0; i < scale && i < maxscale; i++) {
|
||||
remainder = quotient % divisor;
|
||||
quotient /= divisor;
|
||||
}
|
||||
}
|
||||
|
||||
/* If a value <= 9.9 after rounding and ... */
|
||||
if (quotient <= 9 && remainder < 950 && i > 0 && flags & HN_DECIMAL) {
|
||||
/* baselen + \0 + .N */
|
||||
if (len < baselen + 1 + 2)
|
||||
return (-1);
|
||||
s1 = (int)quotient + ((remainder + 50) / 1000);
|
||||
s2 = ((remainder + 50) / 100) % 10;
|
||||
r = snprintf(buf, len, "%d%s%d%s%s%s",
|
||||
sign * s1, localeconv()->decimal_point, s2,
|
||||
sep, SCALE2PREFIX(i), suffix);
|
||||
} else
|
||||
r = snprintf(buf, len, "%" PRId64 "%s%s%s",
|
||||
sign * (quotient + (remainder + 50) / 1000),
|
||||
sep, SCALE2PREFIX(i), suffix);
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2003 Luigi Rizzo
|
||||
* Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
|
||||
* Copyright (c) 1994 Ugen J.S.Antsilevich
|
||||
*
|
||||
* Idea and grammar partially left from:
|
||||
* Copyright (c) 1993 Daniel Boulet
|
||||
*
|
||||
* Redistribution and use in source forms, with and without modification,
|
||||
* are permitted provided that this entire comment appears intact.
|
||||
*
|
||||
* Redistribution in binary form may occur without any restrictions.
|
||||
* Obviously, it would be nice if you gave credit where credit is due
|
||||
* but requiring it would be too onerous.
|
||||
*
|
||||
* This software is provided ``AS IS'' without any warranties of any kind.
|
||||
*
|
||||
* NEW command line interface for IP firewall facility
|
||||
*
|
||||
* $FreeBSD: head/sbin/ipfw/ipfw2.h 272840 2014-10-09 19:32:35Z melifaro $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Options that can be set on the command line.
|
||||
* When reading commands from a file, a subset of the options can also
|
||||
* be applied globally by specifying them before the file name.
|
||||
* After that, each line can contain its own option that changes
|
||||
* the global value.
|
||||
* XXX The context is not restored after each line.
|
||||
*/
|
||||
|
||||
struct cmdline_opts {
|
||||
/* boolean options: */
|
||||
int do_value_as_ip; /* show table value as IP */
|
||||
int do_resolv; /* try to resolve all ip to names */
|
||||
int do_time; /* Show time stamps */
|
||||
int do_quiet; /* Be quiet in add and flush */
|
||||
int do_pipe; /* this cmd refers to a pipe/queue/sched */
|
||||
int do_nat; /* this cmd refers to a nat config */
|
||||
int do_dynamic; /* display dynamic rules */
|
||||
int do_expired; /* display expired dynamic rules */
|
||||
int do_compact; /* show rules in compact mode */
|
||||
int do_force; /* do not ask for confirmation */
|
||||
int show_sets; /* display the set each rule belongs to */
|
||||
int test_only; /* only check syntax */
|
||||
int comment_only; /* only print action and comment */
|
||||
int verbose; /* be verbose on some commands */
|
||||
|
||||
/* The options below can have multiple values. */
|
||||
|
||||
int do_sort; /* field to sort results (0 = no) */
|
||||
/* valid fields are 1 and above */
|
||||
|
||||
int use_set; /* work with specified set number */
|
||||
/* 0 means all sets, otherwise apply to set use_set - 1 */
|
||||
|
||||
};
|
||||
|
||||
extern struct cmdline_opts co;
|
||||
|
||||
/*
|
||||
* _s_x is a structure that stores a string <-> token pairs, used in
|
||||
* various places in the parser. Entries are stored in arrays,
|
||||
* with an entry with s=NULL as terminator.
|
||||
* The search routines are match_token() and match_value().
|
||||
* Often, an element with x=0 contains an error string.
|
||||
*
|
||||
*/
|
||||
struct _s_x {
|
||||
char const *s;
|
||||
int x;
|
||||
};
|
||||
|
||||
extern struct _s_x f_ipdscp[];
|
||||
|
||||
enum tokens {
|
||||
TOK_NULL=0,
|
||||
|
||||
TOK_OR,
|
||||
TOK_NOT,
|
||||
TOK_STARTBRACE,
|
||||
TOK_ENDBRACE,
|
||||
|
||||
TOK_ACCEPT,
|
||||
TOK_COUNT,
|
||||
TOK_PIPE,
|
||||
TOK_LINK,
|
||||
TOK_QUEUE,
|
||||
TOK_FLOWSET,
|
||||
TOK_SCHED,
|
||||
TOK_DIVERT,
|
||||
TOK_TEE,
|
||||
TOK_NETGRAPH,
|
||||
TOK_NGTEE,
|
||||
TOK_FORWARD,
|
||||
TOK_SKIPTO,
|
||||
TOK_DENY,
|
||||
TOK_REJECT,
|
||||
TOK_RESET,
|
||||
TOK_UNREACH,
|
||||
TOK_CHECKSTATE,
|
||||
TOK_NAT,
|
||||
TOK_REASS,
|
||||
TOK_CALL,
|
||||
TOK_RETURN,
|
||||
|
||||
TOK_ALTQ,
|
||||
TOK_LOG,
|
||||
TOK_TAG,
|
||||
TOK_UNTAG,
|
||||
|
||||
TOK_TAGGED,
|
||||
TOK_UID,
|
||||
TOK_GID,
|
||||
TOK_JAIL,
|
||||
TOK_IN,
|
||||
TOK_LIMIT,
|
||||
TOK_KEEPSTATE,
|
||||
TOK_LAYER2,
|
||||
TOK_OUT,
|
||||
TOK_DIVERTED,
|
||||
TOK_DIVERTEDLOOPBACK,
|
||||
TOK_DIVERTEDOUTPUT,
|
||||
TOK_XMIT,
|
||||
TOK_RECV,
|
||||
TOK_VIA,
|
||||
TOK_FRAG,
|
||||
TOK_IPOPTS,
|
||||
TOK_IPLEN,
|
||||
TOK_IPID,
|
||||
TOK_IPPRECEDENCE,
|
||||
TOK_DSCP,
|
||||
TOK_IPTOS,
|
||||
TOK_IPTTL,
|
||||
TOK_IPVER,
|
||||
TOK_ESTAB,
|
||||
TOK_SETUP,
|
||||
TOK_TCPDATALEN,
|
||||
TOK_TCPFLAGS,
|
||||
TOK_TCPOPTS,
|
||||
TOK_TCPSEQ,
|
||||
TOK_TCPACK,
|
||||
TOK_TCPWIN,
|
||||
TOK_ICMPTYPES,
|
||||
TOK_MAC,
|
||||
TOK_MACTYPE,
|
||||
TOK_VERREVPATH,
|
||||
TOK_VERSRCREACH,
|
||||
TOK_ANTISPOOF,
|
||||
TOK_IPSEC,
|
||||
TOK_COMMENT,
|
||||
|
||||
TOK_PLR,
|
||||
TOK_NOERROR,
|
||||
TOK_BUCKETS,
|
||||
TOK_DSTIP,
|
||||
TOK_SRCIP,
|
||||
TOK_DSTPORT,
|
||||
TOK_SRCPORT,
|
||||
TOK_ALL,
|
||||
TOK_MASK,
|
||||
TOK_FLOW_MASK,
|
||||
TOK_SCHED_MASK,
|
||||
TOK_BW,
|
||||
TOK_DELAY,
|
||||
TOK_PROFILE,
|
||||
TOK_BURST,
|
||||
TOK_RED,
|
||||
TOK_GRED,
|
||||
TOK_ECN,
|
||||
TOK_DROPTAIL,
|
||||
TOK_PROTO,
|
||||
/* dummynet tokens */
|
||||
TOK_WEIGHT,
|
||||
TOK_LMAX,
|
||||
TOK_PRI,
|
||||
TOK_TYPE,
|
||||
TOK_SLOTSIZE,
|
||||
|
||||
TOK_IP,
|
||||
TOK_IF,
|
||||
TOK_ALOG,
|
||||
TOK_DENY_INC,
|
||||
TOK_SAME_PORTS,
|
||||
TOK_UNREG_ONLY,
|
||||
TOK_SKIP_GLOBAL,
|
||||
TOK_RESET_ADDR,
|
||||
TOK_ALIAS_REV,
|
||||
TOK_PROXY_ONLY,
|
||||
TOK_REDIR_ADDR,
|
||||
TOK_REDIR_PORT,
|
||||
TOK_REDIR_PROTO,
|
||||
|
||||
TOK_IPV6,
|
||||
TOK_FLOWID,
|
||||
TOK_ICMP6TYPES,
|
||||
TOK_EXT6HDR,
|
||||
TOK_DSTIP6,
|
||||
TOK_SRCIP6,
|
||||
|
||||
TOK_IPV4,
|
||||
TOK_UNREACH6,
|
||||
TOK_RESET6,
|
||||
|
||||
TOK_FIB,
|
||||
TOK_SETFIB,
|
||||
TOK_LOOKUP,
|
||||
TOK_SOCKARG,
|
||||
TOK_SETDSCP,
|
||||
TOK_FLOW,
|
||||
TOK_IFLIST,
|
||||
/* Table tokens */
|
||||
TOK_CREATE,
|
||||
TOK_DESTROY,
|
||||
TOK_LIST,
|
||||
TOK_INFO,
|
||||
TOK_DETAIL,
|
||||
TOK_MODIFY,
|
||||
TOK_FLUSH,
|
||||
TOK_SWAP,
|
||||
TOK_ADD,
|
||||
TOK_DEL,
|
||||
TOK_VALTYPE,
|
||||
TOK_ALGO,
|
||||
TOK_TALIST,
|
||||
TOK_ATOMIC,
|
||||
TOK_LOCK,
|
||||
TOK_UNLOCK,
|
||||
TOK_VLIST,
|
||||
};
|
||||
|
||||
/*
|
||||
* the following macro returns an error message if we run out of
|
||||
* arguments.
|
||||
*/
|
||||
#define NEED(_p, msg) {if (!_p) errx(EX_USAGE, msg);}
|
||||
#define NEED1(msg) {if (!(*av)) errx(EX_USAGE, msg);}
|
||||
|
||||
struct buf_pr {
|
||||
char *buf; /* allocated buffer */
|
||||
char *ptr; /* current pointer */
|
||||
size_t size; /* total buffer size */
|
||||
size_t avail; /* available storage */
|
||||
size_t needed; /* length needed */
|
||||
};
|
||||
|
||||
int pr_u64(struct buf_pr *bp, uint64_t *pd, int width);
|
||||
int bp_alloc(struct buf_pr *b, size_t size);
|
||||
void bp_free(struct buf_pr *b);
|
||||
int bprintf(struct buf_pr *b, char *format, ...);
|
||||
|
||||
|
||||
/* memory allocation support */
|
||||
void *safe_calloc(size_t number, size_t size);
|
||||
void *safe_realloc(void *ptr, size_t size);
|
||||
|
||||
/* string comparison functions used for historical compatibility */
|
||||
int _substrcmp(const char *str1, const char* str2);
|
||||
int _substrcmp2(const char *str1, const char* str2, const char* str3);
|
||||
int stringnum_cmp(const char *a, const char *b);
|
||||
|
||||
/* utility functions */
|
||||
int match_token(struct _s_x *table, char *string);
|
||||
int match_token_relaxed(struct _s_x *table, char *string);
|
||||
char const *match_value(struct _s_x *p, int value);
|
||||
size_t concat_tokens(char *buf, size_t bufsize, struct _s_x *table,
|
||||
char *delimiter);
|
||||
int fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set,
|
||||
uint32_t *clear);
|
||||
void print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set);
|
||||
|
||||
struct _ip_fw3_opheader;
|
||||
int do_cmd(int optname, void *optval, uintptr_t optlen);
|
||||
int do_set3(int optname, struct _ip_fw3_opheader *op3, uintptr_t optlen);
|
||||
int do_get3(int optname, struct _ip_fw3_opheader *op3, size_t *optlen);
|
||||
|
||||
struct in6_addr;
|
||||
void n2mask(struct in6_addr *mask, int n);
|
||||
int contigmask(uint8_t *p, int len);
|
||||
|
||||
/*
|
||||
* Forward declarations to avoid include way too many headers.
|
||||
* C does not allow duplicated typedefs, so we use the base struct
|
||||
* that the typedef points to.
|
||||
* Should the typedefs use a different type, the compiler will
|
||||
* still detect the change when compiling the body of the
|
||||
* functions involved, so we do not lose error checking.
|
||||
*/
|
||||
struct _ipfw_insn;
|
||||
struct _ipfw_insn_altq;
|
||||
struct _ipfw_insn_u32;
|
||||
struct _ipfw_insn_ip6;
|
||||
struct _ipfw_insn_icmp6;
|
||||
|
||||
/*
|
||||
* The reserved set numer. This is a constant in ip_fw.h
|
||||
* but we store it in a variable so other files do not depend
|
||||
* in that header just for one constant.
|
||||
*/
|
||||
extern int resvd_set_number;
|
||||
|
||||
/* first-level command handlers */
|
||||
void ipfw_add(char *av[]);
|
||||
void ipfw_show_nat(int ac, char **av);
|
||||
void ipfw_config_pipe(int ac, char **av);
|
||||
void ipfw_config_nat(int ac, char **av);
|
||||
void ipfw_sets_handler(char *av[]);
|
||||
void ipfw_table_handler(int ac, char *av[]);
|
||||
void ipfw_sysctl_handler(char *av[], int which);
|
||||
void ipfw_delete(char *av[]);
|
||||
void ipfw_flush(int force);
|
||||
void ipfw_zero(int ac, char *av[], int optname);
|
||||
void ipfw_list(int ac, char *av[], int show_counters);
|
||||
void ipfw_internal_handler(int ac, char *av[]);
|
||||
|
||||
#ifdef PF
|
||||
/* altq.c */
|
||||
void altq_set_enabled(int enabled);
|
||||
u_int32_t altq_name_to_qid(const char *name);
|
||||
void print_altq_cmd(struct buf_pr *bp, struct _ipfw_insn_altq *altqptr);
|
||||
#else
|
||||
#define NO_ALTQ
|
||||
#endif
|
||||
|
||||
/* dummynet.c */
|
||||
void dummynet_list(int ac, char *av[], int show_counters);
|
||||
void dummynet_flush(void);
|
||||
int ipfw_delete_pipe(int pipe_or_queue, int n);
|
||||
|
||||
/* ipv6.c */
|
||||
void print_unreach6_code(uint16_t code);
|
||||
void print_ip6(struct buf_pr *bp, struct _ipfw_insn_ip6 *cmd, char const *s);
|
||||
void print_flow6id(struct buf_pr *bp, struct _ipfw_insn_u32 *cmd);
|
||||
void print_icmp6types(struct buf_pr *bp, struct _ipfw_insn_u32 *cmd);
|
||||
void print_ext6hdr(struct buf_pr *bp, struct _ipfw_insn *cmd );
|
||||
|
||||
struct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av, int cblen);
|
||||
struct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av, int cblen);
|
||||
|
||||
void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av, int cblen);
|
||||
void fill_unreach6_code(u_short *codep, char *str);
|
||||
void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av, int cblen);
|
||||
int fill_ext6hdr(struct _ipfw_insn *cmd, char *av);
|
||||
|
||||
/* tables.c */
|
||||
struct _ipfw_obj_ctlv;
|
||||
char *table_search_ctlv(struct _ipfw_obj_ctlv *ctlv, uint16_t idx);
|
||||
void table_sort_ctlv(struct _ipfw_obj_ctlv *ctlv);
|
||||
int table_check_name(char *tablename);
|
||||
void ipfw_list_ta(int ac, char *av[]);
|
||||
void ipfw_list_values(int ac, char *av[]);
|
||||
|
|
@ -0,0 +1,536 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2003 Luigi Rizzo
|
||||
* Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
|
||||
* Copyright (c) 1994 Ugen J.S.Antsilevich
|
||||
*
|
||||
* Idea and grammar partially left from:
|
||||
* Copyright (c) 1993 Daniel Boulet
|
||||
*
|
||||
* Redistribution and use in source forms, with and without modification,
|
||||
* are permitted provided that this entire comment appears intact.
|
||||
*
|
||||
* Redistribution in binary form may occur without any restrictions.
|
||||
* Obviously, it would be nice if you gave credit where credit is due
|
||||
* but requiring it would be too onerous.
|
||||
*
|
||||
* This software is provided ``AS IS'' without any warranties of any kind.
|
||||
*
|
||||
* NEW command line interface for IP firewall facility
|
||||
*
|
||||
* $FreeBSD: head/sbin/ipfw/ipv6.c 270424 2014-08-23 17:37:18Z melifaro $
|
||||
*
|
||||
* ipv6 support
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "ipfw2.h"
|
||||
|
||||
#include <err.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/ip_fw.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define CHECK_LENGTH(v, len) do { \
|
||||
if ((v) < (len)) \
|
||||
errx(EX_DATAERR, "Rule too long"); \
|
||||
} while (0)
|
||||
|
||||
static struct _s_x icmp6codes[] = {
|
||||
{ "no-route", ICMP6_DST_UNREACH_NOROUTE },
|
||||
{ "admin-prohib", ICMP6_DST_UNREACH_ADMIN },
|
||||
{ "address", ICMP6_DST_UNREACH_ADDR },
|
||||
{ "port", ICMP6_DST_UNREACH_NOPORT },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
void
|
||||
fill_unreach6_code(u_short *codep, char *str)
|
||||
{
|
||||
int val;
|
||||
char *s;
|
||||
|
||||
val = strtoul(str, &s, 0);
|
||||
if (s == str || *s != '\0' || val >= 0x100)
|
||||
val = match_token(icmp6codes, str);
|
||||
if (val < 0)
|
||||
errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str);
|
||||
*codep = val;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
print_unreach6_code(uint16_t code)
|
||||
{
|
||||
char const *s = match_value(icmp6codes, code);
|
||||
|
||||
if (s != NULL)
|
||||
printf("unreach6 %s", s);
|
||||
else
|
||||
printf("unreach6 %u", code);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the ip address contained in a command.
|
||||
*/
|
||||
void
|
||||
print_ip6(struct buf_pr *bp, ipfw_insn_ip6 *cmd, char const *s)
|
||||
{
|
||||
struct hostent *he = NULL;
|
||||
int len = F_LEN((ipfw_insn *) cmd) - 1;
|
||||
struct in6_addr *a = &(cmd->addr6);
|
||||
char trad[255];
|
||||
|
||||
bprintf(bp, "%s%s ", cmd->o.len & F_NOT ? " not": "", s);
|
||||
|
||||
if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) {
|
||||
bprintf(bp, "me6");
|
||||
return;
|
||||
}
|
||||
if (cmd->o.opcode == O_IP6) {
|
||||
bprintf(bp, " ip6");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* len == 4 indicates a single IP, whereas lists of 1 or more
|
||||
* addr/mask pairs have len = (2n+1). We convert len to n so we
|
||||
* use that to count the number of entries.
|
||||
*/
|
||||
|
||||
for (len = len / 4; len > 0; len -= 2, a += 2) {
|
||||
int mb = /* mask length */
|
||||
(cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ?
|
||||
128 : contigmask((uint8_t *)&(a[1]), 128);
|
||||
|
||||
if (mb == 128 && co.do_resolv)
|
||||
he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6);
|
||||
if (he != NULL) /* resolved to name */
|
||||
bprintf(bp, "%s", he->h_name);
|
||||
else if (mb == 0) /* any */
|
||||
bprintf(bp, "any");
|
||||
else { /* numeric IP followed by some kind of mask */
|
||||
if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL)
|
||||
bprintf(bp, "Error ntop in print_ip6\n");
|
||||
bprintf(bp, "%s", trad );
|
||||
if (mb < 0) /* XXX not really legal... */
|
||||
bprintf(bp, ":%s",
|
||||
inet_ntop(AF_INET6, &a[1], trad, sizeof(trad)));
|
||||
else if (mb < 128)
|
||||
bprintf(bp, "/%d", mb);
|
||||
}
|
||||
if (len > 2)
|
||||
bprintf(bp, ",");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int cblen)
|
||||
{
|
||||
uint8_t type;
|
||||
|
||||
CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_icmp6));
|
||||
|
||||
bzero(cmd, sizeof(*cmd));
|
||||
while (*av) {
|
||||
if (*av == ',')
|
||||
av++;
|
||||
type = strtoul(av, &av, 0);
|
||||
if (*av != ',' && *av != '\0')
|
||||
errx(EX_DATAERR, "invalid ICMP6 type");
|
||||
/*
|
||||
* XXX: shouldn't this be 0xFF? I can't see any reason why
|
||||
* we shouldn't be able to filter all possiable values
|
||||
* regardless of the ability of the rest of the kernel to do
|
||||
* anything useful with them.
|
||||
*/
|
||||
if (type > ICMP6_MAXTYPE)
|
||||
errx(EX_DATAERR, "ICMP6 type out of range");
|
||||
cmd->d[type / 32] |= ( 1 << (type % 32));
|
||||
}
|
||||
cmd->o.opcode = O_ICMP6TYPE;
|
||||
cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_icmp6types(struct buf_pr *bp, ipfw_insn_u32 *cmd)
|
||||
{
|
||||
int i, j;
|
||||
char sep= ' ';
|
||||
|
||||
bprintf(bp, " ip6 icmp6types");
|
||||
for (i = 0; i < 7; i++)
|
||||
for (j=0; j < 32; ++j) {
|
||||
if ( (cmd->d[i] & (1 << (j))) == 0)
|
||||
continue;
|
||||
bprintf(bp, "%c%d", sep, (i*32 + j));
|
||||
sep = ',';
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_flow6id(struct buf_pr *bp, ipfw_insn_u32 *cmd)
|
||||
{
|
||||
uint16_t i, limit = cmd->o.arg1;
|
||||
char sep = ',';
|
||||
|
||||
bprintf(bp, " flow-id ");
|
||||
for( i=0; i < limit; ++i) {
|
||||
if (i == limit - 1)
|
||||
sep = ' ';
|
||||
bprintf(bp, "%d%c", cmd->d[i], sep);
|
||||
}
|
||||
}
|
||||
|
||||
/* structure and define for the extension header in ipv6 */
|
||||
static struct _s_x ext6hdrcodes[] = {
|
||||
{ "frag", EXT_FRAGMENT },
|
||||
{ "hopopt", EXT_HOPOPTS },
|
||||
{ "route", EXT_ROUTING },
|
||||
{ "dstopt", EXT_DSTOPTS },
|
||||
{ "ah", EXT_AH },
|
||||
{ "esp", EXT_ESP },
|
||||
{ "rthdr0", EXT_RTHDR0 },
|
||||
{ "rthdr2", EXT_RTHDR2 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/* fills command for the extension header filtering */
|
||||
int
|
||||
fill_ext6hdr( ipfw_insn *cmd, char *av)
|
||||
{
|
||||
int tok;
|
||||
char *s = av;
|
||||
|
||||
cmd->arg1 = 0;
|
||||
|
||||
while(s) {
|
||||
av = strsep( &s, ",") ;
|
||||
tok = match_token(ext6hdrcodes, av);
|
||||
switch (tok) {
|
||||
case EXT_FRAGMENT:
|
||||
cmd->arg1 |= EXT_FRAGMENT;
|
||||
break;
|
||||
|
||||
case EXT_HOPOPTS:
|
||||
cmd->arg1 |= EXT_HOPOPTS;
|
||||
break;
|
||||
|
||||
case EXT_ROUTING:
|
||||
cmd->arg1 |= EXT_ROUTING;
|
||||
break;
|
||||
|
||||
case EXT_DSTOPTS:
|
||||
cmd->arg1 |= EXT_DSTOPTS;
|
||||
break;
|
||||
|
||||
case EXT_AH:
|
||||
cmd->arg1 |= EXT_AH;
|
||||
break;
|
||||
|
||||
case EXT_ESP:
|
||||
cmd->arg1 |= EXT_ESP;
|
||||
break;
|
||||
|
||||
case EXT_RTHDR0:
|
||||
cmd->arg1 |= EXT_RTHDR0;
|
||||
break;
|
||||
|
||||
case EXT_RTHDR2:
|
||||
cmd->arg1 |= EXT_RTHDR2;
|
||||
break;
|
||||
|
||||
default:
|
||||
errx( EX_DATAERR, "invalid option for ipv6 exten header" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cmd->arg1 == 0 )
|
||||
return 0;
|
||||
cmd->opcode = O_EXT_HDR;
|
||||
cmd->len |= F_INSN_SIZE( ipfw_insn );
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
print_ext6hdr(struct buf_pr *bp, ipfw_insn *cmd )
|
||||
{
|
||||
char sep = ' ';
|
||||
|
||||
bprintf(bp, " extension header:");
|
||||
if (cmd->arg1 & EXT_FRAGMENT ) {
|
||||
bprintf(bp, "%cfragmentation", sep);
|
||||
sep = ',';
|
||||
}
|
||||
if (cmd->arg1 & EXT_HOPOPTS ) {
|
||||
bprintf(bp, "%chop options", sep);
|
||||
sep = ',';
|
||||
}
|
||||
if (cmd->arg1 & EXT_ROUTING ) {
|
||||
bprintf(bp, "%crouting options", sep);
|
||||
sep = ',';
|
||||
}
|
||||
if (cmd->arg1 & EXT_RTHDR0 ) {
|
||||
bprintf(bp, "%crthdr0", sep);
|
||||
sep = ',';
|
||||
}
|
||||
if (cmd->arg1 & EXT_RTHDR2 ) {
|
||||
bprintf(bp, "%crthdr2", sep);
|
||||
sep = ',';
|
||||
}
|
||||
if (cmd->arg1 & EXT_DSTOPTS ) {
|
||||
bprintf(bp, "%cdestination options", sep);
|
||||
sep = ',';
|
||||
}
|
||||
if (cmd->arg1 & EXT_AH ) {
|
||||
bprintf(bp, "%cauthentication header", sep);
|
||||
sep = ',';
|
||||
}
|
||||
if (cmd->arg1 & EXT_ESP ) {
|
||||
bprintf(bp, "%cencapsulated security payload", sep);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to find ipv6 address by hostname */
|
||||
static int
|
||||
lookup_host6 (char *host, struct in6_addr *ip6addr)
|
||||
{
|
||||
struct hostent *he;
|
||||
|
||||
if (!inet_pton(AF_INET6, host, ip6addr)) {
|
||||
if ((he = gethostbyname2(host, AF_INET6)) == NULL)
|
||||
return(-1);
|
||||
memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr));
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* fill the addr and mask fields in the instruction as appropriate from av.
|
||||
* Update length as appropriate.
|
||||
* The following formats are allowed:
|
||||
* any matches any IP6. Actually returns an empty instruction.
|
||||
* me returns O_IP6_*_ME
|
||||
*
|
||||
* 03f1::234:123:0342 single IP6 addres
|
||||
* 03f1::234:123:0342/24 address/mask
|
||||
* 03f1::234:123:0342/24,03f1::234:123:0343/ List of address
|
||||
*
|
||||
* Set of address (as in ipv6) not supported because ipv6 address
|
||||
* are typically random past the initial prefix.
|
||||
* Return 1 on success, 0 on failure.
|
||||
*/
|
||||
static int
|
||||
fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen)
|
||||
{
|
||||
int len = 0;
|
||||
struct in6_addr *d = &(cmd->addr6);
|
||||
/*
|
||||
* Needed for multiple address.
|
||||
* Note d[1] points to struct in6_add r mask6 of cmd
|
||||
*/
|
||||
|
||||
cmd->o.len &= ~F_LEN_MASK; /* zero len */
|
||||
|
||||
if (strcmp(av, "any") == 0)
|
||||
return (1);
|
||||
|
||||
|
||||
if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/
|
||||
cmd->o.len |= F_INSN_SIZE(ipfw_insn);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (strcmp(av, "me6") == 0) { /* Set the data for "me" opt*/
|
||||
cmd->o.len |= F_INSN_SIZE(ipfw_insn);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (strncmp(av, "table(", 6) == 0) {
|
||||
char *p = strchr(av + 6, ',');
|
||||
uint32_t *dm = ((ipfw_insn_u32 *)cmd)->d;
|
||||
|
||||
if (p)
|
||||
*p++ = '\0';
|
||||
cmd->o.opcode = O_IP_DST_LOOKUP;
|
||||
cmd->o.arg1 = strtoul(av + 6, NULL, 0);
|
||||
if (p) {
|
||||
cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
|
||||
dm[0] = strtoul(p, NULL, 0);
|
||||
} else
|
||||
cmd->o.len |= F_INSN_SIZE(ipfw_insn);
|
||||
return (1);
|
||||
}
|
||||
|
||||
av = strdup(av);
|
||||
while (av) {
|
||||
/*
|
||||
* After the address we can have '/' indicating a mask,
|
||||
* or ',' indicating another address follows.
|
||||
*/
|
||||
|
||||
char *p;
|
||||
int masklen;
|
||||
char md = '\0';
|
||||
|
||||
CHECK_LENGTH(cblen, 1 + len + 2 * F_INSN_SIZE(struct in6_addr));
|
||||
|
||||
if ((p = strpbrk(av, "/,")) ) {
|
||||
md = *p; /* save the separator */
|
||||
*p = '\0'; /* terminate address string */
|
||||
p++; /* and skip past it */
|
||||
}
|
||||
/* now p points to NULL, mask or next entry */
|
||||
|
||||
/* lookup stores address in *d as a side effect */
|
||||
if (lookup_host6(av, d) != 0) {
|
||||
/* XXX: failed. Free memory and go */
|
||||
errx(EX_DATAERR, "bad address \"%s\"", av);
|
||||
}
|
||||
/* next, look at the mask, if any */
|
||||
masklen = (md == '/') ? atoi(p) : 128;
|
||||
if (masklen > 128 || masklen < 0)
|
||||
errx(EX_DATAERR, "bad width \"%s\''", p);
|
||||
else
|
||||
n2mask(&d[1], masklen);
|
||||
|
||||
APPLY_MASK(d, &d[1]) /* mask base address with mask */
|
||||
|
||||
/* find next separator */
|
||||
|
||||
if (md == '/') { /* find separator past the mask */
|
||||
p = strpbrk(p, ",");
|
||||
if (p != NULL)
|
||||
p++;
|
||||
}
|
||||
av = p;
|
||||
|
||||
/* Check this entry */
|
||||
if (masklen == 0) {
|
||||
/*
|
||||
* 'any' turns the entire list into a NOP.
|
||||
* 'not any' never matches, so it is removed from the
|
||||
* list unless it is the only item, in which case we
|
||||
* report an error.
|
||||
*/
|
||||
if (cmd->o.len & F_NOT && av == NULL && len == 0)
|
||||
errx(EX_DATAERR, "not any never matches");
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* A single IP can be stored alone
|
||||
*/
|
||||
if (masklen == 128 && av == NULL && len == 0) {
|
||||
len = F_INSN_SIZE(struct in6_addr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update length and pointer to arguments */
|
||||
len += F_INSN_SIZE(struct in6_addr)*2;
|
||||
d += 2;
|
||||
} /* end while */
|
||||
|
||||
/*
|
||||
* Total length of the command, remember that 1 is the size of
|
||||
* the base command.
|
||||
*/
|
||||
if (len + 1 > F_LEN_MASK)
|
||||
errx(EX_DATAERR, "address list too long");
|
||||
cmd->o.len |= len+1;
|
||||
free(av);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* fills command for ipv6 flow-id filtering
|
||||
* note that the 20 bit flow number is stored in a array of u_int32_t
|
||||
* it's supported lists of flow-id, so in the o.arg1 we store how many
|
||||
* additional flow-id we want to filter, the basic is 1
|
||||
*/
|
||||
void
|
||||
fill_flow6( ipfw_insn_u32 *cmd, char *av, int cblen)
|
||||
{
|
||||
u_int32_t type; /* Current flow number */
|
||||
u_int16_t nflow = 0; /* Current flow index */
|
||||
char *s = av;
|
||||
cmd->d[0] = 0; /* Initializing the base number*/
|
||||
|
||||
while (s) {
|
||||
CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_u32) + nflow + 1);
|
||||
|
||||
av = strsep( &s, ",") ;
|
||||
type = strtoul(av, &av, 0);
|
||||
if (*av != ',' && *av != '\0')
|
||||
errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
|
||||
if (type > 0xfffff)
|
||||
errx(EX_DATAERR, "flow number out of range %s", av);
|
||||
cmd->d[nflow] |= type;
|
||||
nflow++;
|
||||
}
|
||||
if( nflow > 0 ) {
|
||||
cmd->o.opcode = O_FLOW6ID;
|
||||
cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow;
|
||||
cmd->o.arg1 = nflow;
|
||||
}
|
||||
else {
|
||||
errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
|
||||
}
|
||||
}
|
||||
|
||||
ipfw_insn *
|
||||
add_srcip6(ipfw_insn *cmd, char *av, int cblen)
|
||||
{
|
||||
|
||||
fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen);
|
||||
if (cmd->opcode == O_IP_DST_SET) /* set */
|
||||
cmd->opcode = O_IP_SRC_SET;
|
||||
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
|
||||
cmd->opcode = O_IP_SRC_LOOKUP;
|
||||
else if (F_LEN(cmd) == 0) { /* any */
|
||||
} else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */
|
||||
cmd->opcode = O_IP6_SRC_ME;
|
||||
} else if (F_LEN(cmd) ==
|
||||
(F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {
|
||||
/* single IP, no mask*/
|
||||
cmd->opcode = O_IP6_SRC;
|
||||
} else { /* addr/mask opt */
|
||||
cmd->opcode = O_IP6_SRC_MASK;
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
ipfw_insn *
|
||||
add_dstip6(ipfw_insn *cmd, char *av, int cblen)
|
||||
{
|
||||
|
||||
fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen);
|
||||
if (cmd->opcode == O_IP_DST_SET) /* set */
|
||||
;
|
||||
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
|
||||
;
|
||||
else if (F_LEN(cmd) == 0) { /* any */
|
||||
} else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */
|
||||
cmd->opcode = O_IP6_DST_ME;
|
||||
} else if (F_LEN(cmd) ==
|
||||
(F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {
|
||||
/* single IP, no mask*/
|
||||
cmd->opcode = O_IP6_DST;
|
||||
} else { /* addr/mask opt */
|
||||
cmd->opcode = O_IP6_DST_MASK;
|
||||
}
|
||||
return cmd;
|
||||
}
|
|
@ -0,0 +1,801 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: missing.h 8377 2011-04-04 16:08:27Z marta $
|
||||
*
|
||||
* Header for kernel variables and functions that are not available in
|
||||
* userland.
|
||||
*/
|
||||
|
||||
#ifndef _MISSING_H_
|
||||
#define _MISSING_H_
|
||||
|
||||
#define KLD_MODULE /* disable kernel dependencies */
|
||||
|
||||
/* defined as assert */
|
||||
void panic(const char *fmt, ...);
|
||||
|
||||
#define KASSERT(exp,msg) do { \
|
||||
if (__predict_false(!(exp))) \
|
||||
panic msg; \
|
||||
} while (0)
|
||||
/* don't bother to optimize */
|
||||
#ifndef __predict_false
|
||||
#define __predict_false(x) (x) /* __builtin_expect((exp), 0) */
|
||||
#endif // XXX
|
||||
|
||||
|
||||
#ifdef _KERNEL
|
||||
#define NEED_KERNEL
|
||||
#undef _KERNEL
|
||||
#endif
|
||||
|
||||
#include <stdio.h> // printf
|
||||
#include <sys/socket.h> // IFNAMSIZ ?
|
||||
#include <string.h> // strncmp
|
||||
#include <stdlib.h> // bsearch
|
||||
#ifdef NEED_KERNEL
|
||||
#define _KERNEL
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#define __user // not defined here ?
|
||||
#define __init
|
||||
#define __exit
|
||||
|
||||
/* portability features, to be set before the rest: */
|
||||
#define WITHOUT_BPF /* do not use bpf logging */
|
||||
|
||||
#define MALLOC_DECLARE(x) struct __hack /* nothing */
|
||||
// XXX kernel malloc/free
|
||||
extern void *kern_malloc(int);
|
||||
extern void kern_free(void *);
|
||||
#define malloc(_size, type, flags) kern_malloc(_size)
|
||||
#define free(_var, type) kern_free(_var)
|
||||
|
||||
/* inet_ntoa_r() differs in userspace and kernel.
|
||||
* We load netinet/in.h so we get the kernel prototype ?
|
||||
* but we also need to put #defines in the two places where
|
||||
* it is used XXX fixme
|
||||
*/
|
||||
#include <netinet/in.h>
|
||||
|
||||
/* log() conflicts with the math function.
|
||||
* Revise, modifying the first argument.
|
||||
*/
|
||||
#define LOG_ERR 0x100
|
||||
#define LOG_INFO 0x200
|
||||
#ifndef LOG_SECURITY
|
||||
#define LOG_SECURITY 0x400
|
||||
#endif
|
||||
|
||||
#define log(_level, fmt, arg...) do { \
|
||||
int __attribute__((unused)) _querty = _level; \
|
||||
printf("kernel: " fmt, ##arg); } while (0)
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/*
|
||||
* Kernel locking support.
|
||||
* FreeBSD uses mtx in dummynet.c and struct rwlock ip_fw2.c
|
||||
*
|
||||
* In linux we use spinlock_bh to implement both.
|
||||
* For 'struct rwlock' we need an #ifdef to change it to spinlock_t
|
||||
*/
|
||||
|
||||
#ifndef DEFINE_SPINLOCK /* this is for linux 2.4 */
|
||||
#if defined(__APPLE__)
|
||||
#define DEFINE_SPINLOCK(x) struct mtx x;
|
||||
#else /* linux ? */
|
||||
#define DEFINE_SPINLOCK(x) spinlock_t x // = SPIN_LOCK_UNLOCKED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* 20111031
|
||||
* redefine mutex in terms of threads.
|
||||
*/
|
||||
|
||||
#undef _KERNEL
|
||||
// #include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
#ifdef NEED_KERNEL
|
||||
#define _KERNEL
|
||||
#endif
|
||||
struct mtx {
|
||||
pthread_mutex_t p0;
|
||||
};
|
||||
struct rwlock {
|
||||
pthread_mutex_t p0;
|
||||
};
|
||||
struct rmlock {
|
||||
pthread_mutex_t p0;
|
||||
};
|
||||
extern pthread_mutex_t dummynet_mtx_p;
|
||||
extern pthread_mutex_t ipfw_dyn_mtx_p;
|
||||
extern pthread_mutex_t pfil_global_lock_p;
|
||||
|
||||
#define mtx_assert(a, b)
|
||||
/*
|
||||
* the first argument to mtx_init is often a static variable,
|
||||
* so use (void)m to prevent a compiler warning
|
||||
*/
|
||||
#define mtx_init(m, a,b,c) do { \
|
||||
(void)m; pthread_mutex_init(&((m)->p0), NULL); } while (0)
|
||||
#define MTX_SYSINIT(a, m, c, d) // pthread_mutex_init(m##_p, NULL)
|
||||
#define mtx_lock(m) pthread_mutex_lock(m.p0)
|
||||
#define mtx_unlock(m) pthread_mutex_unlock(m.p0)
|
||||
#define mtx_destroy(m) pthread_mutex_destroy(m.p0)
|
||||
#if 1
|
||||
//------------------
|
||||
|
||||
#if 1 // used for IPFW_UH
|
||||
#define rw_assert(a, b)
|
||||
#define rw_destroy(_l)
|
||||
#define rw_init(_l, msg) // XXX mtx_init((_l), 0, 0, 0)
|
||||
#define rw_rlock(_l) mtx_lock(_l)
|
||||
#define rw_runlock(_l) mtx_unlock(_l)
|
||||
#define rw_wlock(_l) mtx_lock(_l)
|
||||
#define rw_wunlock(_l) mtx_unlock(_l)
|
||||
#define rw_init_flags(_l, s, v)
|
||||
#endif // XXX not used anymore
|
||||
|
||||
#define rm_init(_l, msg) // mtx_init(...)
|
||||
#define rm_rlock(_l, _t) ((void)_t, mtx_lock(_l))
|
||||
#define rm_runlock(_l, _t) mtx_unlock(_l)
|
||||
#define rm_wlock(_l) mtx_lock(_l)
|
||||
#define rm_wunlock(_l) mtx_unlock(_l)
|
||||
#define rm_destroy(_l) // XXX
|
||||
#define rm_assert(_l, _w) // XXX
|
||||
|
||||
|
||||
#endif // locking on linux ?
|
||||
|
||||
/* end of locking support */
|
||||
|
||||
/*
|
||||
* Reference to an ipfw rule that can be carried outside critical sections.
|
||||
* A rule is identified by rulenum:rule_id which is ordered.
|
||||
* In version chain_id the rule can be found in slot 'slot', so
|
||||
* we don't need a lookup if chain_id == chain->id.
|
||||
*
|
||||
* On exit from the firewall this structure refers to the rule after
|
||||
* the matching one (slot points to the new rule; rulenum:rule_id-1
|
||||
* is the matching rule), and additional info (e.g. info often contains
|
||||
* the insn argument or tablearg in the low 16 bits, in host format).
|
||||
* On entry, the structure is valid if slot>0, and refers to the starting
|
||||
* rules. 'info' contains the reason for reinject, e.g. divert port,
|
||||
* divert direction, and so on.
|
||||
*/
|
||||
struct ipfw_rule_ref {
|
||||
uint32_t slot; /* slot for matching rule */
|
||||
uint32_t rulenum; /* matching rule number */
|
||||
uint32_t rule_id; /* matching rule id */
|
||||
uint32_t chain_id; /* ruleset id */
|
||||
uint32_t info; /* see below */
|
||||
};
|
||||
|
||||
/* ISO C restricts enumerator values to range of 'int'
|
||||
* so we need IN to have a smaller value
|
||||
*/
|
||||
enum {
|
||||
IPFW_INFO_MASK = 0x0000ffff,
|
||||
IPFW_INFO_OUT = 0x00000000, /* outgoing, just for convenience */
|
||||
IPFW_INFO_IN = 0x00800000, /* incoming, overloads dir */
|
||||
IPFW_ONEPASS = 0x40000000, /* One-pass, do not reinject */
|
||||
IPFW_IS_MASK = 0x30000000, /* which source ? */
|
||||
IPFW_IS_DIVERT = 0x20000000,
|
||||
IPFW_IS_DUMMYNET =0x10000000,
|
||||
IPFW_IS_PIPE = 0x08000000, /* pipe=1, queue = 0 */
|
||||
};
|
||||
|
||||
/* in netinet/in.h */
|
||||
#define in_nullhost(x) ((x).s_addr == INADDR_ANY)
|
||||
|
||||
/* ip_dummynet.c */
|
||||
#ifndef __FreeBSD_version
|
||||
#define __FreeBSD_version 500035
|
||||
#endif
|
||||
|
||||
/* define some macro for ip_dummynet */
|
||||
|
||||
struct malloc_type {
|
||||
};
|
||||
|
||||
#define MALLOC_DEFINE(type, shortdesc, longdesc) \
|
||||
struct malloc_type type[1]; void *md_dummy_ ## type = type
|
||||
|
||||
#define CTASSERT(x)
|
||||
|
||||
|
||||
/*
|
||||
* gettimeofday would be in sys/time.h but it is not
|
||||
* visible if _KERNEL is defined
|
||||
*/
|
||||
//int gettimeofday(struct timeval *, struct timezone *);
|
||||
|
||||
|
||||
extern int hz;
|
||||
extern long tick; /* exists in 2.4 but not in 2.6 */
|
||||
extern int bootverbose;
|
||||
extern struct timeval boottime;
|
||||
|
||||
/* time_uptime is a FreeBSD variable increased each second */
|
||||
extern time_t time_uptime;
|
||||
|
||||
extern int max_linkhdr;
|
||||
extern int ip_defttl;
|
||||
extern u_long in_ifaddrhmask; /* mask for hash table */
|
||||
extern struct in_ifaddrhashhead *in_ifaddrhashtbl; /* inet addr hash table */
|
||||
|
||||
/*-------------------------------------------------*/
|
||||
|
||||
/* define, includes and functions missing in linux */
|
||||
/* include and define */
|
||||
#include <arpa/inet.h> /* inet_ntoa */
|
||||
|
||||
struct mbuf;
|
||||
// XXX #define M_MCAST 0x04 /* send/received as link-level multicast */
|
||||
|
||||
|
||||
/* used by ip_dummynet.c */
|
||||
void reinject_drop(struct mbuf* m);
|
||||
|
||||
#include <sys/socket.h> /* for ETHERTYPE_IP */
|
||||
|
||||
#ifdef _KERNEL
|
||||
#define IF_NAMESIZE 16
|
||||
#ifndef IFNAMSIZ
|
||||
#define IFNAMSIZ IF_NAMESIZE
|
||||
#endif
|
||||
//#include <net/if.h> /* IFNAMESIZ */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* some network structure can be defined in the bsd way
|
||||
* by using the _FAVOR_BSD definition. This is not true
|
||||
* for icmp structure.
|
||||
* XXX struct icmp contains bsd names in
|
||||
* /usr/include/netinet/ip_icmp.h
|
||||
*/
|
||||
|
||||
/* missing definition */
|
||||
#define TH_FIN 0x01
|
||||
#define TH_SYN 0x02
|
||||
#define TH_RST 0x04
|
||||
#define TH_ACK 0x10
|
||||
|
||||
/* 20131101 IPTOS from ip.h */
|
||||
/*
|
||||
* Definitions for DiffServ Codepoints as per RFC2474
|
||||
*/
|
||||
#define IPTOS_DSCP_CS0 0x00
|
||||
#define IPTOS_DSCP_CS1 0x20
|
||||
#define IPTOS_DSCP_AF11 0x28
|
||||
#define IPTOS_DSCP_AF12 0x30
|
||||
#define IPTOS_DSCP_AF13 0x38
|
||||
#define IPTOS_DSCP_CS2 0x40
|
||||
#define IPTOS_DSCP_AF21 0x48
|
||||
#define IPTOS_DSCP_AF22 0x50
|
||||
#define IPTOS_DSCP_AF23 0x58
|
||||
#define IPTOS_DSCP_CS3 0x60
|
||||
#define IPTOS_DSCP_AF31 0x68
|
||||
#define IPTOS_DSCP_AF32 0x70
|
||||
#define IPTOS_DSCP_AF33 0x78
|
||||
#define IPTOS_DSCP_CS4 0x80
|
||||
#define IPTOS_DSCP_AF41 0x88
|
||||
#define IPTOS_DSCP_AF42 0x90
|
||||
#define IPTOS_DSCP_AF43 0x98
|
||||
#define IPTOS_DSCP_CS5 0xa0
|
||||
#define IPTOS_DSCP_EF 0xb8
|
||||
#define IPTOS_DSCP_CS6 0xc0
|
||||
#define IPTOS_DSCP_CS7 0xe0
|
||||
|
||||
/*
|
||||
* ECN (Explicit Congestion Notification) codepoints in RFC3168 mapped to the
|
||||
* lower 2 bits of the TOS field.
|
||||
*/
|
||||
#define IPTOS_ECN_NOTECT 0x00 /* not-ECT */
|
||||
#define IPTOS_ECN_ECT1 0x01 /* ECN-capable transport (1) */
|
||||
#define IPTOS_ECN_ECT0 0x02 /* ECN-capable transport (0) */
|
||||
#define IPTOS_ECN_CE 0x03 /* congestion experienced */
|
||||
#define IPTOS_ECN_MASK 0x03 /* ECN field mask */
|
||||
|
||||
/*------------------------- */
|
||||
|
||||
#define RTF_CLONING 0x100 /* generate new routes on use */
|
||||
|
||||
#define IPPROTO_OSPFIGP 89 /* OSPFIGP */
|
||||
#define IPPROTO_CARP 112 /* CARP */
|
||||
#define CARP_VERSION 2
|
||||
#define CARP_ADVERTISEMENT 0x01
|
||||
#define PRIV_NETINET_IPFW 491 /* Administer IPFW firewall. */
|
||||
#define IP_FORWARDING 0x1 /* most of ip header exists */
|
||||
#define NETISR_IP 2 /* same as AF_INET */
|
||||
#define PRIV_NETINET_DUMMYNET 494 /* Administer DUMMYNET. */
|
||||
|
||||
extern int securelevel;
|
||||
|
||||
#define if_xname name
|
||||
#define if_snd XXX
|
||||
|
||||
// XXX we could use this to point to the incoming peer
|
||||
struct ifnet {
|
||||
char if_xname[IFNAMSIZ]; /* external name (name + unit) */
|
||||
uint32_t if_index; // IP_FW_3
|
||||
};
|
||||
|
||||
struct ifaltq {
|
||||
|
||||
void *ifq_head;
|
||||
};
|
||||
int ffs(int); // XXX where
|
||||
int fls(int); // XXX where
|
||||
|
||||
struct ip;
|
||||
/* machine/in_cksum.h */
|
||||
int in_cksum(struct mbuf *m, int len);
|
||||
#ifndef __FreeBSD__
|
||||
u_short in_cksum_hdr(struct ip *);
|
||||
#endif
|
||||
|
||||
|
||||
#define CTR3(a, ...)
|
||||
#define uma_zone_set_max(a, b) // XXX
|
||||
|
||||
/*
|
||||
* ifnet->if_snd is used in ip_dummynet.c to take the transmission
|
||||
* clock.
|
||||
*/
|
||||
#if defined( __linux__)
|
||||
#define if_xname name
|
||||
#define if_snd XXX
|
||||
|
||||
struct route_in6 {
|
||||
};
|
||||
|
||||
#elif defined( _WIN32 )
|
||||
/* used in ip_dummynet.c */
|
||||
struct ifnet {
|
||||
char if_xname[IFNAMSIZ]; /* external name (name + unit) */
|
||||
// struct ifaltq if_snd; /* output queue (includes altq) */
|
||||
};
|
||||
|
||||
struct net_device {
|
||||
char if_xname[IFNAMSIZ]; /* external name (name + unit) */
|
||||
};
|
||||
#elif defined(__APPLE__)
|
||||
typedef u_int32_t tcp_cc;
|
||||
#ifndef s6_addr32 // XXX
|
||||
#define s6_addr32 __u6_addr.__u6_addr32
|
||||
#endif
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
struct route_in6 {
|
||||
};
|
||||
|
||||
struct icmphdr {
|
||||
u_char icmp_type; /* type of message, see below */
|
||||
u_char icmp_code; /* type sub code */
|
||||
u_short icmp_cksum; /* ones complement cksum of struct */
|
||||
};
|
||||
|
||||
#define IPPROTO_SCTP 132 /* SCTP */
|
||||
|
||||
/* defined in linux/sctp.h with no bsd definition */
|
||||
struct sctphdr {
|
||||
uint16_t src_port; /* source port */
|
||||
uint16_t dest_port; /* destination port */
|
||||
uint32_t v_tag; /* verification tag of packet */
|
||||
uint32_t checksum; /* Adler32 C-Sum */
|
||||
/* chunks follow... */
|
||||
};
|
||||
|
||||
struct carp_header {
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
u_int8_t carp_type:4,
|
||||
carp_version:4;
|
||||
#endif
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
u_int8_t carp_version:4,
|
||||
carp_type:4;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
struct pim {
|
||||
int dummy; /* windows compiler does not like empty definition */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* involves mbufs */
|
||||
//int in_cksum(struct mbuf *m, int len);
|
||||
#define divert_cookie(mtag) 0
|
||||
#define divert_info(mtag) 0
|
||||
#define pf_find_mtag(a) NULL
|
||||
#define pf_get_mtag(a) NULL
|
||||
#if !defined(_WIN32) && !defined(AF_LINK)
|
||||
#define AF_LINK AF_ASH /* ? our sys/socket.h */
|
||||
#endif
|
||||
|
||||
/* search local the ip addresses, used for the "me" keyword */
|
||||
#define INADDR_TO_IFP(ip, b) b = NULL
|
||||
|
||||
/* we don't pullup, either success or free and fail */
|
||||
#define m_pullup(m, x) \
|
||||
((m)->m_len >= x ? (m) : (FREE_PKT(m), NULL))
|
||||
|
||||
struct pf_mtag {
|
||||
void *hdr; /* saved hdr pos in mbuf, for ECN */
|
||||
sa_family_t af; /* for ECN */
|
||||
u_int32_t qid; /* queue id */
|
||||
};
|
||||
|
||||
/* missing kernel functions */
|
||||
char *inet_ntoa(struct in_addr ina);
|
||||
long random(void);
|
||||
|
||||
/*
|
||||
* Return the risult of a/b
|
||||
*
|
||||
* this is used in linux kernel space,
|
||||
* since the 64bit division needs to
|
||||
* be done using a macro
|
||||
*/
|
||||
//int64_t div64(int64_t a, int64_t b);
|
||||
|
||||
/* from bsd sys/queue.h */
|
||||
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = SLIST_FIRST((head)); \
|
||||
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
/*-------------------------------------------------*/
|
||||
#define RT_NUMFIBS 1
|
||||
extern u_int rt_numfibs;
|
||||
|
||||
/* involves kernel locking function */
|
||||
#ifdef RTFREE
|
||||
#undef RTFREE
|
||||
#define RTFREE(a) fprintf(stderr, "RTFREE: commented out locks\n");
|
||||
#endif
|
||||
|
||||
void getmicrouptime(struct timeval *tv);
|
||||
|
||||
/* from sys/netinet/ip_output.c */
|
||||
struct ip_moptions;
|
||||
struct route;
|
||||
struct ip;
|
||||
|
||||
struct inpcb;
|
||||
struct mbuf *ip_reass(struct mbuf *);
|
||||
int ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
|
||||
struct ip_moptions *imo, struct inpcb *inp);
|
||||
|
||||
/* from net/netisr.c -- fails on FreeBSD */
|
||||
int netisr_dispatch(u_int proto, struct mbuf *m);
|
||||
|
||||
|
||||
/* definition moved in missing.c */
|
||||
int sooptcopyout(struct sockopt *sopt, const void *buf, size_t len);
|
||||
int copyout(const void *kaddr, void *uaddr, size_t len);
|
||||
|
||||
int sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen);
|
||||
|
||||
/* defined in session.c */
|
||||
int priv_check(struct thread *td, int priv);
|
||||
|
||||
/* struct ucred is in linux/socket.h and has pid, uid, gid.
|
||||
* We need a 'bsd_ucred' to store also the extra info
|
||||
*/
|
||||
|
||||
struct bsd_ucred {
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
uint32_t xid;
|
||||
uint32_t nid;
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#if 0 // XXX
|
||||
int
|
||||
cred_check(void *insn, int proto, struct ifnet *oif,
|
||||
struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,
|
||||
u_int16_t src_port, struct bsd_ucred *u, int *ugid_lookupp,
|
||||
struct sk_buff *skb);
|
||||
#endif
|
||||
|
||||
struct ucred;
|
||||
int securelevel_ge(struct ucred *cr, int level);
|
||||
|
||||
/*
|
||||
* stripped down version of the sysctl api
|
||||
*/
|
||||
struct sysctl_oid;
|
||||
struct sysctl_req {
|
||||
void *oldptr; /* store here the original value */
|
||||
int oldlen;
|
||||
void *newptr; /* NULL on reads */
|
||||
int newlen;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
#define module_param_named(_name, _var, _ty, _perm)
|
||||
#else /* !_WIN32 */
|
||||
|
||||
#endif /* !_WIN32 so maybe __linux__ */
|
||||
|
||||
#if 0 // XXX disable sysctl defined (__linux__) && !defined (EMULATE_SYSCTL)
|
||||
#define SYSCTL_DECL(_1)
|
||||
#define SYSCTL_OID(_1, _2, _3, _4, _5, _6, _7, _8)
|
||||
#define SYSCTL_NODE(_1, _2, _3, _4, _5, _6)
|
||||
#define _SYSCTL_BASE(_name, _var, _ty, _perm) \
|
||||
module_param_named(_name, *(_var), _ty, \
|
||||
( (_perm) == CTLFLAG_RD) ? 0444: 0644 )
|
||||
#define SYSCTL_PROC(_base, _oid, _name, _mode, _var, _val, _desc, _a, _b)
|
||||
|
||||
#define SYSCTL_INT(_base, _oid, _name, _mode, _var, _val, _desc) \
|
||||
_SYSCTL_BASE(_name, _var, int, _mode)
|
||||
|
||||
#define SYSCTL_LONG(_base, _oid, _name, _mode, _var, _val, _desc) \
|
||||
_SYSCTL_BASE(_name, _var, long, _mode)
|
||||
|
||||
#define SYSCTL_ULONG(_base, _oid, _name, _mode, _var, _val, _desc) \
|
||||
_SYSCTL_BASE(_name, _var, ulong, _mode)
|
||||
|
||||
#define SYSCTL_UINT(_base, _oid, _name, _mode, _var, _val, _desc) \
|
||||
_SYSCTL_BASE(_name, _var, uint, _mode)
|
||||
|
||||
#define TUNABLE_INT(_name, _ptr)
|
||||
|
||||
#define SYSCTL_VNET_PROC SYSCTL_PROC
|
||||
#define SYSCTL_VNET_INT SYSCTL_INT
|
||||
#define SYSCTL_VNET_UINT SYSCTL_UINT
|
||||
|
||||
#endif
|
||||
|
||||
#define SYSCTL_HANDLER_ARGS \
|
||||
struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req
|
||||
typedef int (sysctl_h_fn_t)(SYSCTL_HANDLER_ARGS);
|
||||
int sysctl_handle_int(SYSCTL_HANDLER_ARGS);
|
||||
int sysctl_handle_long(SYSCTL_HANDLER_ARGS);
|
||||
|
||||
#ifdef EMULATE_SYSCTL /* mandatory here */
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
|
||||
#ifdef SYSCTL_NODE
|
||||
#undef SYSCTL_NODE
|
||||
#endif
|
||||
#define SYSCTL_NODE(a,b,c,d,e,f) int a; (void)a
|
||||
#define SYSCTL_DECL(a)
|
||||
|
||||
#define GST_HARD_LIMIT 100
|
||||
|
||||
/* In the module, GST is implemented as an array of
|
||||
* sysctlentry, but while passing data to the userland
|
||||
* pointers are useless, the buffer is actually made of:
|
||||
* - sysctlhead (fixed size, containing lengths)
|
||||
* - data (typically 32 bit)
|
||||
* - name (zero-terminated and padded to mod4)
|
||||
*/
|
||||
|
||||
struct sysctlentry {
|
||||
struct sysctlhead head;
|
||||
char* name;
|
||||
void* data;
|
||||
sysctl_h_fn_t *fn;
|
||||
};
|
||||
|
||||
struct sysctltable {
|
||||
int count; //number of valid tables
|
||||
int totalsize; //total size of valid entries of al the valid tables
|
||||
void* namebuffer; //a buffer for all chained names
|
||||
struct sysctlentry entry[GST_HARD_LIMIT];
|
||||
};
|
||||
|
||||
#ifdef SYSBEGIN
|
||||
#undef SYSBEGIN
|
||||
#endif
|
||||
#define SYSBEGIN(x) void sysctl_addgroup_##x() {
|
||||
#ifdef SYSEND
|
||||
#undef SYSEND
|
||||
#endif
|
||||
#define SYSEND }
|
||||
|
||||
/* XXX remove duplication */
|
||||
#define SYSCTL_INT(a,b,c,d,e,f,g) \
|
||||
sysctl_pushback(STRINGIFY(a) "." STRINGIFY(c) + 1, \
|
||||
(d) | (SYSCTLTYPE_INT << 2), sizeof(*e), e, NULL)
|
||||
|
||||
#define SYSCTL_UINT(a,b,c,d,e,f,g) \
|
||||
sysctl_pushback(STRINGIFY(a) "." STRINGIFY(c) + 1, \
|
||||
(d) | (SYSCTLTYPE_UINT << 2), sizeof(*e), e, NULL)
|
||||
|
||||
#define SYSCTL_LONG(a,b,c,d,e,f,g) \
|
||||
sysctl_pushback(STRINGIFY(a) "." STRINGIFY(c) + 1, \
|
||||
(d) | (SYSCTLTYPE_LONG << 2), sizeof(*e), e, NULL)
|
||||
|
||||
#define SYSCTL_ULONG(a,b,c,d,e,f,g) \
|
||||
sysctl_pushback(STRINGIFY(a) "." STRINGIFY(c) + 1, \
|
||||
(d) | (SYSCTLTYPE_ULONG << 2), sizeof(*e), e, NULL)
|
||||
#define TUNABLE_INT(a,b)
|
||||
|
||||
#define SYSCTL_PROC(a,b,c,d,e,f,g,h,i) \
|
||||
sysctl_pushback(STRINGIFY(a) "." STRINGIFY(c) + 1, \
|
||||
(d), 4 /* XXX large */, (void *)(f /* arg2 */), g)
|
||||
|
||||
#define SYSCTL_VNET_PROC SYSCTL_PROC
|
||||
#define SYSCTL_VNET_INT SYSCTL_INT
|
||||
#define SYSCTL_VNET_UINT SYSCTL_UINT
|
||||
|
||||
void keinit_GST(void);
|
||||
void keexit_GST(void);
|
||||
int kesysctl_emu_set(void* p, int l);
|
||||
int kesysctl_emu_get(struct sockopt* sopt);
|
||||
void sysctl_pushback(char* name, int flags, int datalen, void* data, sysctl_h_fn_t *fn);
|
||||
|
||||
#endif /* EMULATE_SYSCTL */
|
||||
|
||||
struct ifnet;
|
||||
void ether_demux(struct ifnet *ifp, struct mbuf *m);
|
||||
|
||||
int ether_output_frame(struct ifnet *ifp, struct mbuf *m);
|
||||
|
||||
void in_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum);
|
||||
|
||||
void icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu);
|
||||
|
||||
#define in_localip(_x) (0)
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
struct rtentry;
|
||||
#endif
|
||||
void rtfree(struct rtentry *rt);
|
||||
|
||||
u_short in_cksum_skip(struct mbuf *m, int len, int skip);
|
||||
|
||||
#ifdef INP_LOCK_ASSERT
|
||||
#undef INP_LOCK_ASSERT
|
||||
#define INP_LOCK_ASSERT(a)
|
||||
#endif
|
||||
|
||||
int jailed(struct ucred *cred);
|
||||
|
||||
/*
|
||||
* Return 1 if an internet address is for a ``local'' host
|
||||
* (one to which we have a connection). If subnetsarelocal
|
||||
* is true, this includes other subnets of the local net.
|
||||
* Otherwise, it includes only the directly-connected (sub)nets.
|
||||
*/
|
||||
int in_localaddr(struct in_addr in);
|
||||
|
||||
int fnmatch(const char *pattern, const char *string, int flags);
|
||||
|
||||
/* vnet wrappers, in vnet.h and ip_var.h */
|
||||
//int ipfw_init(void);
|
||||
//void ipfw_destroy(void);
|
||||
|
||||
#define MTAG_IPFW 1148380143 /* IPFW-tagged cookie */
|
||||
#define MTAG_IPFW_RULE 1262273568 /* rule reference */
|
||||
#define MTAG_IPFW_CALL 1308397630 /* call stack */
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define offsetof(type, field) __builtin_offsetof(type, field)
|
||||
#endif
|
||||
struct ip_fw_args;
|
||||
extern int (*ip_dn_io_ptr)(struct mbuf **m, int dir, struct ip_fw_args *fwa);
|
||||
|
||||
#if 1 /* include vnet.h */
|
||||
#define curvnet NULL
|
||||
#define CURVNET_SET(_v)
|
||||
#define CURVNET_RESTORE()
|
||||
#define VNET_ASSERT(condition)
|
||||
|
||||
#define VNET_NAME(n) n
|
||||
#define VNET_DECLARE(t, n) extern t n
|
||||
#define VNET_DEFINE(t, n) t n
|
||||
#define _VNET_PTR(b, n) &VNET_NAME(n)
|
||||
/*
|
||||
* Virtualized global variable accessor macros.
|
||||
*/
|
||||
#define VNET_VNET_PTR(vnet, n) (&(n))
|
||||
#define VNET_VNET(vnet, n) (n)
|
||||
|
||||
#define VNET_PTR(n) (&(n))
|
||||
#define VNET(n) (n)
|
||||
|
||||
#define IS_DEFAULT_VNET(x) (1) // always true
|
||||
#endif
|
||||
|
||||
VNET_DECLARE(int, ip_defttl);
|
||||
#define V_ip_defttl VNET(ip_defttl);
|
||||
|
||||
|
||||
// int ipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir, struct inpcb *inp);
|
||||
// XXX used in netmap_io.c
|
||||
int ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir, struct inpcb *inp);
|
||||
int ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir, struct inpcb *inp);
|
||||
|
||||
/* hooks for divert */
|
||||
extern void (*ip_divert_ptr)(struct mbuf *m, int incoming);
|
||||
|
||||
extern int (*ip_dn_ctl_ptr)(struct sockopt *);
|
||||
typedef int ip_fw_ctl_t(struct sockopt *);
|
||||
extern ip_fw_ctl_t *ip_fw_ctl_ptr;
|
||||
|
||||
|
||||
/* netgraph prototypes */
|
||||
typedef int ng_ipfw_input_t(struct mbuf **, int, struct ip_fw_args *, int);
|
||||
extern ng_ipfw_input_t *ng_ipfw_input_p;
|
||||
|
||||
/* For kernel ipfw_ether and ipfw_bridge. */
|
||||
struct ip_fw_args;
|
||||
|
||||
#define V_ip_fw_ctl_ptr VNET(ip_fw_ctl_ptr)
|
||||
#define V_tcbinfo VNET(tcbinfo)
|
||||
#define V_udbinfo VNET(udbinfo)
|
||||
#endif /* _KERNEL */
|
||||
|
||||
// sys/eventhandler.h
|
||||
#define EVENTHANDLER_DECLARE(a, b)
|
||||
|
||||
/* application specific */
|
||||
struct sess;
|
||||
typedef int (handler_t)(struct sess *sess, void *arg);
|
||||
|
||||
/*
|
||||
* flags to control the callback
|
||||
* WANT_READ select on read
|
||||
* WANT_WRITE select on write
|
||||
* WANT_RUN run unconditionally
|
||||
* WANT_DELETE session is exiting
|
||||
*/
|
||||
enum flags_t {
|
||||
WANT_READ=1, WANT_WRITE=2, WANT_RUN=4,
|
||||
WANT_DELETE=0x8000
|
||||
};
|
||||
|
||||
struct sess {
|
||||
struct sess *next;
|
||||
int fd;
|
||||
handler_t *func;
|
||||
void *arg;
|
||||
enum flags_t flags;
|
||||
void *private; /* pointer managed by the session code */
|
||||
};
|
||||
struct sess *
|
||||
new_session(int fd, handler_t *func, void *arg, enum flags_t flags);
|
||||
|
||||
|
||||
void netmap_add_port(const char *dev);
|
||||
#endif /* !_MISSING_H_ */
|
|
@ -0,0 +1,264 @@
|
|||
/*-
|
||||
* Copyright (c) 1998-2010 Luigi Rizzo, Universita` di Pisa
|
||||
* Portions Copyright (c) 2000 Akamba Corp.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD: head/sys/netinet/ip_dummynet.h 266941 2014-06-01 07:28:24Z hiren $
|
||||
*/
|
||||
|
||||
#ifndef _IP_DUMMYNET_H
|
||||
#define _IP_DUMMYNET_H
|
||||
|
||||
/*
|
||||
* Definition of the kernel-userland API for dummynet.
|
||||
*
|
||||
* Setsockopt() and getsockopt() pass a batch of objects, each
|
||||
* of them starting with a "struct dn_id" which should fully identify
|
||||
* the object and its relation with others in the sequence.
|
||||
* The first object in each request should have
|
||||
* type= DN_CMD_*, id = DN_API_VERSION.
|
||||
* For other objects, type and subtype specify the object, len indicates
|
||||
* the total length including the header, and 'id' identifies the specific
|
||||
* object.
|
||||
*
|
||||
* Most objects are numbered with an identifier in the range 1..65535.
|
||||
* DN_MAX_ID indicates the first value outside the range.
|
||||
*/
|
||||
|
||||
#define DN_API_VERSION 12500000
|
||||
#define DN_MAX_ID 0x10000
|
||||
|
||||
struct dn_id {
|
||||
uint16_t len; /* total obj len including this header */
|
||||
uint8_t type;
|
||||
uint8_t subtype;
|
||||
uint32_t id; /* generic id */
|
||||
};
|
||||
|
||||
/*
|
||||
* These values are in the type field of struct dn_id.
|
||||
* To preserve the ABI, never rearrange the list or delete
|
||||
* entries with the exception of DN_LAST
|
||||
*/
|
||||
enum {
|
||||
DN_NONE = 0,
|
||||
DN_LINK = 1,
|
||||
DN_FS,
|
||||
DN_SCH,
|
||||
DN_SCH_I,
|
||||
DN_QUEUE,
|
||||
DN_DELAY_LINE,
|
||||
DN_PROFILE,
|
||||
DN_FLOW, /* struct dn_flow */
|
||||
DN_TEXT, /* opaque text is the object */
|
||||
|
||||
DN_CMD_CONFIG = 0x80, /* objects follow */
|
||||
DN_CMD_DELETE, /* subtype + list of entries */
|
||||
DN_CMD_GET, /* subtype + list of entries */
|
||||
DN_CMD_FLUSH,
|
||||
/* for compatibility with FreeBSD 7.2/8 */
|
||||
DN_COMPAT_PIPE,
|
||||
DN_COMPAT_QUEUE,
|
||||
DN_GET_COMPAT,
|
||||
|
||||
/* special commands for emulation of sysctl variables */
|
||||
DN_SYSCTL_GET,
|
||||
DN_SYSCTL_SET,
|
||||
|
||||
DN_LAST,
|
||||
};
|
||||
|
||||
enum { /* subtype for schedulers, flowset and the like */
|
||||
DN_SCHED_UNKNOWN = 0,
|
||||
DN_SCHED_FIFO = 1,
|
||||
DN_SCHED_WF2QP = 2,
|
||||
/* others are in individual modules */
|
||||
};
|
||||
|
||||
enum { /* user flags */
|
||||
DN_HAVE_MASK = 0x0001, /* fs or sched has a mask */
|
||||
DN_NOERROR = 0x0002, /* do not report errors */
|
||||
DN_QHT_HASH = 0x0004, /* qht is a hash table */
|
||||
DN_QSIZE_BYTES = 0x0008, /* queue size is in bytes */
|
||||
DN_HAS_PROFILE = 0x0010, /* a link has a profile */
|
||||
DN_IS_RED = 0x0020,
|
||||
DN_IS_GENTLE_RED= 0x0040,
|
||||
DN_IS_ECN = 0x0080,
|
||||
DN_PIPE_CMD = 0x1000, /* pipe config... */
|
||||
};
|
||||
|
||||
/*
|
||||
* link template.
|
||||
*/
|
||||
struct dn_link {
|
||||
struct dn_id oid;
|
||||
|
||||
/*
|
||||
* Userland sets bw and delay in bits/s and milliseconds.
|
||||
* The kernel converts this back and forth to bits/tick and ticks.
|
||||
* XXX what about burst ?
|
||||
*/
|
||||
int32_t link_nr;
|
||||
int bandwidth; /* bit/s or bits/tick. */
|
||||
int delay; /* ms and ticks */
|
||||
uint64_t burst; /* scaled. bits*Hz XXX */
|
||||
};
|
||||
|
||||
/*
|
||||
* A flowset, which is a template for flows. Contains parameters
|
||||
* from the command line: id, target scheduler, queue sizes, plr,
|
||||
* flow masks, buckets for the flow hash, and possibly scheduler-
|
||||
* specific parameters (weight, quantum and so on).
|
||||
*/
|
||||
struct dn_fs {
|
||||
struct dn_id oid;
|
||||
uint32_t fs_nr; /* the flowset number */
|
||||
uint32_t flags; /* userland flags */
|
||||
int qsize; /* queue size in slots or bytes */
|
||||
int32_t plr; /* PLR, pkt loss rate (2^31-1 means 100%) */
|
||||
uint32_t buckets; /* buckets used for the queue hash table */
|
||||
|
||||
struct ipfw_flow_id flow_mask;
|
||||
uint32_t sched_nr; /* the scheduler we attach to */
|
||||
/* generic scheduler parameters. Leave them at -1 if unset.
|
||||
* Now we use 0: weight, 1: lmax, 2: priority
|
||||
*/
|
||||
int par[4];
|
||||
|
||||
/* RED/GRED parameters.
|
||||
* weight and probabilities are in the range 0..1 represented
|
||||
* in fixed point arithmetic with SCALE_RED decimal bits.
|
||||
*/
|
||||
#define SCALE_RED 16
|
||||
#define SCALE(x) ( (x) << SCALE_RED )
|
||||
#define SCALE_VAL(x) ( (x) >> SCALE_RED )
|
||||
#define SCALE_MUL(x,y) ( ( (x) * (y) ) >> SCALE_RED )
|
||||
int w_q ; /* queue weight (scaled) */
|
||||
int max_th ; /* maximum threshold for queue (scaled) */
|
||||
int min_th ; /* minimum threshold for queue (scaled) */
|
||||
int max_p ; /* maximum value for p_b (scaled) */
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* dn_flow collects flow_id and stats for queues and scheduler
|
||||
* instances, and is used to pass these info to userland.
|
||||
* oid.type/oid.subtype describe the object, oid.id is number
|
||||
* of the parent object.
|
||||
*/
|
||||
struct dn_flow {
|
||||
struct dn_id oid;
|
||||
struct ipfw_flow_id fid;
|
||||
uint64_t tot_pkts; /* statistics counters */
|
||||
uint64_t tot_bytes;
|
||||
uint32_t length; /* Queue length, in packets */
|
||||
uint32_t len_bytes; /* Queue length, in bytes */
|
||||
uint32_t drops;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Scheduler template, mostly indicating the name, number,
|
||||
* sched_mask and buckets.
|
||||
*/
|
||||
struct dn_sch {
|
||||
struct dn_id oid;
|
||||
uint32_t sched_nr; /* N, scheduler number */
|
||||
uint32_t buckets; /* number of buckets for the instances */
|
||||
uint32_t flags; /* have_mask, ... */
|
||||
|
||||
char name[16]; /* null terminated */
|
||||
/* mask to select the appropriate scheduler instance */
|
||||
struct ipfw_flow_id sched_mask; /* M */
|
||||
};
|
||||
|
||||
|
||||
/* A delay profile is attached to a link.
|
||||
* Note that a profile, as any other object, cannot be longer than 2^16
|
||||
*/
|
||||
#define ED_MAX_SAMPLES_NO 1024
|
||||
struct dn_profile {
|
||||
struct dn_id oid;
|
||||
/* fields to simulate a delay profile */
|
||||
#define ED_MAX_NAME_LEN 32
|
||||
char name[ED_MAX_NAME_LEN];
|
||||
int link_nr;
|
||||
int loss_level;
|
||||
int _bandwidth; // XXX use link bandwidth? unused ?
|
||||
int samples_no; /* actual len of samples[] */
|
||||
int samples[ED_MAX_SAMPLES_NO]; /* may be shorter */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Overall structure of dummynet
|
||||
|
||||
In dummynet, packets are selected with the firewall rules, and passed
|
||||
to two different objects: PIPE or QUEUE (bad name).
|
||||
|
||||
A QUEUE defines a classifier, which groups packets into flows
|
||||
according to a 'mask', puts them into independent queues (one
|
||||
per flow) with configurable size and queue management policy,
|
||||
and passes flows to a scheduler:
|
||||
|
||||
(flow_mask|sched_mask) sched_mask
|
||||
+---------+ weight Wx +-------------+
|
||||
| |->-[flow]-->--| |-+
|
||||
-->--| QUEUE x | ... | | |
|
||||
| |->-[flow]-->--| SCHEDuler N | |
|
||||
+---------+ | | |
|
||||
... | +--[LINK N]-->--
|
||||
+---------+ weight Wy | | +--[LINK N]-->--
|
||||
| |->-[flow]-->--| | |
|
||||
-->--| QUEUE y | ... | | |
|
||||
| |->-[flow]-->--| | |
|
||||
+---------+ +-------------+ |
|
||||
+-------------+
|
||||
|
||||
Many QUEUE objects can connect to the same scheduler, each
|
||||
QUEUE object can have its own set of parameters.
|
||||
|
||||
In turn, the SCHEDuler 'forks' multiple instances according
|
||||
to a 'sched_mask', each instance manages its own set of queues
|
||||
and transmits on a private instance of a configurable LINK.
|
||||
|
||||
A PIPE is a simplified version of the above, where there
|
||||
is no flow_mask, and each scheduler instance handles a single queue.
|
||||
|
||||
The following data structures (visible from userland) describe
|
||||
the objects used by dummynet:
|
||||
|
||||
+ dn_link, contains the main configuration parameters related
|
||||
to delay and bandwidth;
|
||||
+ dn_profile describes a delay profile;
|
||||
+ dn_flow describes the flow status (flow id, statistics)
|
||||
|
||||
+ dn_sch describes a scheduler
|
||||
+ dn_fs describes a flowset (msk, weight, queue parameters)
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
#endif /* _IP_DUMMYNET_H */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -3,9 +3,11 @@
|
|||
noinst_LTLIBRARIES = libpgw.la
|
||||
|
||||
libpgw_la_SOURCES = \
|
||||
pgw_ipfw.h \
|
||||
pgw_event.h pgw_context.h pgw_sm.h \
|
||||
pgw_gtp_path.h pgw_s5c_build.h pgw_s5c_handler.h \
|
||||
pgw_fd_path.h pgw_gx_handler.h \
|
||||
pgw_ipfw.c \
|
||||
pgw_init.c pgw_event.c pgw_context.c pgw_sm.c \
|
||||
pgw_gtp_path.c pgw_s5c_build.c pgw_s5c_handler.c \
|
||||
pgw_fd_path.c pgw_gx_handler.c
|
||||
|
@ -14,20 +16,23 @@ libpgw_la_DEPENDENCIES = \
|
|||
$(top_srcdir)/lib/core/src/libcore.la \
|
||||
$(top_srcdir)/lib/fd/gx/libfdgx.la \
|
||||
$(top_srcdir)/lib/fd/libfd.la \
|
||||
$(top_srcdir)/lib/gtp/libgtp.la
|
||||
$(top_srcdir)/lib/gtp/libgtp.la \
|
||||
$(top_srcdir)/lib/ipfw/libipfw.la
|
||||
|
||||
libpgw_la_LIBADD = \
|
||||
$(top_srcdir)/lib/core/src/libcore.la \
|
||||
$(top_srcdir)/lib/fd/gx/libfdgx.la \
|
||||
$(top_srcdir)/lib/fd/libfd.la \
|
||||
$(top_srcdir)/lib/gtp/libgtp.la
|
||||
$(top_srcdir)/lib/gtp/libgtp.la \
|
||||
$(top_srcdir)/lib/ipfw/libipfw.la
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/lib/core/include \
|
||||
-I$(top_srcdir)/lib/base \
|
||||
-I$(top_srcdir)/lib/fd/gx \
|
||||
-I$(top_srcdir)/lib/fd \
|
||||
-I$(top_srcdir)/lib/gtp
|
||||
-I$(top_srcdir)/lib/gtp \
|
||||
-I$(top_srcdir)/lib/ipfw
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall -Werror
|
||||
|
|
|
@ -19,6 +19,7 @@ index_declare(pgw_sess_pool, pgw_sess_t, MAX_POOL_OF_SESS);
|
|||
index_declare(pgw_bearer_pool, pgw_bearer_t, MAX_POOL_OF_BEARER);
|
||||
|
||||
pool_declare(pgw_ip_pool_pool, pgw_ip_pool_t, MAX_POOL_OF_SESS);
|
||||
pool_declare(pgw_pf_pool, pgw_pf_t, MAX_POOL_OF_PF);
|
||||
|
||||
static int context_initiaized = 0;
|
||||
|
||||
|
@ -36,6 +37,7 @@ status_t pgw_context_init()
|
|||
index_init(&pgw_bearer_pool, MAX_POOL_OF_BEARER);
|
||||
|
||||
pool_init(&pgw_ip_pool_pool, MAX_POOL_OF_SESS);
|
||||
pool_init(&pgw_pf_pool, MAX_POOL_OF_PF);
|
||||
|
||||
self.sess_hash = hash_make();
|
||||
|
||||
|
@ -73,6 +75,7 @@ status_t pgw_context_final()
|
|||
index_size(&pgw_ip_pool_pool) - pool_avail(&pgw_ip_pool_pool),
|
||||
index_size(&pgw_ip_pool_pool));
|
||||
|
||||
pool_final(&pgw_pf_pool);
|
||||
pool_final(&pgw_ip_pool_pool);
|
||||
|
||||
index_final(&pgw_bearer_pool);
|
||||
|
@ -652,6 +655,8 @@ pgw_bearer_t* pgw_bearer_add(pgw_sess_t *sess)
|
|||
index_alloc(&pgw_bearer_pool, &bearer);
|
||||
d_assert(bearer, return NULL, "Bearer context allocation failed");
|
||||
|
||||
list_init(&bearer->pf_list);
|
||||
|
||||
bearer->pgw_s5u_teid = bearer->index;
|
||||
bearer->pgw_s5u_addr = pgw_self()->s5u_addr;
|
||||
|
||||
|
@ -666,6 +671,8 @@ status_t pgw_bearer_remove(pgw_bearer_t *bearer)
|
|||
d_assert(bearer, return CORE_ERROR, "Null param");
|
||||
d_assert(bearer->sess, return CORE_ERROR, "Null param");
|
||||
|
||||
pgw_pf_remove_all(bearer);
|
||||
|
||||
list_remove(&bearer->sess->bearer_list, bearer);
|
||||
index_free(&pgw_bearer_pool, bearer);
|
||||
|
||||
|
@ -824,6 +831,80 @@ pgw_bearer_t* pgw_bearer_find_by_packet(pkbuf_t *pkt)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
pgw_pf_t *pgw_pf_add(pgw_bearer_t *bearer, c_uint32_t precedence)
|
||||
{
|
||||
pgw_pf_t *pf = NULL;
|
||||
|
||||
d_assert(bearer, return NULL, "Null param");
|
||||
|
||||
pool_alloc_node(&pgw_pf_pool, &pf);
|
||||
d_assert(pf, return NULL, "Null param");
|
||||
|
||||
pf->identifier = NEXT_ID(bearer->pf_identifier, 1, 15);
|
||||
|
||||
list_append(&bearer->pf_list, pf);
|
||||
|
||||
pf->bearer = bearer;
|
||||
|
||||
return pf;
|
||||
}
|
||||
|
||||
status_t pgw_pf_remove(pgw_pf_t *pf)
|
||||
{
|
||||
d_assert(pf, return CORE_ERROR, "Null param");
|
||||
d_assert(pf->bearer, return CORE_ERROR, "Null param");
|
||||
|
||||
list_remove(&pf->bearer->pf_list, pf);
|
||||
pool_free_node(&pgw_pf_pool, pf);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t pgw_pf_remove_all(pgw_bearer_t *bearer)
|
||||
{
|
||||
pgw_pf_t *pf = NULL, *next_pf = NULL;
|
||||
|
||||
d_assert(bearer, return CORE_ERROR, "Null param");
|
||||
|
||||
pf = pgw_pf_first(bearer);
|
||||
while (pf)
|
||||
{
|
||||
next_pf = pgw_pf_next(pf);
|
||||
|
||||
pgw_pf_remove(pf);
|
||||
|
||||
pf = next_pf;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
pgw_pf_t* pgw_pf_find_by_id(pgw_bearer_t *bearer, c_uint8_t id)
|
||||
{
|
||||
pgw_pf_t *pf = NULL;
|
||||
|
||||
pf = pgw_pf_first(bearer);
|
||||
while (pf)
|
||||
{
|
||||
if (pf->identifier == id)
|
||||
return pf;
|
||||
|
||||
pf = pgw_pf_next(pf);
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
pgw_pf_t* pgw_pf_first(pgw_bearer_t *bearer)
|
||||
{
|
||||
return list_first(&bearer->pf_list);
|
||||
}
|
||||
|
||||
pgw_pf_t* pgw_pf_next(pgw_pf_t *pf)
|
||||
{
|
||||
return list_next(pf);
|
||||
}
|
||||
|
||||
status_t pgw_ip_pool_generate()
|
||||
{
|
||||
int i, j, k;
|
||||
|
|
|
@ -114,11 +114,52 @@ typedef struct _pgw_bearer_t {
|
|||
c_uint32_t sgw_s5u_teid;
|
||||
c_uint32_t sgw_s5u_addr;
|
||||
|
||||
/* QoS Infomration */
|
||||
qos_t qos;
|
||||
|
||||
/* Packet Filter Identifier Generator(1~15) */
|
||||
c_uint8_t pf_identifier;
|
||||
/* Packet Filter List */
|
||||
list_t pf_list;
|
||||
|
||||
pgw_sess_t *sess;
|
||||
} pgw_bearer_t;
|
||||
|
||||
typedef struct _pgw_rule_t {
|
||||
c_uint8_t proto;
|
||||
struct {
|
||||
struct {
|
||||
c_uint32_t addr;
|
||||
c_uint32_t mask;
|
||||
} local;
|
||||
struct {
|
||||
c_uint32_t addr;
|
||||
c_uint32_t mask;
|
||||
} remote;
|
||||
} ipv4;
|
||||
struct {
|
||||
struct {
|
||||
c_uint16_t low;
|
||||
c_uint32_t high;
|
||||
} local;
|
||||
struct {
|
||||
c_uint16_t low;
|
||||
c_uint32_t high;
|
||||
} remote;
|
||||
} port;
|
||||
} pgw_rule_t;
|
||||
|
||||
typedef struct _pgw_pf_t {
|
||||
lnode_t node;
|
||||
|
||||
ED3(c_uint8_t spare:2;,
|
||||
c_uint8_t direction:2;,
|
||||
c_uint8_t identifier:4;)
|
||||
pgw_rule_t rule;
|
||||
|
||||
pgw_bearer_t *bearer;
|
||||
} pgw_pf_t;
|
||||
|
||||
CORE_DECLARE(status_t) pgw_context_init(void);
|
||||
CORE_DECLARE(status_t) pgw_context_final(void);
|
||||
CORE_DECLARE(pgw_context_t*) pgw_self(void);
|
||||
|
@ -166,6 +207,15 @@ CORE_DECLARE(pgw_bearer_t*) pgw_bearer_next(pgw_bearer_t *bearer);
|
|||
|
||||
CORE_DECLARE(pgw_bearer_t*) pgw_bearer_find_by_packet(pkbuf_t *pkt);
|
||||
|
||||
CORE_DECLARE(pgw_pf_t*) pgw_pf_add(
|
||||
pgw_bearer_t *bearer, c_uint32_t precedence);
|
||||
CORE_DECLARE(status_t ) pgw_pf_remove(pgw_pf_t *pf);
|
||||
CORE_DECLARE(status_t ) pgw_pf_remove_all(pgw_bearer_t *bearer);
|
||||
CORE_DECLARE(pgw_pf_t*) pgw_pf_find_by_id(
|
||||
pgw_bearer_t *pgw_bearer, c_uint8_t id);
|
||||
CORE_DECLARE(pgw_pf_t*) pgw_pf_first(pgw_bearer_t *bearer);
|
||||
CORE_DECLARE(pgw_pf_t*) pgw_pf_next(pgw_pf_t *pf);
|
||||
|
||||
CORE_DECLARE(status_t ) pgw_ip_pool_generate();
|
||||
CORE_DECLARE(pgw_ip_pool_t*) pgw_ip_pool_alloc();
|
||||
CORE_DECLARE(status_t ) pgw_ip_pool_free(pgw_ip_pool_t *ip_pool);
|
||||
|
|
|
@ -6,46 +6,7 @@
|
|||
#include "gx_message.h"
|
||||
#include "pgw_gtp_path.h"
|
||||
#include "pgw_s5c_build.h"
|
||||
|
||||
void pgw_gx_handle_create_bearer_request(pgw_sess_t *sess, pcc_rule_t *pcc_rule)
|
||||
{
|
||||
status_t rv;
|
||||
gtp_xact_t *xact = NULL;
|
||||
gtp_header_t h;
|
||||
pkbuf_t *pkbuf = NULL;
|
||||
pgw_bearer_t *bearer = NULL;
|
||||
|
||||
d_assert(sess, return, "Null param");
|
||||
d_assert(pcc_rule, return, "Null param");
|
||||
|
||||
bearer = pgw_bearer_find_by_qci_arp(sess,
|
||||
pcc_rule->qos.qci,
|
||||
pcc_rule->qos.arp.priority_level,
|
||||
pcc_rule->qos.arp.pre_emption_capability,
|
||||
pcc_rule->qos.arp.pre_emption_vulnerability);
|
||||
if (bearer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bearer = pgw_bearer_add(sess);
|
||||
d_assert(bearer, return, "Null param");
|
||||
memcpy(&bearer->qos, &pcc_rule->qos, sizeof(qos_t));
|
||||
memcpy(&bearer->qos, &pcc_rule->qos, sizeof(qos_t));
|
||||
|
||||
memset(&h, 0, sizeof(gtp_header_t));
|
||||
h.type = GTP_CREATE_BEARER_REQUEST_TYPE;
|
||||
h.teid = sess->sgw_s5c_teid;
|
||||
|
||||
rv = pgw_s5c_build_create_bearer_request(&pkbuf, h.type, bearer);
|
||||
d_assert(rv == CORE_OK, return, "S11 build error");
|
||||
|
||||
xact = gtp_xact_local_create(sess->sgw, &h, pkbuf);
|
||||
d_assert(xact, return, "Null param");
|
||||
|
||||
rv = gtp_xact_commit(xact);
|
||||
d_assert(rv == CORE_OK, return, "xact_commit error");
|
||||
}
|
||||
#include "pgw_ipfw.h"
|
||||
|
||||
void pgw_gx_handle_cca_initial_request(
|
||||
gtp_xact_t *xact, pgw_sess_t *sess,
|
||||
|
@ -54,15 +15,18 @@ void pgw_gx_handle_cca_initial_request(
|
|||
status_t rv;
|
||||
gtp_header_t h;
|
||||
pkbuf_t *pkbuf = NULL;
|
||||
int i = 0;
|
||||
int i = 0, j = 0;
|
||||
pgw_bearer_t *bearer = NULL;
|
||||
|
||||
d_assert(xact, return, "Null param");
|
||||
d_assert(sess, return, "Null param");
|
||||
d_assert(cca_message, return, "Null param");
|
||||
d_assert(req, return, "Null param");
|
||||
|
||||
/* Setup GTP Node between PGW and SGW */
|
||||
CONNECT_SGW_GTP_NODE(sess, xact);
|
||||
|
||||
/* Send Create Session Request with Creating Default Bearer */
|
||||
memset(&h, 0, sizeof(gtp_header_t));
|
||||
h.type = GTP_CREATE_SESSION_RESPONSE_TYPE;
|
||||
h.teid = sess->sgw_s5c_teid;
|
||||
|
@ -77,9 +41,67 @@ void pgw_gx_handle_cca_initial_request(
|
|||
rv = gtp_xact_commit(xact);
|
||||
d_assert(rv == CORE_OK, return, "xact_commit error");
|
||||
|
||||
/* Find Dedicated Bearer */
|
||||
for (i = 0; i < cca_message->num_of_pcc_rule; i++)
|
||||
{
|
||||
pgw_gx_handle_create_bearer_request(sess, &cca_message->pcc_rule[i]);
|
||||
pcc_rule_t *pcc_rule = &cca_message->pcc_rule[i];
|
||||
bearer = pgw_bearer_find_by_qci_arp(sess,
|
||||
pcc_rule->qos.qci,
|
||||
pcc_rule->qos.arp.priority_level,
|
||||
pcc_rule->qos.arp.pre_emption_capability,
|
||||
pcc_rule->qos.arp.pre_emption_vulnerability);
|
||||
if (!bearer)
|
||||
bearer = pgw_bearer_add(sess);
|
||||
d_assert(bearer, return, "Null param");
|
||||
|
||||
memcpy(&bearer->qos, &pcc_rule->qos, sizeof(qos_t));
|
||||
|
||||
for (j = 0; j < pcc_rule->num_of_flow; j++)
|
||||
{
|
||||
flow_t *flow = &pcc_rule->flow[j];
|
||||
pgw_rule_t rule;
|
||||
pgw_pf_t *pf = NULL;
|
||||
|
||||
d_assert(flow, return, "Null param");
|
||||
d_assert(flow->description, return, "Null param");
|
||||
|
||||
rv = pgw_compile_packet_filter(&rule, flow->description);
|
||||
d_assert(rv == CORE_OK, return, "Failed to compile packet filter");
|
||||
|
||||
pf = pgw_pf_add(bearer, pcc_rule->precedence);
|
||||
d_assert(pf, return, "Null param");
|
||||
|
||||
memcpy(&pf->rule, &rule, sizeof(pgw_rule_t));
|
||||
pf->direction = flow->direction;
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip Default Bearer */
|
||||
bearer = pgw_default_bearer_in_sess(sess);
|
||||
d_assert(bearer, return, "Null param");
|
||||
|
||||
/* Send Create Bearer Request for Dedicated Bearer */
|
||||
bearer = pgw_bearer_next(bearer);
|
||||
while(bearer)
|
||||
{
|
||||
gtp_xact_t *xact = NULL;
|
||||
gtp_header_t h;
|
||||
pkbuf_t *pkbuf = NULL;
|
||||
|
||||
memset(&h, 0, sizeof(gtp_header_t));
|
||||
h.type = GTP_CREATE_BEARER_REQUEST_TYPE;
|
||||
h.teid = sess->sgw_s5c_teid;
|
||||
|
||||
rv = pgw_s5c_build_create_bearer_request(&pkbuf, h.type, bearer);
|
||||
d_assert(rv == CORE_OK, return, "S11 build error");
|
||||
|
||||
xact = gtp_xact_local_create(sess->sgw, &h, pkbuf);
|
||||
d_assert(xact, return, "Null param");
|
||||
|
||||
rv = gtp_xact_commit(xact);
|
||||
d_assert(rv == CORE_OK, return, "xact_commit error");
|
||||
|
||||
bearer = pgw_bearer_next(bearer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
#define TRACE_MODULE _pgw_ipfw
|
||||
|
||||
#include "pgw_ipfw.h"
|
||||
|
||||
#include "ipfw2.h"
|
||||
#include "objs/include_e/netinet/ip_fw.h"
|
||||
|
||||
#define MAX_NUM_OF_TOKEN 32
|
||||
#define MAX_NUM_OF_RULE_BUFFER 1024
|
||||
|
||||
void compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, void *tstate);
|
||||
|
||||
status_t pgw_compile_packet_filter(pgw_rule_t *pgw_rule, c_int8_t *description)
|
||||
{
|
||||
pgw_rule_t zero_rule;
|
||||
char *token, *dir;
|
||||
char *saveptr;
|
||||
int i = 2;
|
||||
|
||||
char *av[MAX_NUM_OF_TOKEN];
|
||||
uint32_t rulebuf[MAX_NUM_OF_RULE_BUFFER];
|
||||
int rbufsize;
|
||||
struct ip_fw_rule *rule = (struct ip_fw_rule *)rulebuf;
|
||||
|
||||
int l;
|
||||
ipfw_insn *cmd;
|
||||
|
||||
d_assert(pgw_rule, return CORE_ERROR, "Null param");
|
||||
d_assert(description, return CORE_ERROR, "Null param");
|
||||
|
||||
rbufsize = sizeof(rulebuf);
|
||||
memset(rulebuf, 0, rbufsize);
|
||||
|
||||
av[0] = NULL;
|
||||
|
||||
/* ACTION */
|
||||
token = strtok_r(description, " ", &saveptr);
|
||||
if (strcmp(token, "permit") != 0)
|
||||
{
|
||||
d_error("Not begins with reserved keyword : 'permit'");
|
||||
return CORE_ERROR;
|
||||
}
|
||||
av[1] = token;
|
||||
|
||||
/* Save DIRECTION */
|
||||
dir = token = strtok_r(NULL, " ", &saveptr);
|
||||
if (strcmp(token, "out") != 0)
|
||||
{
|
||||
d_error("Not begins with reserved keyword : 'permit out'");
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
/* ADDR */
|
||||
token = strtok_r(NULL, " ", &saveptr);
|
||||
while(token != NULL)
|
||||
{
|
||||
av[i++] = token;
|
||||
token = strtok_r(NULL, " ", &saveptr);
|
||||
}
|
||||
|
||||
/* Add DIRECTION */
|
||||
av[i++] = dir;
|
||||
|
||||
av[i] = NULL;
|
||||
|
||||
compile_rule(av, (uint32_t *)rule, &rbufsize, NULL);
|
||||
|
||||
memset(pgw_rule, 0, sizeof(pgw_rule_t));
|
||||
for (l = rule->act_ofs, cmd = rule->cmd;
|
||||
l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd))
|
||||
{
|
||||
switch(cmd->opcode)
|
||||
{
|
||||
case O_PROTO:
|
||||
pgw_rule->proto = cmd->arg1;
|
||||
break;
|
||||
case O_IP_SRC:
|
||||
case O_IP_SRC_MASK:
|
||||
{
|
||||
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
|
||||
pgw_rule->ipv4.local.addr = a[0];
|
||||
pgw_rule->ipv4.local.mask = a[1];
|
||||
break;
|
||||
}
|
||||
case O_IP_DST:
|
||||
case O_IP_DST_MASK:
|
||||
{
|
||||
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
|
||||
pgw_rule->ipv4.remote.addr = a[0];
|
||||
pgw_rule->ipv4.remote.mask = a[1];
|
||||
break;
|
||||
}
|
||||
case O_IP_SRCPORT:
|
||||
{
|
||||
uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
|
||||
pgw_rule->port.local.low = p[0];
|
||||
pgw_rule->port.local.high = p[1];
|
||||
break;
|
||||
}
|
||||
case O_IP_DSTPORT:
|
||||
{
|
||||
uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
|
||||
pgw_rule->port.remote.low = p[0];
|
||||
pgw_rule->port.remote.high = p[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(&zero_rule, 0, sizeof(pgw_rule_t));
|
||||
if (memcmp(pgw_rule, &zero_rule, sizeof(pgw_rule_t)) == 0)
|
||||
{
|
||||
d_error("Cannot find Flow-Description");
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef __PGW_IPFW_H__
|
||||
#define __PGW_IPFW_H__
|
||||
|
||||
#include "core_debug.h"
|
||||
|
||||
#include "pgw_context.h"
|
||||
|
||||
CORE_DECLARE(status_t) pgw_compile_packet_filter(
|
||||
pgw_rule_t *pf, c_int8_t *description);
|
||||
|
||||
#endif /* __PGW_IPFW_H__ */
|
|
@ -170,6 +170,10 @@ status_t pgw_s5c_build_create_bearer_request(
|
|||
gtp_f_teid_t pgw_s5u_teid;
|
||||
gtp_bearer_qos_t bearer_qos;
|
||||
char bearer_qos_buf[GTP_BEARER_QOS_LEN];
|
||||
gtp_tft_t tft;
|
||||
int i, j, len;
|
||||
char tft_buf[GTP_MAX_TRAFFIC_FLOW_TEMPLATE];
|
||||
pgw_pf_t *pf = NULL;
|
||||
|
||||
d_assert(bearer, return CORE_ERROR, "Null param");
|
||||
sess = bearer->sess;
|
||||
|
@ -215,6 +219,95 @@ status_t pgw_s5c_build_create_bearer_request(
|
|||
gtp_build_bearer_qos(&req->bearer_contexts.bearer_level_qos,
|
||||
&bearer_qos, bearer_qos_buf, GTP_BEARER_QOS_LEN);
|
||||
|
||||
/* Bearer TFT */
|
||||
memset(&tft, 0, sizeof(tft));
|
||||
tft.code = GTP_TFT_CODE_CREATE_NEW_TFT;
|
||||
|
||||
i = 0;
|
||||
pf = pgw_pf_first(bearer);
|
||||
while(pf)
|
||||
{
|
||||
tft.pf[i].direction = pf->direction;
|
||||
tft.pf[i].identifier = pf->identifier - 1;
|
||||
tft.pf[i].precedence = i+1;
|
||||
|
||||
j = 0, len = 0;
|
||||
if (pf->rule.proto)
|
||||
{
|
||||
tft.pf[i].component[j].type =
|
||||
GTP_PACKET_FILTER_PROTOCOL_IDENTIFIER_NEXT_HEADER_TYPE;
|
||||
tft.pf[i].component[j].proto = pf->rule.proto;
|
||||
j++; len += 2;
|
||||
}
|
||||
|
||||
if (pf->rule.ipv4.local.addr)
|
||||
{
|
||||
tft.pf[i].component[j].type =
|
||||
GTP_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE;
|
||||
tft.pf[i].component[j].ipv4.addr = pf->rule.ipv4.local.addr;
|
||||
tft.pf[i].component[j].ipv4.mask = pf->rule.ipv4.local.mask;
|
||||
j++; len += 9;
|
||||
}
|
||||
|
||||
if (pf->rule.ipv4.remote.addr)
|
||||
{
|
||||
tft.pf[i].component[j].type =
|
||||
GTP_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE;
|
||||
tft.pf[i].component[j].ipv4.addr = pf->rule.ipv4.remote.addr;
|
||||
tft.pf[i].component[j].ipv4.mask = pf->rule.ipv4.remote.mask;
|
||||
j++; len += 9;
|
||||
}
|
||||
|
||||
if (pf->rule.port.local.low)
|
||||
{
|
||||
if (pf->rule.port.local.low == pf->rule.port.local.high)
|
||||
{
|
||||
tft.pf[i].component[j].type =
|
||||
GTP_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE;
|
||||
tft.pf[i].component[j].port.low = pf->rule.port.local.low;
|
||||
j++; len += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
tft.pf[i].component[j].type =
|
||||
GTP_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE;
|
||||
tft.pf[i].component[j].port.low = pf->rule.port.local.low;
|
||||
tft.pf[i].component[j].port.high = pf->rule.port.local.high;
|
||||
j++; len += 5;
|
||||
}
|
||||
}
|
||||
|
||||
if (pf->rule.port.remote.low)
|
||||
{
|
||||
if (pf->rule.port.remote.low == pf->rule.port.remote.high)
|
||||
{
|
||||
tft.pf[i].component[j].type =
|
||||
GTP_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE;
|
||||
tft.pf[i].component[j].port.low = pf->rule.port.remote.low;
|
||||
j++; len += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
tft.pf[i].component[j].type =
|
||||
GTP_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE;
|
||||
tft.pf[i].component[j].port.low = pf->rule.port.remote.low;
|
||||
tft.pf[i].component[j].port.high = pf->rule.port.remote.high;
|
||||
j++; len += 5;
|
||||
}
|
||||
}
|
||||
|
||||
tft.pf[i].num_of_component = j;
|
||||
tft.pf[i].length = len;
|
||||
i++;
|
||||
|
||||
pf = pgw_pf_next(pf);
|
||||
}
|
||||
tft.num_of_packet_filter = i;
|
||||
|
||||
req->bearer_contexts.tft.presence = 1;
|
||||
gtp_build_tft(&req->bearer_contexts.tft,
|
||||
&tft, tft_buf, GTP_MAX_TRAFFIC_FLOW_TEMPLATE);
|
||||
|
||||
gtp_message.h.type = type;
|
||||
rv = gtp_build_msg(pkbuf, >p_message);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR, "gtp build failed");
|
||||
|
|
Loading…
Reference in New Issue