]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/netatm/ipatm/ipatm_if.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / 6 / sys / netatm / ipatm / ipatm_if.c
1 /*-
2  * ===================================
3  * HARP  |  Host ATM Research Platform
4  * ===================================
5  *
6  *
7  * This Host ATM Research Platform ("HARP") file (the "Software") is
8  * made available by Network Computing Services, Inc. ("NetworkCS")
9  * "AS IS".  NetworkCS does not provide maintenance, improvements or
10  * support of any kind.
11  *
12  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
13  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
14  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
15  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
16  * In no event shall NetworkCS be responsible for any damages, including
17  * but not limited to consequential damages, arising from or relating to
18  * any use of the Software or related support.
19  *
20  * Copyright 1994-1998 Network Computing Services, Inc.
21  *
22  * Copies of this Software may be made, however, the above copyright
23  * notice must be reproduced on all copies.
24  */
25
26 /*
27  * IP Over ATM Support
28  * -------------------
29  *
30  * Interface Manager
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/systm.h>
39 #include <sys/errno.h>
40 #include <sys/time.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/syslog.h>
44 #include <sys/malloc.h>
45 #include <sys/kernel.h>
46 #include <net/if.h>
47 #include <netinet/in.h>
48 #include <netatm/port.h>
49 #include <netatm/queue.h>
50 #include <netatm/atm.h>
51 #include <netatm/atm_sys.h>
52 #include <netatm/atm_sap.h>
53 #include <netatm/atm_cm.h>
54 #include <netatm/atm_if.h>
55 #include <netatm/atm_sigmgr.h>
56 #include <netatm/atm_stack.h>
57 #include <netatm/atm_pcb.h>
58 #include <netatm/atm_var.h>
59
60 #include <netatm/ipatm/ipatm_var.h>
61 #include <netatm/ipatm/ipatm_serv.h>
62
63 static MALLOC_DEFINE(M_IPATM_NIF, "ipatm nif", "IP/ATM network interfaces");
64
65 /*
66  * Local functions
67  */
68 static void     ipatm_closenif(struct ip_nif *);
69
70
71 /*
72  * Process Network Interface status change
73  * 
74  * Called whenever a network interface status change is requested.
75  *
76  * Called at splnet.
77  *
78  * Arguments:
79  *      cmd     command code
80  *      nip     pointer to atm network interface control block
81  *      arg     command specific parameter
82  *
83  * Returns:
84  *      0       command successful
85  *      errno   command failed - reason indicated
86  *
87  */
88 int
89 ipatm_nifstat(cmd, nip, arg)
90         int             cmd;
91         struct atm_nif  *nip;
92         intptr_t        arg;
93 {
94         struct in_ifaddr        *ia;
95         struct siginst          *sip;
96         struct ip_nif           *inp;
97         int     err = 0;
98
99         /*
100          * Look for corresponding IP interface
101          */
102         for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
103                 if (inp->inf_nif == nip)
104                         break;
105         }
106
107         /*
108          * Process command
109          */
110         switch (cmd) {
111
112         case NCM_ATTACH:
113                 /*
114                  * Make sure i/f isn't already attached
115                  */
116                 if (inp != NULL) {
117                         err = EEXIST;
118                         break;
119                 }
120
121                 /*
122                  * Get a new interface block
123                  */
124                 inp = malloc(sizeof(*inp), M_IPATM_NIF, M_WAITOK | M_ZERO);
125                 inp->inf_nif = nip;
126                 inp->inf_state = IPNIF_ADDR;
127                 inp->inf_arpnotify = ipatm_arpnotify;
128                 inp->inf_ipinput = ipatm_ipinput;
129                 inp->inf_createsvc = ipatm_createsvc;
130                 LINK2TAIL(inp, struct ip_nif, ipatm_nif_head, inf_next);
131                 break;
132
133         case NCM_DETACH:
134                 /*
135                  * Make sure i/f is attached
136                  */
137                 if (inp == NULL) {
138                         err = ENODEV;
139                         break;
140                 }
141
142                 /*
143                  * Validate interface stuff
144                  */
145                 if (Q_HEAD(inp->inf_vcq, struct ipvcc))
146                         panic("ipatm_nifstat: ipvcc queue not empty");
147
148                 /*
149                  * If we're active, close all our VCCs and tell the
150                  * interface service about the deactivation
151                  */
152                 if (inp->inf_state == IPNIF_ACTIVE) {
153
154                         ipatm_closenif(inp);
155
156                         if (inp->inf_serv)
157                                 (void) (*inp->inf_serv->is_ifdact)(inp);
158                 }
159
160                 /*
161                  * Clean up and free block
162                  */
163                 UNLINK(inp, struct ip_nif, ipatm_nif_head, inf_next);
164                 free(inp, M_IPATM_NIF);
165                 break;
166
167         case NCM_SETADDR:
168                 /*
169                  * We only care about IP addresses
170                  */
171                 if (((struct ifaddr *)arg)->ifa_addr->sa_family != AF_INET)
172                         break;
173
174                 /*
175                  * Make sure i/f is there
176                  */
177                 ia = (struct in_ifaddr *)arg;
178                 if (inp == NULL)
179                         panic("ipatm_nifstat: setaddr missing ip_nif");
180
181                 /*
182                  * Process new address
183                  */
184                 switch (inp->inf_state) {
185
186                 case IPNIF_SIGMGR:
187                 case IPNIF_ADDR:
188                         inp->inf_addr = ia;
189
190                         /*
191                          * If signalling manager is not set, wait for it
192                          */
193                         sip = nip->nif_pif->pif_siginst;
194                         if (sip == NULL) {
195                                 inp->inf_state = IPNIF_SIGMGR;
196                                 break;
197                         }
198
199                         /*
200                          * Otherwise, everything's set
201                          */
202                         inp->inf_state = IPNIF_ACTIVE;
203
204                         /*
205                          * Tell interface service we're around
206                          */
207                         if (sip->si_ipserv) {
208                                 inp->inf_serv = sip->si_ipserv;
209                                 err = (*inp->inf_serv->is_ifact)(inp);
210                         }
211
212                         /*
213                          * Reset state if there's been a problem
214                          */
215                         if (err) {
216                                 inp->inf_serv = NULL;
217                                 inp->inf_addr = NULL;
218                                 inp->inf_state = IPNIF_ADDR;
219                         }
220                         break;
221
222                 case IPNIF_ACTIVE:
223                         /*
224                          * We dont support an address change
225                          */
226                         err = EEXIST;
227                         break;
228                 }
229                 break;
230
231         case NCM_SIGATTACH:
232                 /*
233                  * Make sure i/f is attached
234                  */
235                 if (inp == NULL) {
236                         err = ENODEV;
237                         break;
238                 }
239
240                 /*
241                  * Are we waiting for the sigmgr attach??
242                  */
243                 if (inp->inf_state != IPNIF_SIGMGR) {
244                         /*
245                          * No, nothing else to do
246                          */
247                         break;
248                 }
249
250                 /*
251                  * OK, everything's set
252                  */
253                 inp->inf_state = IPNIF_ACTIVE;
254
255                 /*
256                  * Tell interface service we're around
257                  */
258                 sip = nip->nif_pif->pif_siginst;
259                 if (sip->si_ipserv) {
260                         inp->inf_serv = sip->si_ipserv;
261                         err = (*inp->inf_serv->is_ifact)(inp);
262                 }
263
264                 /*
265                  * Just report any problems, since a NCM_SIGDETACH will
266                  * be coming down immediately
267                  */
268                 break;
269
270         case NCM_SIGDETACH:
271                 /*
272                  * Make sure i/f is attached
273                  */
274                 if (inp == NULL) {
275                         err = ENODEV;
276                         break;
277                 }
278
279                 /*
280                  * Are we currently active??
281                  */
282                 if (inp->inf_state != IPNIF_ACTIVE) {
283                         /*
284                          * No, nothing else to do
285                          */
286                         break;
287                 }
288
289                 /*
290                  * Close all the IP VCCs for this interface
291                  */
292                 ipatm_closenif(inp);
293
294                 /*
295                  * Tell interface service that i/f has gone down
296                  */
297                 if (inp->inf_serv)
298                         (void) (*inp->inf_serv->is_ifdact)(inp);
299
300                 /*
301                  * Just have to wait for another sigattach
302                  */
303                 inp->inf_serv = NULL;
304                 inp->inf_state = IPNIF_SIGMGR;
305                 break;
306
307         default:
308                 log(LOG_ERR, "ipatm_nifstat: unknown command %d\n", cmd);
309         }
310
311         return (err);
312 }
313
314
315 /*
316  * Close all VCCs on a Network Interface
317  * 
318  * Called at splnet.
319  *
320  * Arguments:
321  *      inp     pointer to IP network interface
322  *
323  * Returns:
324  *      none
325  *
326  */
327 static void
328 ipatm_closenif(inp)
329         struct ip_nif   *inp;
330 {
331         struct ipvcc    *ivp, *inext;
332
333         /*
334          * Close each IP VCC on this interface
335          */
336         for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; ivp = inext) {
337
338                 inext = Q_NEXT(ivp, struct ipvcc, iv_elem);
339
340                 (void) ipatm_closevc(ivp, T_ATM_CAUSE_UNSPECIFIED_NORMAL);
341         }
342 }
343