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