Merge from vendor branch SENDMAIL:
[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.6 2005/02/01 00:51:50 joerg 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(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 (((struct ifaddr *)arg)->ifa_addr->sa_family != AF_INET)
154                         break;
155
156                 /*
157                  * Make sure i/f is there
158                  */
159                 ia = (struct in_ifaddr *)arg;
160                 if (inp == NULL)
161                         panic("ipatm_nifstat: setaddr missing ip_nif");
162
163                 /*
164                  * Process new address
165                  */
166                 switch (inp->inf_state) {
167
168                 case IPNIF_SIGMGR:
169                 case IPNIF_ADDR:
170                         inp->inf_addr = ia;
171
172                         /*
173                          * If signalling manager is not set, wait for it
174                          */
175                         sip = nip->nif_pif->pif_siginst;
176                         if (sip == NULL) {
177                                 inp->inf_state = IPNIF_SIGMGR;
178                                 break;
179                         }
180
181                         /*
182                          * Otherwise, everything's set
183                          */
184                         inp->inf_state = IPNIF_ACTIVE;
185
186                         /*
187                          * Tell interface service we're around
188                          */
189                         if (sip->si_ipserv) {
190                                 inp->inf_serv = sip->si_ipserv;
191                                 err = (*inp->inf_serv->is_ifact)(inp);
192                         }
193
194                         /*
195                          * Reset state if there's been a problem
196                          */
197                         if (err) {
198                                 inp->inf_serv = NULL;
199                                 inp->inf_addr = NULL;
200                                 inp->inf_state = IPNIF_ADDR;
201                         }
202                         break;
203
204                 case IPNIF_ACTIVE:
205                         /*
206                          * We dont support an address change
207                          */
208                         err = EEXIST;
209                         break;
210                 }
211                 break;
212
213         case NCM_SIGATTACH:
214                 /*
215                  * Make sure i/f is attached
216                  */
217                 if (inp == NULL) {
218                         err = ENODEV;
219                         break;
220                 }
221
222                 /*
223                  * Are we waiting for the sigmgr attach??
224                  */
225                 if (inp->inf_state != IPNIF_SIGMGR) {
226                         /*
227                          * No, nothing else to do
228                          */
229                         break;
230                 }
231
232                 /*
233                  * OK, everything's set
234                  */
235                 inp->inf_state = IPNIF_ACTIVE;
236
237                 /*
238                  * Tell interface service we're around
239                  */
240                 sip = nip->nif_pif->pif_siginst;
241                 if (sip->si_ipserv) {
242                         inp->inf_serv = sip->si_ipserv;
243                         err = (*inp->inf_serv->is_ifact)(inp);
244                 }
245
246                 /*
247                  * Just report any problems, since a NCM_SIGDETACH will
248                  * be coming down immediately
249                  */
250                 break;
251
252         case NCM_SIGDETACH:
253                 /*
254                  * Make sure i/f is attached
255                  */
256                 if (inp == NULL) {
257                         err = ENODEV;
258                         break;
259                 }
260
261                 /*
262                  * Are we currently active??
263                  */
264                 if (inp->inf_state != IPNIF_ACTIVE) {
265                         /*
266                          * No, nothing else to do
267                          */
268                         break;
269                 }
270
271                 /*
272                  * Close all the IP VCCs for this interface
273                  */
274                 ipatm_closenif(inp);
275
276                 /*
277                  * Tell interface service that i/f has gone down
278                  */
279                 if (inp->inf_serv)
280                         (void) (*inp->inf_serv->is_ifdact)(inp);
281
282                 /*
283                  * Just have to wait for another sigattach
284                  */
285                 inp->inf_serv = NULL;
286                 inp->inf_state = IPNIF_SIGMGR;
287                 break;
288
289         default:
290                 log(LOG_ERR, "ipatm_nifstat: unknown command %d\n", cmd);
291         }
292
293         return (err);
294 }
295
296
297 /*
298  * Close all VCCs on a Network Interface
299  * 
300  * Called at splnet.
301  *
302  * Arguments:
303  *      inp     pointer to IP network interface
304  *
305  * Returns:
306  *      none
307  *
308  */
309 static void
310 ipatm_closenif(inp)
311         struct ip_nif   *inp;
312 {
313         struct ipvcc    *ivp, *inext;
314
315         /*
316          * Close each IP VCC on this interface
317          */
318         for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; ivp = inext) {
319
320                 inext = Q_NEXT(ivp, struct ipvcc, iv_elem);
321
322                 (void) ipatm_closevc(ivp, T_ATM_CAUSE_UNSPECIFIED_NORMAL);
323         }
324 }
325