import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / arch / ia64 / sn / io / drivers / ifconfig_net.c
1 /* $Id: ifconfig_net.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $
2  *
3  * This file is subject to the terms and conditions of the GNU General Public
4  * License.  See the file "COPYING" in the main directory of this archive
5  * for more details.
6  *
7  *  ifconfig_net - SGI's Persistent Network Device names.
8  *
9  * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc.  All rights reserved.
10  */
11
12 #include <linux/types.h>
13 #include <linux/config.h>
14 #include <linux/slab.h>
15 #include <linux/ctype.h>
16 #include <linux/module.h>
17 #include <linux/init.h>
18
19 #include <linux/pci.h>
20 #include <linux/netdevice.h>
21 #include <linux/etherdevice.h>
22 #include <linux/skbuff.h>
23
24 #include <asm/sn/sgi.h>
25 #include <asm/uaccess.h>
26 #include <linux/devfs_fs.h>
27 #include <linux/devfs_fs_kernel.h>
28 #include <asm/io.h>
29 #include <asm/sn/iograph.h>
30 #include <asm/sn/invent.h>
31 #include <asm/sn/hcl.h>
32 #include <asm/sn/labelcl.h>
33 #include <asm/sn/ifconfig_net.h>
34
35 #define SGI_IFCONFIG_NET "SGI-PERSISTENT NETWORK DEVICE NAME DRIVER"
36 #define SGI_IFCONFIG_NET_VERSION "1.0"
37
38 /*
39  * Some Global definitions.
40  */
41 static vertex_hdl_t ifconfig_net_handle;
42 static unsigned long ifconfig_net_debug;
43 static struct ifname_MAC *new_devices;
44 static struct ifname_num *ifname_num;
45
46
47 /*
48  * ifconfig_net_open - Opens the special device node "/devhw/.ifconfig_net".
49  */
50 static int ifconfig_net_open(struct inode * inode, struct file * filp)
51 {
52         if (ifconfig_net_debug) {
53                 printk("ifconfig_net_open called.\n");
54         }
55
56         return(0);
57
58 }
59
60 /*
61  * ifconfig_net_close - Closes the special device node "/devhw/.ifconfig_net".
62  */
63 static int ifconfig_net_close(struct inode * inode, struct file * filp)
64 {
65
66         if (ifconfig_net_debug) {
67                 printk("ifconfig_net_close called.\n");
68         }
69
70         return(0);
71 }
72
73 /*
74  * assign_ifname - Assign the next available interface name from the persistent list.
75  */
76 void
77 assign_ifname(struct net_device *dev,
78                   struct ifname_num *ifname_num)
79
80 {
81
82         /*
83          * Handle eth devices.
84          */
85         if ( (memcmp(dev->name, "eth", 3) == 0) ) {
86                 if (ifname_num->next_eth != -1) {
87                         /*
88                          * Assign it the next available eth interface number. 
89                          */
90                         memset(dev->name, 0, strlen(dev->name));
91                         sprintf(dev->name, "eth%d", (int)ifname_num->next_eth);
92                         ifname_num->next_eth++;
93                 } 
94
95                 return;
96         }
97
98         /*
99          * Handle fddi devices.
100          */
101         if ( (memcmp(dev->name, "fddi", 4) == 0) ) {
102                 if (ifname_num->next_fddi != -1) {
103                         /*
104                          * Assign it the next available fddi interface number.
105                          */
106                         memset(dev->name, 0, strlen(dev->name));
107                         sprintf(dev->name, "fddi%d", (int)ifname_num->next_fddi);
108                         ifname_num->next_fddi++;
109                 }
110
111                 return;
112         }
113
114         /*
115          * Handle hip devices.
116          */
117         if ( (memcmp(dev->name, "hip", 3) == 0) ) {
118                 if (ifname_num->next_hip != -1) {
119                         /*
120                          * Assign it the next available hip interface number.
121                          */
122                         memset(dev->name, 0, strlen(dev->name));
123                         sprintf(dev->name, "hip%d", (int)ifname_num->next_hip);
124                         ifname_num->next_hip++;
125                 }
126
127                 return;
128         }
129
130         /*
131          * Handle tr devices.
132          */
133         if ( (memcmp(dev->name, "tr", 2) == 0) ) {
134                 if (ifname_num->next_tr != -1) {
135                         /*
136                          * Assign it the next available tr interface number.
137                          */
138                         memset(dev->name, 0, strlen(dev->name));
139                         sprintf(dev->name, "tr%d", (int)ifname_num->next_tr);
140                         ifname_num->next_tr++;
141                 }
142
143                 return;
144         }
145
146         /*
147          * Handle fc devices.
148          */
149         if ( (memcmp(dev->name, "fc", 2) == 0) ) {
150                 if (ifname_num->next_fc != -1) {
151                         /*
152                          * Assign it the next available fc interface number.
153                          */
154                         memset(dev->name, 0, strlen(dev->name));
155                         sprintf(dev->name, "fc%d", (int)ifname_num->next_fc);
156                         ifname_num->next_fc++;
157                 }
158
159                 return;
160         }
161 }
162
163 /*
164  * find_persistent_ifname: Returns the entry that was seen in previous boot.
165  */
166 struct ifname_MAC *
167 find_persistent_ifname(struct net_device *dev,
168         struct ifname_MAC *ifname_MAC)
169
170 {
171
172         while (ifname_MAC->addr_len) {
173                 if (memcmp(dev->dev_addr, ifname_MAC->dev_addr, dev->addr_len) == 0)
174                         return(ifname_MAC);
175
176                 ifname_MAC++;
177         }
178
179         return(NULL);
180 }
181
182 /*
183  * ifconfig_net_ioctl: ifconfig_net driver ioctl interface.
184  */
185 static int ifconfig_net_ioctl(struct inode * inode, struct file * file,
186         unsigned int cmd, unsigned long arg)
187 {
188
189         extern struct net_device *__dev_get_by_name(const char *);
190 #ifdef CONFIG_NET
191         struct net_device *dev;
192         struct ifname_MAC *found;
193         char temp[64];
194 #endif
195         struct ifname_MAC *ifname_MAC;
196         struct ifname_MAC *temp_new_devices;
197         unsigned long size;
198
199
200         if (ifconfig_net_debug) {
201                 printk("HCL: hcl_ioctl called.\n");
202         }
203
204         /*
205          * Read in the header and see how big of a buffer we really need to 
206          * allocate.
207          */
208         ifname_num = (struct ifname_num *) kmalloc(sizeof(struct ifname_num), 
209                         GFP_KERNEL);
210         if (copy_from_user( ifname_num, (char *) arg, sizeof(struct ifname_num)))
211                 return -EFAULT;
212         size = ifname_num->size;
213         kfree(ifname_num);
214         ifname_num = (struct ifname_num *) kmalloc(size, GFP_KERNEL);
215         if (ifname_num <= 0)
216                 return -ENOMEM;
217         ifname_MAC = (struct ifname_MAC *) ((char *)ifname_num + (sizeof(struct ifname_num)) );
218
219         if (copy_from_user( ifname_num, (char *) arg, size)){
220                 kfree(ifname_num);
221                 return -EFAULT;
222         }
223         new_devices =  kmalloc(size - sizeof(struct ifname_num), GFP_KERNEL);
224         if (new_devices <= 0){
225                 kfree(ifname_num);
226                 return -ENOMEM;
227         }
228         temp_new_devices = new_devices;
229
230         memset(new_devices, 0, size - sizeof(struct ifname_num));
231
232 #ifdef CONFIG_NET
233         /*
234          * Go through the net device entries and make them persistent!
235          */
236         for (dev = dev_base; dev != NULL; dev = dev->next) {
237                 /*
238                  * Skip NULL entries or "lo"
239                  */
240                 if ( (dev->addr_len == 0) || ( !strncmp(dev->name, "lo", strlen(dev->name))) ){
241                         continue;
242                 }
243
244                 /*
245                  * See if we have a persistent interface name for this device.
246                  */
247                 found = NULL;
248                 found = find_persistent_ifname(dev, ifname_MAC);
249                 if (found) {
250                         strcpy(dev->name, found->name);
251                 } else {
252                         /* Never seen this before .. */
253                         assign_ifname(dev, ifname_num);
254
255                         /* 
256                          * Save the information for the next boot.
257                          */
258                         sprintf(temp,"%s %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
259                                 dev->dev_addr[0],  dev->dev_addr[1],  dev->dev_addr[2],
260                                 dev->dev_addr[3],  dev->dev_addr[4],  dev->dev_addr[5]);
261                         strcpy(temp_new_devices->name, dev->name);
262                         temp_new_devices->addr_len = dev->addr_len;
263                         memcpy(temp_new_devices->dev_addr, dev->dev_addr, dev->addr_len);
264                         temp_new_devices++;
265                 }
266                 
267         }
268 #endif
269
270         /*
271          * Copy back to the User Buffer area any new devices encountered.
272          */
273         kfree(new_devices);
274         return copy_to_user((char *)arg + (sizeof(struct ifname_num)), new_devices, 
275                         size - sizeof(struct ifname_num))?-EFAULT:0;
276
277
278 }
279
280 struct file_operations ifconfig_net_fops = {
281         ioctl:ifconfig_net_ioctl,       /* ioctl */
282         open:ifconfig_net_open,         /* open */
283         release:ifconfig_net_close      /* release */
284 };
285
286
287 /*
288  * init_ifconfig_net() - Boot time initialization.  Ensure that it is called 
289  *      after devfs has been initialized.
290  *
291  */
292 #ifdef MODULE
293 int init_module (void)
294 #else
295 int __init init_ifconfig_net(void)
296 #endif
297 {
298         ifconfig_net_handle = NULL;
299         ifconfig_net_handle = hwgraph_register(hwgraph_root, ".ifconfig_net",
300                         0, DEVFS_FL_AUTO_DEVNUM,
301                         0, 0,
302                         S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
303                         &ifconfig_net_fops, NULL);
304
305         if (ifconfig_net_handle == NULL) {
306                 panic("Unable to create SGI PERSISTENT NETWORK DEVICE Name Driver.\n");
307         }
308
309         return(0);
310
311 }