mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 13:26:27 +00:00
parent
77d53f13ca
commit
4f084d1f9e
@ -16,6 +16,7 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/sched/task.h>
|
||||
#include <linux/usb.h>
|
||||
#include <lx_emul/nic.h>
|
||||
#include <lx_user/init.h>
|
||||
#include <genode_c_api/uplink.h>
|
||||
#include <genode_c_api/mac_address_reporter.h>
|
||||
@ -30,230 +31,17 @@ struct task_struct *lx_user_new_usb_task(int (*func)(void*), void *args,
|
||||
}
|
||||
|
||||
|
||||
static struct genode_uplink *dev_genode_uplink(struct net_device *dev)
|
||||
{
|
||||
return (struct genode_uplink *)dev->ifalias;
|
||||
}
|
||||
|
||||
|
||||
struct genode_uplink_rx_context
|
||||
{
|
||||
struct net_device *dev;
|
||||
};
|
||||
|
||||
|
||||
struct genode_uplink_tx_packet_context
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
};
|
||||
|
||||
|
||||
static unsigned long uplink_tx_packet_content(struct genode_uplink_tx_packet_context *ctx,
|
||||
char *dst, unsigned long dst_len)
|
||||
{
|
||||
struct sk_buff * const skb = ctx->skb;
|
||||
|
||||
skb_push(skb, ETH_HLEN);
|
||||
|
||||
if (dst_len < skb->len) {
|
||||
printk("uplink_tx_packet_content: packet exceeds uplink packet size\n");
|
||||
memset(dst, 0, dst_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
skb_copy_from_linear_data(skb, dst, skb->len);
|
||||
|
||||
/* clear unused part of the destination buffer */
|
||||
memset(dst + skb->len, 0, dst_len - skb->len);
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
|
||||
static rx_handler_result_t handle_rx(struct sk_buff **pskb)
|
||||
{
|
||||
struct sk_buff *skb = *pskb;
|
||||
struct net_device *dev = skb->dev;
|
||||
struct genode_uplink_tx_packet_context ctx = { .skb = skb };
|
||||
|
||||
/* if uplink still exists */
|
||||
if (dev->ifalias) {
|
||||
bool progress = genode_uplink_tx_packet(dev_genode_uplink(dev),
|
||||
uplink_tx_packet_content,
|
||||
&ctx);
|
||||
if (!progress)
|
||||
printk("handle_rx: uplink saturated, dropping packet\n");
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
return RX_HANDLER_CONSUMED;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create Genode uplink for given net device
|
||||
*
|
||||
* The uplink is registered at the dev->ifalias pointer.
|
||||
*/
|
||||
static void handle_create_uplink(struct net_device *dev)
|
||||
{
|
||||
struct genode_uplink_args args;
|
||||
|
||||
if (dev_genode_uplink(dev))
|
||||
return;
|
||||
|
||||
if (!netif_carrier_ok(dev))
|
||||
return;
|
||||
|
||||
printk("create uplink for net device %s\n", &dev->name[0]);
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
if (dev->addr_len != sizeof(args.mac_address)) {
|
||||
printk("error: net device has unexpected addr_len %u\n", dev->addr_len);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < dev->addr_len; i++)
|
||||
args.mac_address[i] = dev->dev_addr[i];
|
||||
}
|
||||
|
||||
args.label = &dev->name[0];
|
||||
|
||||
dev->ifalias = (struct dev_ifalias *)genode_uplink_create(&args);
|
||||
}
|
||||
|
||||
|
||||
static void handle_destroy_uplink(struct net_device *dev)
|
||||
{
|
||||
struct genode_uplink *uplink = dev_genode_uplink(dev);
|
||||
|
||||
if (!uplink)
|
||||
return;
|
||||
|
||||
if (netif_carrier_ok(dev))
|
||||
return;
|
||||
|
||||
printk("destroy uplink for net device %s\n", &dev->name[0]);
|
||||
genode_uplink_destroy(uplink);
|
||||
|
||||
dev->ifalias = NULL;
|
||||
}
|
||||
|
||||
|
||||
static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_context *ctx,
|
||||
char const *ptr, unsigned long len)
|
||||
{
|
||||
struct sk_buff *skb = alloc_skb(len, GFP_KERNEL);
|
||||
|
||||
if (!skb) {
|
||||
printk("alloc_skb failed\n");
|
||||
return GENODE_UPLINK_RX_RETRY;
|
||||
}
|
||||
|
||||
skb_copy_to_linear_data(skb, ptr, len);
|
||||
skb_put(skb, len);
|
||||
skb->dev = ctx->dev;
|
||||
|
||||
if (dev_queue_xmit(skb) < 0) {
|
||||
printk("lx_user: failed to xmit packet\n");
|
||||
return GENODE_UPLINK_RX_REJECTED;
|
||||
}
|
||||
|
||||
return GENODE_UPLINK_RX_ACCEPTED;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* custom MAC address
|
||||
*/
|
||||
bool use_mac_address;
|
||||
unsigned char mac_address[6];
|
||||
static bool mac_address_configured = false;
|
||||
|
||||
static void handle_mac_address(struct net_device *dev)
|
||||
{
|
||||
int err;
|
||||
struct sockaddr addr;
|
||||
struct genode_mac_address dev_addr;
|
||||
|
||||
if (mac_address_configured || !netif_device_present(dev)) return;
|
||||
|
||||
if (use_mac_address) {
|
||||
memcpy(&addr.sa_data, mac_address, ETH_ALEN);
|
||||
addr.sa_family = dev->type;
|
||||
err = dev_set_mac_address(dev, &addr, NULL);
|
||||
if (err < 0)
|
||||
printk("Warning: Could not set configured MAC address: %pM (err=%d)\n",
|
||||
mac_address, err);
|
||||
}
|
||||
|
||||
memcpy(dev_addr.addr, dev->dev_addr, sizeof(dev_addr));
|
||||
genode_mac_address_register(dev->name, dev_addr);
|
||||
|
||||
mac_address_configured =true;
|
||||
}
|
||||
|
||||
|
||||
static int network_loop(void *arg)
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
struct net_device *dev;
|
||||
|
||||
for_each_netdev(&init_net, dev) {
|
||||
|
||||
handle_mac_address(dev);
|
||||
|
||||
/* enable link sensing, repeated calls are handled by testing IFF_UP */
|
||||
dev_open(dev, 0);
|
||||
|
||||
/* install rx handler once */
|
||||
if (!netdev_is_rx_handler_busy(dev))
|
||||
netdev_rx_handler_register(dev, handle_rx, NULL);
|
||||
|
||||
/* respond to cable plug/unplug */
|
||||
handle_create_uplink(dev);
|
||||
handle_destroy_uplink(dev);
|
||||
|
||||
/* transmit packets received from the uplink session */
|
||||
if (netif_carrier_ok(dev)) {
|
||||
|
||||
struct genode_uplink_rx_context ctx = { .dev = dev };
|
||||
|
||||
while (genode_uplink_rx(dev_genode_uplink(dev),
|
||||
uplink_rx_one_packet,
|
||||
&ctx));
|
||||
}
|
||||
};
|
||||
|
||||
/* block until lx_emul_task_unblock */
|
||||
lx_emul_task_schedule(true);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct task_struct *net_task;
|
||||
|
||||
void lx_user_init(void)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
lx_emul_usb_client_init();
|
||||
|
||||
pid = kernel_thread(network_loop, NULL, "network_loop",
|
||||
CLONE_FS | CLONE_FILES);
|
||||
net_task = find_task_by_pid_ns(pid, NULL);
|
||||
lx_emul_nic_init();
|
||||
}
|
||||
|
||||
|
||||
void lx_user_handle_io(void)
|
||||
{
|
||||
lx_emul_usb_client_ticker();
|
||||
if (net_task) lx_emul_task_unblock(net_task);
|
||||
lx_emul_nic_handle_io();
|
||||
}
|
||||
|
||||
|
||||
@ -269,11 +57,10 @@ void rtmsg_ifinfo(int type, struct net_device * dev,
|
||||
unsigned int change, gfp_t flags,
|
||||
u32 portid, const struct nlmsghdr *nlh)
|
||||
{
|
||||
/* trigger handle_create_uplink / handle_destroy_uplink */
|
||||
if (net_task) lx_emul_task_unblock(net_task);
|
||||
lx_emul_nic_handle_io();
|
||||
|
||||
if (force_uplink_destroy) {
|
||||
struct genode_uplink *uplink = dev_genode_uplink(dev);
|
||||
struct genode_uplink *uplink = (struct genode_uplink *)dev->ifalias;
|
||||
printk("force destroy uplink for net device %s\n", &dev->name[0]);
|
||||
genode_uplink_destroy(uplink);
|
||||
force_uplink_destroy = false;
|
||||
@ -284,7 +71,9 @@ void rtmsg_ifinfo(int type, struct net_device * dev,
|
||||
void lx_emul_usb_client_device_unregister_callback(struct usb_device *)
|
||||
{
|
||||
force_uplink_destroy = true;
|
||||
mac_address_configured = false;
|
||||
|
||||
/* set mac as unconfigured by setting nothing */
|
||||
lx_emul_nic_set_mac_address(NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,15 +23,13 @@
|
||||
#include <lx_kit/env.h>
|
||||
#include <lx_user/io.h>
|
||||
#include <lx_emul/init.h>
|
||||
#include <lx_emul/nic.h>
|
||||
|
||||
/* C-interface */
|
||||
#include <usb_net.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
extern bool use_mac_address;
|
||||
extern unsigned char mac_address[6];
|
||||
|
||||
struct Main
|
||||
{
|
||||
Env &env;
|
||||
@ -90,12 +88,10 @@ struct Main
|
||||
usb_config = config_rom.xml().attribute_value("configuration", 0ul);
|
||||
|
||||
/* retrieve possible MAC */
|
||||
use_mac_address = config_rom.xml().has_attribute("mac");
|
||||
if (use_mac_address) {
|
||||
if (config_rom.xml().has_attribute("mac")) {
|
||||
auto const mac = config_rom.xml().attribute_value("mac", Nic::Mac_address{});
|
||||
mac.copy(mac_address);
|
||||
use_mac_address = true;
|
||||
log("Trying to use configured mac: ", mac);
|
||||
lx_emul_nic_set_mac_address(mac.addr, sizeof(mac.addr));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -8,6 +8,7 @@ SRC_C += dummies.c \
|
||||
lx_emul.c \
|
||||
lx_user.c
|
||||
|
||||
SRC_C += lx_emul/nic.c
|
||||
SRC_C += lx_emul/virt/shadow/drivers/usb/core/buffer.c
|
||||
SRC_C += lx_emul/virt/shadow/drivers/usb/core/hcd.c
|
||||
SRC_C += lx_emul/virt/usb_client.c
|
||||
|
31
repos/dde_linux/src/include/lx_emul/nic.h
Normal file
31
repos/dde_linux/src/include/lx_emul/nic.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* \brief Lx_emul support for NICs
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2024-10-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#ifndef _LX_EMUL__NIC_H_
|
||||
#define _LX_EMUL__NIC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void lx_emul_nic_init(void);
|
||||
extern void lx_emul_nic_handle_io(void);
|
||||
extern void lx_emul_nic_set_mac_address(const unsigned char *mac,
|
||||
unsigned long size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LX_EMUL__USB_H_ */
|
||||
|
258
repos/dde_linux/src/lib/lx_emul/nic.c
Normal file
258
repos/dde_linux/src/lib/lx_emul/nic.c
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* \brief PC Ethernet driver
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2024-10-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <lx_emul/nic.h>
|
||||
#include <genode_c_api/uplink.h>
|
||||
#include <genode_c_api/mac_address_reporter.h>
|
||||
|
||||
|
||||
static struct genode_uplink *dev_genode_uplink(struct net_device *dev)
|
||||
{
|
||||
return (struct genode_uplink *)dev->ifalias;
|
||||
}
|
||||
|
||||
|
||||
struct genode_uplink_rx_context
|
||||
{
|
||||
struct net_device *dev;
|
||||
};
|
||||
|
||||
|
||||
struct genode_uplink_tx_packet_context
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
};
|
||||
|
||||
|
||||
static unsigned long uplink_tx_packet_content(struct genode_uplink_tx_packet_context *ctx,
|
||||
char *dst, unsigned long dst_len)
|
||||
{
|
||||
struct sk_buff * const skb = ctx->skb;
|
||||
|
||||
skb_push(skb, ETH_HLEN);
|
||||
|
||||
if (dst_len < skb->len) {
|
||||
printk("uplink_tx_packet_content: packet exceeds uplink packet size\n");
|
||||
memset(dst, 0, dst_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
skb_copy_from_linear_data(skb, dst, skb->len);
|
||||
|
||||
/* clear unused part of the destination buffer */
|
||||
memset(dst + skb->len, 0, dst_len - skb->len);
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
|
||||
static rx_handler_result_t handle_rx(struct sk_buff **pskb)
|
||||
{
|
||||
struct sk_buff *skb = *pskb;
|
||||
struct net_device *dev = skb->dev;
|
||||
struct genode_uplink_tx_packet_context ctx = { .skb = skb };
|
||||
struct genode_uplink *uplink = dev_genode_uplink(dev);
|
||||
|
||||
if (!uplink)
|
||||
return RX_HANDLER_PASS;
|
||||
|
||||
{
|
||||
bool progress = genode_uplink_tx_packet(uplink,
|
||||
uplink_tx_packet_content,
|
||||
&ctx);
|
||||
if (!progress)
|
||||
printk("handle_rx: uplink saturated, dropping packet\n");
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
return RX_HANDLER_CONSUMED;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create Genode uplink for given net device
|
||||
*
|
||||
* The uplink is registered at the dev->ifalias pointer.
|
||||
*/
|
||||
static void handle_create_uplink(struct net_device *dev)
|
||||
{
|
||||
struct genode_uplink_args args;
|
||||
|
||||
if (dev_genode_uplink(dev))
|
||||
return;
|
||||
|
||||
if (!netif_carrier_ok(dev))
|
||||
return;
|
||||
|
||||
printk("create uplink for net device %s\n", &dev->name[0]);
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
if (dev->addr_len != sizeof(args.mac_address)) {
|
||||
printk("error: net device has unexpected addr_len %u\n", dev->addr_len);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < dev->addr_len; i++)
|
||||
args.mac_address[i] = dev->dev_addr[i];
|
||||
}
|
||||
|
||||
args.label = &dev->name[0];
|
||||
|
||||
dev->ifalias = (struct dev_ifalias *)genode_uplink_create(&args);
|
||||
}
|
||||
|
||||
|
||||
static void handle_destroy_uplink(struct net_device *dev)
|
||||
{
|
||||
struct genode_uplink *uplink = dev_genode_uplink(dev);
|
||||
|
||||
if (!uplink)
|
||||
return;
|
||||
|
||||
if (netif_carrier_ok(dev))
|
||||
return;
|
||||
|
||||
genode_uplink_destroy(uplink);
|
||||
|
||||
dev->ifalias = NULL;
|
||||
}
|
||||
|
||||
|
||||
static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_context *ctx,
|
||||
char const *ptr, unsigned long len)
|
||||
{
|
||||
struct sk_buff *skb = alloc_skb(len, GFP_KERNEL);
|
||||
|
||||
if (!skb) {
|
||||
printk("alloc_skb failed\n");
|
||||
return GENODE_UPLINK_RX_RETRY;
|
||||
}
|
||||
|
||||
skb_copy_to_linear_data(skb, ptr, len);
|
||||
skb_put(skb, len);
|
||||
skb->dev = ctx->dev;
|
||||
|
||||
if (dev_queue_xmit(skb) < 0) {
|
||||
printk("lx_user: failed to xmit packet\n");
|
||||
return GENODE_UPLINK_RX_REJECTED;
|
||||
}
|
||||
|
||||
return GENODE_UPLINK_RX_ACCEPTED;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* custom MAC address
|
||||
*/
|
||||
static unsigned char mac_address[6];
|
||||
static bool mac_address_configured = false;
|
||||
|
||||
static void handle_mac_address(struct net_device *dev)
|
||||
{
|
||||
int err;
|
||||
struct sockaddr addr;
|
||||
struct genode_mac_address dev_addr;
|
||||
|
||||
if (mac_address_configured || !netif_device_present(dev)) return;
|
||||
|
||||
if (mac_address[0] || mac_address[1] || mac_address[2] ||
|
||||
mac_address[3] || mac_address[4] || mac_address[5]) {
|
||||
memcpy(&addr.sa_data, mac_address, ETH_ALEN);
|
||||
addr.sa_family = dev->type;
|
||||
err = dev_set_mac_address(dev, &addr, NULL);
|
||||
if (err < 0)
|
||||
printk("Warning: Could not set configured MAC address: %pM (err=%d)\n",
|
||||
mac_address, err);
|
||||
}
|
||||
|
||||
memcpy(dev_addr.addr, dev->dev_addr, sizeof(dev_addr));
|
||||
genode_mac_address_register(dev->name, dev_addr);
|
||||
|
||||
mac_address_configured =true;
|
||||
}
|
||||
|
||||
|
||||
static int nic_task_function(void *arg)
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
struct net_device *dev;
|
||||
|
||||
for_each_netdev(&init_net, dev) {
|
||||
|
||||
handle_mac_address(dev);
|
||||
|
||||
/* enable link sensing, repeated calls are handled by testing IFF_UP */
|
||||
dev_open(dev, 0);
|
||||
|
||||
/* install rx handler once */
|
||||
if (!netdev_is_rx_handler_busy(dev))
|
||||
netdev_rx_handler_register(dev, handle_rx, NULL);
|
||||
|
||||
/* respond to cable plug/unplug */
|
||||
handle_create_uplink(dev);
|
||||
handle_destroy_uplink(dev);
|
||||
|
||||
/* transmit packets received from the uplink session */
|
||||
if (netif_carrier_ok(dev)) {
|
||||
|
||||
struct genode_uplink_rx_context ctx = { .dev = dev };
|
||||
|
||||
while (genode_uplink_rx(dev_genode_uplink(dev),
|
||||
uplink_rx_one_packet,
|
||||
&ctx));
|
||||
}
|
||||
};
|
||||
|
||||
/* block until lx_emul_task_unblock */
|
||||
lx_emul_task_schedule(true);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct task_struct *nic_task_struct_ptr;
|
||||
|
||||
|
||||
void lx_emul_nic_init(void)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,3,0)
|
||||
pid = kernel_thread(nic_task_function, NULL, "user_task", CLONE_FS | CLONE_FILES);
|
||||
#else
|
||||
pid = kernel_thread(nic_task_function, NULL, CLONE_FS | CLONE_FILES);
|
||||
#endif
|
||||
|
||||
nic_task_struct_ptr = find_task_by_pid_ns(pid, NULL);
|
||||
}
|
||||
|
||||
|
||||
void lx_emul_nic_handle_io(void)
|
||||
{
|
||||
if (nic_task_struct_ptr) lx_emul_task_unblock(nic_task_struct_ptr);
|
||||
}
|
||||
|
||||
|
||||
void lx_emul_nic_set_mac_address(const unsigned char *mac, unsigned long size)
|
||||
{
|
||||
memcpy(mac_address, mac, min(sizeof(mac_address), size));
|
||||
mac_address_configured = false;
|
||||
}
|
@ -11,214 +11,17 @@
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <lx_user/init.h>
|
||||
#include <genode_c_api/uplink.h>
|
||||
#include <genode_c_api/mac_address_reporter.h>
|
||||
|
||||
|
||||
static struct genode_uplink *dev_genode_uplink(struct net_device *dev)
|
||||
{
|
||||
return (struct genode_uplink *)dev->ifalias;
|
||||
}
|
||||
|
||||
|
||||
struct genode_uplink_rx_context
|
||||
{
|
||||
struct net_device *dev;
|
||||
};
|
||||
|
||||
|
||||
struct genode_uplink_tx_packet_context
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
};
|
||||
|
||||
|
||||
static unsigned long uplink_tx_packet_content(struct genode_uplink_tx_packet_context *ctx,
|
||||
char *dst, unsigned long dst_len)
|
||||
{
|
||||
struct sk_buff * const skb = ctx->skb;
|
||||
|
||||
skb_push(skb, ETH_HLEN);
|
||||
|
||||
if (dst_len < skb->len) {
|
||||
printk("uplink_tx_packet_content: packet exceeds uplink packet size\n");
|
||||
memset(dst, 0, dst_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
skb_copy_from_linear_data(skb, dst, skb->len);
|
||||
|
||||
/* clear unused part of the destination buffer */
|
||||
memset(dst + skb->len, 0, dst_len - skb->len);
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
|
||||
static rx_handler_result_t handle_rx(struct sk_buff **pskb)
|
||||
{
|
||||
struct sk_buff *skb = *pskb;
|
||||
struct net_device *dev = skb->dev;
|
||||
struct genode_uplink_tx_packet_context ctx = { .skb = skb };
|
||||
struct genode_uplink *uplink = dev_genode_uplink(dev);
|
||||
|
||||
if (!uplink)
|
||||
return RX_HANDLER_PASS;
|
||||
|
||||
{
|
||||
bool progress = genode_uplink_tx_packet(uplink,
|
||||
uplink_tx_packet_content,
|
||||
&ctx);
|
||||
if (!progress)
|
||||
printk("handle_rx: uplink saturated, dropping packet\n");
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
return RX_HANDLER_CONSUMED;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create Genode uplink for given net device
|
||||
*
|
||||
* The uplink is registered at the dev->ifalias pointer.
|
||||
*/
|
||||
static void handle_create_uplink(struct net_device *dev)
|
||||
{
|
||||
struct genode_uplink_args args;
|
||||
|
||||
if (dev_genode_uplink(dev))
|
||||
return;
|
||||
|
||||
if (!netif_carrier_ok(dev))
|
||||
return;
|
||||
|
||||
printk("create uplink for net device %s\n", &dev->name[0]);
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
if (dev->addr_len != sizeof(args.mac_address)) {
|
||||
printk("error: net device has unexpected addr_len %u\n", dev->addr_len);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < dev->addr_len; i++)
|
||||
args.mac_address[i] = dev->dev_addr[i];
|
||||
}
|
||||
|
||||
args.label = &dev->name[0];
|
||||
|
||||
dev->ifalias = (struct dev_ifalias *)genode_uplink_create(&args);
|
||||
}
|
||||
|
||||
|
||||
static void handle_destroy_uplink(struct net_device *dev)
|
||||
{
|
||||
struct genode_uplink *uplink = dev_genode_uplink(dev);
|
||||
|
||||
if (!uplink)
|
||||
return;
|
||||
|
||||
if (netif_carrier_ok(dev))
|
||||
return;
|
||||
|
||||
genode_uplink_destroy(uplink);
|
||||
|
||||
dev->ifalias = NULL;
|
||||
}
|
||||
|
||||
|
||||
static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_context *ctx,
|
||||
char const *ptr, unsigned long len)
|
||||
{
|
||||
struct sk_buff *skb = alloc_skb(len, GFP_KERNEL);
|
||||
|
||||
if (!skb) {
|
||||
printk("alloc_skb failed\n");
|
||||
return GENODE_UPLINK_RX_RETRY;
|
||||
}
|
||||
|
||||
skb_copy_to_linear_data(skb, ptr, len);
|
||||
skb_put(skb, len);
|
||||
skb->dev = ctx->dev;
|
||||
|
||||
if (dev_queue_xmit(skb) < 0) {
|
||||
printk("lx_user: failed to xmit packet\n");
|
||||
return GENODE_UPLINK_RX_REJECTED;
|
||||
}
|
||||
|
||||
return GENODE_UPLINK_RX_ACCEPTED;
|
||||
}
|
||||
|
||||
|
||||
static int user_task_function(void *arg)
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
struct net_device *dev;
|
||||
|
||||
for_each_netdev(&init_net, dev) {
|
||||
struct genode_mac_address dev_addr;
|
||||
|
||||
/* enable link sensing, repeated calls are handled by testing IFF_UP */
|
||||
dev_open(dev, 0);
|
||||
|
||||
memcpy(dev_addr.addr, dev->dev_addr, sizeof(dev_addr));
|
||||
genode_mac_address_register(dev->name, dev_addr);
|
||||
|
||||
/* install rx handler once */
|
||||
if (!netdev_is_rx_handler_busy(dev))
|
||||
netdev_rx_handler_register(dev, handle_rx, NULL);
|
||||
|
||||
/* respond to cable plug/unplug */
|
||||
handle_create_uplink(dev);
|
||||
handle_destroy_uplink(dev);
|
||||
|
||||
/* transmit packets received from the uplink session */
|
||||
if (netif_carrier_ok(dev)) {
|
||||
|
||||
struct genode_uplink_rx_context ctx = { .dev = dev };
|
||||
|
||||
while (genode_uplink_rx(dev_genode_uplink(dev),
|
||||
uplink_rx_one_packet,
|
||||
&ctx));
|
||||
}
|
||||
};
|
||||
|
||||
/* block until lx_emul_task_unblock */
|
||||
lx_emul_task_schedule(true);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct task_struct *user_task_struct_ptr; /* used by 'Main' for lx_emul_task_unblock */
|
||||
#include <lx_emul/nic.h>
|
||||
|
||||
|
||||
void lx_user_init(void)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
pid = kernel_thread(user_task_function, NULL, "user_task", CLONE_FS | CLONE_FILES);
|
||||
|
||||
user_task_struct_ptr = find_task_by_pid_ns(pid, NULL);
|
||||
lx_emul_nic_init();
|
||||
}
|
||||
|
||||
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
/*
|
||||
* Called whenever the link state changes
|
||||
*/
|
||||
void rtmsg_ifinfo(int type, struct net_device * dev, unsigned int change, gfp_t flags,
|
||||
u32 portid, const struct nlmsghdr *nlh)
|
||||
void lx_user_handle_io(void)
|
||||
{
|
||||
/* trigger handle_create_uplink / handle_destroy_uplink */
|
||||
if (user_task_struct_ptr)
|
||||
lx_emul_task_unblock(user_task_struct_ptr);
|
||||
lx_emul_nic_handle_io();
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <lx_kit/init.h>
|
||||
#include <lx_kit/env.h>
|
||||
#include <lx_emul/init.h>
|
||||
#include <lx_emul/task.h>
|
||||
#include <lx_user/io.h>
|
||||
#include <genode_c_api/uplink.h>
|
||||
#include <genode_c_api/mac_address_reporter.h>
|
||||
|
||||
@ -26,8 +26,6 @@ namespace Pc {
|
||||
}
|
||||
|
||||
|
||||
extern task_struct *user_task_struct_ptr;
|
||||
|
||||
struct Pc::Main
|
||||
{
|
||||
Env &_env;
|
||||
@ -52,11 +50,8 @@ struct Pc::Main
|
||||
|
||||
void _handle_signal()
|
||||
{
|
||||
if (user_task_struct_ptr)
|
||||
lx_emul_task_unblock(user_task_struct_ptr);
|
||||
|
||||
lx_user_handle_io();
|
||||
Lx_kit::env().scheduler.execute();
|
||||
|
||||
genode_uplink_notify_peers();
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <lx_emul.h>
|
||||
#include <lx_emul/nic.h>
|
||||
|
||||
#include <net/rtnetlink.h>
|
||||
#include <linux/mutex.h>
|
||||
@ -56,3 +57,13 @@ void rtnl_unlock(void)
|
||||
{
|
||||
netdev_run_todo();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called whenever the link state changes
|
||||
*/
|
||||
void rtmsg_ifinfo(int type, struct net_device * dev, unsigned int change, gfp_t flags,
|
||||
u32 portid, const struct nlmsghdr *nlh)
|
||||
{
|
||||
lx_emul_nic_handle_io();
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ SRC_CC += main.cc
|
||||
SRC_C += dummies.c
|
||||
SRC_C += lx_emul.c
|
||||
SRC_C += lx_emul/common_dummies.c
|
||||
SRC_C += lx_emul/nic.c
|
||||
SRC_C += lx_user.c
|
||||
SRC_C += rtnetlink.c
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user