📄 dev.c
字号:
netdev_fc_slots[bit].stimul = NULL; netdev_fc_slots[bit].dev = NULL; clear_bit(bit, &netdev_fc_mask); clear_bit(bit, &netdev_fc_xoff); } restore_flags(flags);}static void netdev_wakeup(void){ unsigned long xoff; cli(); xoff = netdev_fc_xoff; netdev_fc_xoff = 0; netdev_dropping = 0; netdev_throttle_events++; while (xoff) { int i = ffz(~xoff); xoff &= ~(1<<i); netdev_fc_slots[i].stimul(netdev_fc_slots[i].dev); } sti();}#endifstatic void dev_clear_backlog(struct device *dev){ struct sk_buff *curr; unsigned long flags; /* * * Let now clear backlog queue. -AS * * We are competing here both with netif_rx() and net_bh(). * We don't want either of those to mess with skb ptrs * while we work on them, thus we must grab the * skb_queue_lock. */ if (backlog.qlen) { repeat: spin_lock_irqsave(&skb_queue_lock, flags); for (curr = backlog.next; curr != (struct sk_buff *)(&backlog); curr = curr->next) if (curr->dev == dev) { __skb_unlink(curr, &backlog); spin_unlock_irqrestore(&skb_queue_lock, flags); kfree_skb(curr); goto repeat; } spin_unlock_irqrestore(&skb_queue_lock, flags);#ifdef CONFIG_NET_HW_FLOWCONTROL if (netdev_dropping) netdev_wakeup();#else netdev_dropping = 0;#endif }}/* * Receive a packet from a device driver and queue it for the upper * (protocol) levels. It always succeeds. */void netif_rx(struct sk_buff *skb){#ifndef CONFIG_CPU_IS_SLOW if(skb->stamp.tv_sec==0) get_fast_time(&skb->stamp);#else skb->stamp = xtime;#endif /* The code is rearranged so that the path is the most short when CPU is congested, but is still operating. */ if (backlog.qlen <= netdev_max_backlog) { if (backlog.qlen) { if (netdev_dropping == 0) { skb_queue_tail(&backlog,skb); mark_bh(NET_BH); return; } atomic_inc(&netdev_rx_dropped); kfree_skb(skb); return; }#ifdef CONFIG_NET_HW_FLOWCONTROL if (netdev_dropping) netdev_wakeup();#else netdev_dropping = 0;#endif skb_queue_tail(&backlog,skb); mark_bh(NET_BH); return; } netdev_dropping = 1; atomic_inc(&netdev_rx_dropped); kfree_skb(skb);}#ifdef CONFIG_BRIDGEstatic inline void handle_bridge(struct sk_buff *skb, unsigned short type){ /* * The br_stats.flags is checked here to save the expense of a * function call. */ if ((br_stats.flags & BR_UP) && br_call_bridge(skb, type)) { /* * We pass the bridge a complete frame. This means * recovering the MAC header first. */ int offset; skb=skb_clone(skb, GFP_ATOMIC); if(skb==NULL) return; offset=skb->data-skb->mac.raw; skb_push(skb,offset); /* Put header back on for bridge */ if(br_receive_frame(skb)) return; kfree_skb(skb); } return;}#endif/* * When we are called the queue is ready to grab, the interrupts are * on and hardware can interrupt and queue to the receive queue as we * run with no problems. * This is run as a bottom half after an interrupt handler that does * mark_bh(NET_BH); */void net_bh(void){ struct packet_type *ptype; struct packet_type *pt_prev; unsigned short type;#ifndef _HURD_ unsigned long start_time = jiffies;#ifdef CONFIG_CPU_IS_SLOW static unsigned long start_busy = 0; static unsigned long ave_busy = 0; if (start_busy == 0) start_busy = start_time; net_cpu_congestion = ave_busy>>8;#endif#endif NET_PROFILE_ENTER(net_bh); /* * Can we send anything now? We want to clear the * decks for any more sends that get done as we * process the input. This also minimises the * latency on a transmit interrupt bh. */ if (qdisc_head.forw != &qdisc_head) qdisc_run_queues(); /* * Any data left to process. This may occur because a * mark_bh() is done after we empty the queue including * that from the device which does a mark_bh() just after */ /* * While the queue is not empty.. * * Note that the queue never shrinks due to * an interrupt, so we can do this test without * disabling interrupts. */ while (!skb_queue_empty(&backlog)) { struct sk_buff * skb;#ifndef _HURD_ /* Give chance to other bottom halves to run */ if (jiffies - start_time > 1) goto net_bh_break;#endif /* * We have a packet. Therefore the queue has shrunk */ skb = skb_dequeue(&backlog);#ifndef _HURD_#ifdef CONFIG_CPU_IS_SLOW if (ave_busy > 128*16) { kfree_skb(skb); while ((skb = skb_dequeue(&backlog)) != NULL) kfree_skb(skb); break; }#endif#endif#if 0 NET_PROFILE_SKB_PASSED(skb, net_bh_skb);#endif#ifdef CONFIG_NET_FASTROUTE if (skb->pkt_type == PACKET_FASTROUTE) { dev_queue_xmit(skb); continue; }#endif /* * Bump the pointer to the next structure. * * On entry to the protocol layer. skb->data and * skb->nh.raw point to the MAC and encapsulated data */ /* XXX until we figure out every place to modify.. */ skb->h.raw = skb->nh.raw = skb->data; if (skb->mac.raw < skb->head || skb->mac.raw > skb->data) { printk(KERN_CRIT "%s: wrong mac.raw ptr, proto=%04x\n", skb->dev->name, skb->protocol); kfree_skb(skb); continue; } /* * Fetch the packet protocol ID. */ type = skb->protocol;#ifdef CONFIG_BRIDGE /* * If we are bridging then pass the frame up to the * bridging code (if this protocol is to be bridged). * If it is bridged then move on */ handle_bridge(skb, type);#endif /* * We got a packet ID. Now loop over the "known protocols" * list. There are two lists. The ptype_all list of taps (normally empty) * and the main protocol list which is hashed perfectly for normal protocols. */ pt_prev = NULL; for (ptype = ptype_all; ptype!=NULL; ptype=ptype->next) { if (!ptype->dev || ptype->dev == skb->dev) { if(pt_prev) { struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC); if(skb2) pt_prev->func(skb2,skb->dev, pt_prev); } pt_prev=ptype; } } for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next) { if (ptype->type == type && (!ptype->dev || ptype->dev==skb->dev)) { /* * We already have a match queued. Deliver * to it and then remember the new match */ if(pt_prev) { struct sk_buff *skb2; skb2=skb_clone(skb, GFP_ATOMIC); /* * Kick the protocol handler. This should be fast * and efficient code. */ if(skb2) pt_prev->func(skb2, skb->dev, pt_prev); } /* Remember the current last to do */ pt_prev=ptype; } } /* End of protocol list loop */ /* * Is there a last item to send to ? */ if(pt_prev) pt_prev->func(skb, skb->dev, pt_prev); /* * Has an unknown packet has been received ? */ else { kfree_skb(skb); } } /* End of queue loop */ /* * We have emptied the queue */ /* * One last output flush. */ if (qdisc_head.forw != &qdisc_head) qdisc_run_queues();#ifndef _HURD_#ifdef CONFIG_CPU_IS_SLOW if (1) { unsigned long start_idle = jiffies; ave_busy += ((start_idle - start_busy)<<3) - (ave_busy>>4); start_busy = 0; }#endif#endif#ifdef CONFIG_NET_HW_FLOWCONTROL if (netdev_dropping) netdev_wakeup();#else netdev_dropping = 0;#endif NET_PROFILE_LEAVE(net_bh); return;#ifndef _HURD_net_bh_break: mark_bh(NET_BH); NET_PROFILE_LEAVE(net_bh); return;#endif}/* Protocol dependent address dumping routines */static gifconf_func_t * gifconf_list [NPROTO];int register_gifconf(unsigned int family, gifconf_func_t * gifconf){ if (family>=NPROTO) return -EINVAL; gifconf_list[family] = gifconf; return 0;}/* * Map an interface index to its name (SIOCGIFNAME) *//* * This call is useful, but I'd remove it too. * * The reason is purely aestetical, it is the only call * from SIOC* family using struct ifreq in reversed manner. * Besides that, it is pretty silly to put "drawing" facility * to kernel, it is useful only to print ifindices * in readable form, is not it? --ANK * * We need this ioctl for efficient implementation of the * if_indextoname() function required by the IPv6 API. Without * it, we would have to search all the interfaces to find a * match. --pb */static int dev_ifname(struct ifreq *arg){ struct device *dev; struct ifreq ifr; int err; /* * Fetch the caller's info block. */ err = copy_from_user(&ifr, arg, sizeof(struct ifreq)); if (err) return -EFAULT; dev = dev_get_by_index(ifr.ifr_ifindex); if (!dev) return -ENODEV; strcpy(ifr.ifr_name, dev->name); err = copy_to_user(arg, &ifr, sizeof(struct ifreq)); return (err)?-EFAULT:0;}/* * Perform a SIOCGIFCONF call. This structure will change * size eventually, and there is nothing I can do about it. * Thus we will need a 'compatibility mode'. */#ifdef _HURD_int dev_ifconf(char *arg)#elsestatic int dev_ifconf(char *arg)#endif{ struct ifconf ifc; struct device *dev; char *pos; int len; int total; int i; /* * Fetch the caller's info block. */ if (copy_from_user(&ifc, arg, sizeof(struct ifconf))) return -EFAULT; pos = ifc.ifc_buf; len = ifc.ifc_len; /* * Loop over the interfaces, and write an info block for each. */ total = 0; for (dev = dev_base; dev != NULL; dev = dev->next) { for (i=0; i<NPROTO; i++) { if (gifconf_list[i]) { int done; if (pos==NULL) { done = gifconf_list[i](dev, NULL, 0); } else { done = gifconf_list[i](dev, pos+total, len-total); } if (done<0) return -EFAULT; total += done; } } } /* * All done. Write the updated control block back to the caller. */ ifc.ifc_len = total; if (copy_to_user(arg, &ifc, sizeof(struct ifconf))) return -EFAULT; /* * Both BSD and Solaris return 0 here, so we do too. */ return 0;}/* * This is invoked by the /proc filesystem handler to display a device * in detail. */#ifdef CONFIG_PROC_FSstatic int sprintf_stats(char *buffer, struct device *dev){ struct net_device_stats *stats = (dev->get_stats ? dev->get_stats(dev): NULL); int size; if (stats) size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu %8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", dev->name, stats->rx_bytes, stats->rx_packets, stats->rx_errors, stats->rx_dropped + stats->rx_missed_errors, stats->rx_fifo_errors, stats->rx_length_errors + stats->rx_over_errors + stats->rx_crc_errors + stats->rx_frame_errors, stats->rx_compressed, stats->multicast, stats->tx_bytes, stats->tx_packets, stats->tx_errors, stats->tx_dropped, stats->tx_fifo_errors, stats->collisions, stats->tx_carrier_errors + stats->tx_aborted_errors + stats->tx_window_errors + stats->tx_heartbeat_errors, stats->tx_compressed); else size = sprintf(buffer, "%6s: No statistics available.\n", dev->name); return size;}/* * Called from the PROCfs module. This now uses the new arbitrary sized /proc/net interface * to create /proc/net/dev */int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy){ int len=0; off_t begin=0; off_t pos=0; int size; struct device *dev; size = sprintf(buffer, "Inter-| Receive | Transmit\n" " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n"); pos+=size; len+=size; for (dev = dev_base; dev != NULL; dev = dev->next) { size = sprintf_stats(buffer+len, dev); len+=size; pos=begin+len; if(pos<offset) { len=0; begin=pos; } if(pos>offset+length) break; } *start=buffer+(offset-begin); /* Start of wanted data */ len-=(offset-begin); /* Start slop */ if(len>length) len=length; /* Ending slop */ return len;}static int dev_proc_stats(char *buffer, char **start, off_t offset, int length, int *eof, void *data){ int len; len = sprintf(buffer, "%08x %08x %08x %08x %08x\n", atomic_read(&netdev_rx_dropped),#ifdef CONFIG_NET_HW_FLOWCONTROL netdev_throttle_events,#else 0,#endif#ifdef CONFIG_NET_FASTROUTE dev_fastroute_stat.hits, dev_fastroute_stat.succeed, dev_fastroute_stat.deferred#else 0, 0, 0#endif ); len -= offset; if (len > length) len = length; if(len < 0) len = 0; *start = buffer + offset; *eof = 1; return len;}#endif /* CONFIG_PROC_FS */#ifdef CONFIG_NET_RADIO#ifdef CONFIG_PROC_FS/* * Print one entry of /proc/net/wireless * This is a clone of /proc/net/dev (just above) */static int sprintf_wireless_stats(char *buffer, struct device *dev){ /* Get stats from the driver */ struct iw_statistics *stats = (dev->get_wireless_stats ? dev->get_wireless_stats(dev) : (struct iw_statistics *) NULL); int size; if(stats != (struct iw_statistics *) NULL) { size = sprintf(buffer, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d\n", dev->name, stats->status, stats->qual.qual, stats->qual.updated & 1 ? '.' : ' ', stats->qual.level, stats->qual.updated & 2 ? '.' : ' ', stats->qual.noise, stats->qual.updated & 4 ? '.' : ' ', stats->discard.nwid, stats->discard.code, stats->discard.misc); stats->qual.updated = 0; } else size = 0; return size;}/* * Print info for /proc/net/wireless (print all entries) * This is a clone of /proc/net/dev (just above) */int dev_get_wireless_info(char * buffer, char **start, off_t offset, int length, int dummy){ int len = 0; off_t begin = 0; off_t pos = 0; int size; struct device * dev; size = sprintf(buffer, "Inter-| sta-| Quality | Discarded packets\n" " face | tus | link level noise | nwid crypt misc\n" ); pos+=size; len+=size; for(dev = dev_base; dev != NULL; dev = dev->next) { size = sprintf_wireless_stats(buffer+len, dev); len+=size; pos=begin+len; if(pos < offset) { len=0; begin=pos; } if(pos > offset + length) break; } *start = buffer + (offset - begin); /* Start of wanted data */ len -= (offset - begin); /* Start slop */ if(len > length) len = length; /* Ending slop */ return len;}#endif /* CONFIG_PROC_FS */#endif /* CONFIG_NET_RADIO */void dev_set_promiscuity(struct device *dev, int inc){ unsigned short old_flags = dev->flags; dev->flags |= IFF_PROMISC; if ((dev->promiscuity += inc) == 0) dev->flags &= ~IFF_PROMISC; if (dev->flags^old_flags) {#ifdef CONFIG_NET_FASTROUTE if (dev->flags&IFF_PROMISC) { netdev_fastroute_obstacles++; dev_clear_fastroute(dev); } else netdev_fastroute_obstacles--;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -