18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * NET3: Fibre Channel device handling subroutines 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Vineet Abraham <vma@iol.unh.edu> 68c2ecf20Sopenharmony_ci * v 1.0 03/22/99 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 108c2ecf20Sopenharmony_ci#include <linux/types.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci#include <linux/mm.h> 148c2ecf20Sopenharmony_ci#include <linux/socket.h> 158c2ecf20Sopenharmony_ci#include <linux/in.h> 168c2ecf20Sopenharmony_ci#include <linux/inet.h> 178c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 188c2ecf20Sopenharmony_ci#include <linux/fcdevice.h> 198c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 208c2ecf20Sopenharmony_ci#include <linux/errno.h> 218c2ecf20Sopenharmony_ci#include <linux/timer.h> 228c2ecf20Sopenharmony_ci#include <linux/net.h> 238c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 248c2ecf20Sopenharmony_ci#include <linux/init.h> 258c2ecf20Sopenharmony_ci#include <linux/export.h> 268c2ecf20Sopenharmony_ci#include <net/arp.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Put the headers on a Fibre Channel packet. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int fc_header(struct sk_buff *skb, struct net_device *dev, 338c2ecf20Sopenharmony_ci unsigned short type, 348c2ecf20Sopenharmony_ci const void *daddr, const void *saddr, unsigned int len) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct fch_hdr *fch; 378c2ecf20Sopenharmony_ci int hdr_len; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* 408c2ecf20Sopenharmony_ci * Add the 802.2 SNAP header if IP as the IPv4 code calls 418c2ecf20Sopenharmony_ci * dev->hard_header directly. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci if (type == ETH_P_IP || type == ETH_P_ARP) 448c2ecf20Sopenharmony_ci { 458c2ecf20Sopenharmony_ci struct fcllc *fcllc; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci hdr_len = sizeof(struct fch_hdr) + sizeof(struct fcllc); 488c2ecf20Sopenharmony_ci fch = skb_push(skb, hdr_len); 498c2ecf20Sopenharmony_ci fcllc = (struct fcllc *)(fch+1); 508c2ecf20Sopenharmony_ci fcllc->dsap = fcllc->ssap = EXTENDED_SAP; 518c2ecf20Sopenharmony_ci fcllc->llc = UI_CMD; 528c2ecf20Sopenharmony_ci fcllc->protid[0] = fcllc->protid[1] = fcllc->protid[2] = 0x00; 538c2ecf20Sopenharmony_ci fcllc->ethertype = htons(type); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci else 568c2ecf20Sopenharmony_ci { 578c2ecf20Sopenharmony_ci hdr_len = sizeof(struct fch_hdr); 588c2ecf20Sopenharmony_ci fch = skb_push(skb, hdr_len); 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if(saddr) 628c2ecf20Sopenharmony_ci memcpy(fch->saddr,saddr,dev->addr_len); 638c2ecf20Sopenharmony_ci else 648c2ecf20Sopenharmony_ci memcpy(fch->saddr,dev->dev_addr,dev->addr_len); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if(daddr) 678c2ecf20Sopenharmony_ci { 688c2ecf20Sopenharmony_ci memcpy(fch->daddr,daddr,dev->addr_len); 698c2ecf20Sopenharmony_ci return hdr_len; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci return -hdr_len; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic const struct header_ops fc_header_ops = { 758c2ecf20Sopenharmony_ci .create = fc_header, 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic void fc_setup(struct net_device *dev) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci dev->header_ops = &fc_header_ops; 818c2ecf20Sopenharmony_ci dev->type = ARPHRD_IEEE802; 828c2ecf20Sopenharmony_ci dev->hard_header_len = FC_HLEN; 838c2ecf20Sopenharmony_ci dev->mtu = 2024; 848c2ecf20Sopenharmony_ci dev->addr_len = FC_ALEN; 858c2ecf20Sopenharmony_ci dev->tx_queue_len = 100; /* Long queues on fc */ 868c2ecf20Sopenharmony_ci dev->flags = IFF_BROADCAST; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci memset(dev->broadcast, 0xFF, FC_ALEN); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/** 928c2ecf20Sopenharmony_ci * alloc_fcdev - Register fibre channel device 938c2ecf20Sopenharmony_ci * @sizeof_priv: Size of additional driver-private structure to be allocated 948c2ecf20Sopenharmony_ci * for this fibre channel device 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * Fill in the fields of the device structure with fibre channel-generic values. 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci * Constructs a new net device, complete with a private data area of 998c2ecf20Sopenharmony_ci * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for 1008c2ecf20Sopenharmony_ci * this private data area. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_cistruct net_device *alloc_fcdev(int sizeof_priv) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci return alloc_netdev(sizeof_priv, "fc%d", NET_NAME_UNKNOWN, fc_setup); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(alloc_fcdev); 107