genode/repos/dde_linux/src/lib/lxip/lxc_emul.c

535 lines
9.5 KiB
C

/**
* \brief Linux emulation code
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2013-08-30
*/
/*
* Copyright (C) 2013-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Linux includes */
#include <linux/inetdevice.h>
#include <linux/net.h>
#include <linux/netdevice.h>
#include <uapi/linux/rtnetlink.h>
#include <net/sock.h>
#include <net/route.h>
#include <net/ip_fib.h>
#include <net/tcp.h>
#include <net/tcp_states.h>
/***********************
** linux/genetlink.h **
***********************/
/* needed by af_netlink.c */
atomic_t genl_sk_destructing_cnt;
wait_queue_head_t genl_sk_destructing_waitq;
/****************************
** asm-generic/atomic64.h **
****************************/
long long atomic64_read(const atomic64_t *v)
{
return v->counter;
}
void atomic64_set(atomic64_t *v, long long i)
{
v->counter = i;
}
/********************
** linux/bitmap.h **
********************/
void bitmap_fill(unsigned long *dst, int nbits)
{
int count = nbits / (8 * sizeof (long));
int i;
memset(dst, 0xff, count * sizeof(long));
dst += count;
count = nbits % (8 * sizeof(long));
for (i = 0; i < count; i++)
*dst |= (1 << i);
}
void bitmap_zero(unsigned long *dst, int nbits)
{
int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
memset(dst, 0, len);
}
/*****************
** linux/gfp.h **
*****************/
unsigned long get_zeroed_page(gfp_t gfp_mask)
{
return (unsigned long)kzalloc(PAGE_SIZE, 0);
}
/********************
** linux/percpu.h **
********************/
void *__alloc_percpu(size_t size, size_t align)
{
return kmalloc(size, 0);
}
/******************
** linux/hash.h **
******************/
u32 hash_32(u32 val, unsigned int bits)
{
enum { GOLDEN_RATIO_PRIME_32 = 0x9e370001UL };
u32 hash = val * GOLDEN_RATIO_PRIME_32;
hash = hash >> (32 - bits);
return hash;
}
/******************
** linux/dcache **
******************/
unsigned int full_name_hash(const unsigned char *name, unsigned int len)
{
unsigned hash = 0, i;
for (i = 0; i < len; i++)
hash += name[i];
return hash;
}
/******************************
* net/core/net/namespace.h **
******************************/
int register_pernet_subsys(struct pernet_operations *ops)
{
if (ops->init)
ops->init(&init_net);
return 0;
}
int register_pernet_device(struct pernet_operations *ops)
{
return register_pernet_subsys(ops);
}
/*************************
** net/net_namespace.h **
*************************/
int rt_genid(struct net *net)
{
int ret = atomic_read(&net->rt_genid);
return -1;
}
/**********************
** linx/rtnetlink.h **
**********************/
struct netdev_queue *dev_ingress_queue(struct net_device *dev)
{
return dev->ingress_queue;
}
/****************
** linux/ip.h **
****************/
struct iphdr *ip_hdr(const struct sk_buff *skb)
{
return (struct iphdr *)skb_network_header(skb);
}
/*******************************
** asm-generic/bitops/find.h **
*******************************/
unsigned long find_first_zero_bit(unsigned long const *addr, unsigned long size)
{
unsigned long i, j;
for (i = 0; i < (size / BITS_PER_LONG); i++)
if (addr[i] != ~0UL)
break;
if (i == size)
return size;
for (j = 0; j < BITS_PER_LONG; j++)
if ((~addr[i]) & (1 << j))
break;
return (i * BITS_PER_LONG) + j;
}
/****************************
** asm-generic/getorder.h **
****************************/
int get_order(unsigned long size)
{
int order;
size--;
size >>= PAGE_SHIFT;
order = __builtin_ctzl(size);
return order;
}
/*********************
** linux/jiffies.h **
*********************/
clock_t jiffies_to_clock_t(unsigned long j)
{
return j / HZ; /* XXX not sure if this is enough */
}
/*********************
** linux/utsname.h **
*********************/
struct uts_name init_uts_ns;
struct new_utsname *init_utsname(void) { return &init_uts_ns.name; }
struct new_utsname *utsname(void) { return init_utsname(); }
/**********************
** linux/notifier.h **
**********************/
int raw_notifier_chain_register(struct raw_notifier_head *nh,
struct notifier_block *n)
{
struct notifier_block *nl = nh->head;
struct notifier_block *pr = 0;
while (nl) {
if (n->priority > nl->priority)
break;
pr = nl;
nl = nl->next;
}
n->next = nl;
if (pr)
pr->next = n;
else
nh->head = n;
return 0;
}
int raw_notifier_call_chain(struct raw_notifier_head *nh,
unsigned long val, void *v)
{
int ret = NOTIFY_DONE;
struct notifier_block *nb = nh->head;
while (nb) {
ret = nb->notifier_call(nb, val, v);
if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
break;
nb = nb->next;
}
return ret;
}
int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
struct notifier_block *n)
{
return raw_notifier_chain_register((struct raw_notifier_head *)nh, n);
}
int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v)
{
return raw_notifier_call_chain((struct raw_notifier_head *)nh, val, v);
}
/****************************
** asm-generic/checksum.h **
****************************/
__sum16 csum_fold(__wsum csum)
{
u32 sum = (u32)csum;
sum = (sum & 0xffff) + (sum >> 16);
sum = (sum & 0xffff) + (sum >> 16);
return (__sum16)~sum;
}
/*******************
** net/checksum.h **
********************/
__wsum csum_add(__wsum csum, __wsum addend)
{
u32 res = (u32)csum;
res += (u32)addend;
return (__wsum)(res + (res < (u32)addend));
}
__wsum csum_block_add(__wsum csum, __wsum csum2, int offset)
{
u32 sum = (u32)csum2;
if (offset&1)
sum = ((sum&0xFF00FF)<<8)+((sum>>8)&0xFF00FF);
return csum_add(csum, (__wsum)sum);
}
__wsum csum_block_add_ext(__wsum csum, __wsum csum2, int offset, int len)
{
return csum_block_add(csum, csum2, offset);
}
/***************************
** Linux socket function **
***************************/
static const struct net_proto_family *net_families[NPROTO];
int sock_register(const struct net_proto_family *ops)
{
if (ops->family >= NPROTO) {
printk("protocol %d >= NPROTO (%d)\n", ops->family, NPROTO);
return -ENOBUFS;
}
net_families[ops->family] = ops;
pr_info("NET: Registered protocol family %d\n", ops->family);
return 0;
}
struct socket *sock_alloc(void)
{
struct socket *sock = (struct socket *)kzalloc(sizeof(struct socket), 0);
/*
* Linux normally allocates the socket_wq when calling
* sock_alloc_inode() while we do it here hoping for the best.
*/
sock->wq = (struct socket_wq*)kzalloc(sizeof(*sock->wq), 0);
if (!sock->wq) {
kfree(sock);
return NULL;
}
return sock;
}
int sock_create_lite(int family, int type, int protocol, struct socket **res)
{
struct socket *sock = sock_alloc();
if (!sock)
return -ENOMEM;
sock->type = type;
*res = sock;
return 0;
}
int sock_create_kern(struct net *net, int family, int type, int proto,
struct socket **res)
{
struct socket *sock;
const struct net_proto_family *pf;
int err;
if (family < 0 || family > NPROTO)
return -EAFNOSUPPORT;
if (type < 0 || type > SOCK_MAX)
return -EINVAL;
pf = net_families[family];
if (!pf) {
printk("No protocol found for family %d\n", family);
return -ENOPROTOOPT;
}
sock = sock_alloc();
if (!sock) {
printk("Could not allocate socket\n");
return -ENFILE;
}
sock->type = type;
err = pf->create(&init_net, sock, proto, 1);
if (err) {
kfree(sock);
return err;
}
*res = sock;
return 0;
}
static void sock_init(void)
{
skb_init();
}
core_initcall(sock_init);
/*************************
** Lxip initialization **
*************************/
/*
* Header declarations and tuning
*/
struct net init_net;
unsigned long *sysctl_local_reserved_ports;
struct pernet_operations loopback_net_ops;
/**
* nr_free_buffer_pages - count number of pages beyond high watermark
*
* nr_free_buffer_pages() counts the number of pages which are beyond the
* high
* watermark within ZONE_DMA and ZONE_NORMAL.
*/
unsigned long nr_free_buffer_pages(void)
{
return 1000;
}
/*
* Declare stuff used
*/
int __ip_auto_config_setup(char *addrs);
void core_sock_init(void);
void core_netlink_proto_init(void);
void subsys_net_dev_init(void);
void fs_inet_init(void);
void module_driver_init(void);
void module_cubictcp_register(void);
void late_ip_auto_config(void);
void late_tcp_congestion_default(void);
/**
* Initialize sub-systems
*/
int lxip_init(char const *address_config)
{
/* init data */
INIT_LIST_HEAD(&init_net.dev_base_head);
/* call __setup stuff */
__ip_auto_config_setup((char *)address_config);
core_sock_init();
core_netlink_proto_init();
/* sub-systems */
subsys_net_dev_init();
fs_inet_init();
/* enable local accepts */
IPV4_DEVCONF_ALL(&init_net, ACCEPT_LOCAL) = 0x1;
/* congestion control */
module_cubictcp_register();
/* driver */
module_driver_init();
/* late */
late_tcp_congestion_default();
/* dhcp or static configuration */
late_ip_auto_config();
return 0;
}
/******************
** Lxip private **
******************/
void set_sock_wait(struct socket *sock, unsigned long ptr)
{
sock->sk->sk_wq = (struct socket_wq *)ptr;
}
int socket_check_state(struct socket *socket)
{
if (socket->sk->sk_state == TCP_CLOSE_WAIT)
return -EINTR;
return 0;
}
void log_sock(struct socket *socket)
{
printk("\nNEW socket %p sk %p fsk %x &sk %p &fsk %p\n\n",
socket, socket->sk, socket->flags, &socket->sk, &socket->flags);
}