Initial import from FreeBSD RELENG_4:
[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  *
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 <netatm/ipatm/ipatm_var.h>
41 #include <netatm/ipatm/ipatm_serv.h>
42
43 #ifndef lint
44 __RCSID("@(#) $FreeBSD: src/sys/netatm/ipatm/ipatm_if.c,v 1.4 2000/01/17 20:49:43 mks Exp $");
45 #endif
46
47
48 /*
49  * Local functions
50  */
51 static void     ipatm_closenif __P((struct ip_nif *));
52
53
54 /*
55  * Process Network Interface status change
56  * 
57  * Called whenever a network interface status change is requested.
58  *
59  * Called at splnet.
60  *
61  * Arguments:
62  *      cmd     command code
63  *      nip     pointer to atm network interface control block
64  *      arg     command specific parameter
65  *
66  * Returns:
67  *      0       command successful
68  *      errno   command failed - reason indicated
69  *
70  */
71 int
72 ipatm_nifstat(cmd, nip, arg)
73         int             cmd;
74         struct atm_nif  *nip;
75         int             arg;
76 {
77         struct in_ifaddr        *ia;
78         struct siginst          *sip;
79         struct ip_nif           *inp;
80         int     err = 0;
81
82         /*
83          * Look for corresponding IP interface
84          */
85         for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
86                 if (inp->inf_nif == nip)
87                         break;
88         }
89
90         /*
91          * Process command
92          */
93         switch (cmd) {
94
95         case NCM_ATTACH:
96                 /*
97                  * Make sure i/f isn't already attached
98                  */
99                 if (inp != NULL) {
100                         err = EEXIST;
101                         break;
102                 }
103
104                 /*
105                  * Get a new interface block
106                  */
107                 inp = (struct ip_nif *)atm_allocate(&ipatm_nifpool);
108                 if (inp == NULL) {
109                         err = ENOMEM;
110                         break;
111                 }
112                 inp->inf_nif = nip;
113                 inp->inf_state = IPNIF_ADDR;
114                 inp->inf_arpnotify = ipatm_arpnotify;
115                 inp->inf_ipinput = ipatm_ipinput;
116                 inp->inf_createsvc = ipatm_createsvc;
117                 LINK2TAIL(inp, struct ip_nif, ipatm_nif_head, inf_next);
118                 break;
119
120         case NCM_DETACH:
121                 /*
122                  * Make sure i/f is attached
123                  */
124                 if (inp == NULL) {
125                         err = ENODEV;
126                         break;
127                 }
128
129                 /*
130                  * Validate interface stuff
131                  */
132                 if (Q_HEAD(inp->inf_vcq, struct ipvcc))
133                         panic("ipatm_nifstat: ipvcc queue not empty");
134
135                 /*
136                  * If we're active, close all our VCCs and tell the
137                  * interface service about the deactivation
138                  */
139                 if (inp->inf_state == IPNIF_ACTIVE) {
140
141                         ipatm_closenif(inp);
142
143                         if (inp->inf_serv)
144                                 (void) (*inp->inf_serv->is_ifdact)(inp);
145                 }
146
147                 /*
148                  * Clean up and free block
149                  */
150                 UNLINK(inp, struct ip_nif, ipatm_nif_head, inf_next);
151                 atm_free((caddr_t)inp);
152                 break;
153
154         case NCM_SETADDR:
155                 /*
156                  * We only care about IP addresses
157                  */
158 #if (defined(BSD) && (BSD >= 199103))
159                 if (((struct ifaddr *)arg)->ifa_addr->sa_family != AF_INET)
160 #else
161                 if (((struct ifaddr *)arg)->ifa_addr.sa_family != AF_INET)
162 #endif
163                         break;
164
165                 /*
166                  * Make sure i/f is there
167                  */
168                 ia = (struct in_ifaddr *)arg;
169                 if (inp == NULL)
170                         panic("ipatm_nifstat: setaddr missing ip_nif");
171
172                 /*
173                  * Process new address
174                  */
175                 switch (inp->inf_state) {
176
177                 case IPNIF_SIGMGR:
178                 case IPNIF_ADDR:
179                         inp->inf_addr = ia;
180
181                         /*
182                          * If signalling manager is not set, wait for it
183                          */
184                         sip = nip->nif_pif->pif_siginst;
185                         if (sip == NULL) {
186                                 inp->inf_state = IPNIF_SIGMGR;
187                                 break;
188                         }
189
190                         /*
191                          * Otherwise, everything's set
192                          */
193                         inp->inf_state = IPNIF_ACTIVE;
194
195                         /*
196                          * Tell interface service we're around
197                          */
198                         if (sip->si_ipserv) {
199                                 inp->inf_serv = sip->si_ipserv;
200                                 err = (*inp->inf_serv->is_ifact)(inp);
201                         }
202
203                         /*
204                          * Reset state if there's been a problem
205                          */
206                         if (err) {
207                                 inp->inf_serv = NULL;
208                                 inp->inf_addr = NULL;
209                                 inp->inf_state = IPNIF_ADDR;
210                         }
211                         break;
212
213                 case IPNIF_ACTIVE:
214                         /*
215                          * We dont support an address change
216                          */
217                         err = EEXIST;
218                         break;
219                 }
220                 break;
221
222         case NCM_SIGATTACH:
223                 /*
224                  * Make sure i/f is attached
225                  */
226                 if (inp == NULL) {
227                         err = ENODEV;
228                         break;
229                 }
230
231                 /*
232                  * Are we waiting for the sigmgr attach??
233                  */
234                 if (inp->inf_state != IPNIF_SIGMGR) {
235                         /*
236                          * No, nothing else to do
237                          */
238                         break;
239                 }
240
241                 /*
242                  * OK, everything's set
243                  */
244                 inp->inf_state = IPNIF_ACTIVE;
245
246                 /*
247                  * Tell interface service we're around
248                  */
249                 sip = nip->nif_pif->pif_siginst;
250                 if (sip->si_ipserv) {
251                         inp->inf_serv = sip->si_ipserv;
252                         err = (*inp->inf_serv->is_ifact)(inp);
253                 }
254
255                 /*
256                  * Just report any problems, since a NCM_SIGDETACH will
257                  * be coming down immediately
258                  */
259                 break;
260
261         case NCM_SIGDETACH:
262                 /*
263                  * Make sure i/f is attached
264                  */
265                 if (inp == NULL) {
266                         err = ENODEV;
267                         break;
268                 }
269
270                 /*
271                  * Are we currently active??
272                  */
273                 if (inp->inf_state != IPNIF_ACTIVE) {
274                         /*
275                          * No, nothing else to do
276                          */
277                         break;
278                 }
279
280                 /*
281                  * Close all the IP VCCs for this interface
282                  */
283                 ipatm_closenif(inp);
284
285                 /*
286                  * Tell interface service that i/f has gone down
287                  */
288                 if (inp->inf_serv)
289                         (void) (*inp->inf_serv->is_ifdact)(inp);
290
291                 /*
292                  * Just have to wait for another sigattach
293                  */
294                 inp->inf_serv = NULL;
295                 inp->inf_state = IPNIF_SIGMGR;
296                 break;
297
298         default:
299                 log(LOG_ERR, "ipatm_nifstat: unknown command %d\n", cmd);
300         }
301
302         return (err);
303 }
304
305
306 /*
307  * Close all VCCs on a Network Interface
308  * 
309  * Called at splnet.
310  *
311  * Arguments:
312  *      inp     pointer to IP network interface
313  *
314  * Returns:
315  *      none
316  *
317  */
318 static void
319 ipatm_closenif(inp)
320         struct ip_nif   *inp;
321 {
322         struct ipvcc    *ivp, *inext;
323
324         /*
325          * Close each IP VCC on this interface
326          */
327         for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; ivp = inext) {
328
329                 inext = Q_NEXT(ivp, struct ipvcc, iv_elem);
330
331                 (void) ipatm_closevc(ivp, T_ATM_CAUSE_UNSPECIFIED_NORMAL);
332         }
333 }
334