int dev_open(struct device *dev) { int ret = 0; /* * Call device private open method */ if (dev->open) ret = dev->open(dev); /* * If it went open OK then set the flags */ if (ret == 0) { dev->flags |= (IFF_UP | IFF_RUNNING); /* * Initialise multicasting status */ #ifdef CONFIG_IP_MULTICAST /* * Join the all host group */ ip_mc_allhost(dev); #endif dev_mc_upload(dev); notifier_call_chain(&netdev_chain, NETDEV_UP, dev); } return(ret); }
int dev_mc_delete(struct device *dev, void *addr, int alen, int glbl) { struct dev_mc_list *dmi, **dmip; for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) { /* * Find the entry we want to delete. The device could * have variable length entries so check these too. */ if (memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && alen==dmi->dmi_addrlen) { if (glbl) { int old_glbl = dmi->dmi_gusers; dmi->dmi_gusers = 0; if (old_glbl == 0) return -ENOENT; } if(--dmi->dmi_users) return 0; /* * Last user. So delete the entry. */ *dmip = dmi->next; dev->mc_count--; kfree_s(dmi,sizeof(*dmi)); /* * We have altered the list, so the card * loaded filter is now wrong. Fix it */ dev_mc_upload(dev); return 0; } } return -ENOENT; }
int dev_open(struct device *dev) { int ret = -ENODEV; /* * Call device private open method */ if (dev->open) ret = dev->open(dev); /* * If it went open OK then set the flags */ if (ret == 0) { dev->flags |= (IFF_UP | IFF_RUNNING); /* * Initialise multicasting status */ dev_mc_upload(dev); notifier_call_chain(&netdev_chain, NETDEV_UP, dev); } return(ret); }
void dev_mc_delete(struct device *dev, void *addr, int alen, int all) { struct dev_mc_list **dmi; for(dmi=&dev->mc_list;*dmi!=NULL;dmi=&(*dmi)->next) { if(memcmp((*dmi)->dmi_addr,addr,(*dmi)->dmi_addrlen)==0 && alen==(*dmi)->dmi_addrlen) { struct dev_mc_list *tmp= *dmi; if(--(*dmi)->dmi_users && !all) return; *dmi=(*dmi)->next; dev->mc_count--; kfree_s(tmp,sizeof(*tmp)); dev_mc_upload(dev); return; } } }
int dev_mc_add(struct device *dev, void *addr, int alen, int glbl) { int err = 0; struct dev_mc_list *dmi, *dmi1; dmi1 = (struct dev_mc_list *)kmalloc(sizeof(*dmi), gfp_any()); start_bh_atomic(); for(dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next) { if (memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && dmi->dmi_addrlen==alen) { if (glbl) { int old_glbl = dmi->dmi_gusers; dmi->dmi_gusers = 1; if (old_glbl) goto done; } dmi->dmi_users++; goto done; } } if ((dmi=dmi1)==NULL) { end_bh_atomic(); return -ENOMEM; } memcpy(dmi->dmi_addr, addr, alen); dmi->dmi_addrlen=alen; dmi->next=dev->mc_list; dmi->dmi_users=1; dmi->dmi_gusers=glbl ? 1 : 0; dev->mc_list=dmi; dev->mc_count++; end_bh_atomic(); dev_mc_upload(dev); return 0; done: end_bh_atomic(); if (dmi1) kfree(dmi1); return err; }
void dev_mc_add(struct device *dev, void *addr, int alen, int newonly) { struct dev_mc_list *dmi; for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next) { if(memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && dmi->dmi_addrlen==alen) { if(!newonly) dmi->dmi_users++; return; } } dmi=(struct dev_mc_list *)kmalloc(sizeof(*dmi),GFP_KERNEL); if(dmi==NULL) return; /* GFP_KERNEL so can't happen anyway */ memcpy(dmi->dmi_addr, addr, alen); dmi->dmi_addrlen=alen; dmi->next=dev->mc_list; dmi->dmi_users=1; dev->mc_list=dmi; dev->mc_count++; dev_mc_upload(dev); }
int dev_mc_add(struct device *dev, void *addr, int alen, int glbl) { struct dev_mc_list *dmi; for(dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next) { if (memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && dmi->dmi_addrlen==alen) { if (glbl) { int old_glbl = dmi->dmi_gusers; dmi->dmi_gusers = 1; if (old_glbl) return 0; } dmi->dmi_users++; return 0; } } /* GFP_ATOMIC!! It is used by IPv6 from interrupt, when new address arrives. Particularly, it means that this part of code is weirdly racy, and needs numerous *_bh_atomic --ANK */ dmi=(struct dev_mc_list *)kmalloc(sizeof(*dmi), GFP_ATOMIC); if (dmi==NULL) return -ENOBUFS; memcpy(dmi->dmi_addr, addr, alen); dmi->dmi_addrlen=alen; dmi->next=dev->mc_list; dmi->dmi_users=1; dmi->dmi_gusers=glbl ? 1 : 0; dev->mc_list=dmi; dev->mc_count++; dev_mc_upload(dev); return 0; }
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. */ if ((dev = dev_get(ifr.ifr_name)) == NULL) return(-ENODEV); switch(getset) { case SIOCGIFFLAGS: /* Get interface flags */ ifr.ifr_flags = dev->flags; memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); ret = 0; break; case SIOCSIFFLAGS: /* Set interface flags */ { int old_flags = dev->flags; #ifdef CONFIG_SLAVE_BALANCING if(dev->flags&IFF_SLAVE) return -EBUSY; #endif 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 | IFF_SLAVE | IFF_MASTER | IFF_MULTICAST); #ifdef CONFIG_SLAVE_BALANCING if(!(dev->flags&IFF_MASTER) && dev->slave) { dev->slave->flags&=~IFF_SLAVE; dev->slave=NULL; } #endif /* * Load in the correct multicast list now the flags have changed. */ dev_mc_upload(dev); #if 0 if( dev->set_multicast_list!=NULL) { /* * Has promiscuous mode been turned off */ if ( (old_flags & IFF_PROMISC) && ((dev->flags & IFF_PROMISC) == 0)) dev->set_multicast_list(dev,0,NULL); /* * Has it been turned on */ if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0)) dev->set_multicast_list(dev,-1,NULL); } #endif /* * Have we downed the interface */ if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) { ret = dev_close(dev); } else { /* * Have we upped the interface */ ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP)) ? dev_open(dev) : 0; /* * Check the flags. */ if(ret<0) dev->flags&=~IFF_UP; /* Didn't open so down the if */ } } break; case SIOCGIFADDR: /* Get interface address (and family) */ (*(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: /* Set interface address (and family) */ dev->pa_addr = (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr; dev->family = ifr.ifr_addr.sa_family; #ifdef CONFIG_INET /* This is naughty. When net-032e comes out It wants moving into the net032 code not the kernel. Till then it can sit here (SIGH) */ dev->pa_mask = ip_get_mask(dev->pa_addr); #endif dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; ret = 0; break; case SIOCGIFBRDADDR: /* Get the broadcast address */ (*(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: /* Set the broadcast address */ dev->pa_brdaddr = (*(struct sockaddr_in *) &ifr.ifr_broadaddr).sin_addr.s_addr; ret = 0; break; case SIOCGIFDSTADDR: /* Get the destination address (for point-to-point links) */ (*(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: /* Set the destination address (for point-to-point links) */ dev->pa_dstaddr = (*(struct sockaddr_in *) &ifr.ifr_dstaddr).sin_addr.s_addr; ret = 0; break; case SIOCGIFNETMASK: /* Get the netmask for the interface */ (*(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: /* Set the netmask for the interface */ { unsigned long mask = (*(struct sockaddr_in *) &ifr.ifr_netmask).sin_addr.s_addr; ret = -EINVAL; /* * The mask we set must be legal. */ if (bad_mask(mask,0)) break; dev->pa_mask = mask; ret = 0; } break; case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */ ifr.ifr_metric = dev->metric; memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); ret = 0; break; case SIOCSIFMETRIC: /* Set the metric on the interface (currently unused) */ dev->metric = ifr.ifr_metric; ret = 0; break; case SIOCGIFMTU: /* Get the MTU of a device */ ifr.ifr_mtu = dev->mtu; memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); ret = 0; break; case SIOCSIFMTU: /* Set the MTU of a device */ /* * MTU must be positive and under the page size problem */ if(ifr.ifr_mtu<1 || ifr.ifr_mtu>3800) return -EINVAL; dev->mtu = ifr.ifr_mtu; ret = 0; break; case SIOCGIFMEM: /* Get the per device memory space. We can add this but currently do not support it */ printk("NET: ioctl(SIOCGIFMEM, %p)\n", arg); ret = -EINVAL; break; case SIOCSIFMEM: /* Set the per device memory buffer space. Not applicable in our case */ printk("NET: ioctl(SIOCSIFMEM, %p)\n", arg); ret = -EINVAL; break; case OLD_SIOCGIFHWADDR: /* Get the hardware address. This will change and SIFHWADDR will be added */ memcpy(ifr.old_ifr_hwaddr,dev->dev_addr, MAX_ADDR_LEN); memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); ret=0; break; case SIOCGIFHWADDR: memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); ifr.ifr_hwaddr.sa_family=dev->type; memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); ret=0; break; case SIOCSIFHWADDR: if(dev->set_mac_address==NULL) return -EOPNOTSUPP; if(ifr.ifr_hwaddr.sa_family!=dev->type) return -EINVAL; ret=dev->set_mac_address(dev,ifr.ifr_hwaddr.sa_data); break; case SIOCGIFMAP: ifr.ifr_map.mem_start=dev->mem_start; ifr.ifr_map.mem_end=dev->mem_end; ifr.ifr_map.base_addr=dev->base_addr; ifr.ifr_map.irq=dev->irq; ifr.ifr_map.dma=dev->dma; ifr.ifr_map.port=dev->if_port; memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); ret=0; break; case SIOCSIFMAP: if(dev->set_config==NULL) return -EOPNOTSUPP; return dev->set_config(dev,&ifr.ifr_map); case SIOCGIFSLAVE: #ifdef CONFIG_SLAVE_BALANCING if(dev->slave==NULL) return -ENOENT; strncpy(ifr.ifr_name,dev->name,sizeof(ifr.ifr_name)); memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); ret=0; #else return -ENOENT; #endif break; #ifdef CONFIG_SLAVE_BALANCING case SIOCSIFSLAVE: { /* * Fun game. Get the device up and the flags right without * letting some scummy user confuse us. */ unsigned long flags; struct device *slave=dev_get(ifr.ifr_slave); save_flags(flags); if(slave==NULL) { return -ENODEV; } cli(); if((slave->flags&(IFF_UP|IFF_RUNNING))!=(IFF_UP|IFF_RUNNING)) { restore_flags(flags); return -EINVAL; } if(dev->flags&IFF_SLAVE) { restore_flags(flags); return -EBUSY; } if(dev->slave!=NULL) { restore_flags(flags); return -EBUSY; } if(slave->flags&IFF_SLAVE) { restore_flags(flags); return -EBUSY; } dev->slave=slave; slave->flags|=IFF_SLAVE; dev->flags|=IFF_MASTER; restore_flags(flags); ret=0; } break; #endif case SIOCADDMULTI: if(dev->set_multicast_list==NULL) return -EINVAL; if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC) return -EINVAL; dev_mc_add(dev,ifr.ifr_hwaddr.sa_data, dev->addr_len, 1); return 0; case SIOCDELMULTI: if(dev->set_multicast_list==NULL) return -EINVAL; if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC) return -EINVAL; dev_mc_delete(dev,ifr.ifr_hwaddr.sa_data,dev->addr_len, 1); return 0; /* * Unknown or private ioctl */ default: if((getset >= SIOCDEVPRIVATE) && (getset <= (SIOCDEVPRIVATE + 15))) { if(dev->do_ioctl==NULL) return -EOPNOTSUPP; ret=dev->do_ioctl(dev, &ifr, getset); memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); break; } ret = -EINVAL; } return(ret); }
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. */ /* * * net_alias_dev_get(): dev_get() with added alias naming magic. * only allow alias creation/deletion if (getset==SIOCSIFADDR) * */ #ifdef CONFIG_KERNELD dev_load(ifr.ifr_name); #endif #ifdef CONFIG_NET_ALIAS if ((dev = net_alias_dev_get(ifr.ifr_name, getset == SIOCSIFADDR, &err, NULL, NULL)) == NULL) return(err); #else if ((dev = dev_get(ifr.ifr_name)) == NULL) return(-ENODEV); #endif switch(getset) { case SIOCGIFFLAGS: /* Get interface flags */ ifr.ifr_flags = (dev->flags & ~IFF_SOFTHEADERS); goto rarok; case SIOCSIFFLAGS: /* Set interface flags */ { int old_flags = dev->flags; if(securelevel>0) ifr.ifr_flags&=~IFF_PROMISC; /* * We are not allowed to potentially close/unload * a device until we get this lock. */ dev_lock_wait(); /* * Set the flags on our device. */ dev->flags = (ifr.ifr_flags & ( IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK | IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING | IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI | IFF_SLAVE | IFF_MASTER | IFF_MULTICAST)) | (dev->flags & (IFF_SOFTHEADERS|IFF_UP)); /* * Load in the correct multicast list now the flags have changed. */ dev_mc_upload(dev); /* * Have we downed the interface. We handle IFF_UP ourselves * according to user attempts to set it, rather than blindly * setting it. */ if ((old_flags^ifr.ifr_flags)&IFF_UP) /* Bit is different ? */ { if(old_flags&IFF_UP) /* Gone down */ ret=dev_close(dev); else /* Come up */ { ret=dev_open(dev); if(ret<0) dev->flags&=~IFF_UP; /* Open failed */ } } else ret=0; /* * Load in the correct multicast list now the flags have changed. */ dev_mc_upload(dev); } break; case SIOCGIFADDR: /* Get interface address (and family) */ if(ifr.ifr_addr.sa_family==AF_UNSPEC) { memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); ifr.ifr_hwaddr.sa_family=dev->type; goto rarok; } else { (*(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; } goto rarok; case SIOCSIFADDR: /* Set interface address (and family) */ /* * BSDism. SIOCSIFADDR family=AF_UNSPEC sets the * physical address. We can cope with this now. */ if(ifr.ifr_addr.sa_family==AF_UNSPEC) { if(dev->set_mac_address==NULL) return -EOPNOTSUPP; if(securelevel>0) return -EPERM; ret=dev->set_mac_address(dev,&ifr.ifr_addr); } else { u32 new_pa_addr = (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr; u16 new_family = ifr.ifr_addr.sa_family; if (new_family == dev->family && new_pa_addr == dev->pa_addr) { ret =0; break; } if (dev->flags & IFF_UP) notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); /* * if dev is an alias, must rehash to update * address change */ #ifdef CONFIG_NET_ALIAS if (net_alias_is(dev)) net_alias_dev_rehash(dev ,&ifr.ifr_addr); #endif dev->pa_addr = new_pa_addr; dev->family = new_family; #ifdef CONFIG_INET /* This is naughty. When net-032e comes out It wants moving into the net032 code not the kernel. Till then it can sit here (SIGH) */ if (!dev->pa_mask) dev->pa_mask = ip_get_mask(dev->pa_addr); #endif if (!dev->pa_brdaddr) dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; if (dev->flags & IFF_UP) notifier_call_chain(&netdev_chain, NETDEV_UP, dev); ret = 0; } break; case SIOCGIFBRDADDR: /* Get the broadcast address */ (*(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; goto rarok; case SIOCSIFBRDADDR: /* Set the broadcast address */ dev->pa_brdaddr = (*(struct sockaddr_in *) &ifr.ifr_broadaddr).sin_addr.s_addr; ret = 0; break; case SIOCGIFDSTADDR: /* Get the destination address (for point-to-point links) */ (*(struct sockaddr_in *) &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr; (*(struct sockaddr_in *) &ifr.ifr_dstaddr).sin_family = dev->family; (*(struct sockaddr_in *) &ifr.ifr_dstaddr).sin_port = 0; goto rarok; case SIOCSIFDSTADDR: /* Set the destination address (for point-to-point links) */ dev->pa_dstaddr = (*(struct sockaddr_in *) &ifr.ifr_dstaddr).sin_addr.s_addr; ret = 0; break; case SIOCGIFNETMASK: /* Get the netmask for the interface */ (*(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; goto rarok; case SIOCSIFNETMASK: /* Set the netmask for the interface */ { unsigned long mask = (*(struct sockaddr_in *) &ifr.ifr_netmask).sin_addr.s_addr; ret = -EINVAL; /* * The mask we set must be legal. */ if (bad_mask(mask,0)) break; dev->pa_mask = mask; ret = 0; } break; case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */ ifr.ifr_metric = dev->metric; goto rarok; case SIOCSIFMETRIC: /* Set the metric on the interface (currently unused) */ dev->metric = ifr.ifr_metric; ret=0; break; case SIOCGIFMTU: /* Get the MTU of a device */ ifr.ifr_mtu = dev->mtu; goto rarok; case SIOCSIFMTU: /* Set the MTU of a device */ if (dev->change_mtu) ret = dev->change_mtu(dev, ifr.ifr_mtu); else { /* * MTU must be positive. */ if(ifr.ifr_mtu<68) return -EINVAL; dev->mtu = ifr.ifr_mtu; ret = 0; } break; case SIOCGIFMEM: /* Get the per device memory space. We can add this but currently do not support it */ ret = -EINVAL; break; case SIOCSIFMEM: /* Set the per device memory buffer space. Not applicable in our case */ ret = -EINVAL; break; case SIOCGIFHWADDR: memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); ifr.ifr_hwaddr.sa_family=dev->type; goto rarok; case SIOCSIFHWADDR: if(dev->set_mac_address==NULL) return -EOPNOTSUPP; if(securelevel > 0) return -EPERM; if(ifr.ifr_hwaddr.sa_family!=dev->type) return -EINVAL; ret=dev->set_mac_address(dev,&ifr.ifr_hwaddr); break; case SIOCGIFMAP: ifr.ifr_map.mem_start=dev->mem_start; ifr.ifr_map.mem_end=dev->mem_end; ifr.ifr_map.base_addr=dev->base_addr; ifr.ifr_map.irq=dev->irq; ifr.ifr_map.dma=dev->dma; ifr.ifr_map.port=dev->if_port; goto rarok; case SIOCSIFMAP: if(dev->set_config==NULL) return -EOPNOTSUPP; return dev->set_config(dev,&ifr.ifr_map); case SIOCADDMULTI: if(dev->set_multicast_list==NULL) return -EINVAL; if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC) return -EINVAL; dev_mc_add(dev,ifr.ifr_hwaddr.sa_data, dev->addr_len, 1); return 0; case SIOCDELMULTI: if(dev->set_multicast_list==NULL) return -EINVAL; if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC) return -EINVAL; dev_mc_delete(dev,ifr.ifr_hwaddr.sa_data,dev->addr_len, 1); return 0; /* * Unknown or private ioctl */ default: if((getset >= SIOCDEVPRIVATE) && (getset <= (SIOCDEVPRIVATE + 15))) { if(dev->do_ioctl==NULL) return -EOPNOTSUPP; ret=dev->do_ioctl(dev, &ifr, getset); memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); break; } #ifdef CONFIG_NET_RADIO if((getset >= SIOCIWFIRST) && (getset <= SIOCIWLAST)) { if(dev->do_ioctl==NULL) return -EOPNOTSUPP; /* Perform the ioctl */ ret=dev->do_ioctl(dev, &ifr, getset); /* If return args... */ if(IW_IS_GET(getset)) memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); break; } #endif /* CONFIG_NET_RADIO */ ret = -EINVAL; } return(ret); /* * The load of calls that return an ifreq and ok (saves memory). */ rarok: memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); return 0; }