kernel: Add a few forgotten crit_exit()s and fix a wrong crit_enter().
[dragonfly.git] / sys / netproto / atm / uni / uniarp_vcm.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/uni/uniarp_vcm.c,v 1.5 2000/01/17 20:49:55 mks Exp $
27  */
28
29 /*
30  * ATM Forum UNI Support
31  * ---------------------
32  *
33  * UNI ATMARP support (RFC1577) - Virtual Channel Management
34  *
35  */
36
37 #include <netproto/atm/kern_include.h>
38
39 #include <netproto/atm/ipatm/ipatm_var.h>
40 #include <netproto/atm/ipatm/ipatm_serv.h>
41 #include "uniip_var.h"
42
43 /*
44  * Local variables
45  */
46 static struct attr_llc  uniarp_llc = {
47         T_ATM_PRESENT,
48         {
49                 T_ATM_LLC_SHARING,
50                 8,
51                 {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06}
52         }
53 };
54
55 static struct t_atm_cause       uniarp_cause = {
56         T_ATM_ITU_CODING,
57         T_ATM_LOC_USER,
58         T_ATM_CAUSE_TEMPORARY_FAILURE,
59         {0, 0, 0, 0}
60 };
61
62
63 /*
64  * Process a new PVC requiring ATMARP support
65  * 
66  * This function is called after IP/ATM has successfully opened a PVC which
67  * requires ATMARP support.  We will send an InATMARP request over the PVC
68  * to elicit a response from the PVC's ATMARP peer informing us of its
69  * network address.  This information will also be used by IP/ATM in order 
70  * to complete its address-to-VC mapping table.
71  *
72  * Arguments:
73  *      ivp     pointer to PVC's IPVCC control block
74  *
75  * Returns:
76  *      MAP_PROCEEDING  - OK so far, querying for peer's mapping
77  *      MAP_FAILED      - error, unable to allocate resources
78  *
79  */
80 int
81 uniarp_pvcopen(struct ipvcc *ivp)
82 {
83         struct uniip    *uip;
84         struct uniarp   *uap;
85         int             err;
86
87         ATM_DEBUG1("uniarp_pvcopen: ivp=%p\n", ivp);
88
89         ivp->iv_arpent = NULL;
90
91         /*
92          * Check things out
93          */
94         if ((ivp->iv_flags & IVF_LLC) == 0)
95                 return (MAP_FAILED);
96
97         /*
98          * Get uni interface
99          */
100         uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
101         if (uip == NULL)
102                 return (MAP_FAILED);
103
104         /*
105          * Get an arp map entry
106          */
107         uap = (struct uniarp *)atm_allocate(&uniarp_pool);
108         if (uap == NULL)
109                 return (MAP_FAILED);
110
111         /*
112          * Create our CM connection
113          */
114         err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc,
115                         ivp->iv_conn, &ivp->iv_arpconn);
116         if (err) {
117                 /*
118                  * We don't take no (or maybe) for an answer
119                  */
120                 if (ivp->iv_arpconn) {
121                         atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
122                         ivp->iv_arpconn = NULL;
123                 }
124                 atm_free((caddr_t)uap);
125                 return (MAP_FAILED);
126         }
127
128         /*
129          * Get map entry set up
130          */
131         crit_enter();
132         uap->ua_dstatm.address_format = T_ATM_ABSENT;
133         uap->ua_dstatmsub.address_format = T_ATM_ABSENT;
134         uap->ua_intf = uip;
135
136         /*
137          * Put ivp on arp entry chain
138          */
139         LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
140         ivp->iv_arpent = (struct arpmap *)uap;
141
142         /*
143          * Put arp entry on pvc chain
144          */
145         LINK2TAIL(uap, struct uniarp, uniarp_pvctab, ua_next);
146
147         /*
148          * Send Inverse ATMARP request
149          */
150         uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp);
151
152         /*
153          * Start resend timer 
154          */
155         uap->ua_aging = UNIARP_REVALID_AGE;
156
157         crit_exit();
158         return (MAP_PROCEEDING);
159 }
160
161
162 /*
163  * Process a new outgoing SVC requiring ATMARP support
164  * 
165  * This function is called by the IP/ATM module to resolve a destination 
166  * IP address to an ATM address in order to open an SVC to that destination.
167  * If a valid mapping is already in our cache, then we just tell the caller
168  * about it and that's that.  Otherwise, we have to allocate a new arp entry
169  * and issue a query for the mapping.
170  *
171  * Arguments:
172  *      ivp     pointer to SVC's IPVCC control block
173  *      dst     pointer to destination IP address
174  *
175  * Returns:
176  *      MAP_VALID       - Got the answer, returned via iv_arpent field.
177  *      MAP_PROCEEDING  - OK so far, querying for peer's mapping
178  *      MAP_FAILED      - error, unable to allocate resources
179  *
180  */
181 int
182 uniarp_svcout(struct ipvcc *ivp, struct in_addr *dst)
183 {
184         struct uniip    *uip;
185         struct uniarp   *uap;
186
187         crit_enter();
188
189         ATM_DEBUG2("uniarp_svcout: ivp=%p,dst=0x%x\n", ivp, dst->s_addr);
190
191         ivp->iv_arpent = NULL;
192
193         /*
194          * Get uni interface
195          */
196         uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
197         if (uip == NULL) {
198                 crit_exit();
199                 return (MAP_FAILED);
200         }
201
202         /*
203          * Lookup IP destination address
204          */
205         UNIARP_LOOKUP(dst->s_addr, uap);
206
207         if (uap) {
208                 /*
209                  * We've got an entry, verify interface
210                  */
211                 if (uap->ua_intf != uip) {
212                         crit_exit();
213                         return (MAP_FAILED);
214                 }
215
216                 /*
217                  * Chain this vcc onto entry
218                  */
219                 LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
220                 ivp->iv_arpent = (struct arpmap *)uap;
221                 uap->ua_flags |= UAF_USED;
222
223                 if (uap->ua_flags & UAF_VALID) {
224                         /*
225                          * Entry is valid, we're done
226                          */
227                         crit_exit();
228                         return (MAP_VALID);
229                 } else {
230                         /*
231                          * We're already looking for this address
232                          */
233                         crit_exit();
234                         return (MAP_PROCEEDING);
235                 }
236         }
237
238         /*
239          * No info in the cache.  If we're the server, then
240          * we're already authoritative, so just deny request.
241          * If we're a client but the server VCC isn't open we
242          * also deny the request.
243          */
244         if (uip->uip_arpstate != UIAS_CLIENT_ACTIVE) {
245                 crit_exit();
246                 return (MAP_FAILED);
247         }
248
249         /*
250          * We're a client with an open VCC to the server, get a new arp entry
251          */
252         uap = (struct uniarp *)atm_allocate(&uniarp_pool);
253         if (uap == NULL) {
254                 crit_exit();
255                 return (MAP_FAILED);
256         }
257
258         /*
259          * Get entry set up
260          */
261         uap->ua_dstip.s_addr = dst->s_addr;
262         uap->ua_dstatm.address_format = T_ATM_ABSENT;
263         uap->ua_dstatm.address_length = 0;
264         uap->ua_dstatmsub.address_format = T_ATM_ABSENT;
265         uap->ua_dstatmsub.address_length = 0;
266         uap->ua_intf = uip;
267
268         /*
269          * Link ipvcc to arp entry for later notification
270          */
271         LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
272         ivp->iv_arpent = (struct arpmap *)uap;
273         uap->ua_flags |= UAF_USED;
274
275         /*
276          * Add arp entry to table
277          */
278         UNIARP_ADD(uap);
279
280         /*
281          * Issue arp request for this address
282          */
283         uniarp_arp_req(uip, dst);
284
285         /*
286          * Start retry timer
287          */
288         UNIARP_TIMER(uap, UNIARP_ARP_RETRY);
289
290         crit_exit();
291         return (MAP_PROCEEDING);
292 }
293
294
295 /*
296  * Process a new incoming SVC requiring ATMARP support
297  * 
298  * This function is called by the IP/ATM module to resolve a caller's ATM
299  * address to its IP address for an incoming call in order to allow a
300  * bi-directional flow of IP packets on the SVC.  If a valid mapping is
301  * already in our cache, then we will use it.  Otherwise, we have to allocate
302  * a new arp entry and wait for the SVC to become active so that we can issue
303  * an InATMARP to the peer.
304  *
305  * Arguments:
306  *      ivp     pointer to SVC's IPVCC control block
307  *      dst     pointer to caller's ATM address
308  *      dstsub  pointer to caller's ATM subaddress
309  *
310  * Returns:
311  *      MAP_VALID       - Got the answer, returned via iv_arpent field.
312  *      MAP_PROCEEDING  - OK so far, querying for peer's mapping
313  *      MAP_FAILED      - error, unable to allocate resources
314  *
315  */
316 int
317 uniarp_svcin(struct ipvcc *ivp, Atm_addr *dst, Atm_addr *dstsub)
318 {
319         struct uniip    *uip;
320         struct uniarp   *uap;
321         int     found = 0, i;
322
323         crit_enter();
324
325         ATM_DEBUG1("uniarp_svcin: ivp=%p\n", ivp);
326
327         /*
328          * Clear ARP entry field
329          */
330         ivp->iv_arpent = NULL;
331
332         /*
333          * Check things out
334          */
335         if ((ivp->iv_flags & IVF_LLC) == 0)
336                 return (MAP_FAILED);
337
338         /*
339          * Get uni interface
340          */
341         uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
342         if (uip == NULL) {
343                 crit_exit();
344                 return (MAP_FAILED);
345         }
346
347         /*
348          * Make sure we're configured as a client or server
349          */
350         if (uip->uip_arpstate == UIAS_NOTCONF) {
351                 crit_exit();
352                 return (MAP_FAILED);
353         }
354
355         /*
356          * If we know the caller's ATM address, look it up
357          */
358         uap = NULL;
359         if (dst->address_format != T_ATM_ABSENT) {
360                 for (i = 0; (i < UNIARP_HASHSIZ) && (found == 0); i++) {
361                         for (uap = uniarp_arptab[i]; uap; uap = uap->ua_next) {
362                                 if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) &&
363                                     ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub)){
364                                         found = 1;
365                                         break;
366                                 }
367                         }
368                 }
369                 if (uap == NULL) {
370                         for (uap = uniarp_nomaptab; uap; uap = uap->ua_next) {
371                                 if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) &&
372                                     ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub))
373                                         break;
374                         }
375                 }
376         }
377
378         if (uap) {
379                 /*
380                  * We've got an entry, verify interface
381                  */
382                 if (uap->ua_intf != uip) {
383                         crit_exit();
384                         return (MAP_FAILED);
385                 }
386
387                 /*
388                  * Chain the vcc onto this entry
389                  */
390                 LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
391                 ivp->iv_arpent = (struct arpmap *)uap;
392                 uap->ua_flags |= UAF_USED;
393
394                 if (uap->ua_flags & UAF_VALID) {
395                         /*
396                          * Entry is valid, we're done
397                          */
398                         crit_exit();
399                         return (MAP_VALID);
400                 } else {
401                         /*
402                          * We're already looking for this address
403                          */
404                         crit_exit();
405                         return (MAP_PROCEEDING);
406                 }
407         }
408
409         /*
410          * No info in the cache - get a new arp entry
411          */
412         uap = (struct uniarp *)atm_allocate(&uniarp_pool);
413         if (uap == NULL) {
414                 crit_exit();
415                 return (MAP_FAILED);
416         }
417
418         /*
419          * Get entry set up
420          */
421         ATM_ADDR_COPY(dst, &uap->ua_dstatm);
422         ATM_ADDR_COPY(dstsub, &uap->ua_dstatmsub);
423         uap->ua_intf = uip;
424
425         /*
426          * Link ipvcc to arp entry for later notification
427          */
428         LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
429         ivp->iv_arpent = (struct arpmap *)uap;
430         uap->ua_flags |= UAF_USED;
431
432         /*
433          * Add arp entry to 'nomap' table
434          */
435         LINK2TAIL(uap, struct uniarp, uniarp_nomaptab, ua_next);
436
437         crit_exit();
438
439         /*
440          * Now we just wait for SVC to become active
441          */
442         return (MAP_PROCEEDING);
443 }
444
445
446 /*
447  * Process ARP SVC activation notification
448  *
449  * This function is called by the IP/ATM module whenever a previously
450  * opened SVC has successfully been connected.
451  *
452  * Arguments:
453  *      ivp     pointer to SVC's IPVCC control block
454  *
455  * Returns:
456  *      0       activation processing successful
457  *      errno   activation failed - reason indicated
458  *
459  */
460 int
461 uniarp_svcactive(struct ipvcc *ivp)
462 {
463         struct ip_nif   *inp;
464         struct uniip    *uip;
465         struct uniarp   *uap;
466         int     err;
467
468         crit_enter();
469
470         ATM_DEBUG1("uniarp_svcactive: ivp=%p\n", ivp);
471
472         inp = ivp->iv_ipnif;
473         uip = (struct uniip *)inp->inf_isintf;
474         uap = (struct uniarp *)ivp->iv_arpent;
475
476         /*
477          * First, we need to create our CM connection
478          */
479         err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc,
480                         ivp->iv_conn, &ivp->iv_arpconn);
481         if (err) {
482                 /*
483                  * We don't take no (or maybe) for an answer
484                  */
485                 if (ivp->iv_arpconn) {
486                         atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
487                         ivp->iv_arpconn = NULL;
488                 }
489                 crit_exit();
490                 return (err);
491         }
492
493         /*
494          * Is this the client->server vcc??
495          */
496         if (uip->uip_arpsvrvcc == ivp) {
497
498                 /*
499                  * Yep, go into the client registration phase
500                  */
501                 uip->uip_arpstate = UIAS_CLIENT_REGISTER;
502
503                 /*
504                  * To register ourselves, RFC1577 says we should wait
505                  * around for the server to send us an InATMARP_Request.
506                  * However, draft-1577+ just has us send an ATMARP_Request
507                  * for our own address.  To keep everyone happy, we'll go 
508                  * with both and see what works!
509                  */
510                 uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr));
511
512                 /*
513                  * Start retry timer
514                  */
515                 UNIIP_ARP_TIMER(uip, 1 * ATM_HZ);
516
517                 crit_exit();
518                 return (0);
519         }
520
521         /*
522          * Send an InATMARP_Request on this VCC to find out/notify who's at 
523          * the other end.  If we're the server, this will start off the
524          * RFC1577 registration procedure.  If we're a client, then this
525          * SVC is for user data and it's pretty likely that both ends are
526          * going to be sending packets.  So, if we're the caller, we'll be
527          * nice and let the callee know right away who we are.  If we're the
528          * callee, let's find out asap the caller's IP address.
529          */
530         uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp);
531
532         /*
533          * Start retry timer if entry isn't valid yet
534          */
535         if (((uap->ua_flags & UAF_VALID) == 0) &&
536             ((uap->ua_time.ti_flag & TIF_QUEUED) == 0))
537                 UNIARP_TIMER(uap, UNIARP_ARP_RETRY);
538
539         crit_exit();
540         return (0);
541 }
542
543
544 /*
545  * Process VCC close
546  * 
547  * This function is called just prior to IP/ATM closing a VCC which 
548  * supports ATMARP.  We'll sever our links to the VCC and then
549  * figure out how much more cleanup we need to do for now.
550  *
551  * Arguments:
552  *      ivp     pointer to VCC's IPVCC control block
553  *
554  * Returns:
555  *      none
556  *
557  */
558 void
559 uniarp_vcclose(struct ipvcc *ivp)
560 {
561         struct uniip    *uip;
562         struct uniarp   *uap;
563
564         ATM_DEBUG1("uniarp_vcclose: ivp=%p\n", ivp);
565
566         /*
567          * Close our CM connection
568          */
569         if (ivp->iv_arpconn) {
570                 atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
571                 ivp->iv_arpconn = NULL;
572         }
573
574         /*
575          * Get atmarp entry
576          */
577         if ((uap = (struct uniarp *)ivp->iv_arpent) == NULL)
578                 return;
579         uip = uap->ua_intf;
580
581         crit_enter();
582
583         /*
584          * If this is the arpserver VCC, then schedule ourselves to
585          * reopen the connection soon
586          */
587         if (uip->uip_arpsvrvcc == ivp) {
588                 uip->uip_arpsvrvcc = NULL;
589                 uip->uip_arpstate = UIAS_CLIENT_POPEN;
590                 UNIIP_ARP_CANCEL(uip);
591                 UNIIP_ARP_TIMER(uip, 5 * ATM_HZ);
592         }
593
594         /*
595          * Remove IP VCC from chain
596          */
597         UNLINK(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
598
599         /*
600          * SVCs and PVCs are handled separately
601          */
602         if (ivp->iv_flags & IVF_SVC) {
603                 /*
604                  * If the mapping is currently valid or in use, or if there 
605                  * are other VCCs still using this mapping, we're done for now
606                  */
607                 if ((uap->ua_flags & (UAF_VALID | UAF_LOCKED)) ||
608                     (uap->ua_origin >= UAO_PERM) ||
609                     (uap->ua_ivp != NULL)) {
610                         crit_exit();
611                         return;
612                 }
613
614                 /*
615                  * Unlink the entry
616                  */
617                 if (uap->ua_dstip.s_addr == 0) {
618                         UNLINK(uap, struct uniarp, uniarp_nomaptab, ua_next);
619                 } else {
620                         UNIARP_DELETE(uap);
621                 }
622         } else {
623                 /*
624                  * Remove entry from pvc table
625                  */
626                 UNLINK(uap, struct uniarp, uniarp_pvctab, ua_next);
627         }
628
629         UNIARP_CANCEL(uap);
630
631         /*
632          * Finally, free the entry
633          */
634         atm_free((caddr_t)uap);
635
636         crit_exit();
637         return;
638 }
639
640
641 /*
642  * Process ATMARP VCC Connected Notification
643  * 
644  * Arguments:
645  *      toku    owner's connection token (ipvcc protocol block)
646  *
647  * Returns:
648  *      none
649  *
650  */
651 void
652 uniarp_connected(void *toku)
653 {
654
655         /*
656          * Since we only do atm_cm_addllc()'s on active connections,
657          * we should never get called here...
658          */
659         panic("uniarp_connected");
660 }
661
662
663 /*
664  * Process ATMARP VCC Cleared Notification
665  * 
666  * Arguments:
667  *      toku    owner's connection token (ipvcc protocol block)
668  *      cause   pointer to cause code
669  *
670  * Returns:
671  *      none
672  *
673  */
674 void
675 uniarp_cleared(void *toku, struct t_atm_cause *cause)
676 {
677         struct ipvcc    *ivp = toku;
678
679         crit_enter();
680
681         /*
682          * We're done with VCC
683          */
684         ivp->iv_arpconn = NULL;
685
686         /*
687          * If IP is finished with VCC, then we'll free it
688          */
689         if (ivp->iv_state == IPVCC_FREE)
690                 atm_free((caddr_t)ivp);
691
692         crit_exit();
693 }
694