Example #1
0
static int igmp6_group_dropped(struct ifmcaddr6 *mc)
{
	struct net_device *dev = mc->idev->dev;
	char buf[MAX_ADDR_LEN];
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
#endif

	spin_lock_bh(&mc->mca_lock);
#ifdef CONFIG_IPV6_MLD6_DEBUG
	in6_ntop(&mc->mca_addr, abuf);
	MDBG3((KERN_DEBUG
		"igmp6_group_dropped(mc=%p): mca_addr=%s, flag=%08x\n", 
		mc, abuf, mc->mca_flags));
#endif
	if (mc->mca_flags&MAF_LOADED) {
		mc->mca_flags &= ~MAF_LOADED;
		if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)
			dev_mc_delete(dev, buf, dev->addr_len, 0);
	}
	spin_unlock_bh(&mc->mca_lock);

	if (dev->flags&IFF_UP)
		igmp6_leave_group(mc);
	return 0;
}
Example #2
0
void ip_mc_filter_del(struct device *dev, unsigned long addr)
{
	char buf[6];
	if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_FDDI)
		return; /* Only do ethernet or FDDI for now */
	ip_mc_map(addr,buf);
	dev_mc_delete(dev,buf,ETH_ALEN,0);
}
Example #3
0
static void ip_mc_filter_del(struct in_device *in_dev, u32 addr)
{
	char buf[MAX_ADDR_LEN];
	struct device *dev = in_dev->dev;

	if (arp_mc_map(addr, buf, dev, 0) == 0)
		dev_mc_delete(dev,buf,dev->addr_len,0);
}
Example #4
0
static int igmp6_group_dropped(struct ifmcaddr6 *mc)
{
	char buf[MAX_ADDR_LEN];

	if (mc->mca_flags&MAF_LOADED) {
		mc->mca_flags &= ~MAF_LOADED;
		if (ndisc_mc_map(&mc->mca_addr, buf, mc->dev, 0) == 0)
			dev_mc_delete(mc->dev, buf, mc->dev->addr_len, 0);
	}

	if (mc->dev->flags&IFF_UP)
		igmp6_leave_group(mc);
	return 0;
}
Example #5
0
static int igmp6_group_dropped(struct ifmcaddr6 *mc)
{
	struct net_device *dev = mc->idev->dev;
	char buf[MAX_ADDR_LEN];

	spin_lock_bh(&mc->mca_lock);
	if (mc->mca_flags&MAF_LOADED) {
		mc->mca_flags &= ~MAF_LOADED;
		if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)
			dev_mc_delete(dev, buf, dev->addr_len, 0);
	}
	spin_unlock_bh(&mc->mca_lock);

	if (dev->flags&IFF_UP)
		igmp6_leave_group(mc);
	return 0;
}
Example #6
0
static void packet_dev_mc(struct net_device *dev, struct packet_mclist *i, int what)
{
	switch (i->type) {
	case PACKET_MR_MULTICAST:
		if (what > 0)
			dev_mc_add(dev, i->addr, i->alen, 0);
		else
			dev_mc_delete(dev, i->addr, i->alen, 0);
		break;
	case PACKET_MR_PROMISC:
		dev_set_promiscuity(dev, what);
		break;
	case PACKET_MR_ALLMULTI:
		dev_set_allmulti(dev, what);
		break;
	default:;
	}
}
static void vlan_flush_mc_list(struct net_device *dev)
{
	struct dev_mc_list *dmi = dev->mc_list;

	while (dmi) {
		printk(KERN_DEBUG "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from vlan interface\n",
		       dev->name,
		       dmi->dmi_addr[0],
		       dmi->dmi_addr[1],
		       dmi->dmi_addr[2],
		       dmi->dmi_addr[3],
		       dmi->dmi_addr[4],
		       dmi->dmi_addr[5]);
		dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
		dmi = dev->mc_list;
	}

	/* dev->mc_list is NULL by the time we get here. */
	vlan_destroy_mc_list(VLAN_DEV_INFO(dev)->old_mc_list);
	VLAN_DEV_INFO(dev)->old_mc_list = NULL;
}
Example #8
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);
}
/** Taken from Gleb + Lennert's VLAN code, and modified... */
void vlan_dev_set_multicast_list(struct net_device *vlan_dev)
{
	struct dev_mc_list *dmi;
	struct net_device *real_dev;
	int inc;

	if (vlan_dev && (vlan_dev->priv_flags & IFF_802_1Q_VLAN)) {
		/* Then it's a real vlan device, as far as we can tell.. */
		real_dev = VLAN_DEV_INFO(vlan_dev)->real_dev;

		/* compare the current promiscuity to the last promisc we had.. */
		inc = vlan_dev->promiscuity - VLAN_DEV_INFO(vlan_dev)->old_promiscuity;
		if (inc) {
			printk(KERN_INFO "%s: dev_set_promiscuity(master, %d)\n",
			       vlan_dev->name, inc);
			dev_set_promiscuity(real_dev, inc); /* found in dev.c */
			VLAN_DEV_INFO(vlan_dev)->old_promiscuity = vlan_dev->promiscuity;
		}

		inc = vlan_dev->allmulti - VLAN_DEV_INFO(vlan_dev)->old_allmulti;
		if (inc) {
			printk(KERN_INFO "%s: dev_set_allmulti(master, %d)\n",
			       vlan_dev->name, inc);
			dev_set_allmulti(real_dev, inc); /* dev.c */
			VLAN_DEV_INFO(vlan_dev)->old_allmulti = vlan_dev->allmulti;
		}

		/* looking for addresses to add to master's list */
		for (dmi = vlan_dev->mc_list; dmi != NULL; dmi = dmi->next) {
			if (vlan_should_add_mc(dmi, VLAN_DEV_INFO(vlan_dev)->old_mc_list)) {
				dev_mc_add(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
				printk(KERN_DEBUG "%s: add %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address to master interface\n",
				       vlan_dev->name,
				       dmi->dmi_addr[0],
				       dmi->dmi_addr[1],
				       dmi->dmi_addr[2],
				       dmi->dmi_addr[3],
				       dmi->dmi_addr[4],
				       dmi->dmi_addr[5]);
			}
		}

		/* looking for addresses to delete from master's list */
		for (dmi = VLAN_DEV_INFO(vlan_dev)->old_mc_list; dmi != NULL; dmi = dmi->next) {
			if (vlan_should_add_mc(dmi, vlan_dev->mc_list)) {
				/* if we think we should add it to the new list, then we should really
				 * delete it from the real list on the underlying device.
				 */
				dev_mc_delete(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
				printk(KERN_DEBUG "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n",
				       vlan_dev->name,
				       dmi->dmi_addr[0],
				       dmi->dmi_addr[1],
				       dmi->dmi_addr[2],
				       dmi->dmi_addr[3],
				       dmi->dmi_addr[4],
				       dmi->dmi_addr[5]);
			}
		}

		/* save multicast list */
		vlan_copy_mc_list(vlan_dev->mc_list, VLAN_DEV_INFO(vlan_dev));
	}
}
Example #10
0
File: dev.c Project: 0xffea/gnumach
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;
}