📄 sdla_x25.c
字号:
* 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){ x25_channel_t* chan = dev->priv; int hdr_len = dev->hard_header_len; skb->protocol = htons(type); if (!chan->protocol){ hdr_len = wanrouter_encapsulate(skb, dev, type); if (hdr_len < 0){ hdr_len = 0; skb->protocol = htons(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 net_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;}/*============================================================================ * Handle transmit timeout event from netif watchdog */static void if_tx_timeout(struct net_device *dev){ x25_channel_t* chan = dev->priv; sdla_t *card = chan->card; /* 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->if_send_stat.if_send_tbusy_timeout; printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname, dev->name); netif_wake_queue (dev);}/*========================================================================= * 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 net_device* dev){ x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; TX25Status* status = card->flags; int udp_type; unsigned long smp_flags=0; ++chan->if_send_stat.if_send_entry; netif_stop_queue(dev); /* No need to check frame length, since socket code * will perform the check for us */ chan->tick_counter = jiffies; /* Critical region starts here */ S508_S514_lock(card, &smp_flags); if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ printk(KERN_INFO "Hit critical in if_send()! %lx\n",card->wandev.critical); goto if_send_crit_exit; } 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, dev, skb, chan->common.lcn)) { status->imask |= INTR_ON_TIMER; if (udp_type == UDP_XPIPE_TYPE){ chan->if_send_stat.if_send_PIPE_request++; } } netif_start_queue(dev); clear_bit(SEND_CRIT,(void*)&card->wandev.critical); S508_S514_unlock(card, &smp_flags); return 0; } if (chan->transmit_length){ //FIXME: This check doesn't make sense any more if (chan->common.state != WAN_CONNECTED){ chan->transmit_length=0; atomic_set(&chan->common.driver_busy,0); }else{ netif_stop_queue(dev); ++card->u.x.tx_interrupts_pending; status->imask |= INTR_ON_TX_FRAME; clear_bit(SEND_CRIT,(void*)&card->wandev.critical); S508_S514_unlock(card, &smp_flags); return 1; } } if (card->wandev.state != WAN_CONNECTED){ ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; ++chan->if_send_stat.if_send_wan_disconnected; }else if ( chan->protocol && (chan->protocol != skb->protocol)){ printk(KERN_INFO "%s: unsupported Ethertype 0x%04X on interface %s!\n", chan->name, htons(skb->protocol), dev->name); printk(KERN_INFO "PROTO %Xn", htons(chan->protocol)); ++chan->ifstats.tx_errors; ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; ++chan->if_send_stat.if_send_protocol_error; }else switch (chan->common.state){ case WAN_DISCONNECTED: /* Try to establish connection. If succeded, then start * transmission, else drop a packet. */ if (chan->common.usedby == API){ ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; break; }else{ if (chan_connect(dev) != 0){ ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; break; } } /* fall through */ case WAN_CONNECTED: if( skb->protocol == htons(ETH_P_IPX)) { if(chan->enable_IPX) { switch_net_numbers( skb->data, chan->network_number, 0); } else { ++card->wandev.stats.tx_dropped; ++chan->ifstats.tx_dropped; ++chan->if_send_stat.if_send_protocol_error; goto if_send_crit_exit; } } /* We never drop here, if cannot send than, copy * a packet into a transmit buffer */ chan_send(dev, skb->data, skb->len, 0); break; default: ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; break; }if_send_crit_exit: dev_kfree_skb_any(skb); netif_start_queue(dev); clear_bit(SEND_CRIT,(void*)&card->wandev.critical); S508_S514_unlock(card, &smp_flags); return 0;}/*============================================================================ * Setup so that a frame can be transmitted on the occurrence of a transmit * interrupt. *===========================================================================*/static void setup_for_delayed_transmit(struct net_device* dev, void* buf, unsigned len){ x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; TX25Status* status = card->flags; ++chan->if_send_stat.if_send_adptr_bfrs_full; if(chan->transmit_length) { printk(KERN_INFO "%s: Error, transmit length set in delayed transmit!\n", card->devname); return; } if (chan->common.usedby == API){ if (len > X25_CHAN_MTU+sizeof(x25api_hdr_t)) { ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; printk(KERN_INFO "%s: Length is too big for delayed transmit\n", card->devname); return; } }else{ if (len > X25_MAX_DATA) { ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; printk(KERN_INFO "%s: Length is too big for delayed transmit\n", card->devname); return; } } chan->transmit_length = len; atomic_set(&chan->common.driver_busy,1); memcpy(chan->transmit_buffer, buf, len); ++chan->if_send_stat.if_send_tx_int_enabled; /* Enable Transmit Interrupt */ ++card->u.x.tx_interrupts_pending; status->imask |= INTR_ON_TX_FRAME;}/*=============================================================== * net_device_stats * * Get ethernet-style interface statistics. * Return a pointer to struct enet_statistics. * *==============================================================*/static struct net_device_stats *if_stats(struct net_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; card->in_isr = 1; ++card->statistics.isr_entry; if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ card->in_isr=0; status->iflags = 0; return; } if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){ printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02x\n", card->devname, card->wandev.critical, status->iflags); card->in_isr = 0; status->iflags = 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) */ switch (status->iflags){ case RX_INTR_PENDING: /* receive interrupt */ rx_intr(card); break; case TX_INTR_PENDING: /* transmit interrupt */ tx_intr(card); break; case MODEM_INTR_PENDING: /* modem status interrupt */ status_intr(card); break; case X25_ASY_TRANS_INTR_PENDING: /* network event interrupt */ event_intr(card); break; case TIMER_INTR_PENDING: timer_intr(card); break; default: /* unwanted interrupt */ spur_intr(card); } card->in_isr = 0; status->iflags = 0; /* clear interrupt condition */}/* * 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 * coming 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; struct net_device* dev = find_channel(card,lcn); x25_channel_t* chan; struct sk_buff* skb=NULL; if (dev == NULL){ /* 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; /* Copy the data from the board, into an * skb buffer */ if (wanpipe_pull_data_in_skb(card,dev,&skb)){ ++chan->ifstats.rx_dropped; ++card->wandev.stats.rx_dropped; ++chan->rx_intr_stat.rx_intr_no_socket; ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; return; } dev->last_rx = jiffies; /* timestamp */ /* ------------ API ----------------*/ if (chan->common.usedby == API){ if (bh_enqueue(dev, skb)){ ++chan->ifstats.rx_dropped; ++card->wandev.stats.rx_dropped; ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; dev_kfree_skb_any(skb); return; } ++chan->ifstats.rx_packets; chan->ifstats.rx_bytes += skb->len; chan->rx_skb = NULL; if (!test_and_set_bit(0, &chan->tq_working)){ wanpipe_queue_work(&chan->common.wanpipe_work); } return; } /* ------------- WANPIPE -------------------*/ /* set rx_skb to NULL so we won't access it later when kernel already owns it */ chan->rx_skb=NULL; /* Decapsulate packet, if necessary */ if (!skb->protocol && !wanrouter_type_trans(skb, dev)){ /* can't decapsulate packet */ dev_kfree_skb_any(skb); ++chan->ifstats.rx_errors; ++chan->ifstats.rx_dropped; ++card->wandev.stats.rx_dropped; ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; }else{ if( handle_IPXWAN(skb->data, chan->name, chan->enable_IPX, chan->network_number, skb->protocol)){ if( chan->enable_IPX ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -