📄 sdla_x25.c
字号:
*/static int del_if (wan_device_t* wandev, struct device* dev){ if (dev->priv) { kfree(dev->priv); dev->priv = NULL; } return 0;}/****** WANPIPE-specific entry points ***************************************//*============================================================================ * Execute adapter interface command. */static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err, len; TX25Cmd 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-- && x25_error(card, err, cmd.command, cmd.lcn)); /* return result */ if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd))) 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 device* dev){ x25_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; /* Initialize media-specific parameters */ dev->type = 30; /* ARP h/w type */ dev->mtu = X25_CHAN_MTU; dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ dev->addr_len = 2; /* hardware address length */ if (!chan->svc) *(unsigned short*)dev->dev_addr = htons(chan->lcn); /* Initialize hardware parameters (just for reference) */ dev->irq = wandev->irq; dev->dma = wandev->dma; dev->base_addr = wandev->ioport; dev->mem_start = (unsigned long)wandev->maddr; dev->mem_end = dev->mem_end + wandev->msize - 1; /* Set transmit buffer queue length */ dev->tx_queue_len = 10; /* Initialize socket buffers */ dev_init_buffers(dev); set_chan_state(dev, WAN_DISCONNECTED); return 0;}/*============================================================================ * Open network interface. * o prevent module from unloading by incrementing use count * o if link is disconnected then initiate connection * * Return 0 if O.k. or errno. */static int if_open (struct device* dev){ x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; if (dev->start) return -EBUSY; /* only one open is allowed */ if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; wanpipe_open(card); /* If this is the first open, initiate physical connection */ if (card->open_cnt == 1) connect(card); card->wandev.critical = 0; return 0;}/*============================================================================ * Close network interface. * o reset flags. * o if there's no more open channels then disconnect physical link. */static int if_close (struct device* dev){ x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; dev->start = 0; if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING)) chan_disc(dev); wanpipe_close(card); /* If this is the last close, disconnect physical link */ if (!card->open_cnt) disconnect(card); card->wandev.critical = 0; 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 device* dev, unsigned short type, void* daddr, void* saddr, unsigned len){ x25_channel_t* chan = dev->priv; int hdr_len = dev->hard_header_len; skb->protocol = type; if (!chan->protocol) { hdr_len = wanrouter_encapsulate(skb, dev); if (hdr_len < 0) { hdr_len = 0; skb->protocol = 0; } } 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 device *dev=skb->dev; x25_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;}/*============================================================================ * Send a packet on a network interface. * o set tbusy flag (marks start of the transmission). * 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 device* dev){ x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; struct device *dev2; TX25Status* status = card->flags; unsigned long host_cpu_flags; if (dev->tbusy) { ++chan->ifstats.rx_dropped; if ((jiffies - chan->tick_counter) < (5*HZ)) { return dev->tbusy; } printk(KERN_INFO "%s: Transmit time out %s!\n", card->devname, dev->name) ; for( dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { dev2->tbusy = 0; } } chan->tick_counter = jiffies; disable_irq(card->hw.irq); ++card->irq_dis_if_send_count; if (test_and_set_bit(0, (void*)&card->wandev.critical)) { printk(KERN_INFO "Hit critical in if_send()!\n"); if (card->wandev.critical == CRITICAL_IN_ISR) { card->wandev.enable_tx_int = 1; dev->tbusy = 1; save_flags(host_cpu_flags); cli(); if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) enable_irq(card->hw.irq); restore_flags(host_cpu_flags); return dev->tbusy; } dev_kfree_skb(skb); save_flags(host_cpu_flags); cli(); if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) enable_irq(card->hw.irq); restore_flags(host_cpu_flags); return dev->tbusy; } /* Below is only until we have per-channel IPX going.... */ if(!(chan->svc)) chan->protocol = skb->protocol; if (card->wandev.state != WAN_CONNECTED) ++chan->ifstats.tx_dropped; /* Below is only until we have per-channel IPX going.... */ else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol))) { printk(KERN_INFO "%s: unsupported Ethertype 0x%04X on interface %s!\n", card->devname, skb->protocol, dev->name); ++chan->ifstats.tx_errors; } else switch (chan->state) { case WAN_DISCONNECTED: /* Try to establish connection. If succeded, then start * transmission, else drop a packet. */ if (chan_connect(dev) != 0) { ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; break; } /* fall through */ case WAN_CONNECTED: if( skb->protocol == ETH_P_IPX ) { if(card->wandev.enable_IPX) { switch_net_numbers( skb->data, card->wandev.network_number, 0); } else { ++card->wandev.stats.tx_dropped; ++chan->ifstats.tx_dropped; goto tx_done; } } dev->trans_start = jiffies; if(chan_send(dev, skb)) { dev->tbusy = 1; status->imask |= 0x2; } break; default: ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; }tx_done: if (!dev->tbusy) dev_kfree_skb(skb); card->wandev.critical = 0; save_flags(host_cpu_flags); cli(); if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) enable_irq(card->hw.irq); restore_flags(host_cpu_flags); return dev->tbusy;}/*============================================================================ * Get Ethernet-style interface statistics. * Return a pointer to struct net_device_stats */ static struct net_device_stats* if_stats (struct device* dev){ x25_channel_t* chan = dev->priv; if(chan==NULL) return NULL; return &chan->ifstats;}/****** Interrupt Handlers **************************************************//*============================================================================ * X.25 Interrupt Service Routine. */ static void wpx_isr (sdla_t* card){ TX25Status* status = card->flags; struct device *dev; unsigned long host_cpu_flags; card->in_isr = 1; card->buff_int_mode_unbusy = 0; if (test_and_set_bit(0, (void*)&card->wandev.critical)) { printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags); card->in_isr = 0; return; } /* For all interrupts set the critical flag to CRITICAL_RX_INTR. * If the if_send routine is called with this flag set it will set * the enable transmit flag to 1. (for a delayed interrupt) */ card->wandev.critical = CRITICAL_IN_ISR; switch (status->iflags) { case 0x01: /* receive interrupt */ rx_intr(card); break; case 0x02: /* transmit interrupt */ tx_intr(card); card->buff_int_mode_unbusy = 1; status->imask &= ~0x2; break; case 0x04: /* modem status interrupt */ status_intr(card); break; case 0x10: /* network event interrupt */ event_intr(card); break; default: /* unwanted interrupt */ spur_intr(card); } card->wandev.critical = CRITICAL_INTR_HANDLED; if( card->wandev.enable_tx_int) { card->wandev.enable_tx_int = 0; status->imask |= 0x2; } save_flags(host_cpu_flags); cli(); card->in_isr = 0; status->iflags = 0; /* clear interrupt condition */ card->wandev.critical = 0; restore_flags(host_cpu_flags); if(card->buff_int_mode_unbusy) { for(dev = card->wandev.dev; dev; dev = dev->slave) { if(((x25_channel_t*)dev->priv)->devtint) { mark_bh(NET_BH); return; } } }}/*============================================================================ * Receive interrupt handler. * This routine handles fragmented IP packets using M-bit according to the * RFC1356. * o map ligical channel number to network interface. * o allocate socket buffer or append received packet to the existing one. * o if M-bit is reset (i.e. it's the last packet in a sequence) then * decapsulate packet and pass socket buffer to the protocol stack. * * Notes: * 1. When allocating a socket buffer, if M-bit is set then more data is * comming and we have to allocate buffer for the maximum IP packet size * expected on this channel. * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no * socket buffers available) the whole packet sequence must be discarded. */static void rx_intr (sdla_t* card){ TX25Mbox* rxmb = card->rxmb; unsigned lcn = rxmb->cmd.lcn; /* logical channel number */ unsigned len = rxmb->cmd.length; /* packet length */ unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ wan_device_t* wandev = &card->wandev; struct device* dev = get_dev_by_lcn(wandev, lcn); x25_channel_t* chan; struct sk_buff* skb; void* bufptr; if (dev == NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -