📄 sdla_fr.c
字号:
* Return: 1 physical address resolved. * 0 physical address not resolved */static int if_rebuild_hdr(struct sk_buff *skb){ struct 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;}/*============================================================================ * 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 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){ fr_channel_t *chan = dev->priv; sdla_t *card = chan->card; int retry = 0, err; unsigned char *sendpacket; struct device *dev2; unsigned long check_braddr, check_mcaddr; fr508_flags_t *adptr_flags = card->flags; int udp_type, send_data; fr_dlci_interface_t *dlci_interface = chan->dlci_int_interface; unsigned long host_cpu_flags; ++chan->if_send_entry; if (dev->tbusy) { /* 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_busy; ++chan->ifstats.collisions; if ((jiffies - chan->tick_counter) < (5 * HZ)) return 1; printk(KERN_INFO "%s: Transmit timed out\n", chan->name); ++chan->if_send_busy_timeout; /* unbusy all the interfaces on the card */ for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) dev2->tbusy = 0; } sendpacket = skb->data; udp_type = udp_pkt_type(skb, card); if (udp_type == UDP_DRVSTATS_TYPE) { ++chan->if_send_DRVSTATS_request; process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, 0, chan); dev_kfree_skb(skb); return 0; } else if (udp_type == UDP_FPIPE_TYPE) ++chan->if_send_FPIPE_request; /* retreive source address in two forms: broadcast & multicast */ check_braddr = sendpacket[17]; check_mcaddr = sendpacket[14]; check_braddr = check_braddr << 8; check_mcaddr = check_mcaddr << 8; check_braddr |= sendpacket[16]; check_mcaddr |= sendpacket[15]; check_braddr = check_braddr << 8; check_mcaddr = check_mcaddr << 8; check_braddr |= sendpacket[15]; check_mcaddr |= sendpacket[16]; check_braddr = check_braddr << 8; check_mcaddr = check_mcaddr << 8; check_braddr |= sendpacket[14]; check_mcaddr |= sendpacket[17]; /* if the Source Address is a Multicast address */ if ((chan->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) && (check_mcaddr <= 0xFFFFFFFE)) { printk(KERN_INFO "%s: Multicast Src. Addr. silently discarded\n" ,card->devname); dev_kfree_skb(skb); ++chan->ifstats.tx_dropped; ++chan->if_send_multicast; return 0; } disable_irq(card->hw.irq); ++card->irq_dis_if_send_count; if (test_and_set_bit(0, (void *) &card->wandev.critical)) { if (card->wandev.critical == CRITICAL_IN_ISR) { ++chan->if_send_critical_ISR; if (card->intr_mode == DLCI_LIST_INTR_MODE) { /* The enable_tx_int flag is set here so that if * the critical flag is set due to an interrupt * then we want to enable transmit interrupts * again. */ card->wandev.enable_tx_int = 1; /* Setting this flag to WAITING_TO_BE_ENABLED * specifies that interrupt bit has to be * enabled for that particular interface. * (delayed interrupt) */ chan->tx_int_status = WAITING_TO_BE_ENABLED; /* This is used for enabling dynamic calculation * of CIRs relative to the packet length. */ chan->pkt_length = skb->len; dev->tbusy = 1; chan->tick_counter = jiffies; } else { card->wandev.enable_tx_int = 1; dev->tbusy = 1; chan->tick_counter = jiffies; } 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 1; } ++chan->if_send_critical_non_ISR; ++chan->ifstats.tx_dropped; 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 0; } card->wandev.critical = 0x21; if (udp_type == UDP_FPIPE_TYPE) { err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, 0, chan); } else if (card->wandev.state != WAN_CONNECTED) { ++chan->if_send_wan_disconnected; ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; } else if (chan->state != WAN_CONNECTED) { ++chan->if_send_dlci_disconnected; update_chan_state(dev); ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; } else if (!is_tx_ready(card, chan)) { if (card->intr_mode == DLCI_LIST_INTR_MODE) { dlci_interface->gen_interrupt |= 0x40; dlci_interface->packet_length = skb->len; } dev->tbusy = 1; chan->tick_counter = jiffies; adptr_flags->imask |= 0x02; ++chan->if_send_no_bfrs; retry = 1; } else { send_data = 1; /* If it's an IPX packet */ if (sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && sendpacket[6] == 0x81 && sendpacket[7] == 0x37) { if (card->wandev.enable_IPX) { switch_net_numbers(sendpacket, card->wandev.network_number, 0); } else { /* increment some statistic here! */ send_data = 0; } } if (send_data) { err = (card->hw.fwid == SFID_FR508) ? fr508_send(card, chan->dlci, 0, skb->len, skb->data) : fr502_send(card, chan->dlci, 0, skb->len, skb->data); if (err) { if (card->intr_mode == DLCI_LIST_INTR_MODE) { dlci_interface->gen_interrupt |= 0x40; dlci_interface->packet_length = skb->len; } dev->tbusy = 1; chan->tick_counter = jiffies; adptr_flags->imask |= 0x02; retry = 1; ++chan->if_send_adptr_bfrs_full; ++chan->ifstats.tx_errors; ++card->wandev.stats.tx_errors; } else { ++chan->if_send_bfrs_passed_to_adptr; ++chan->ifstats.tx_packets; ++card->wandev.stats.tx_packets; chan->ifstats.tx_bytes += skb->len; card->wandev.stats.tx_bytes += skb->len; } } } if (!retry) 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 retry;}/*============================================================================ * Reply to UDP Management system. * Return nothing. */static int reply_udp(unsigned char *data, unsigned int mbox_len){ unsigned short len, udp_length, temp, i, ip_length; unsigned long sum; /* Set length of packet */ len = mbox_len + 62; /* fill in UDP reply */ data[38] = 0x02; /* fill in UDP length */ udp_length = mbox_len + 40; /* put it on an even boundary */ if (udp_length & 0x0001) { udp_length += 1; len += 1; } temp = (udp_length << 8) | (udp_length >> 8); memcpy(&data[26], &temp, 2); /* swap UDP ports */ memcpy(&temp, &data[22], 2); memcpy(&data[22], &data[24], 2); memcpy(&data[24], &temp, 2); /* add UDP pseudo header */ temp = 0x1100; memcpy(&data[udp_length + 22], &temp, 2); temp = (udp_length << 8) | (udp_length >> 8); memcpy(&data[udp_length + 24], &temp, 2); /* calculate UDP checksum */ data[28] = data[29] = 0; sum = 0; for (i = 0; i < udp_length + 12; i += 2) { memcpy(&temp, &data[14 + i], 2); sum += (unsigned long) temp; } while (sum >> 16) sum = (sum & 0xffffUL) + (sum >> 16); temp = (unsigned short) sum; temp = ~temp; if (temp == 0) temp = 0xffff; memcpy(&data[28], &temp, 2); /* fill in IP length */ ip_length = udp_length + 20; temp = (ip_length << 8) | (ip_length >> 8); memcpy(&data[4], &temp, 2); /* swap IP addresses */ memcpy(&temp, &data[14], 2); memcpy(&data[14], &data[18], 2); memcpy(&data[18], &temp, 2); memcpy(&temp, &data[16], 2); memcpy(&data[16], &data[20], 2); memcpy(&data[20], &temp, 2); /* fill in IP checksum */ data[12] = data[13] = 0; sum = 0; for (i = 0; i < 20; i += 2) { memcpy(&temp, &data[2 + i], 2); sum += (unsigned long) temp; } while (sum >> 16) sum = (sum & 0xffffUL) + (sum >> 16); temp = (unsigned short) sum; temp = ~temp; if (temp == 0) temp = 0xffff; memcpy(&data[12], &temp, 2); return len;} /* reply_udp *//* If incoming is 0 (outgoing)- if the net numbers is ours make it 0 if incoming is 1 - if the net number is 0 make it ours */static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming){ unsigned long pnetwork_number; pnetwork_number = (unsigned long) ((sendpacket[14] << 24) + (sendpacket[15] << 16) + (sendpacket[16] << 8) + sendpacket[17]); if (!incoming) { /* If the destination network number is ours, make it 0 */ if (pnetwork_number == network_number) { sendpacket[14] = sendpacket[15] = sendpacket[16] = sendpacket[17] = 0x00; } } else { /* If the incoming network is 0, make it ours */ if (pnetwork_number == 0) { sendpacket[14] = (unsigned char) (network_number >> 24); sendpacket[15] = (unsigned char) ((network_number & 0x00FF0000) >> 16); sendpacket[16] = (unsigned char) ((network_number & 0x0000FF00) >> 8); sendpacket[17] = (unsigned char) (network_number & 0x000000FF); } } pnetwork_number = (unsigned long) ((sendpacket[26] << 24) + (sendpacket[27] << 16) + (sendpacket[28] << 8) + sendpacket[29]); if (!incoming) { /* If the source network is ours, make it 0 */ if (pnetwork_number == network_number) { sendpacket[26] = sendpacket[27] = sendpacket[28] = sendpacket[29] = 0x00; } } else { /* If the source network is 0, make it ours */ if (pnetwork_number == 0) { sendpacket[26] = (unsigned char) (network_number >> 24); sendpacket[27] = (unsigned char) ((network_number & 0x00FF0000) >> 16); sendpacket[28] = (unsigned char) ((network_number & 0x0000FF00) >> 8); sendpacket[29] = (unsigned char) (network_number & 0x000000FF); } }} /* switch_net_numbers *//*============================================================================ * Get Ethernet-style interface statistics. * Return a pointer to struct net_device_stats. */static struct net_device_stats *if_stats(struct device *dev){ fr_channel_t *chan = dev->priv; if(chan==NULL) return NULL; return &chan->ifstats;}/****** Interrupt Handlers **************************************************//*============================================================================ * S502 frame relay interrupt service routine. */static void fr502_isr(sdla_t * card){ fr502_flags_t *flags = card->flags; switch (flags->iflag) { case 0x01: /* receive interrupt */ fr502_rx_intr(card); break; case 0x02: /* transmit interrupt */ flags->imask &= ~0x02; tx_intr(card); break; default: spur_intr(card); } flags->iflag = 0;}/*============================================================================ * S508 frame relay interrupt service routine. */static void fr508_isr(sdla_t * card){ fr508_flags_t *flags = card->flags; fr_buf_ctl_t *bctl; char *ptr = &flags->iflag;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -