18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/init.h>
78c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
88c2ecf20Sopenharmony_ci#include <net_kern.h>
98c2ecf20Sopenharmony_ci#include "pcap_user.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistruct pcap_init {
128c2ecf20Sopenharmony_ci	char *host_if;
138c2ecf20Sopenharmony_ci	int promisc;
148c2ecf20Sopenharmony_ci	int optimize;
158c2ecf20Sopenharmony_ci	char *filter;
168c2ecf20Sopenharmony_ci};
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_civoid pcap_init(struct net_device *dev, void *data)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	struct uml_net_private *pri;
218c2ecf20Sopenharmony_ci	struct pcap_data *ppri;
228c2ecf20Sopenharmony_ci	struct pcap_init *init = data;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	pri = netdev_priv(dev);
258c2ecf20Sopenharmony_ci	ppri = (struct pcap_data *) pri->user;
268c2ecf20Sopenharmony_ci	ppri->host_if = init->host_if;
278c2ecf20Sopenharmony_ci	ppri->promisc = init->promisc;
288c2ecf20Sopenharmony_ci	ppri->optimize = init->optimize;
298c2ecf20Sopenharmony_ci	ppri->filter = init->filter;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	printk("pcap backend, host interface %s\n", ppri->host_if);
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic int pcap_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	return pcap_user_read(fd, skb_mac_header(skb),
378c2ecf20Sopenharmony_ci			      skb->dev->mtu + ETH_HEADER_OTHER,
388c2ecf20Sopenharmony_ci			      (struct pcap_data *) &lp->user);
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic int pcap_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	return -EPERM;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic const struct net_kern_info pcap_kern_info = {
478c2ecf20Sopenharmony_ci	.init			= pcap_init,
488c2ecf20Sopenharmony_ci	.protocol		= eth_protocol,
498c2ecf20Sopenharmony_ci	.read			= pcap_read,
508c2ecf20Sopenharmony_ci	.write			= pcap_write,
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ciint pcap_setup(char *str, char **mac_out, void *data)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	struct pcap_init *init = data;
568c2ecf20Sopenharmony_ci	char *remain, *host_if = NULL, *options[2] = { NULL, NULL };
578c2ecf20Sopenharmony_ci	int i;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	*init = ((struct pcap_init)
608c2ecf20Sopenharmony_ci		{ .host_if 	= "eth0",
618c2ecf20Sopenharmony_ci		  .promisc 	= 1,
628c2ecf20Sopenharmony_ci		  .optimize 	= 0,
638c2ecf20Sopenharmony_ci		  .filter 	= NULL });
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	remain = split_if_spec(str, &host_if, &init->filter,
668c2ecf20Sopenharmony_ci			       &options[0], &options[1], mac_out, NULL);
678c2ecf20Sopenharmony_ci	if (remain != NULL) {
688c2ecf20Sopenharmony_ci		printk(KERN_ERR "pcap_setup - Extra garbage on "
698c2ecf20Sopenharmony_ci		       "specification : '%s'\n", remain);
708c2ecf20Sopenharmony_ci		return 0;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (host_if != NULL)
748c2ecf20Sopenharmony_ci		init->host_if = host_if;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(options); i++) {
778c2ecf20Sopenharmony_ci		if (options[i] == NULL)
788c2ecf20Sopenharmony_ci			continue;
798c2ecf20Sopenharmony_ci		if (!strcmp(options[i], "promisc"))
808c2ecf20Sopenharmony_ci			init->promisc = 1;
818c2ecf20Sopenharmony_ci		else if (!strcmp(options[i], "nopromisc"))
828c2ecf20Sopenharmony_ci			init->promisc = 0;
838c2ecf20Sopenharmony_ci		else if (!strcmp(options[i], "optimize"))
848c2ecf20Sopenharmony_ci			init->optimize = 1;
858c2ecf20Sopenharmony_ci		else if (!strcmp(options[i], "nooptimize"))
868c2ecf20Sopenharmony_ci			init->optimize = 0;
878c2ecf20Sopenharmony_ci		else {
888c2ecf20Sopenharmony_ci			printk(KERN_ERR "pcap_setup : bad option - '%s'\n",
898c2ecf20Sopenharmony_ci			       options[i]);
908c2ecf20Sopenharmony_ci			return 0;
918c2ecf20Sopenharmony_ci		}
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	return 1;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic struct transport pcap_transport = {
988c2ecf20Sopenharmony_ci	.list 		= LIST_HEAD_INIT(pcap_transport.list),
998c2ecf20Sopenharmony_ci	.name 		= "pcap",
1008c2ecf20Sopenharmony_ci	.setup  	= pcap_setup,
1018c2ecf20Sopenharmony_ci	.user 		= &pcap_user_info,
1028c2ecf20Sopenharmony_ci	.kern 		= &pcap_kern_info,
1038c2ecf20Sopenharmony_ci	.private_size 	= sizeof(struct pcap_data),
1048c2ecf20Sopenharmony_ci	.setup_size 	= sizeof(struct pcap_init),
1058c2ecf20Sopenharmony_ci};
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic int register_pcap(void)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	register_transport(&pcap_transport);
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cilate_initcall(register_pcap);
114