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