📄 sdla_fr.c
字号:
} if (dev->priv) { kfree(dev->priv); dev->priv = NULL; } return 0;}/****** WANPIPE-specific entry points ***************************************//*============================================================================ * Execute adapter interface command. */static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data){ fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err, len; fr_cmd_t cmd; if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) return -EFAULT; /* execute command */ do { memcpy(&mbox->cmd, &cmd, sizeof(cmd)); if (cmd.length){ if( copy_from_user((void*)&mbox->data, u_data, cmd.length)) return -EFAULT; } if (sdla_exec(mbox)) err = mbox->cmd.result; else return -EIO; } while (err && retry-- && fr_event(card, err, mbox)); /* return result */ if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) return -EFAULT; len = mbox->cmd.length; if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len)) return -EFAULT; return 0;}/****** Network Device Interface ********************************************//*============================================================================ * Initialize Linux network interface. * * This routine is called only once for each interface, during Linux network * interface registration. Returning anything but zero will fail interface * registration. */static int if_init (struct net_device* dev){ fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; wan_device_t* wandev = &card->wandev; /* Initialize device driver entry points */ dev->open = &if_open; dev->stop = &if_close; dev->hard_header = &if_header; dev->rebuild_header = &if_rebuild_hdr; dev->hard_start_xmit = &if_send; dev->get_stats = &if_stats; dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; /* Initialize media-specific parameters */ dev->type = ARPHRD_DLCI; /* ARP h/w type */ dev->flags |= IFF_POINTOPOINT; /* Enable Multicast addressing */ if (chan->mc == WANOPT_YES){ dev->flags |= IFF_MULTICAST; } dev->mtu = wandev->mtu - FR_HEADER_LEN; /* For an API, the maximum number of bytes that the stack will pass to the driver is (dev->mtu + dev->hard_header_len). So, adjust the mtu so that a frame of maximum size can be transmitted by the API. */ if(chan->usedby == API) { dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); } dev->hard_header_len = FR_HEADER_LEN;/* media header length */ dev->addr_len = 2; /* hardware address length */ *(unsigned short*)dev->dev_addr = htons(chan->dlci); /* Initialize hardware parameters (just for reference) */ dev->irq = wandev->irq; dev->dma = wandev->dma; dev->base_addr = wandev->ioport; dev->mem_start = wandev->maddr; dev->mem_end = wandev->maddr + wandev->msize - 1; /* Set transmit buffer queue length */ dev->tx_queue_len = 100; /* Initialize socket buffers */ dev_init_buffers(dev); set_chan_state(dev, WAN_DISCONNECTED); return 0;}/*============================================================================ * Open network interface. * o if this is the first open, then enable communications and interrupts. * o prevent module from unloading by incrementing use count * * Return 0 if O.k. or errno. */static int if_open (struct net_device* dev){ fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; int err = 0; struct timeval tv; if (netif_running(dev)) return -EBUSY; /* only one open is allowed */ if (test_and_set_bit(1, (void*)&card->wandev.critical)) return -EAGAIN; /* If signalling is set to NO, then setup * DLCI addresses right away. Don't have to wait for * link to connect. */ if (card->wandev.signalling == WANOPT_NO){ printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", card->wandev.name); if (fr_init_dlci(card,chan)){ return -EAGAIN; } } if (card->wandev.station == WANOPT_CPE) { /* CPE: issue full status enquiry */ fr_issue_isf(card, FR_ISF_FSE); } else { /* FR switch: activate DLCI(s) */ /* For Switch emulation we have to ADD and ACTIVATE * the DLCI(s) that were configured with the SET_DLCI_ * CONFIGURATION command. Add and Activate will fail if * DLCI specified is not included in the list. * * Also If_open is called once for each interface. But * it does not get in here for all the interface. So * we have to pass the entire list of DLCI(s) to add * activate routines. */ fr_add_dlci(card, chan->dlci); fr_activate_dlci(card, chan->dlci); } netif_start_queue(dev); wanpipe_open(card); update_chan_state(dev); do_gettimeofday( &tv ); chan->router_start_time = tv.tv_sec; clear_bit(1, (void*)&card->wandev.critical); return err;}/*============================================================================ * Close network interface. * o if this is the last open, then disable communications and interrupts. * o reset flags. */static int if_close (struct net_device* dev){ fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; if (test_and_set_bit(1, (void*)&card->wandev.critical)) return -EAGAIN; netif_stop_queue(dev); wanpipe_close(card); if (card->wandev.station == WANOPT_NODE) { fr_delete_dlci (card,chan->dlci); } clear_bit(1, (void*)&card->wandev.critical); return 0;}/*============================================================================ * Build media header. * o encapsulate packet according to encapsulation type. * * The trick here is to put packet type (Ethertype) into 'protocol' field of * the socket buffer, so that we don't forget it. If encapsulation fails, * set skb->protocol to 0 and discard packet later. * * Return: media header length. */static int if_header (struct sk_buff* skb, struct net_device* dev, unsigned short type, void* daddr, void* saddr, unsigned len){ int hdr_len = 0; skb->protocol = type; hdr_len = wanrouter_encapsulate(skb, dev); if (hdr_len < 0) { hdr_len = 0; skb->protocol = 0; } skb_push(skb, 1); skb->data[0] = Q922_UI; ++hdr_len; return hdr_len;}/*============================================================================ * Re-build media header. * * Return: 1 physical address resolved. * 0 physical address not resolved */static int if_rebuild_hdr (struct sk_buff* skb){ struct net_device *dev = skb->dev; fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", card->devname, dev->name); return 1;}/*============================================================================ * Handle transmit timeout event from netif watchdog */static void if_tx_timeout (struct net_device *dev){ fr_channel_t* chan = dev->priv; /* If our device stays busy for at least 5 seconds then we will * kick start the device by making dev->tbusy = 0. We expect * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. */ chan->drvstats_if_send.if_send_tbusy++; ++chan->ifstats.collisions; printk (KERN_INFO "%s: Transmit timed out\n", chan->name); chan->drvstats_if_send.if_send_tbusy_timeout++; netif_start_queue (dev);}/*============================================================================ * Send a packet on a network interface. * o set tbusy flag (marks start of the transmission) to block a timer-based * transmit from overlapping. * o set critical flag when accessing board. * o check link state. If link is not up, then drop the packet. * o check channel status. If it's down then initiate a call. * o pass a packet to corresponding WAN device. * o free socket buffer * * Return: 0 complete (socket buffer must be freed) * non-0 packet may be re-transmitted (tbusy must be set) * * Notes: * 1. This routine is called either by the protocol stack or by the "net * bottom half" (with interrupts enabled). * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */static int if_send (struct sk_buff* skb, struct net_device* dev){ fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; int err; unsigned char *sendpacket; fr508_flags_t* adptr_flags = card->flags; int udp_type, send_data; unsigned long smp_flags=0; void* data; unsigned len; chan->drvstats_if_send.if_send_entry++; if (skb == NULL) { /* if we get here, some higher layer thinks we've missed an * tx-done interrupt. */ printk(KERN_INFO "%s: interface %s got kicked!\n", card->devname, dev->name); chan->drvstats_if_send.if_send_skb_null ++; netif_wake_queue(dev); return 0; } /* We must set the 'tbusy' flag if we already have a packet queued for transmission in the transmit interrupt handler. However, we must ensure that the transmit interrupt does not reset the 'tbusy' flag just before we set it, as this will result in a "transmit timeout". */ set_bit(2, (void*)&card->wandev.critical); if(chan->transmit_length) { netif_stop_queue(dev); chan->tick_counter = jiffies; clear_bit(2, (void*)&card->wandev.critical); return 1; } clear_bit(2, (void*)&card->wandev.critical); data = skb->data; sendpacket = skb->data; len = skb->len; udp_type = udp_pkt_type(skb, card); if(udp_type != UDP_INVALID_TYPE) { if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, chan->dlci)) { adptr_flags->imask |= FR_INTR_TIMER; if (udp_type == UDP_FPIPE_TYPE){ chan->drvstats_if_send. if_send_PIPE_request ++; } } return 0; } if((chan->usedby == API) && (len <= sizeof(api_tx_hdr_t))) { //FIXME: increment some error statistic dev_kfree_skb(skb); return 0; } //FIXME: can we do better than sendpacket[2]? if ((chan->usedby == WANPIPE) && (sendpacket[2] == 0x45)) { /* check to see if the source IP address is a broadcast or */ /* multicast IP address */ if(chk_bcast_mcast_addr(card, dev, skb)) return 0; } /* Lock the 508 card: SMP Supported */ s508_s514_lock(card,&smp_flags); if (test_and_set_bit(0, (void*)&card->wandev.critical)) { chan->drvstats_if_send.if_send_critical_non_ISR ++; chan->ifstats.tx_dropped ++; printk(KERN_INFO "%s Critical in IF_SEND %02X\n", card->devname, card->wandev.critical); dev_kfree_skb(skb); /* Unlock the 508 card */ s508_s514_unlock(card,&smp_flags); return 0; } if (card->wandev.state != WAN_CONNECTED) { chan->drvstats_if_send.if_send_wan_disconnected ++; ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; } else if (chan->state != WAN_CONNECTED) { chan->drvstats_if_send.if_send_dlci_disconnected ++; /* Critical area on 514, since disabl_irq is not used * thus, interrupt would execute a command at * the same time as if_send. */ set_bit(1, (void*)&card->wandev.critical); update_chan_state(dev); clear_bit(1, (void*)&card->wandev.critical); ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; } else if (!is_tx_ready(card, chan)) { setup_for_delayed_transmit(dev, data, len); chan->drvstats_if_send.if_send_no_bfrs++; } else { send_data = 1; //FIXME: IPX is not implemented in this version of Frame Relay ? if((chan->usedby == WANPIPE) && sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && sendpacket[6] == 0x81 && sendpacket[7] == 0x37) { if( chan->enable_IPX ) { switch_net_numbers(sendpacket, chan->network_number, 0); } else { //FIXME: Take this out when IPX is fixed printk(KERN_INFO "%s: WARNING: Unsupported IPX data in send, packet dropped\n", card->devname); send_data = 0; } } if (send_data) { unsigned char attr = 0; /* For an API transmission, get rid of the API header */ if (chan->usedby == API) { api_tx_hdr_t* api_tx_hdr; api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; attr = api_tx_hdr->attr; data += sizeof(api_tx_hdr_t); len -= sizeof(api_tx_hdr_t); } err = fr_send(card, chan->dlci, attr, len, data); if (err) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -