📄 sdla_chdlc.c
字号:
if(skb == NULL) { /* If we get here, some higher layer thinks we've missed an * tx-done interrupt. */ printk(KERN_INFO "%s: interface %s got kicked!\n", card->devname, dev->name); netif_wake_queue(dev); return 0; } if(ntohs(skb->protocol) != 0x16) { /* check the udp packet type */ udp_type = udp_pkt_type(skb, card); if(udp_type == UDP_CPIPE_TYPE) { if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, chdlc_priv_area)) chdlc_int->interrupt_permission |= APP_INT_ON_TIMER; return 0; } /* check to see if the source IP address is a broadcast or */ /* multicast IP address */ if(chk_bcast_mcast_addr(card, dev, skb)) return 0; } /* Lock the 508 Card: SMP is supported */ if(card->hw.type != SDLA_S514){ s508_lock(card,&smp_flags); } if(test_and_set_bit(0, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical in if_send: %x\n", card->wandev.name,card->wandev.critical); ++card->wandev.stats.tx_dropped;#ifdef LINUX_2_1 dev_kfree_skb(skb);#else dev_kfree_skb(skb, FREE_WRITE);#endif if(card->hw.type != SDLA_S514){ s508_unlock(card,&smp_flags); } return 0; } if(card->u.c.state != WAN_CONNECTED) ++card->wandev.stats.tx_dropped; else if(!skb->protocol) ++card->wandev.stats.tx_errors; else { void* data = skb->data; unsigned len = skb->len; unsigned char attr; /* If it's an API packet pull off the API * header. Also check that the packet size * is larger than the API header */ if (card->u.c.usedby == API){ api_tx_hdr_t* api_tx_hdr; if (len <= sizeof(api_tx_hdr_t)){#ifdef LINUX_2_1 dev_kfree_skb(skb);#else dev_kfree_skb(skb, FREE_WRITE);#endif ++card->wandev.stats.tx_dropped; clear_bit(0, (void*)&card->wandev.critical); if(card->hw.type != SDLA_S514){ s508_unlock(card,&smp_flags); } return 0; } api_tx_hdr = (api_tx_hdr_t *)data; attr = api_tx_hdr->attr; data += sizeof(api_tx_hdr_t); len -= sizeof(api_tx_hdr_t); } if(chdlc_send(card, data, len)) { netif_stop_queue(dev); chdlc_priv_area->tick_counter = jiffies; chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; } else { ++card->wandev.stats.tx_packets; card->wandev.stats.tx_bytes += len; } } if (!netif_queue_stopped(dev)) dev_kfree_skb(skb); clear_bit(0, (void*)&card->wandev.critical); if(card->hw.type != SDLA_S514){ s508_unlock(card,&smp_flags); } return netif_queue_stopped(dev);}/*============================================================================ * Check to see if the packet to be transmitted contains a broadcast or * multicast source IP address. */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;#ifdef LINUX_2_1 struct in_device *in_dev;#endif /* read the IP source address from the outgoing packet */ src_ip_addr = *(u32 *)(skb->data + 12); /* read the IP broadcast address for the device */#ifdef LINUX_2_1 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);#ifdef LINUX_2_1 dev_kfree_skb(skb);#else dev_kfree_skb(skb, FREE_WRITE);#endif ++card->wandev.stats.tx_dropped; return 1; } /* check if the IP Source Address is a Multicast address */ if((ntohl(src_ip_addr) >= 0xE0000001) && (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", card->devname);#ifdef LINUX_2_1 dev_kfree_skb(skb);#else dev_kfree_skb(skb, FREE_WRITE);#endif ++card->wandev.stats.tx_dropped; return 1; } return 0;}/*============================================================================ * Reply to UDP Management system. * Return length of reply. */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; chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; /* Set length of packet */ len = sizeof(ip_pkt_t)+ sizeof(udp_pkt_t)+ sizeof(wp_mgmt_t)+ sizeof(cblock_t)+ sizeof(trace_info_t)+ mbox_len; /* fill in UDP reply */ c_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)+ sizeof(trace_info_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); c_udp_pkt->udp_pkt.udp_length = temp; /* swap UDP ports */ temp = c_udp_pkt->udp_pkt.udp_src_port; c_udp_pkt->udp_pkt.udp_src_port = c_udp_pkt->udp_pkt.udp_dst_port; c_udp_pkt->udp_pkt.udp_dst_port = temp; /* add UDP pseudo header */ temp = 0x1100; *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; temp = (udp_length<<8)|(udp_length>>8); *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; /* calculate UDP checksum */ c_udp_pkt->udp_pkt.udp_checksum = 0; c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); /* fill in IP length */ ip_length = len; temp = (ip_length<<8)|(ip_length>>8); c_udp_pkt->ip_pkt.total_length = temp; /* swap IP addresses */ ip_temp = c_udp_pkt->ip_pkt.ip_src_address; c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; /* fill in IP checksum */ c_udp_pkt->ip_pkt.hdr_checksum = 0; c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,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; }/*============================================================================ * Get ethernet-style interface statistics. * Return a pointer to struct net_device_stats. */#ifdef LINUX_2_1static struct net_device_stats* if_stats (struct net_device* dev){ sdla_t *my_card; chdlc_private_area_t* chdlc_priv_area = dev->priv; my_card = chdlc_priv_area->card; return &my_card->wandev.stats; }#elsestatic struct net_device_stats* if_stats (struct net_device* dev){ sdla_t *my_card; chdlc_private_area_t* chdlc_priv_area = dev->priv; my_card = chdlc_priv_area->card; return &my_card->wandev.stats;}#endif/****** Cisco HDLC Firmware Interface Functions *******************************//*============================================================================ * Read firmware code version. * Put code version as ASCII string in str. */static int chdlc_read_version (sdla_t* card, char* str){ CHDLC_MAILBOX_STRUCT* mb = card->mbox; int len; char err; mb->buffer_length = 0; mb->command = READ_CHDLC_CODE_VERSION; err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; if(err != COMMAND_OK) { chdlc_error(card,err,mb); } else if (str) { /* is not null */ len = mb->buffer_length; memcpy(str, mb->data, len); str[len] = '\0'; } return (err);}/*----------------------------------------------------------------------------- * Configure CHDLC firmware. */static int chdlc_configure (sdla_t* card, void* data){ int err; CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); mailbox->buffer_length = data_length; memcpy(mailbox->data, data, data_length); mailbox->command = SET_CHDLC_CONFIGURATION; err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; if (err != COMMAND_OK) chdlc_error (card, err, mailbox); return err;}/*============================================================================ * Set interrupt mode -- HDLC Version. */static int chdlc_set_intr_mode (sdla_t* card, unsigned mode){ CHDLC_MAILBOX_STRUCT* mb = card->mbox; CHDLC_INT_TRIGGERS_STRUCT* int_data = (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; int err; int_data->CHDLC_interrupt_triggers = mode; int_data->IRQ = card->hw.irq; int_data->interrupt_timer = 1; mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; if (err != COMMAND_OK) chdlc_error (card, err, mb); return err;}/*============================================================================ * Enable communications. */static int chdlc_comm_enable (sdla_t* card){ int err; CHDLC_MAILBOX_STRUCT* mb = card->mbox; mb->buffer_length = 0; mb->command = ENABLE_CHDLC_COMMUNICATIONS; err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; if (err != COMMAND_OK) chdlc_error(card, err, mb); return err;}/*============================================================================ * Disable communications and Drop the Modem lines (DCD and RTS). */static int chdlc_comm_disable (sdla_t* card){ int err; CHDLC_MAILBOX_STRUCT* mb = card->mbox; mb->buffer_length = 0; mb->command = DISABLE_CHDLC_COMMUNICATIONS; err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; if (err != COMMAND_OK) chdlc_error(card,err,mb); mb->command = SET_MODEM_STATUS; mb->buffer_length = 1; mb->data[0] = 0; err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; if (err != COMMAND_OK) chdlc_error(card,err,mb); return err;}/*============================================================================ * Read communication error statistics. */static int chdlc_read_comm_err_stats (sdla_t* card){ int err; CHDLC_MAILBOX_STRUCT* mb = card->mbox; mb->buffer_length = 0; mb->command = READ_COMMS_ERROR_STATS; err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; if (err != COMMAND_OK) chdlc_error(card,err,mb); return err;}/*============================================================================ * Read CHDLC operational statistics. */static int chdlc_read_op_stats (sdla_t* card){ int err; CHDLC_MAILBOX_STRUCT* mb = card->mbox; mb->buffer_length = 0; mb->command = READ_CHDLC_OPERATIONAL_STATS; err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; if (err != COMMAND_OK) chdlc_error(card,err,mb); return err;}/*============================================================================ * Update communications error and general packet statistics. */static int update_comms_stats(sdla_t* card, chdlc_private_area_t* chdlc_priv_area){ CHDLC_MAILBOX_STRUCT* mb = card->mbox; COMMS_ERROR_STATS_STRUCT* err_stats; CHDLC_OPERATIONAL_STATS_STRUCT *op_stats;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -