1cbe86d393b80f2c71edebdd2c19d9344381d89c
[dragonfly.git] / sys / netproto / atm / ipatm / ipatm_event.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_event.c,v 1.4 1999/08/28 00:48:43 peter Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/ipatm/ipatm_event.c,v 1.3 2003/08/07 21:17:34 dillon Exp $
28  */
29
30 /*
31  * IP Over ATM Support
32  * -------------------
33  *
34  * IP VCC event handler
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
40 #include "ipatm.h"
41 #include "ipatm_var.h"
42 #include "ipatm_serv.h"
43
44 /*
45  * Process an IP VCC timeout
46  * 
47  * Called when a previously scheduled ipvcc control block timer expires.  
48  * Processing will be based on the current ipvcc state.
49  *
50  * Called at splnet.
51  *
52  * Arguments:
53  *      tip     pointer to ipvcc timer control block
54  *
55  * Returns:
56  *      none
57  *
58  */
59 void
60 ipatm_timeout(tip)
61         struct atm_time *tip;
62 {
63         struct ipvcc    *ivp;
64
65         /*
66          * Back-off to ipvcc control block
67          */
68         ivp = (struct ipvcc *)
69                         ((caddr_t)tip - (int)(&((struct ipvcc *)0)->iv_time));
70
71         /*
72          * Process timeout based on protocol state
73          */
74         switch (ivp->iv_state) {
75
76         case IPVCC_PMAP:
77                 /*
78                  * Give up waiting for arp response
79                  */
80                 (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE);
81                 break;
82
83         case IPVCC_POPEN:
84         case IPVCC_PACCEPT:
85                 /*
86                  * Give up waiting for signalling manager response
87                  */
88                 (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE);
89                 break;
90
91         case IPVCC_ACTPENT:
92                 /*
93                  * Try again to get an ARP entry
94                  */
95                 switch ((*ivp->iv_ipnif->inf_serv->is_arp_pvcopen)(ivp)) {
96
97                 case MAP_PROCEEDING:
98                         /*
99                          * Wait for answer
100                          */
101                         ivp->iv_state = IPVCC_ACTIVE;
102                         break;
103
104                 case MAP_VALID:
105                         /*
106                          * We've got our answer already
107                          */
108                         ivp->iv_state = IPVCC_ACTIVE;
109                         ivp->iv_flags |= IVF_MAPOK;
110                         ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr;
111                         break;
112
113                 case MAP_FAILED:
114                         /*
115                          * Try again later
116                          */
117                         IPVCC_TIMER(ivp, 5 * ATM_HZ);
118                         break;
119
120                 default:
121                         panic("ipatm_timeout: invalid am_pvcopen return");
122                 }
123                 break;
124
125         default:
126                 log(LOG_ERR, "ipatm: invalid timer state: ivp=%p, state=%d\n",
127                         ivp, ivp->iv_state);
128         }
129 }
130
131
132 /*
133  * Process IP VCC Connected Notification
134  * 
135  * Arguments:
136  *      toku    owner's connection token (ipvcc protocol block)
137  *
138  * Returns:
139  *      none
140  *
141  */
142 void
143 ipatm_connected(toku)
144         void            *toku;
145 {
146         struct ipvcc    *ivp = (struct ipvcc *)toku;
147
148         /*
149          * SVC is connected
150          */
151         if ((ivp->iv_state != IPVCC_POPEN) &&
152             (ivp->iv_state != IPVCC_PACCEPT)) {
153                 log(LOG_ERR, "ipatm: invalid CALL_CONNECTED state=%d\n",
154                         ivp->iv_state);
155                 return;
156         }
157
158         /*
159          * Verify possible negotiated parameter values
160          */
161         if (ivp->iv_state == IPVCC_POPEN) {
162                 Atm_attributes  *ap = &ivp->iv_conn->co_connvc->cvc_attr;
163                 int             mtu = (ivp->iv_flags & IVF_LLC) ?
164                                                 ATM_NIF_MTU + IPATM_LLC_LEN :
165                                                 ATM_NIF_MTU;
166
167                 /*       
168                  * Verify final MTU
169                  */     
170                 if (ap->aal.type == ATM_AAL5) {
171                         if ((ap->aal.v.aal5.forward_max_SDU_size < mtu) ||
172                             (ap->aal.v.aal5.backward_max_SDU_size > mtu)) {
173                                 (void) ipatm_closevc(ivp,
174                                       T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED);
175                                 return;
176                         }
177                 } else {
178                         if ((ap->aal.v.aal4.forward_max_SDU_size < mtu) ||
179                             (ap->aal.v.aal4.backward_max_SDU_size > mtu)) {
180                                 (void) ipatm_closevc(ivp,
181                                       T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED);
182                                 return;
183                         }
184                 }
185         }
186
187         /*
188          * Finish up VCC activation
189          */
190         ipatm_activate(ivp);
191 }
192
193
194 /*
195  * Process IP VCC Cleared Notification
196  * 
197  * Arguments:
198  *      toku    owner's connection token (ipvcc protocol block)
199  *      cause   pointer to cause code
200  *
201  * Returns:
202  *      none
203  *
204  */
205 void
206 ipatm_cleared(toku, cause)
207         void            *toku;
208         struct t_atm_cause      *cause;
209 {
210         struct ipvcc    *ivp = (struct ipvcc *)toku;
211
212
213         /*
214          * VCC has been cleared, so figure out what's next
215          */
216         ivp->iv_conn = NULL;
217
218         switch (ivp->iv_state) {
219
220         case IPVCC_POPEN:
221                 /*
222                  * Call setup failed, see if there is another
223                  * set of vcc parameters to try
224                  */
225                 ivp->iv_state = IPVCC_CLOSED;
226                 if (ipatm_retrysvc(ivp)) {
227                         (void) ipatm_closevc(ivp, cause->cause_value);
228                 }
229                 break;
230
231         case IPVCC_PACCEPT:
232         case IPVCC_ACTPENT:
233         case IPVCC_ACTIVE:
234                 ivp->iv_state = IPVCC_CLOSED;
235                 (void) ipatm_closevc(ivp, cause->cause_value);
236                 break;
237         }
238 }
239
240
241 /*
242  * Process an ARP Event Notification
243  * 
244  * Arguments:
245  *      ivp     pointer to IP VCC control block
246  *      event   ARP event type
247  *
248  * Returns:
249  *      none
250  *
251  */
252 void
253 ipatm_arpnotify(ivp, event)
254         struct ipvcc    *ivp;
255         int             event;
256 {
257         struct sockaddr_in      sin;
258         struct ifnet            *ifp;
259
260         /*
261          * Process event
262          */
263         switch (event) {
264
265         case MAP_VALID:
266                 switch (ivp->iv_state) {
267
268                 case IPVCC_PMAP:
269                         /*
270                          * We've got our destination, however, first we'll
271                          * check to make sure no other VCC to our destination
272                          * has also had it's ARP table entry completed.
273                          * If we don't find a better VCC to use, then we'll
274                          * go ahead and open this SVC.
275                          */
276                         sin.sin_family = AF_INET;
277                         sin.sin_addr.s_addr = ivp->iv_dst.s_addr;
278                         if (ipatm_iptovc(&sin, ivp->iv_ipnif->inf_nif) != ivp) {
279                                 /*
280                                  * We found a better VCC, so use it and
281                                  * get rid of this VCC
282                                  */
283                                 if (ivp->iv_queue) {
284                                         ifp = (struct ifnet *)
285                                                 ivp->iv_ipnif->inf_nif;
286                                         (void) ipatm_ifoutput(ifp, 
287                                                 ivp->iv_queue, 
288                                                 (struct sockaddr *)&sin);
289                                         ivp->iv_queue = NULL;
290                                 }
291                                 (void) ipatm_closevc(ivp,
292                                                 T_ATM_CAUSE_UNSPECIFIED_NORMAL);
293
294                         } else {
295                                 /*
296                                  * We like this VCC...
297                                  */
298                                 ivp->iv_flags |= IVF_MAPOK;
299                                 if (ipatm_opensvc(ivp)) {
300                                         (void) ipatm_closevc(ivp,
301                                                 T_ATM_CAUSE_TEMPORARY_FAILURE);
302                                 }
303                         }
304                         break;
305
306                 case IPVCC_POPEN:
307                 case IPVCC_PACCEPT:
308                 case IPVCC_ACTIVE:
309                         /*
310                          * Everything looks good, so accept new mapping
311                          */
312                         ivp->iv_flags |= IVF_MAPOK;
313                         ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr;
314
315                         /*
316                          * Send queued packet
317                          */
318                         if ((ivp->iv_state == IPVCC_ACTIVE) && ivp->iv_queue) {
319                                 sin.sin_family = AF_INET;
320                                 sin.sin_addr.s_addr = ivp->iv_dst.s_addr;
321                                 ifp = (struct ifnet *)ivp->iv_ipnif->inf_nif;
322                                 (void) ipatm_ifoutput(ifp, ivp->iv_queue, 
323                                         (struct sockaddr *)&sin);
324                                 ivp->iv_queue = NULL;
325                         }
326                         break;
327                 }
328                 break;
329
330         case MAP_INVALID:
331                 switch (ivp->iv_state) {
332
333                 case IPVCC_POPEN:
334                 case IPVCC_PACCEPT:
335                 case IPVCC_ACTIVE:
336
337                         /*
338                          * Mapping has gone stale, so we cant use this VCC
339                          * until the mapping is refreshed
340                          */
341                         ivp->iv_flags &= ~IVF_MAPOK;
342                         break;
343                 }
344                 break;
345
346         case MAP_FAILED:
347                 /*
348                  * ARP lookup failed, just trash it all
349                  */
350                 (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE);
351                 break;
352
353         case MAP_CHANGED:
354                 /*
355                  * ARP mapping has changed
356                  */
357                 if (ivp->iv_flags & IVF_PVC) {
358                         /*
359                          * For PVCs, just reset lookup cache if needed
360                          */
361                         if (last_map_ipvcc == ivp) {
362                                 last_map_ipdst = 0;
363                                 last_map_ipvcc = NULL;
364                         }
365                 } else {
366                         /*
367                          * Close SVC if it has already used this mapping
368                          */
369                         switch (ivp->iv_state) {
370
371                         case IPVCC_POPEN:
372                         case IPVCC_ACTIVE:
373                                 (void) ipatm_closevc(ivp,
374                                         T_ATM_CAUSE_UNSPECIFIED_NORMAL);
375                                 break;
376                         }
377                 }
378                 break;
379
380         default:
381                 log(LOG_ERR, "ipatm: unknown arp event %d, ivp=%p\n",
382                         event, ivp);
383         }
384 }
385
386
387 /*
388  * Process an IP VCC idle timer tick
389  * 
390  * This function is called every IPATM_IDLE_TIME seconds, in order to
391  * scan for idle IP VCC's.  If an active VCC reaches the idle time limit,
392  * then it will be closed.
393  *
394  * Called at splnet.
395  *
396  * Arguments:
397  *      tip     pointer to the VCC idle timer control block
398  *
399  * Returns:
400  *      none
401  *
402  */
403 void
404 ipatm_itimeout(tip)
405         struct atm_time *tip;
406 {
407         struct ipvcc    *ivp, *inext;
408         struct ip_nif   *inp;
409
410
411         /*
412          * Schedule next timeout
413          */
414         atm_timeout(&ipatm_itimer, IPATM_IDLE_TIME, ipatm_itimeout);
415
416         /*
417          * Check for disabled idle timeout
418          */
419         if (ipatm_vcidle == 0)
420                 return;
421
422         /*
423          * Check out all IP VCCs
424          */
425         for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
426                 for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp;
427                                 ivp = inext) {
428
429                         inext = Q_NEXT(ivp, struct ipvcc, iv_elem);
430
431                         /*
432                          * Looking for active, idle SVCs
433                          */
434                         if (ivp->iv_flags & (IVF_PVC | IVF_NOIDLE))
435                                 continue;
436                         if (ivp->iv_state != IPVCC_ACTIVE)
437                                 continue;
438                         if (++ivp->iv_idle < ipatm_vcidle)
439                                 continue;
440
441                         /*
442                          * OK, we found one - close the VCC
443                          */
444                         (void) ipatm_closevc(ivp,
445                                         T_ATM_CAUSE_UNSPECIFIED_NORMAL);
446                 }
447         }
448 }
449