162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/init.h>
762306a36Sopenharmony_ci#include <linux/netdevice.h>
862306a36Sopenharmony_ci#include <net_kern.h>
962306a36Sopenharmony_ci#include "pcap_user.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistruct pcap_init {
1262306a36Sopenharmony_ci	char *host_if;
1362306a36Sopenharmony_ci	int promisc;
1462306a36Sopenharmony_ci	int optimize;
1562306a36Sopenharmony_ci	char *filter;
1662306a36Sopenharmony_ci};
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_civoid pcap_init_kern(struct net_device *dev, void *data)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	struct uml_net_private *pri;
2162306a36Sopenharmony_ci	struct pcap_data *ppri;
2262306a36Sopenharmony_ci	struct pcap_init *init = data;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	pri = netdev_priv(dev);
2562306a36Sopenharmony_ci	ppri = (struct pcap_data *) pri->user;
2662306a36Sopenharmony_ci	ppri->host_if = init->host_if;
2762306a36Sopenharmony_ci	ppri->promisc = init->promisc;
2862306a36Sopenharmony_ci	ppri->optimize = init->optimize;
2962306a36Sopenharmony_ci	ppri->filter = init->filter;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	printk("pcap backend, host interface %s\n", ppri->host_if);
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic int pcap_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	return pcap_user_read(fd, skb_mac_header(skb),
3762306a36Sopenharmony_ci			      skb->dev->mtu + ETH_HEADER_OTHER,
3862306a36Sopenharmony_ci			      (struct pcap_data *) &lp->user);
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic int pcap_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	return -EPERM;
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic const struct net_kern_info pcap_kern_info = {
4762306a36Sopenharmony_ci	.init			= pcap_init_kern,
4862306a36Sopenharmony_ci	.protocol		= eth_protocol,
4962306a36Sopenharmony_ci	.read			= pcap_read,
5062306a36Sopenharmony_ci	.write			= pcap_write,
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ciint pcap_setup(char *str, char **mac_out, void *data)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct pcap_init *init = data;
5662306a36Sopenharmony_ci	char *remain, *host_if = NULL, *options[2] = { NULL, NULL };
5762306a36Sopenharmony_ci	int i;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	*init = ((struct pcap_init)
6062306a36Sopenharmony_ci		{ .host_if 	= "eth0",
6162306a36Sopenharmony_ci		  .promisc 	= 1,
6262306a36Sopenharmony_ci		  .optimize 	= 0,
6362306a36Sopenharmony_ci		  .filter 	= NULL });
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	remain = split_if_spec(str, &host_if, &init->filter,
6662306a36Sopenharmony_ci			       &options[0], &options[1], mac_out, NULL);
6762306a36Sopenharmony_ci	if (remain != NULL) {
6862306a36Sopenharmony_ci		printk(KERN_ERR "pcap_setup - Extra garbage on "
6962306a36Sopenharmony_ci		       "specification : '%s'\n", remain);
7062306a36Sopenharmony_ci		return 0;
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (host_if != NULL)
7462306a36Sopenharmony_ci		init->host_if = host_if;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(options); i++) {
7762306a36Sopenharmony_ci		if (options[i] == NULL)
7862306a36Sopenharmony_ci			continue;
7962306a36Sopenharmony_ci		if (!strcmp(options[i], "promisc"))
8062306a36Sopenharmony_ci			init->promisc = 1;
8162306a36Sopenharmony_ci		else if (!strcmp(options[i], "nopromisc"))
8262306a36Sopenharmony_ci			init->promisc = 0;
8362306a36Sopenharmony_ci		else if (!strcmp(options[i], "optimize"))
8462306a36Sopenharmony_ci			init->optimize = 1;
8562306a36Sopenharmony_ci		else if (!strcmp(options[i], "nooptimize"))
8662306a36Sopenharmony_ci			init->optimize = 0;
8762306a36Sopenharmony_ci		else {
8862306a36Sopenharmony_ci			printk(KERN_ERR "pcap_setup : bad option - '%s'\n",
8962306a36Sopenharmony_ci			       options[i]);
9062306a36Sopenharmony_ci			return 0;
9162306a36Sopenharmony_ci		}
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	return 1;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic struct transport pcap_transport = {
9862306a36Sopenharmony_ci	.list 		= LIST_HEAD_INIT(pcap_transport.list),
9962306a36Sopenharmony_ci	.name 		= "pcap",
10062306a36Sopenharmony_ci	.setup  	= pcap_setup,
10162306a36Sopenharmony_ci	.user 		= &pcap_user_info,
10262306a36Sopenharmony_ci	.kern 		= &pcap_kern_info,
10362306a36Sopenharmony_ci	.private_size 	= sizeof(struct pcap_data),
10462306a36Sopenharmony_ci	.setup_size 	= sizeof(struct pcap_init),
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic int register_pcap(void)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	register_transport(&pcap_transport);
11062306a36Sopenharmony_ci	return 0;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cilate_initcall(register_pcap);
114