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