📄 dev.c
字号:
if (backlog != NULL) return(1); printk("INET: dev_rint: no longer dropping packets.\n"); dropping = 0; } skb = alloc_skb(sizeof(*skb) + len, GFP_ATOMIC); if (skb == NULL) { printk("dev_rint: packet dropped on %s (no memory) !\n", dev->name); dropping = 1; return(1); } skb->mem_len = sizeof(*skb) + len; skb->mem_addr = (struct sk_buff *) skb; /* First we copy the packet into a buffer, and save it for later. */ to = skb->data; left = len; len2 = len; while (len2 > 0) { amount = min(len2, (unsigned long) dev->rmem_end - (unsigned long) buff); memcpy(to, buff, amount); len2 -= amount; left -= amount; buff += amount; to += amount; if ((unsigned long) buff == dev->rmem_end) buff = (unsigned char *) dev->rmem_start; } } skb->len = len; skb->dev = dev; skb->free = 1; netif_rx(skb); /* OK, all done. */ return(0);}/* This routine causes all interfaces to try to send some data. */voiddev_transmit(void){ struct device *dev; for (dev = dev_base; dev != NULL; dev = dev->next) { if (!dev->tbusy) { dev_tint(dev); } }}static volatile char in_bh = 0;int in_inet_bh() /* Used by timer.c */{ return(in_bh==0?0:1);}/* * This function gets called periodically, to see if we can * process any data that came in from some interface. * */voidinet_bh(void *tmp){ struct sk_buff *skb; struct packet_type *ptype; unsigned short type; unsigned char flag = 0; int nitcount; /* Atomically check and mark our BUSY state. */ if (set_bit(1, (void*)&in_bh)) return; /* Can we send anything now? */ dev_transmit(); /* Any data left to process? */ while((skb=skb_dequeue(&backlog))!=NULL) { nitcount=dev_nit; flag=0; sti(); /* * Bump the pointer to the next structure. * This assumes that the basic 'skb' pointer points to * the MAC header, if any (as indicated by its "length" * field). Take care now! */ skb->h.raw = skb->data + skb->dev->hard_header_len; skb->len -= skb->dev->hard_header_len; /* * Fetch the packet protocol ID. This is also quite ugly, as * it depends on the protocol driver (the interface itself) to * know what the type is, or where to get it from. The Ethernet * interfaces fetch the ID from the two bytes in the Ethernet MAC * header (the h_proto field in struct ethhdr), but drivers like * SLIP and PLIP have no alternative but to force the type to be * IP or something like that. Sigh- FvK */ type = skb->dev->type_trans(skb, skb->dev); /* * We got a packet ID. Now loop over the "known protocols" * table (which is actually a linked list, but this will * change soon if I get my way- FvK), and forward the packet * to anyone who wants it. */ for (ptype = ptype_base; ptype != NULL; ptype = ptype->next) { if (ptype->type == type || ptype->type == NET16(ETH_P_ALL)) { struct sk_buff *skb2; if (ptype->type==NET16(ETH_P_ALL)) nitcount--; if (ptype->copy || nitcount) { /* copy if we need to */ skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC); if (skb2 == NULL) continue; memcpy(skb2, (const void *) skb, skb->mem_len); skb2->mem_addr = skb2; skb2->h.raw = (unsigned char *)( (unsigned long) skb2 + (unsigned long) skb->h.raw - (unsigned long) skb ); skb2->free = 1; } else { skb2 = skb; } /* This used to be in the 'else' part, but then * we don't have this flag set when we get a * protocol that *does* require copying... -FvK */ flag = 1; /* Kick the protocol handler. */ ptype->func(skb2, skb->dev, ptype); } } /* * That's odd. We got an unknown packet. Who's using * stuff like Novell or Amoeba on this network?? */ if (!flag) { DPRINTF((DBG_DEV, "INET: unknown packet type 0x%04X (ignored)\n", type)); skb->sk = NULL; kfree_skb(skb, FREE_WRITE); } /* Again, see if we can transmit anything now. */ dev_transmit(); cli(); } in_bh = 0; sti(); dev_transmit();}/* * 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; struct sk_buff *skb; for(i = 0;i < DEV_NUMBUFFS; i++) { while((skb=skb_dequeue(&dev->buffs[i]))!=NULL) { skb->magic = 0; skb->next = NULL; skb->prev = NULL; dev->queue_xmit(skb,dev,-i - 1); if (dev->tbusy) return; } }}/* Perform a SIOCGIFCONF call. */static intdev_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; /* 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)) continue; 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); if (len < sizeof(struct ifreq)) break; } /* 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)); return(pos - arg);}/* Print device statistics. */char *sprintf_stats(char *buffer, struct device *dev){ char *pos = buffer; struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL); if (stats) pos += sprintf(pos, "%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 pos += sprintf(pos, "%6s: No statistics available.\n", dev->name); return pos;}/* Called from the PROCfs module. */intdev_get_info(char *buffer){ char *pos = buffer; struct device *dev; pos += sprintf(pos, "Inter-| Receive | Transmit\n" " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n"); for (dev = dev_base; dev != NULL; dev = dev->next) { pos = sprintf_stats(pos, dev); } return pos - buffer;}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. */static intdev_ifsioc(void *arg, unsigned int getset){ struct ifreq ifr; struct device *dev; int ret; /* Fetch the caller's info block. */ 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. */ if ((dev = dev_get(ifr.ifr_name)) == NULL) return(-EINVAL); switch(getset) { case SIOCGIFFLAGS: ifr.ifr_flags = dev->flags; memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); ret = 0; break; case SIOCSIFFLAGS: { int old_flags = dev->flags; dev->flags = ifr.ifr_flags & ( IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK | IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING | IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI); if ( (old_flags & IFF_PROMISC) && ((dev->flags & IFF_PROMISC) == 0)) dev->set_multicast_list(dev,0,NULL); if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0)) dev->set_multicast_list(dev,-1,NULL); if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) { ret = dev_close(dev); } else { ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP)) ? dev_open(dev) : 0; if(ret<0) dev->flags&=~IFF_UP; /* Didnt open so down the if */ } } break; case SIOCGIFADDR: (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family; (*(struct sockaddr_in *) &ifr.ifr_addr).sin_port = 0; memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); ret = 0; break; case SIOCSIFADDR: dev->pa_addr = (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr; dev->family = ifr.ifr_addr.sa_family; dev->pa_mask = get_mask(dev->pa_addr); dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; ret = 0; break; case SIOCGIFBRDADDR: (*(struct sockaddr_in *) &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr; (*(struct sockaddr_in *) &ifr.ifr_broadaddr).sin_family = dev->family; (*(struct sockaddr_in *) &ifr.ifr_broadaddr).sin_port = 0; memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); ret = 0; break; case SIOCSIFBRDADDR: dev->pa_brdaddr = (*(struct sockaddr_in *) &ifr.ifr_broadaddr).sin_addr.s_addr; ret = 0; break; case SIOCGIFDSTADDR: (*(struct sockaddr_in *) &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr; (*(struct sockaddr_in *) &ifr.ifr_broadaddr).sin_family = dev->family; (*(struct sockaddr_in *) &ifr.ifr_broadaddr).sin_port = 0; memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); ret = 0; break; case SIOCSIFDSTADDR: dev->pa_dstaddr = (*(struct sockaddr_in *) &ifr.ifr_dstaddr).sin_addr.s_addr; ret = 0; break; case SIOCGIFNETMASK: (*(struct sockaddr_in *) &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask; (*(struct sockaddr_in *) &ifr.ifr_netmask).sin_family = dev->family; (*(struct sockaddr_in *) &ifr.ifr_netmask).sin_port = 0; memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); ret = 0; break; case SIOCSIFNETMASK: { unsigned long mask = (*(struct sockaddr_in *) &ifr.ifr_netmask).sin_addr.s_addr; ret = -EINVAL; if (bad_mask(mask,0)) break; dev->pa_mask = mask; ret = 0; break; } case SIOCGIFMETRIC: ifr.ifr_metric = dev->metric; memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); ret = 0; break; case SIOCSIFMETRIC: dev->metric = ifr.ifr_metric; ret = 0; break; case SIOCGIFMTU: ifr.ifr_mtu = dev->mtu; memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); ret = 0; break; case SIOCSIFMTU: dev->mtu = ifr.ifr_mtu; ret = 0; break; case SIOCGIFMEM: printk("NET: ioctl(SIOCGIFMEM, 0x%08X)\n", (int)arg); ret = -EINVAL; break; case SIOCSIFMEM: printk("NET: ioctl(SIOCSIFMEM, 0x%08X)\n", (int)arg); ret = -EINVAL; break; case SIOCGIFHWADDR: memcpy(ifr.ifr_hwaddr,dev->dev_addr, MAX_ADDR_LEN); memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); ret=0; break; default: ret = -EINVAL; } return(ret);}/* This function handles all "interface"-type I/O control requests. */intdev_ioctl(unsigned int cmd, void *arg){ struct iflink iflink; struct ddi_device *dev; switch(cmd) { case IP_SET_DEV: printk("Your network configuration program needs upgrading.\n"); return -EINVAL; case SIOCGIFCONF: (void) dev_ifconf((char *) arg); return 0; case SIOCGIFFLAGS: case SIOCGIFADDR: case SIOCGIFDSTADDR: case SIOCGIFBRDADDR: case SIOCGIFNETMASK: case SIOCGIFMETRIC: case SIOCGIFMTU: case SIOCGIFMEM: case SIOCGIFHWADDR: return dev_ifsioc(arg, cmd); case SIOCSIFFLAGS: case SIOCSIFADDR: case SIOCSIFDSTADDR: case SIOCSIFBRDADDR: case SIOCSIFNETMASK: case SIOCSIFMETRIC: case SIOCSIFMTU: case SIOCSIFMEM: if (!suser()) return -EPERM; return dev_ifsioc(arg, cmd); case SIOCSIFLINK: if (!suser()) return -EPERM; memcpy_fromfs(&iflink, arg, sizeof(iflink)); dev = ddi_map(iflink.id); if (dev == NULL) return -EINVAL; /* Now allocate an interface and connect it. */ printk("AF_INET: DDI \"%s\" linked to stream \"%s\"\n", dev->name, iflink.stream); return 0; default: return -EINVAL; }}/* Initialize the DEV module. */voiddev_init(void){ struct device *dev, *dev2; /* Add the devices. * If the call to dev->init fails, the dev is removed * from the chain disconnecting the device until the * next reboot. */ dev2 = NULL; for (dev = dev_base; dev != NULL; dev=dev->next) { if (dev->init && dev->init(dev)) { if (dev2 == NULL) dev_base = dev->next; else dev2->next = dev->next; } else { dev2 = dev; } } /* Set up some IP addresses. */ ip_bcast = in_aton("255.255.255.255");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -