kernel tree reorganization stage 1: Major cvs repository work (not logged as
[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.4 2003/08/07 21:54:34 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             s, 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         s = splnet();
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         (void) splx(s);
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         int     s = splnet();
191
192         ATM_DEBUG2("uniarp_svcout: ivp=%p,dst=0x%x\n", ivp, dst->s_addr);
193
194         ivp->iv_arpent = NULL;
195
196         /*
197          * Get uni interface
198          */
199         uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
200         if (uip == NULL) {
201                 (void) splx(s);
202                 return (MAP_FAILED);
203         }
204
205         /*
206          * Lookup IP destination address
207          */
208         UNIARP_LOOKUP(dst->s_addr, uap);
209
210         if (uap) {
211                 /*
212                  * We've got an entry, verify interface
213                  */
214                 if (uap->ua_intf != uip) {
215                         (void) splx(s);
216                         return (MAP_FAILED);
217                 }
218
219                 /*
220                  * Chain this vcc onto entry
221                  */
222                 LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
223                 ivp->iv_arpent = (struct arpmap *)uap;
224                 uap->ua_flags |= UAF_USED;
225
226                 if (uap->ua_flags & UAF_VALID) {
227                         /*
228                          * Entry is valid, we're done
229                          */
230                         (void) splx(s);
231                         return (MAP_VALID);
232                 } else {
233                         /*
234                          * We're already looking for this address
235                          */
236                         (void) splx(s);
237                         return (MAP_PROCEEDING);
238                 }
239         }
240
241         /*
242          * No info in the cache.  If we're the server, then
243          * we're already authoritative, so just deny request.
244          * If we're a client but the server VCC isn't open we
245          * also deny the request.
246          */
247         if (uip->uip_arpstate != UIAS_CLIENT_ACTIVE) {
248                 (void) splx(s);
249                 return (MAP_FAILED);
250         }
251
252         /*
253          * We're a client with an open VCC to the server, get a new arp entry
254          */
255         uap = (struct uniarp *)atm_allocate(&uniarp_pool);
256         if (uap == NULL) {
257                 (void) splx(s);
258                 return (MAP_FAILED);
259         }
260
261         /*
262          * Get entry set up
263          */
264         uap->ua_dstip.s_addr = dst->s_addr;
265         uap->ua_dstatm.address_format = T_ATM_ABSENT;
266         uap->ua_dstatm.address_length = 0;
267         uap->ua_dstatmsub.address_format = T_ATM_ABSENT;
268         uap->ua_dstatmsub.address_length = 0;
269         uap->ua_intf = uip;
270
271         /*
272          * Link ipvcc to arp entry for later notification
273          */
274         LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
275         ivp->iv_arpent = (struct arpmap *)uap;
276         uap->ua_flags |= UAF_USED;
277
278         /*
279          * Add arp entry to table
280          */
281         UNIARP_ADD(uap);
282
283         /*
284          * Issue arp request for this address
285          */
286         (void) uniarp_arp_req(uip, dst);
287
288         /*
289          * Start retry timer
290          */
291         UNIARP_TIMER(uap, UNIARP_ARP_RETRY);
292
293         (void) splx(s);
294         return (MAP_PROCEEDING);
295 }
296
297
298 /*
299  * Process a new incoming SVC requiring ATMARP support
300  * 
301  * This function is called by the IP/ATM module to resolve a caller's ATM
302  * address to its IP address for an incoming call in order to allow a
303  * bi-directional flow of IP packets on the SVC.  If a valid mapping is
304  * already in our cache, then we will use it.  Otherwise, we have to allocate
305  * a new arp entry and wait for the SVC to become active so that we can issue
306  * an InATMARP to the peer.
307  *
308  * Arguments:
309  *      ivp     pointer to SVC's IPVCC control block
310  *      dst     pointer to caller's ATM address
311  *      dstsub  pointer to caller's ATM subaddress
312  *
313  * Returns:
314  *      MAP_VALID       - Got the answer, returned via iv_arpent field.
315  *      MAP_PROCEEDING  - OK so far, querying for peer's mapping
316  *      MAP_FAILED      - error, unable to allocate resources
317  *
318  */
319 int
320 uniarp_svcin(ivp, dst, dstsub)
321         struct ipvcc    *ivp;
322         Atm_addr        *dst;
323         Atm_addr        *dstsub;
324 {
325         struct uniip    *uip;
326         struct uniarp   *uap;
327         int     found = 0, i, s = splnet();
328
329         ATM_DEBUG1("uniarp_svcin: ivp=%p\n", ivp);
330
331         /*
332          * Clear ARP entry field
333          */
334         ivp->iv_arpent = NULL;
335
336         /*
337          * Check things out
338          */
339         if ((ivp->iv_flags & IVF_LLC) == 0)
340                 return (MAP_FAILED);
341
342         /*
343          * Get uni interface
344          */
345         uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
346         if (uip == NULL) {
347                 (void) splx(s);
348                 return (MAP_FAILED);
349         }
350
351         /*
352          * Make sure we're configured as a client or server
353          */
354         if (uip->uip_arpstate == UIAS_NOTCONF) {
355                 (void) splx(s);
356                 return (MAP_FAILED);
357         }
358
359         /*
360          * If we know the caller's ATM address, look it up
361          */
362         uap = NULL;
363         if (dst->address_format != T_ATM_ABSENT) {
364                 for (i = 0; (i < UNIARP_HASHSIZ) && (found == 0); i++) {
365                         for (uap = uniarp_arptab[i]; uap; uap = uap->ua_next) {
366                                 if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) &&
367                                     ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub)){
368                                         found = 1;
369                                         break;
370                                 }
371                         }
372                 }
373                 if (uap == NULL) {
374                         for (uap = uniarp_nomaptab; uap; uap = uap->ua_next) {
375                                 if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) &&
376                                     ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub))
377                                         break;
378                         }
379                 }
380         }
381
382         if (uap) {
383                 /*
384                  * We've got an entry, verify interface
385                  */
386                 if (uap->ua_intf != uip) {
387                         (void) splx(s);
388                         return (MAP_FAILED);
389                 }
390
391                 /*
392                  * Chain the vcc onto this entry
393                  */
394                 LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
395                 ivp->iv_arpent = (struct arpmap *)uap;
396                 uap->ua_flags |= UAF_USED;
397
398                 if (uap->ua_flags & UAF_VALID) {
399                         /*
400                          * Entry is valid, we're done
401                          */
402                         (void) splx(s);
403                         return (MAP_VALID);
404                 } else {
405                         /*
406                          * We're already looking for this address
407                          */
408                         (void) splx(s);
409                         return (MAP_PROCEEDING);
410                 }
411         }
412
413         /*
414          * No info in the cache - get a new arp entry
415          */
416         uap = (struct uniarp *)atm_allocate(&uniarp_pool);
417         if (uap == NULL) {
418                 (void) splx(s);
419                 return (MAP_FAILED);
420         }
421
422         /*
423          * Get entry set up
424          */
425         ATM_ADDR_COPY(dst, &uap->ua_dstatm);
426         ATM_ADDR_COPY(dstsub, &uap->ua_dstatmsub);
427         uap->ua_intf = uip;
428
429         /*
430          * Link ipvcc to arp entry for later notification
431          */
432         LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
433         ivp->iv_arpent = (struct arpmap *)uap;
434         uap->ua_flags |= UAF_USED;
435
436         /*
437          * Add arp entry to 'nomap' table
438          */
439         LINK2TAIL(uap, struct uniarp, uniarp_nomaptab, ua_next);
440
441         (void) splx(s);
442
443         /*
444          * Now we just wait for SVC to become active
445          */
446         return (MAP_PROCEEDING);
447 }
448
449
450 /*
451  * Process ARP SVC activation notification
452  *
453  * This function is called by the IP/ATM module whenever a previously
454  * opened SVC has successfully been connected.
455  *
456  * Arguments:
457  *      ivp     pointer to SVC's IPVCC control block
458  *
459  * Returns:
460  *      0       activation processing successful
461  *      errno   activation failed - reason indicated
462  *
463  */
464 int
465 uniarp_svcactive(ivp)
466         struct ipvcc    *ivp;
467 {
468         struct ip_nif   *inp;
469         struct uniip    *uip;
470         struct uniarp   *uap;
471         int     err, s = splnet();
472
473         ATM_DEBUG1("uniarp_svcactive: ivp=%p\n", ivp);
474
475         inp = ivp->iv_ipnif;
476         uip = (struct uniip *)inp->inf_isintf;
477         uap = (struct uniarp *)ivp->iv_arpent;
478
479         /*
480          * First, we need to create our CM connection
481          */
482         err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc,
483                         ivp->iv_conn, &ivp->iv_arpconn);
484         if (err) {
485                 /*
486                  * We don't take no (or maybe) for an answer
487                  */
488                 if (ivp->iv_arpconn) {
489                         (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
490                         ivp->iv_arpconn = NULL;
491                 }
492                 return (err);
493         }
494
495         /*
496          * Is this the client->server vcc??
497          */
498         if (uip->uip_arpsvrvcc == ivp) {
499
500                 /*
501                  * Yep, go into the client registration phase
502                  */
503                 uip->uip_arpstate = UIAS_CLIENT_REGISTER;
504
505                 /*
506                  * To register ourselves, RFC1577 says we should wait
507                  * around for the server to send us an InATMARP_Request.
508                  * However, draft-1577+ just has us send an ATMARP_Request
509                  * for our own address.  To keep everyone happy, we'll go 
510                  * with both and see what works!
511                  */
512                 (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr));
513
514                 /*
515                  * Start retry timer
516                  */
517                 UNIIP_ARP_TIMER(uip, 1 * ATM_HZ);
518
519                 (void) splx(s);
520                 return (0);
521         }
522
523         /*
524          * Send an InATMARP_Request on this VCC to find out/notify who's at 
525          * the other end.  If we're the server, this will start off the
526          * RFC1577 registration procedure.  If we're a client, then this
527          * SVC is for user data and it's pretty likely that both ends are
528          * going to be sending packets.  So, if we're the caller, we'll be
529          * nice and let the callee know right away who we are.  If we're the
530          * callee, let's find out asap the caller's IP address.
531          */
532         (void) uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp);
533
534         /*
535          * Start retry timer if entry isn't valid yet
536          */
537         if (((uap->ua_flags & UAF_VALID) == 0) &&
538             ((uap->ua_time.ti_flag & TIF_QUEUED) == 0))
539                 UNIARP_TIMER(uap, UNIARP_ARP_RETRY);
540
541         (void) splx(s);
542         return (0);
543 }
544
545
546 /*
547  * Process VCC close
548  * 
549  * This function is called just prior to IP/ATM closing a VCC which 
550  * supports ATMARP.  We'll sever our links to the VCC and then
551  * figure out how much more cleanup we need to do for now.
552  *
553  * Arguments:
554  *      ivp     pointer to VCC's IPVCC control block
555  *
556  * Returns:
557  *      none
558  *
559  */
560 void
561 uniarp_vcclose(ivp)
562         struct ipvcc    *ivp;
563 {
564         struct uniip    *uip;
565         struct uniarp   *uap;
566         int     s;
567
568         ATM_DEBUG1("uniarp_vcclose: ivp=%p\n", ivp);
569
570         /*
571          * Close our CM connection
572          */
573         if (ivp->iv_arpconn) {
574                 (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
575                 ivp->iv_arpconn = NULL;
576         }
577
578         /*
579          * Get atmarp entry
580          */
581         if ((uap = (struct uniarp *)ivp->iv_arpent) == NULL)
582                 return;
583         uip = uap->ua_intf;
584
585         s = splnet();
586
587         /*
588          * If this is the arpserver VCC, then schedule ourselves to
589          * reopen the connection soon
590          */
591         if (uip->uip_arpsvrvcc == ivp) {
592                 uip->uip_arpsvrvcc = NULL;
593                 uip->uip_arpstate = UIAS_CLIENT_POPEN;
594                 UNIIP_ARP_CANCEL(uip);
595                 UNIIP_ARP_TIMER(uip, 5 * ATM_HZ);
596         }
597
598         /*
599          * Remove IP VCC from chain
600          */
601         UNLINK(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
602
603         /*
604          * SVCs and PVCs are handled separately
605          */
606         if (ivp->iv_flags & IVF_SVC) {
607                 /*
608                  * If the mapping is currently valid or in use, or if there 
609                  * are other VCCs still using this mapping, we're done for now
610                  */
611                 if ((uap->ua_flags & (UAF_VALID | UAF_LOCKED)) ||
612                     (uap->ua_origin >= UAO_PERM) ||
613                     (uap->ua_ivp != NULL)) {
614                         (void) splx(s);
615                         return;
616                 }
617
618                 /*
619                  * Unlink the entry
620                  */
621                 if (uap->ua_dstip.s_addr == 0) {
622                         UNLINK(uap, struct uniarp, uniarp_nomaptab, ua_next);
623                 } else {
624                         UNIARP_DELETE(uap);
625                 }
626         } else {
627                 /*
628                  * Remove entry from pvc table
629                  */
630                 UNLINK(uap, struct uniarp, uniarp_pvctab, ua_next);
631         }
632
633         UNIARP_CANCEL(uap);
634
635         /*
636          * Finally, free the entry
637          */
638         atm_free((caddr_t)uap);
639
640         (void) splx(s);
641         return;
642 }
643
644
645 /*
646  * Process ATMARP VCC Connected Notification
647  * 
648  * Arguments:
649  *      toku    owner's connection token (ipvcc protocol block)
650  *
651  * Returns:
652  *      none
653  *
654  */
655 void
656 uniarp_connected(toku)
657         void            *toku;
658 {
659
660         /*
661          * Since we only do atm_cm_addllc()'s on active connections,
662          * we should never get called here...
663          */
664         panic("uniarp_connected");
665 }
666
667
668 /*
669  * Process ATMARP VCC Cleared Notification
670  * 
671  * Arguments:
672  *      toku    owner's connection token (ipvcc protocol block)
673  *      cause   pointer to cause code
674  *
675  * Returns:
676  *      none
677  *
678  */
679 void
680 uniarp_cleared(toku, cause)
681         void            *toku;
682         struct t_atm_cause      *cause;
683 {
684         struct ipvcc    *ivp = toku;
685         int             s;
686
687         s = splnet();
688
689         /*
690          * We're done with VCC
691          */
692         ivp->iv_arpconn = NULL;
693
694         /*
695          * If IP is finished with VCC, then we'll free it
696          */
697         if (ivp->iv_state == IPVCC_FREE)
698                 atm_free((caddr_t)ivp);
699
700         (void) splx(s);
701 }
702