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