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