📄 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. */
void
dev_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.
*
*/
void
inet_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 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;
/* 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. */
int
dev_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 int
dev_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. */
int
dev_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. */
void
dev_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 + -