162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * NET3:	Fibre Channel device handling subroutines
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *		Vineet Abraham <vma@iol.unh.edu>
662306a36Sopenharmony_ci *		v 1.0 03/22/99
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/uaccess.h>
1062306a36Sopenharmony_ci#include <linux/types.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/string.h>
1362306a36Sopenharmony_ci#include <linux/mm.h>
1462306a36Sopenharmony_ci#include <linux/socket.h>
1562306a36Sopenharmony_ci#include <linux/in.h>
1662306a36Sopenharmony_ci#include <linux/inet.h>
1762306a36Sopenharmony_ci#include <linux/netdevice.h>
1862306a36Sopenharmony_ci#include <linux/fcdevice.h>
1962306a36Sopenharmony_ci#include <linux/skbuff.h>
2062306a36Sopenharmony_ci#include <linux/errno.h>
2162306a36Sopenharmony_ci#include <linux/timer.h>
2262306a36Sopenharmony_ci#include <linux/net.h>
2362306a36Sopenharmony_ci#include <linux/proc_fs.h>
2462306a36Sopenharmony_ci#include <linux/init.h>
2562306a36Sopenharmony_ci#include <linux/export.h>
2662306a36Sopenharmony_ci#include <net/arp.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/*
2962306a36Sopenharmony_ci *	Put the headers on a Fibre Channel packet.
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic int fc_header(struct sk_buff *skb, struct net_device *dev,
3362306a36Sopenharmony_ci		     unsigned short type,
3462306a36Sopenharmony_ci		     const void *daddr, const void *saddr, unsigned int len)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct fch_hdr *fch;
3762306a36Sopenharmony_ci	int hdr_len;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/*
4062306a36Sopenharmony_ci	 * Add the 802.2 SNAP header if IP as the IPv4 code calls
4162306a36Sopenharmony_ci	 * dev->hard_header directly.
4262306a36Sopenharmony_ci	 */
4362306a36Sopenharmony_ci	if (type == ETH_P_IP || type == ETH_P_ARP)
4462306a36Sopenharmony_ci	{
4562306a36Sopenharmony_ci		struct fcllc *fcllc;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci		hdr_len = sizeof(struct fch_hdr) + sizeof(struct fcllc);
4862306a36Sopenharmony_ci		fch = skb_push(skb, hdr_len);
4962306a36Sopenharmony_ci		fcllc = (struct fcllc *)(fch+1);
5062306a36Sopenharmony_ci		fcllc->dsap = fcllc->ssap = EXTENDED_SAP;
5162306a36Sopenharmony_ci		fcllc->llc = UI_CMD;
5262306a36Sopenharmony_ci		fcllc->protid[0] = fcllc->protid[1] = fcllc->protid[2] = 0x00;
5362306a36Sopenharmony_ci		fcllc->ethertype = htons(type);
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci	else
5662306a36Sopenharmony_ci	{
5762306a36Sopenharmony_ci		hdr_len = sizeof(struct fch_hdr);
5862306a36Sopenharmony_ci		fch = skb_push(skb, hdr_len);
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if(saddr)
6262306a36Sopenharmony_ci		memcpy(fch->saddr,saddr,dev->addr_len);
6362306a36Sopenharmony_ci	else
6462306a36Sopenharmony_ci		memcpy(fch->saddr,dev->dev_addr,dev->addr_len);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if(daddr)
6762306a36Sopenharmony_ci	{
6862306a36Sopenharmony_ci		memcpy(fch->daddr,daddr,dev->addr_len);
6962306a36Sopenharmony_ci		return hdr_len;
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci	return -hdr_len;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic const struct header_ops fc_header_ops = {
7562306a36Sopenharmony_ci	.create	 = fc_header,
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic void fc_setup(struct net_device *dev)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	dev->header_ops		= &fc_header_ops;
8162306a36Sopenharmony_ci	dev->type		= ARPHRD_IEEE802;
8262306a36Sopenharmony_ci	dev->hard_header_len	= FC_HLEN;
8362306a36Sopenharmony_ci	dev->mtu		= 2024;
8462306a36Sopenharmony_ci	dev->addr_len		= FC_ALEN;
8562306a36Sopenharmony_ci	dev->tx_queue_len	= 100; /* Long queues on fc */
8662306a36Sopenharmony_ci	dev->flags		= IFF_BROADCAST;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	memset(dev->broadcast, 0xFF, FC_ALEN);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/**
9262306a36Sopenharmony_ci * alloc_fcdev - Register fibre channel device
9362306a36Sopenharmony_ci * @sizeof_priv: Size of additional driver-private structure to be allocated
9462306a36Sopenharmony_ci *	for this fibre channel device
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * Fill in the fields of the device structure with fibre channel-generic values.
9762306a36Sopenharmony_ci *
9862306a36Sopenharmony_ci * Constructs a new net device, complete with a private data area of
9962306a36Sopenharmony_ci * size @sizeof_priv.  A 32-byte (not bit) alignment is enforced for
10062306a36Sopenharmony_ci * this private data area.
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_cistruct net_device *alloc_fcdev(int sizeof_priv)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	return alloc_netdev(sizeof_priv, "fc%d", NET_NAME_UNKNOWN, fc_setup);
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ciEXPORT_SYMBOL(alloc_fcdev);
107