162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * INET An implementation of the TCP/IP protocol suite for the LINUX 462306a36Sopenharmony_ci * operating system. INET is implemented using the BSD Socket 562306a36Sopenharmony_ci * interface as the means of communication with the user level. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * FDDI-type device handling. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Version: @(#)fddi.c 1.0.0 08/12/96 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Authors: Lawrence V. Stefani, <stefani@lkg.dec.com> 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * fddi.c is based on previous eth.c and tr.c work by 1462306a36Sopenharmony_ci * Ross Biro 1562306a36Sopenharmony_ci * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> 1662306a36Sopenharmony_ci * Mark Evans, <evansmp@uhura.aston.ac.uk> 1762306a36Sopenharmony_ci * Florian La Roche, <rzsfl@rz.uni-sb.de> 1862306a36Sopenharmony_ci * Alan Cox, <gw4pts@gw4pts.ampr.org> 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Changes 2162306a36Sopenharmony_ci * Alan Cox : New arp/rebuild header 2262306a36Sopenharmony_ci * Maciej W. Rozycki : IPv6 support 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <linux/module.h> 2662306a36Sopenharmony_ci#include <linux/types.h> 2762306a36Sopenharmony_ci#include <linux/kernel.h> 2862306a36Sopenharmony_ci#include <linux/string.h> 2962306a36Sopenharmony_ci#include <linux/mm.h> 3062306a36Sopenharmony_ci#include <linux/socket.h> 3162306a36Sopenharmony_ci#include <linux/in.h> 3262306a36Sopenharmony_ci#include <linux/inet.h> 3362306a36Sopenharmony_ci#include <linux/netdevice.h> 3462306a36Sopenharmony_ci#include <linux/fddidevice.h> 3562306a36Sopenharmony_ci#include <linux/if_ether.h> 3662306a36Sopenharmony_ci#include <linux/skbuff.h> 3762306a36Sopenharmony_ci#include <linux/errno.h> 3862306a36Sopenharmony_ci#include <net/arp.h> 3962306a36Sopenharmony_ci#include <net/sock.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * Create the FDDI MAC header for an arbitrary protocol layer 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * saddr=NULL means use device source address 4562306a36Sopenharmony_ci * daddr=NULL means leave destination address (eg unresolved arp) 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int fddi_header(struct sk_buff *skb, struct net_device *dev, 4962306a36Sopenharmony_ci unsigned short type, 5062306a36Sopenharmony_ci const void *daddr, const void *saddr, unsigned int len) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci int hl = FDDI_K_SNAP_HLEN; 5362306a36Sopenharmony_ci struct fddihdr *fddi; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if(type != ETH_P_IP && type != ETH_P_IPV6 && type != ETH_P_ARP) 5662306a36Sopenharmony_ci hl=FDDI_K_8022_HLEN-3; 5762306a36Sopenharmony_ci fddi = skb_push(skb, hl); 5862306a36Sopenharmony_ci fddi->fc = FDDI_FC_K_ASYNC_LLC_DEF; 5962306a36Sopenharmony_ci if(type == ETH_P_IP || type == ETH_P_IPV6 || type == ETH_P_ARP) 6062306a36Sopenharmony_ci { 6162306a36Sopenharmony_ci fddi->hdr.llc_snap.dsap = FDDI_EXTENDED_SAP; 6262306a36Sopenharmony_ci fddi->hdr.llc_snap.ssap = FDDI_EXTENDED_SAP; 6362306a36Sopenharmony_ci fddi->hdr.llc_snap.ctrl = FDDI_UI_CMD; 6462306a36Sopenharmony_ci fddi->hdr.llc_snap.oui[0] = 0x00; 6562306a36Sopenharmony_ci fddi->hdr.llc_snap.oui[1] = 0x00; 6662306a36Sopenharmony_ci fddi->hdr.llc_snap.oui[2] = 0x00; 6762306a36Sopenharmony_ci fddi->hdr.llc_snap.ethertype = htons(type); 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* Set the source and destination hardware addresses */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (saddr != NULL) 7362306a36Sopenharmony_ci memcpy(fddi->saddr, saddr, dev->addr_len); 7462306a36Sopenharmony_ci else 7562306a36Sopenharmony_ci memcpy(fddi->saddr, dev->dev_addr, dev->addr_len); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (daddr != NULL) 7862306a36Sopenharmony_ci { 7962306a36Sopenharmony_ci memcpy(fddi->daddr, daddr, dev->addr_len); 8062306a36Sopenharmony_ci return hl; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return -hl; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* 8762306a36Sopenharmony_ci * Determine the packet's protocol ID and fill in skb fields. 8862306a36Sopenharmony_ci * This routine is called before an incoming packet is passed 8962306a36Sopenharmony_ci * up. It's used to fill in specific skb fields and to set 9062306a36Sopenharmony_ci * the proper pointer to the start of packet data (skb->data). 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci__be16 fddi_type_trans(struct sk_buff *skb, struct net_device *dev) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct fddihdr *fddi = (struct fddihdr *)skb->data; 9662306a36Sopenharmony_ci __be16 type; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* 9962306a36Sopenharmony_ci * Set mac.raw field to point to FC byte, set data field to point 10062306a36Sopenharmony_ci * to start of packet data. Assume 802.2 SNAP frames for now. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci skb->dev = dev; 10462306a36Sopenharmony_ci skb_reset_mac_header(skb); /* point to frame control (FC) */ 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if(fddi->hdr.llc_8022_1.dsap==0xe0) 10762306a36Sopenharmony_ci { 10862306a36Sopenharmony_ci skb_pull(skb, FDDI_K_8022_HLEN-3); 10962306a36Sopenharmony_ci type = htons(ETH_P_802_2); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci else 11262306a36Sopenharmony_ci { 11362306a36Sopenharmony_ci skb_pull(skb, FDDI_K_SNAP_HLEN); /* adjust for 21 byte header */ 11462306a36Sopenharmony_ci type=fddi->hdr.llc_snap.ethertype; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* Set packet type based on destination address and flag settings */ 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (*fddi->daddr & 0x01) 12062306a36Sopenharmony_ci { 12162306a36Sopenharmony_ci if (memcmp(fddi->daddr, dev->broadcast, FDDI_K_ALEN) == 0) 12262306a36Sopenharmony_ci skb->pkt_type = PACKET_BROADCAST; 12362306a36Sopenharmony_ci else 12462306a36Sopenharmony_ci skb->pkt_type = PACKET_MULTICAST; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci else if (dev->flags & IFF_PROMISC) 12862306a36Sopenharmony_ci { 12962306a36Sopenharmony_ci if (memcmp(fddi->daddr, dev->dev_addr, FDDI_K_ALEN)) 13062306a36Sopenharmony_ci skb->pkt_type = PACKET_OTHERHOST; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* Assume 802.2 SNAP frames, for now */ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return type; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciEXPORT_SYMBOL(fddi_type_trans); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic const struct header_ops fddi_header_ops = { 14162306a36Sopenharmony_ci .create = fddi_header, 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic void fddi_setup(struct net_device *dev) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci dev->header_ops = &fddi_header_ops; 14862306a36Sopenharmony_ci dev->type = ARPHRD_FDDI; 14962306a36Sopenharmony_ci dev->hard_header_len = FDDI_K_SNAP_HLEN+3; /* Assume 802.2 SNAP hdr len + 3 pad bytes */ 15062306a36Sopenharmony_ci dev->mtu = FDDI_K_SNAP_DLEN; /* Assume max payload of 802.2 SNAP frame */ 15162306a36Sopenharmony_ci dev->min_mtu = FDDI_K_SNAP_HLEN; 15262306a36Sopenharmony_ci dev->max_mtu = FDDI_K_SNAP_DLEN; 15362306a36Sopenharmony_ci dev->addr_len = FDDI_K_ALEN; 15462306a36Sopenharmony_ci dev->tx_queue_len = 100; /* Long queues on FDDI */ 15562306a36Sopenharmony_ci dev->flags = IFF_BROADCAST | IFF_MULTICAST; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci memset(dev->broadcast, 0xFF, FDDI_K_ALEN); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/** 16162306a36Sopenharmony_ci * alloc_fddidev - Register FDDI device 16262306a36Sopenharmony_ci * @sizeof_priv: Size of additional driver-private structure to be allocated 16362306a36Sopenharmony_ci * for this FDDI device 16462306a36Sopenharmony_ci * 16562306a36Sopenharmony_ci * Fill in the fields of the device structure with FDDI-generic values. 16662306a36Sopenharmony_ci * 16762306a36Sopenharmony_ci * Constructs a new net device, complete with a private data area of 16862306a36Sopenharmony_ci * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for 16962306a36Sopenharmony_ci * this private data area. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_cistruct net_device *alloc_fddidev(int sizeof_priv) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci return alloc_netdev(sizeof_priv, "fddi%d", NET_NAME_UNKNOWN, 17462306a36Sopenharmony_ci fddi_setup); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ciEXPORT_SYMBOL(alloc_fddidev); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 179