/*********************************************************************1*2* Filename: irlan_eth.c3* Version:4* Description:5* Status: Experimental.6* Author: Dag Brattli <[email protected]>7* Created at: Thu Oct 15 08:37:58 19988* Modified at: Tue Mar 21 09:06:41 20009* Modified by: Dag Brattli <[email protected]>10* Sources: skeleton.c by Donald Becker <[email protected]>11* slip.c by Laurence Culhane, <[email protected]>12* Fred N. van Kempen, <[email protected]>13*14* Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved.15*16* This program is free software; you can redistribute it and/or17* modify it under the terms of the GNU General Public License as18* published by the Free Software Foundation; either version 2 of19* the License, or (at your option) any later version.20*21* Neither Dag Brattli nor University of Tromsø admit liability nor22* provide warranty for any of this software. This material is23* provided "AS-IS" and at no charge.24*25********************************************************************/2627#include <linux/netdevice.h>28#include <linux/etherdevice.h>29#include <linux/inetdevice.h>30#include <linux/if_arp.h>31#include <linux/module.h>32#include <linux/sched.h>33#include <net/arp.h>3435#include <net/irda/irda.h>36#include <net/irda/irmod.h>37#include <net/irda/irlan_common.h>38#include <net/irda/irlan_client.h>39#include <net/irda/irlan_event.h>40#include <net/irda/irlan_eth.h>4142static int irlan_eth_open(struct net_device *dev);43static int irlan_eth_close(struct net_device *dev);44static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb,45struct net_device *dev);46static void irlan_eth_set_multicast_list( struct net_device *dev);4748static const struct net_device_ops irlan_eth_netdev_ops = {49.ndo_open = irlan_eth_open,50.ndo_stop = irlan_eth_close,51.ndo_start_xmit = irlan_eth_xmit,52.ndo_set_multicast_list = irlan_eth_set_multicast_list,53.ndo_change_mtu = eth_change_mtu,54.ndo_validate_addr = eth_validate_addr,55};5657/*58* Function irlan_eth_setup (dev)59*60* The network device initialization function.61*62*/63static void irlan_eth_setup(struct net_device *dev)64{65ether_setup(dev);6667dev->netdev_ops = &irlan_eth_netdev_ops;68dev->destructor = free_netdev;697071/*72* Lets do all queueing in IrTTP instead of this device driver.73* Queueing here as well can introduce some strange latency74* problems, which we will avoid by setting the queue size to 0.75*/76/*77* The bugs in IrTTP and IrLAN that created this latency issue78* have now been fixed, and we can propagate flow control properly79* to the network layer. However, this requires a minimal queue of80* packets for the device.81* Without flow control, the Tx Queue is 14 (ttp) + 0 (dev) = 1482* With flow control, the Tx Queue is 7 (ttp) + 4 (dev) = 1183* See irlan_eth_flow_indication()...84* Note : this number was randomly selected and would need to85* be adjusted.86* Jean II */87dev->tx_queue_len = 4;88}8990/*91* Function alloc_irlandev92*93* Allocate network device and control block94*95*/96struct net_device *alloc_irlandev(const char *name)97{98return alloc_netdev(sizeof(struct irlan_cb), name,99irlan_eth_setup);100}101102/*103* Function irlan_eth_open (dev)104*105* Network device has been opened by user106*107*/108static int irlan_eth_open(struct net_device *dev)109{110struct irlan_cb *self = netdev_priv(dev);111112IRDA_DEBUG(2, "%s()\n", __func__ );113114/* Ready to play! */115netif_stop_queue(dev); /* Wait until data link is ready */116117/* We are now open, so time to do some work */118self->disconnect_reason = 0;119irlan_client_wakeup(self, self->saddr, self->daddr);120121/* Make sure we have a hardware address before we return,122so DHCP clients gets happy */123return wait_event_interruptible(self->open_wait,124!self->tsap_data->connected);125}126127/*128* Function irlan_eth_close (dev)129*130* Stop the ether network device, his function will usually be called by131* ifconfig down. We should now disconnect the link, We start the132* close timer, so that the instance will be removed if we are unable133* to discover the remote device after the disconnect.134*/135static int irlan_eth_close(struct net_device *dev)136{137struct irlan_cb *self = netdev_priv(dev);138139IRDA_DEBUG(2, "%s()\n", __func__ );140141/* Stop device */142netif_stop_queue(dev);143144irlan_close_data_channel(self);145irlan_close_tsaps(self);146147irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);148irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);149150/* Remove frames queued on the control channel */151skb_queue_purge(&self->client.txq);152153self->client.tx_busy = 0;154155return 0;156}157158/*159* Function irlan_eth_tx (skb)160*161* Transmits ethernet frames over IrDA link.162*163*/164static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb,165struct net_device *dev)166{167struct irlan_cb *self = netdev_priv(dev);168int ret;169unsigned int len;170171/* skb headroom large enough to contain all IrDA-headers? */172if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) {173struct sk_buff *new_skb =174skb_realloc_headroom(skb, self->max_header_size);175176/* We have to free the original skb anyway */177dev_kfree_skb(skb);178179/* Did the realloc succeed? */180if (new_skb == NULL)181return NETDEV_TX_OK;182183/* Use the new skb instead */184skb = new_skb;185}186187dev->trans_start = jiffies;188189len = skb->len;190/* Now queue the packet in the transport layer */191if (self->use_udata)192ret = irttp_udata_request(self->tsap_data, skb);193else194ret = irttp_data_request(self->tsap_data, skb);195196if (ret < 0) {197/*198* IrTTPs tx queue is full, so we just have to199* drop the frame! You might think that we should200* just return -1 and don't deallocate the frame,201* but that is dangerous since it's possible that202* we have replaced the original skb with a new203* one with larger headroom, and that would really204* confuse do_dev_queue_xmit() in dev.c! I have205* tried :-) DB206*/207/* irttp_data_request already free the packet */208dev->stats.tx_dropped++;209} else {210dev->stats.tx_packets++;211dev->stats.tx_bytes += len;212}213214return NETDEV_TX_OK;215}216217/*218* Function irlan_eth_receive (handle, skb)219*220* This function gets the data that is received on the data channel221*222*/223int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb)224{225struct irlan_cb *self = instance;226struct net_device *dev = self->dev;227228if (skb == NULL) {229dev->stats.rx_dropped++;230return 0;231}232if (skb->len < ETH_HLEN) {233IRDA_DEBUG(0, "%s() : IrLAN frame too short (%d)\n",234__func__, skb->len);235dev->stats.rx_dropped++;236dev_kfree_skb(skb);237return 0;238}239240/*241* Adopt this frame! Important to set all these fields since they242* might have been previously set by the low level IrDA network243* device driver244*/245skb->protocol = eth_type_trans(skb, dev); /* Remove eth header */246247dev->stats.rx_packets++;248dev->stats.rx_bytes += skb->len;249250netif_rx(skb); /* Eat it! */251252return 0;253}254255/*256* Function irlan_eth_flow (status)257*258* Do flow control between IP/Ethernet and IrLAN/IrTTP. This is done by259* controlling the queue stop/start.260*261* The IrDA link layer has the advantage to have flow control, and262* IrTTP now properly handles that. Flow controlling the higher layers263* prevent us to drop Tx packets in here (up to 15% for a TCP socket,264* more for UDP socket).265* Also, this allow us to reduce the overall transmit queue, which means266* less latency in case of mixed traffic.267* Jean II268*/269void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)270{271struct irlan_cb *self;272struct net_device *dev;273274self = (struct irlan_cb *) instance;275276IRDA_ASSERT(self != NULL, return;);277IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);278279dev = self->dev;280281IRDA_ASSERT(dev != NULL, return;);282283IRDA_DEBUG(0, "%s() : flow %s ; running %d\n", __func__,284flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START",285netif_running(dev));286287switch (flow) {288case FLOW_STOP:289/* IrTTP is full, stop higher layers */290netif_stop_queue(dev);291break;292case FLOW_START:293default:294/* Tell upper layers that its time to transmit frames again */295/* Schedule network layer */296netif_wake_queue(dev);297break;298}299}300301/*302* Function set_multicast_list (dev)303*304* Configure the filtering of the device305*306*/307#define HW_MAX_ADDRS 4 /* Must query to get it! */308static void irlan_eth_set_multicast_list(struct net_device *dev)309{310struct irlan_cb *self = netdev_priv(dev);311312IRDA_DEBUG(2, "%s()\n", __func__ );313314/* Check if data channel has been connected yet */315if (self->client.state != IRLAN_DATA) {316IRDA_DEBUG(1, "%s(), delaying!\n", __func__ );317return;318}319320if (dev->flags & IFF_PROMISC) {321/* Enable promiscuous mode */322IRDA_WARNING("Promiscuous mode not implemented by IrLAN!\n");323}324else if ((dev->flags & IFF_ALLMULTI) ||325netdev_mc_count(dev) > HW_MAX_ADDRS) {326/* Disable promiscuous mode, use normal mode. */327IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ );328/* hardware_set_filter(NULL); */329330irlan_set_multicast_filter(self, TRUE);331}332else if (!netdev_mc_empty(dev)) {333IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ );334/* Walk the address list, and load the filter */335/* hardware_set_filter(dev->mc_list); */336337irlan_set_multicast_filter(self, TRUE);338}339else {340IRDA_DEBUG(4, "%s(), Clearing multicast filter\n", __func__ );341irlan_set_multicast_filter(self, FALSE);342}343344if (dev->flags & IFF_BROADCAST)345irlan_set_broadcast_filter(self, TRUE);346else347irlan_set_broadcast_filter(self, FALSE);348}349350351