📄 dev.c
字号:
* This routine causes all interfaces to try to send some data. */ static void dev_transmit(void){ struct device *dev; for (dev = dev_base; dev != NULL; dev = dev->next) { if (dev->flags != 0 && !dev->tbusy) { /* * Kick the device */ dev_tint(dev); } }}/********************************************************************************** Receive Queue Processor ***********************************************************************************//* * 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; /* * 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. */ dev_transmit(); /* * 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 = backlog.next; /* * We have a packet. Therefore the queue has shrunk */ cli(); __skb_unlink(skb, &backlog); backlog_size--; sti(); #ifdef CONFIG_BRIDGE /* * If we are bridging then pass the frame up to the * bridging code. If it is bridged then move on */ if (br_stats.flags & BR_UP) { /* * We pass the bridge a complete frame. This means * recovering the MAC header first. */ int offset=skb->data-skb->mac.raw; cli(); skb_push(skb,offset); /* Put header back on for bridge */ if(br_receive_frame(skb)) { sti(); continue; } /* * Pull the MAC header off for the copy going to * the upper layers. */ skb_pull(skb,offset); sti(); }#endif /* * Bump the pointer to the next structure. * * On entry to the protocol layer. skb->data and * skb->h.raw point to the MAC and encapsulated data */ skb->h.raw = skb->data; /* * Fetch the packet protocol ID. */ type = skb->protocol; /* * 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, FREE_WRITE); /* * Again, see if we can transmit anything now. * [Ought to take this out judging by tests it slows * us down not speeds us up] */#ifdef XMIT_EVERY dev_transmit();#endif } /* End of queue loop */ /* * We have emptied the queue */ /* * One last output flush. */#ifdef XMIT_AFTER dev_transmit();#endif}/* * This routine is called when an device driver (i.e. an * interface) is ready to transmit a packet. */ void dev_tint(struct device *dev){ int i; unsigned long flags; struct sk_buff_head * head; /* * aliases do not transmit (for now :) ) */#ifdef CONFIG_NET_ALIAS if (net_alias_is(dev)) return;#endif head = dev->buffs; save_flags(flags); cli(); /* * Work the queues in priority order */ for(i = 0;i < DEV_NUMBUFFS; i++,head++) { while (!skb_queue_empty(head)) { struct sk_buff *skb; skb = head->next; __skb_unlink(skb, head); /* * Stop anyone freeing the buffer while we retransmit it */ skb_device_lock(skb); restore_flags(flags); /* * Feed them to the output stage and if it fails * indicate they re-queue at the front. */ do_dev_queue_xmit(skb,dev,-i - 1); /* * If we can take no more then stop here. */ if (dev->tbusy) return; cli(); } } restore_flags(flags);}/* * Perform a SIOCGIFCONF call. This structure will change * size shortly, and there is nothing I can do about it. * Thus we will need a 'compatibility mode'. */static int dev_ifconf(char *arg){ struct ifconf ifc; struct ifreq ifr; struct device *dev; char *pos; int len; int err; /* * Fetch the caller's info block. */ err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf)); if(err) return err; memcpy_fromfs(&ifc, arg, sizeof(struct ifconf)); len = ifc.ifc_len; pos = ifc.ifc_buf; /* * We now walk the device list filling each active device * into the array. */ err=verify_area(VERIFY_WRITE,pos,len); if(err) return err; /* * Loop over the interfaces, and write an info block for each. */ for (dev = dev_base; dev != NULL; dev = dev->next) { if(!(dev->flags & IFF_UP)) /* Downed devices don't count */ continue; /* * Have we run out of space here ? */ if (len < sizeof(struct ifreq)) break; memset(&ifr, 0, sizeof(struct ifreq)); strcpy(ifr.ifr_name, dev->name); (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family; (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; /* * Write this block to the caller's space. */ memcpy_tofs(pos, &ifr, sizeof(struct ifreq)); pos += sizeof(struct ifreq); len -= sizeof(struct ifreq); } /* * All done. Write the updated control block back to the caller. */ ifc.ifc_len = (pos - ifc.ifc_buf); ifc.ifc_req = (struct ifreq *) ifc.ifc_buf; memcpy_tofs(arg, &ifc, sizeof(struct ifconf)); /* * Report how much was filled in */ return(pos - arg);}/* * 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 enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL); int size; if (stats) size = sprintf(buffer, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n", dev->name, 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->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); 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 |packets errs drop fifo frame|packets errs drop fifo colls carrier\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;}#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 intsprintf_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: %02x %3d%c %3d%c %3d%c %5d %5d %5d\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 & 3 ? '.' : ' ', stats->discard.nwid, stats->discard.code, stats->discard.misc); else size = 0; return size;}/* * Print info for /proc/net/wireless (print all entries) * This is a clone of /proc/net/dev (just above) */intdev_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 *//* * This checks bitmasks for the ioctl calls for devices. */ static inline int bad_mask(unsigned long mask, unsigned long addr){ if (addr & (mask = ~mask)) return 1; mask = ntohl(mask); if (mask & (mask+1)) return 1; return 0;}/* * Perform the SIOCxIFxxx calls. * * The socket layer has seen an ioctl the address family thinks is * for the device. At this point we get invoked to make a decision */ static int dev_ifsioc(void *arg, unsigned int getset){ struct ifreq ifr; struct device *dev; int ret; /* * Fetch the caller's info block into kernel space */ int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq)); if(err) return err; memcpy_fromfs(&ifr, arg, sizeof(struct ifreq)); /* * See which interface the caller is talking about. */ /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -