📄 sdla_ppp.c
字号:
#if defined(LINUX_2_1) || defined(LINUX_2_4)static int if_rebuild_hdr (struct sk_buff *skb){ netdevice_t *dev = skb->dev; ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", card->devname, dev->name); return 1;}#elsestatic int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, struct sk_buff* skb){ return 1;}#endif#ifdef LINUX_2_4/*============================================================================ * Handle transmit timeout event from netif watchdog */static void if_tx_timeout (netdevice_t *dev){ ppp_private_area_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; ++card->wandev.stats.collisions; printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); ++chan->if_send_stat.if_send_tbusy_timeout; netif_wake_queue (dev);}#endif/*============================================================================ * 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 execute adapter send command. * 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, netdevice_t *dev){ ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; unsigned char *sendpacket; unsigned long smp_flags; ppp_flags_t *flags = card->flags; int udp_type; int err=0; ++ppp_priv_area->if_send_stat.if_send_entry;#ifdef LINUX_2_4 netif_stop_queue(dev);#endif 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); ++ppp_priv_area->if_send_stat.if_send_skb_null; wake_net_dev(dev); return 0; }#ifndef LINUX_2_4 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. */ ++ppp_priv_area->if_send_stat.if_send_tbusy; ++card->wandev.stats.collisions; if ((jiffies - ppp_priv_area->tick_counter) < (5*HZ)) { return 1; } printk (KERN_INFO "%s: Transmit times out on %s\n",card->devname,dev->name); ++ppp_priv_area->if_send_stat.if_send_tbusy_timeout; ++card->wandev.stats.collisions; /* unbusy the card (because only one interface per card)*/ dev->tbusy = 0; } #endif sendpacket = skb->data; udp_type = udp_pkt_type( skb, card ); if (udp_type == UDP_PTPIPE_TYPE){ if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, ppp_priv_area)){ flags->imask |= PPP_INTR_TIMER; } ++ppp_priv_area->if_send_stat.if_send_PIPE_request; start_net_queue(dev); return 0; } /* Check for broadcast and multicast addresses * If found, drop (deallocate) a packet and return. */ if(chk_bcast_mcast_addr(card, dev, skb)){ ++card->wandev.stats.tx_dropped; wan_dev_kfree_skb(skb,FREE_WRITE); start_net_queue(dev); return 0; } if(card->hw.type != SDLA_S514){ s508_lock(card,&smp_flags); } if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical in if_send: %lx\n", card->wandev.name,card->wandev.critical); ++card->wandev.stats.tx_dropped; ++ppp_priv_area->if_send_stat.if_send_critical_non_ISR; start_net_queue(dev); goto if_send_exit_crit; } if (card->wandev.state != WAN_CONNECTED) { ++ppp_priv_area->if_send_stat.if_send_wan_disconnected; ++card->wandev.stats.tx_dropped; start_net_queue(dev); } else if (!skb->protocol) { ++ppp_priv_area->if_send_stat.if_send_protocol_error; ++card->wandev.stats.tx_errors; start_net_queue(dev); } else { /*If it's IPX change the network numbers to 0 if they're ours.*/ if( skb->protocol == htons(ETH_P_IPX) ) { if(ppp_priv_area->enable_IPX) { switch_net_numbers( skb->data, ppp_priv_area->network_number, 0); } else { ++card->wandev.stats.tx_dropped; start_net_queue(dev); goto if_send_exit_crit; } } if (ppp_send(card, skb->data, skb->len, skb->protocol)) { stop_net_queue(dev); ++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full; ++ppp_priv_area->if_send_stat.if_send_tx_int_enabled; } else { ++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr; ++card->wandev.stats.tx_packets;#if defined(LINUX_2_1) || defined(LINUX_2_4) card->wandev.stats.tx_bytes += skb->len;#endif start_net_queue(dev);#ifdef LINUX_2_4 dev->trans_start = jiffies;#endif } } if_send_exit_crit: if (!(err=is_queue_stopped(dev))){ wan_dev_kfree_skb(skb, FREE_WRITE); }else{ ppp_priv_area->tick_counter = jiffies; flags->imask |= PPP_INTR_TXRDY; /* unmask Tx interrupts */ } clear_bit(SEND_CRIT,&card->wandev.critical); if(card->hw.type != SDLA_S514){ s508_unlock(card,&smp_flags); } return err;}/*============================================================================= * Store a UDP management packet for later processing. */static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, netdevice_t* dev, ppp_private_area_t* ppp_priv_area ){ int udp_pkt_stored = 0; if(!ppp_priv_area->udp_pkt_lgth && (skb->len<=MAX_LGTH_UDP_MGNT_PKT)){ ppp_priv_area->udp_pkt_lgth = skb->len; ppp_priv_area->udp_pkt_src = udp_pkt_src; memcpy(ppp_priv_area->udp_pkt_data, skb->data, skb->len); ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UDP; ppp_priv_area->protocol = skb->protocol; udp_pkt_stored = 1; }else{ if (skb->len > MAX_LGTH_UDP_MGNT_PKT){#if defined(LINUX_2_1) || defined(LINUX_2_4) printk(KERN_INFO "%s: PIPEMON UDP request too long : %i\n", card->devname, skb->len);#else printk(KERN_INFO "%s: PIPEMON UDP request too long : %li\n", card->devname, skb->len);#endif }else{ printk(KERN_INFO "%s: PIPEMON UPD request already pending\n", card->devname); } ppp_priv_area->udp_pkt_lgth = 0; } if(udp_pkt_src == UDP_PKT_FRM_STACK){ wan_dev_kfree_skb(skb, FREE_WRITE); }else{ wan_dev_kfree_skb(skb, FREE_READ); } return(udp_pkt_stored);}/*============================================================================ * 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; ppp_udp_pkt_t *p_udp_pkt = (ppp_udp_pkt_t *)data; /* Set length of packet */ len = sizeof(ip_pkt_t)+ sizeof(udp_pkt_t)+ sizeof(wp_mgmt_t)+ sizeof(cblock_t)+ mbox_len; /* fill in UDP reply */ p_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); p_udp_pkt->udp_pkt.udp_length = temp; /* swap UDP ports */ temp = p_udp_pkt->udp_pkt.udp_src_port; p_udp_pkt->udp_pkt.udp_src_port = p_udp_pkt->udp_pkt.udp_dst_port; p_udp_pkt->udp_pkt.udp_dst_port = temp; /* add UDP pseudo header */ temp = 0x1100; *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound)) = temp; temp = (udp_length<<8)|(udp_length>>8); *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound+2)) = temp; /* calculate UDP checksum */ p_udp_pkt->udp_pkt.udp_checksum = 0; p_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); /* fill in IP length */ ip_length = udp_length + sizeof(ip_pkt_t); temp = (ip_length<<8)|(ip_length>>8); p_udp_pkt->ip_pkt.total_length = temp; /* swap IP addresses */ ip_temp = p_udp_pkt->ip_pkt.ip_src_address; p_udp_pkt->ip_pkt.ip_src_address = p_udp_pkt->ip_pkt.ip_dst_address; p_udp_pkt->ip_pkt.ip_dst_address = ip_temp; /* fill in IP checksum */ p_udp_pkt->ip_pkt.hdr_checksum = 0; p_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; }/* 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[6] << 24) + (sendpacket[7] << 16) + (sendpacket[8] << 8) + sendpacket[9]); if (!incoming) { //If the destination network number is ours, make it 0 if( pnetwork_number == network_number) { sendpacket[6] = sendpacket[7] = sendpacket[8] = sendpacket[9] = 0x00; } } else { //If the incoming network is 0, make it ours if( pnetwork_number == 0) { sendpacket[6] = (unsigned char)(network_number >> 24); sendpacket[7] = (unsigned char)((network_number & 0x00FF0000) >> 16); sendpacket[8] = (unsigned char)((network_number & 0x0000FF00) >> 8); sendpacket[9] = (unsigned char)(network_number & 0x000000FF); } } pnetwork_number = (unsigned long)((sendpacket[18] << 24) + (sendpacket[19] << 16) + (sendpacket[20] << 8) + sendpacket[21]); if( !incoming ) { //If the source network is ours, make it 0 if( pnetwork_number == network_number) { sendpacket[18] = sendpacket[19] = sendpacket[20] = sendpacket[21] = 0x00; } } else { //If the source network is 0, make it ours if( pnetwork_number == 0 ) { sendpacket[18] = (unsigned char)(network_number >> 24); sendpacket[19] = (unsigned char)((network_number & 0x00FF0000) >> 16); sendpacket[20] = (unsigned char)((network_number & 0x0000FF00) >> 8); sendpacket[21] = (unsigned char)(network_number & 0x000000FF); } }} /* switch_net_numbers *//*============================================================================ * Get ethernet-style interface statistics. * Return a pointer to struct net_device_stats. */#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{ ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t* card; if( ppp_priv_area == NULL ) return NULL; card = ppp_priv_area->card; return &card->wandev.stats;}/****** PPP Firmware Interface Functions ************************************//*============================================================================ * Read firmware code version. * Put code version as ASCII string in str. */static int ppp_read_version(sdla_t *card, char *str){ ppp_mbox_t *mb = card->mbox;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -