📄 sdla_x25.c
字号:
/* Invalid channel, discard packet */ printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", card->devname, lcn); return; } chan = dev->priv; chan->i_timeout_sofar = jiffies; if (chan->drop_sequence) { if (!(qdm & 0x01)) chan->drop_sequence = 0; return; } skb = chan->rx_skb; if (skb == NULL) { /* Allocate new socket buffer */ int bufsize = (qdm & 0x01) ? dev->mtu : len; skb = dev_alloc_skb(bufsize + dev->hard_header_len); if (skb == NULL) { printk(KERN_INFO "%s: no socket buffers available!\n", card->devname); chan->drop_sequence = 1; /* set flag */ ++chan->ifstats.rx_dropped; return; } skb->dev = dev; skb->protocol = htons(chan->protocol); chan->rx_skb = skb; } if (skb_tailroom(skb) < len) { /* No room for the packet. Call off the whole thing! */ dev_kfree_skb(skb); chan->rx_skb = NULL; if (qdm & 0x01) chan->drop_sequence = 1; printk(KERN_INFO "%s: unexpectedly long packet sequence " "on interface %s!\n", card->devname, dev->name); ++chan->ifstats.rx_length_errors; return; } /* Append packet to the socket buffer */ bufptr = skb_put(skb, len); memcpy(bufptr, rxmb->data, len); if (qdm & 0x01) return; /* more data is comming */ dev->last_rx = jiffies; /* timestamp */ chan->rx_skb = NULL; /* dequeue packet */ /* Decapsulate packet, if necessary */ if (!skb->protocol && !wanrouter_type_trans(skb, dev)) { /* can't decapsulate packet */ dev_kfree_skb(skb); ++chan->ifstats.rx_errors; } else { if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) { if( card->wandev.enable_IPX ) { if(chan_send(dev, skb)) { chan->tx_skb = skb; } else { dev_kfree_skb(skb); } } else { /* FIXME: increment IPX packet dropped statistic */ } } else { netif_rx(skb); ++chan->ifstats.rx_packets; chan->ifstats.rx_bytes += skb->len; } }}/*============================================================================ * Transmit interrupt handler. * o Release socket buffer * o Clear 'tbusy' flag */static void tx_intr (sdla_t* card){ struct device *dev; /* unbusy all devices and then dev_tint(); */ for(dev = card->wandev.dev; dev; dev = dev->slave) { ((x25_channel_t*)dev->priv)->devtint = dev->tbusy; dev->tbusy = 0; }}/*============================================================================ * Modem status interrupt handler. */static void status_intr (sdla_t* card){}/*============================================================================ * Network event interrupt handler. */static void event_intr (sdla_t* card){}/*============================================================================ * Spurious interrupt handler. * o print a warning * o * If number of spurious interrupts exceeded some limit, then ??? */static void spur_intr (sdla_t* card){ printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);}/****** Background Polling Routines ****************************************//*============================================================================ * Main polling routine. * This routine is repeatedly called by the WANPIPE 'thread' to allow for * time-dependent housekeeping work. * * Notes: * 1. This routine may be called on interrupt context with all interrupts * enabled. Beware! */static void wpx_poll (sdla_t* card){ unsigned long host_cpu_flags; disable_irq(card->hw.irq); ++card->irq_dis_poll_count; if (test_and_set_bit(0, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: critical in polling!\n",card->devname); 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; } switch(card->wandev.state) { case WAN_CONNECTED: poll_active(card); break; case WAN_CONNECTING: poll_connecting(card); break; case WAN_DISCONNECTED: poll_disconnected(card); } 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);}/*============================================================================ * Handle physical link establishment phase. * o if connection timed out, disconnect the link. */static void poll_connecting (sdla_t* card){ TX25Status* status = card->flags; if (status->gflags & X25_HDLC_ABM) { wanpipe_set_state(card, WAN_CONNECTED); x25_set_intr_mode(card, 0x83); /* enable Rx interrupts */ status->imask &= ~0x2; /* mask Tx interupts */ } else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT) disconnect(card);}/*============================================================================ * Handle physical link disconnected phase. * o if hold-down timeout has expired and there are open interfaces, connect * link. */static void poll_disconnected (sdla_t* card){ if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) connect(card);}/*============================================================================ * Handle active link phase. * o fetch X.25 asynchronous events. * o kick off transmission on all interfaces. */static void poll_active (sdla_t* card){ struct device* dev; /* Fetch X.25 asynchronous events */ x25_fetch_events(card); for (dev = card->wandev.dev; dev; dev = dev->slave) { x25_channel_t* chan = dev->priv; struct sk_buff* skb = chan->tx_skb; /* If there is a packet queued for transmission then kick * the channel's send routine. When transmission is complete * or if error has occurred, release socket buffer and reset * 'tbusy' flag. */ if (skb && (chan_send(dev, skb) == 0)) { chan->tx_skb = NULL; dev->tbusy = 0; dev_kfree_skb(skb); } /* If SVC has been idle long enough, close virtual circuit */ if(( chan->svc )&&( chan->state == WAN_CONNECTED )) { if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ) { /* Close svc */ printk(KERN_INFO "%s: Closing down Idle link %s on LCN %d\n",card->devname,chan->name,chan->lcn); chan->i_timeout_sofar = jiffies; chan_disc(dev); } } }}/****** SDLA Firmware-Specific Functions ************************************* * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 * asynchronous events' such as restart, interrupt, incoming call request, * call clear request, etc. They can't be ignored and have to be dealt with * immediately. To tackle with this problem we execute each interface command * in a loop until good return code is received or maximum number of retries * is reached. Each interface command returns non-zero return code, an * asynchronous event/error handler x25_error() is called. *//*============================================================================ * Read X.25 firmware version. * Put code version as ASCII string in str. */static int x25_get_version (sdla_t* card, char* str){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_READ_CODE_VERSION; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_READ_CODE_VERSION, 0)); if (!err && str) { int len = mbox->cmd.length; memcpy(str, mbox->data, len); str[len] = '\0'; } return err;}/*============================================================================ * Configure adapter. */static int x25_configure (sdla_t* card, TX25Config* conf){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); mbox->cmd.length = sizeof(TX25Config); mbox->cmd.command = X25_SET_CONFIGURATION; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); return err;}/*============================================================================ * Get communications error statistics. */static int x25_get_err_stats (sdla_t* card){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_HDLC_READ_COMM_ERR; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)); if (!err) { THdlcCommErr* stats = (void*)mbox->data; card->wandev.stats.rx_over_errors = stats->rxOverrun; card->wandev.stats.rx_crc_errors = stats->rxBadCrc; card->wandev.stats.rx_missed_errors = stats->rxAborted; card->wandev.stats.tx_aborted_errors = stats->txAborted; } return err;}/*============================================================================ * Get protocol statistics. */static int x25_get_stats (sdla_t* card){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_READ_STATISTICS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)); if (!err) { TX25Stats* stats = (void*)mbox->data; card->wandev.stats.rx_packets = stats->rxData; card->wandev.stats.tx_packets = stats->rxData; } return err;}/*============================================================================ * Close HDLC link. */static int x25_close_hdlc (sdla_t* card){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_HDLC_LINK_CLOSE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)); return err;}/*============================================================================ * Open HDLC link. */static int x25_open_hdlc (sdla_t* card){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_HDLC_LINK_OPEN; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0)); return err;}/*============================================================================ * Setup HDLC link. */static int x25_setup_hdlc (sdla_t* card){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_HDLC_LINK_SETUP; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0)); return err;}/*============================================================================ * Set (raise/drop) DTR. */static int x25_set_dtr (sdla_t* card, int dtr){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->data[0] = 0; mbox->data[2] = 0; mbox->data[1] = dtr ? 0x02 : 0x01; mbox->cmd.length = 3; mbox->cmd.command = X25_SET_GLOBAL_VARS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0)); return err;}/*============================================================================ * Set interrupt mode. */static int x25_set_intr_mode (sdla_t* card, int mode){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->data[0] = mode; if (card->hw.fwid == SFID_X25_508) { mbox->data[1] = card->hw.irq; mbox->cmd.length = 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -