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