📄 sdla_fr.c
字号:
switch(err) { case FRRES_CIR_OVERFLOW: case FRRES_BUFFER_OVERFLOW: setup_for_delayed_transmit(dev, data, len); chan->drvstats_if_send. if_send_adptr_bfrs_full ++; break; default: chan->drvstats_if_send. if_send_dlci_disconnected ++; ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; break; } } else { chan->drvstats_if_send. if_send_bfr_passed_to_adptr++; ++chan->ifstats.tx_packets; ++card->wandev.stats.tx_packets; chan->ifstats.tx_bytes += len; card->wandev.stats.tx_bytes += len; } } } if (!netif_queue_stopped(dev)) dev_kfree_skb(skb); clear_bit(0, (void*)&card->wandev.critical); s508_s514_unlock(card,&smp_flags); return (netif_queue_stopped(dev));}/*============================================================================ * Setup so that a frame can be transmitted on the occurence of a transmit * interrupt. */static void setup_for_delayed_transmit (struct net_device* dev, void* buf, unsigned len){ fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; fr508_flags_t* adptr_flags = card->flags; fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; if(chan->transmit_length) { printk(KERN_INFO "%s: Big mess in setup_for_del...\n", card->devname); return; } if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) { //FIXME: increment some statistic */ return; } chan->transmit_length = len; memcpy(chan->transmit_buffer, buf, len); dlci_interface->gen_interrupt |= FR_INTR_TXRDY; dlci_interface->packet_length = len; adptr_flags->imask |= FR_INTR_TXRDY; card->u.f.tx_interrupts_pending ++;}/*============================================================================ * Check to see if the packet to be transmitted contains a broadcast or * multicast source IP address. * Return 0 if not broadcast/multicast address, otherwise return 1. */static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, struct sk_buff *skb){ u32 src_ip_addr; u32 broadcast_ip_addr = 0; struct in_device *in_dev; fr_channel_t* chan = dev->priv; /* read the IP source address from the outgoing packet */ src_ip_addr = *(u32 *)(skb->data + 14); /* read the IP broadcast address for the device */ in_dev = dev->ip_ptr; if(in_dev != NULL) { struct in_ifaddr *ifa= in_dev->ifa_list; if(ifa != NULL) broadcast_ip_addr = ifa->ifa_broadcast; else return 0; } /* check if the IP Source Address is a Broadcast address */ if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", card->devname); dev_kfree_skb(skb); ++ chan->ifstats.tx_dropped; return 1; } /* check if the IP Source Address is a Multicast address */ if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) && (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", card->devname); dev_kfree_skb(skb); ++ chan->ifstats.tx_dropped; return 1; } return 0;}/*============================================================================ * Reply to UDP Management system. * Return nothing. */static int reply_udp( unsigned char *data, unsigned int mbox_len ) { unsigned short len, udp_length, temp, ip_length; unsigned long ip_temp; int even_bound = 0; fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; /* Set length of packet */ len = sizeof(fr_encap_hdr_t)+ sizeof(ip_pkt_t)+ sizeof(udp_pkt_t)+ sizeof(wp_mgmt_t)+ sizeof(cblock_t)+ mbox_len; /* fill in UDP reply */ fr_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; /* fill in UDP length */ udp_length = sizeof(udp_pkt_t)+ sizeof(wp_mgmt_t)+ sizeof(cblock_t)+ mbox_len; /* put it on an even boundary */ if ( udp_length & 0x0001 ) { udp_length += 1; len += 1; even_bound = 1; } temp = (udp_length<<8)|(udp_length>>8); fr_udp_pkt->udp_pkt.udp_length = temp; /* swap UDP ports */ temp = fr_udp_pkt->udp_pkt.udp_src_port; fr_udp_pkt->udp_pkt.udp_src_port = fr_udp_pkt->udp_pkt.udp_dst_port; fr_udp_pkt->udp_pkt.udp_dst_port = temp; /* add UDP pseudo header */ temp = 0x1100; *((unsigned short *) (fr_udp_pkt->data+mbox_len+even_bound)) = temp; temp = (udp_length<<8)|(udp_length>>8); *((unsigned short *) (fr_udp_pkt->data+mbox_len+even_bound+2)) = temp; /* calculate UDP checksum */ fr_udp_pkt->udp_pkt.udp_checksum = 0; fr_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET+sizeof(fr_encap_hdr_t)], udp_length+UDP_OFFSET); /* fill in IP length */ ip_length = udp_length + sizeof(ip_pkt_t); temp = (ip_length<<8)|(ip_length>>8); fr_udp_pkt->ip_pkt.total_length = temp; /* swap IP addresses */ ip_temp = fr_udp_pkt->ip_pkt.ip_src_address; fr_udp_pkt->ip_pkt.ip_src_address = fr_udp_pkt->ip_pkt.ip_dst_address; fr_udp_pkt->ip_pkt.ip_dst_address = ip_temp; /* fill in IP checksum */ fr_udp_pkt->ip_pkt.hdr_checksum = 0; fr_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(&data[sizeof(fr_encap_hdr_t)], sizeof(ip_pkt_t)); return len;} /* reply_udp */unsigned short calc_checksum (char *data, int len){ unsigned short temp; unsigned long sum=0; int i; for( i = 0; i <len; i+=2 ) { memcpy(&temp,&data[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; return temp; }/* 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 net_device* dev){ fr_channel_t* chan = dev->priv; if(chan == NULL) return NULL; return &chan->ifstats;}/****** Interrupt Handlers **************************************************//*============================================================================ * S508 frame relay interrupt service routine. */static void fr_isr (sdla_t* card){ fr508_flags_t* flags = card->flags; char *ptr = &flags->iflag; int i,err; fr_mbox_t* mbox = card->mbox; /* This flag prevents nesting of interrupts. See sdla_isr() routine * in sdlamain.c. */ card->in_isr = 1; ++card->statistics.isr_entry; if(test_bit(1, (void*)&card->wandev.critical)) { card->wandev.critical = 0; flags->iflag = 0; card->in_isr = 0; return; } if(card->hw.type != SDLA_S514) { if (test_and_set_bit(0, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical while in ISR (0x%02X)\n", card->devname, card->wandev.critical); ++card->statistics.isr_already_critical; card->in_isr = 0; return; } } switch (flags->iflag) { case FR_INTR_RXRDY: /* receive interrupt */ ++card->statistics.isr_rx; rx_intr(card); break; case FR_INTR_TXRDY: /* transmit interrupt */ ++ card->statistics.isr_tx; tx_intr(card); break; case FR_INTR_READY: Intr_test_counter++; ++card->statistics.isr_intr_test; break; case FR_INTR_DLC: /* Event interrupt occured */ mbox->cmd.command = FR_READ_STATUS; mbox->cmd.length = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; if (err) fr_event(card, err, mbox); break; case FR_INTR_TIMER: /* Timer interrupt */ timer_intr(card); break; default: ++card->statistics.isr_spurious; spur_intr(card); printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", card->devname, flags->iflag); printk(KERN_INFO "%s: ID Bytes = ",card->devname); for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); printk(KERN_INFO "\n"); break; } card->in_isr = 0; flags->iflag = 0; if(card->hw.type != SDLA_S514) clear_bit(0, (void*)&card->wandev.critical);}/*============================================================================ * Receive interrupt handler. * When a receive interrupt occurs do the following: * 1- Find the structure for the dlci that the interrupt occured on * 2- If it doesn't exist then print appropriate msg and goto step 8. * 3- If it exist then copy data to a skb. * 4- If skb contains Sangoma UDP data then process them * 5- If skb contains IPXWAN data then send IPXWAN reply packets * 6- If skb contains Inverse Arp data then send Inv Arp replies * 7- If skb contains any other data then decapsulate the packet and * send it to the stack. * 8- Release the receive element and update receive pointers on the board */static void rx_intr (sdla_t* card){ fr_rx_buf_ctl_t* frbuf = card->rxmb; fr508_flags_t* flags = card->flags; fr_channel_t* chan; char *ptr = &flags->iflag; struct sk_buff* skb; struct net_device* dev; void* buf; unsigned dlci, len, offs, len_incl_hdr; int i, udp_type; if (frbuf->flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", card->devname, (unsigned)frbuf, frbuf->flag); printk(KERN_INFO "%s: ID Bytes = ",card->devname); for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); printk(KERN_INFO "\n"); ++card->statistics.rx_intr_corrupt_rx_bfr; return; } len = frbuf->length; dlci = frbuf->dlci;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -