📄 sdla_fr.c
字号:
"%s: ERROR on DLCI %i: Not configured properly !\n", card->devname, chan->dlci); printk(KERN_INFO "%s: Please contact Sangoma Technologies\n", card->devname); } return 1; } dlci_interface = chan->dlci_int_interface; if(chan->transmit_length) { printk(KERN_INFO "%s: Big mess in setup_for_del...\n", card->devname); return 1; } if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) { //FIXME: increment some statistic */ return 1; } skb_unlink(skb); chan->transmit_length = len; chan->delay_skb = skb; dlci_interface->gen_interrupt |= FR_INTR_TXRDY; dlci_interface->packet_length = len; /* Turn on TX interrupt at the end of if_send */ return 0;}/*============================================================================ * 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, netdevice_t* dev, struct sk_buff *skb){ u32 src_ip_addr; u32 broadcast_ip_addr = 0;#if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev;#endif 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 */#if defined(LINUX_2_1) || defined(LINUX_2_4) 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; }#else broadcast_ip_addr = dev->pa_brdaddr;#endif /* 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); 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); 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)*/0], 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 enet_statistics. */#if defined(LINUX_2_1) || defined(LINUX_2_4)static struct net_device_stats *if_stats(netdevice_t *dev)#elsestatic struct enet_statistics* if_stats (netdevice_t* dev)#endif{ fr_channel_t* chan = dev->priv; if(chan == NULL) return NULL; return &chan->ifstats;}/****** Interrupt Handlers **************************************************//*============================================================================ * fr_isr: S508 frame relay interrupt service routine. * * Description: * Frame relay main interrupt service route. This * function check the interrupt type and takes * the appropriate action. */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; /* All peripheral (configuraiton, re-configuration) events * take presidence over the ISR. Thus, retrigger */ if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { ++card->statistics.isr_already_critical; goto fr_isr_exit; } if(card->hw.type != SDLA_S514) { if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n", card->devname); ++card->statistics.isr_already_critical; goto fr_isr_exit; } } 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; }fr_isr_exit: card->in_isr = 0; flags->iflag = 0; return;}/*=========================================================== * rx_intr Receive interrupt handler. * * Description * Upon receiveing an interrupt: * 1. Check that the firmware is in sync with * the driver. * 2. Find an appropriate network interface * based on the received dlci number. * 3. Check that the netowrk interface exists * and that it's setup properly. * 4. Copy the data into an skb buffer. * 5. Check the packet type and take * appropriate acton: UPD, API, ARP or Data. */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; netdevice_t* dev; void* buf; unsigned dlci, len, offs, len_incl_hdr; int i, udp_type; /* Check that firmware buffers are in sync */ 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; /* Bug Fix: Mar 6 2000 * If we get a corrupted mailbox, it means that driver * is out of sync with the firmware. There is no recovery. * If we don't turn off all interrupts for this card * the machine will crash. */ printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); printk(KERN_INFO "Please contact Sangoma Technologies !\n"); fr_set_intr_mode(card, 0, 0, 0); return; } len = frbuf->length; dlci = frbuf->dlci; offs = frbuf->offset; /* Find the network interface for this packet */ dev = find_channel(card, dlci); /* Check that the network interface is active and * properly setup */ if (dev == NULL) { if( net_ratelimit()) { printk(KERN_INFO "%s: received data
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -