3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
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.
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.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/sys/netatm/uni/uniarp_vcm.c,v 1.5 2000/01/17 20:49:55 mks Exp $
30 * ATM Forum UNI Support
31 * ---------------------
33 * UNI ATMARP support (RFC1577) - Virtual Channel Management
37 #include <netproto/atm/kern_include.h>
39 #include <netproto/atm/ipatm/ipatm_var.h>
40 #include <netproto/atm/ipatm/ipatm_serv.h>
41 #include "uniip_var.h"
46 static struct attr_llc uniarp_llc = {
51 {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06}
55 static struct t_atm_cause uniarp_cause = {
58 T_ATM_CAUSE_TEMPORARY_FAILURE,
64 * Process a new PVC requiring ATMARP support
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.
73 * ivp pointer to PVC's IPVCC control block
76 * MAP_PROCEEDING - OK so far, querying for peer's mapping
77 * MAP_FAILED - error, unable to allocate resources
81 uniarp_pvcopen(struct ipvcc *ivp)
87 ATM_DEBUG1("uniarp_pvcopen: ivp=%p\n", ivp);
89 ivp->iv_arpent = NULL;
94 if ((ivp->iv_flags & IVF_LLC) == 0)
100 uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
105 * Get an arp map entry
107 uap = (struct uniarp *)atm_allocate(&uniarp_pool);
112 * Create our CM connection
114 err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc,
115 ivp->iv_conn, &ivp->iv_arpconn);
118 * We don't take no (or maybe) for an answer
120 if (ivp->iv_arpconn) {
121 atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
122 ivp->iv_arpconn = NULL;
124 atm_free((caddr_t)uap);
129 * Get map entry set up
132 uap->ua_dstatm.address_format = T_ATM_ABSENT;
133 uap->ua_dstatmsub.address_format = T_ATM_ABSENT;
137 * Put ivp on arp entry chain
139 LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
140 ivp->iv_arpent = (struct arpmap *)uap;
143 * Put arp entry on pvc chain
145 LINK2TAIL(uap, struct uniarp, uniarp_pvctab, ua_next);
148 * Send Inverse ATMARP request
150 uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp);
155 uap->ua_aging = UNIARP_REVALID_AGE;
158 return (MAP_PROCEEDING);
163 * Process a new outgoing SVC requiring ATMARP support
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.
172 * ivp pointer to SVC's IPVCC control block
173 * dst pointer to destination IP address
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
182 uniarp_svcout(struct ipvcc *ivp, struct in_addr *dst)
189 ATM_DEBUG2("uniarp_svcout: ivp=%p,dst=0x%x\n", ivp, dst->s_addr);
191 ivp->iv_arpent = NULL;
196 uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
203 * Lookup IP destination address
205 UNIARP_LOOKUP(dst->s_addr, uap);
209 * We've got an entry, verify interface
211 if (uap->ua_intf != uip) {
217 * Chain this vcc onto entry
219 LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
220 ivp->iv_arpent = (struct arpmap *)uap;
221 uap->ua_flags |= UAF_USED;
223 if (uap->ua_flags & UAF_VALID) {
225 * Entry is valid, we're done
231 * We're already looking for this address
234 return (MAP_PROCEEDING);
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.
244 if (uip->uip_arpstate != UIAS_CLIENT_ACTIVE) {
250 * We're a client with an open VCC to the server, get a new arp entry
252 uap = (struct uniarp *)atm_allocate(&uniarp_pool);
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;
269 * Link ipvcc to arp entry for later notification
271 LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
272 ivp->iv_arpent = (struct arpmap *)uap;
273 uap->ua_flags |= UAF_USED;
276 * Add arp entry to table
281 * Issue arp request for this address
283 uniarp_arp_req(uip, dst);
288 UNIARP_TIMER(uap, UNIARP_ARP_RETRY);
291 return (MAP_PROCEEDING);
296 * Process a new incoming SVC requiring ATMARP support
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.
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
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
317 uniarp_svcin(struct ipvcc *ivp, Atm_addr *dst, Atm_addr *dstsub)
325 ATM_DEBUG1("uniarp_svcin: ivp=%p\n", ivp);
328 * Clear ARP entry field
330 ivp->iv_arpent = NULL;
335 if ((ivp->iv_flags & IVF_LLC) == 0)
341 uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
348 * Make sure we're configured as a client or server
350 if (uip->uip_arpstate == UIAS_NOTCONF) {
356 * If we know the caller's ATM address, look it up
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)){
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))
380 * We've got an entry, verify interface
382 if (uap->ua_intf != uip) {
388 * Chain the vcc onto this entry
390 LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
391 ivp->iv_arpent = (struct arpmap *)uap;
392 uap->ua_flags |= UAF_USED;
394 if (uap->ua_flags & UAF_VALID) {
396 * Entry is valid, we're done
402 * We're already looking for this address
405 return (MAP_PROCEEDING);
410 * No info in the cache - get a new arp entry
412 uap = (struct uniarp *)atm_allocate(&uniarp_pool);
421 ATM_ADDR_COPY(dst, &uap->ua_dstatm);
422 ATM_ADDR_COPY(dstsub, &uap->ua_dstatmsub);
426 * Link ipvcc to arp entry for later notification
428 LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
429 ivp->iv_arpent = (struct arpmap *)uap;
430 uap->ua_flags |= UAF_USED;
433 * Add arp entry to 'nomap' table
435 LINK2TAIL(uap, struct uniarp, uniarp_nomaptab, ua_next);
440 * Now we just wait for SVC to become active
442 return (MAP_PROCEEDING);
447 * Process ARP SVC activation notification
449 * This function is called by the IP/ATM module whenever a previously
450 * opened SVC has successfully been connected.
453 * ivp pointer to SVC's IPVCC control block
456 * 0 activation processing successful
457 * errno activation failed - reason indicated
461 uniarp_svcactive(struct ipvcc *ivp)
470 ATM_DEBUG1("uniarp_svcactive: ivp=%p\n", ivp);
473 uip = (struct uniip *)inp->inf_isintf;
474 uap = (struct uniarp *)ivp->iv_arpent;
477 * First, we need to create our CM connection
479 err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc,
480 ivp->iv_conn, &ivp->iv_arpconn);
483 * We don't take no (or maybe) for an answer
485 if (ivp->iv_arpconn) {
486 atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
487 ivp->iv_arpconn = NULL;
494 * Is this the client->server vcc??
496 if (uip->uip_arpsvrvcc == ivp) {
499 * Yep, go into the client registration phase
501 uip->uip_arpstate = UIAS_CLIENT_REGISTER;
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!
510 uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr));
515 UNIIP_ARP_TIMER(uip, 1 * ATM_HZ);
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.
530 uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp);
533 * Start retry timer if entry isn't valid yet
535 if (((uap->ua_flags & UAF_VALID) == 0) &&
536 ((uap->ua_time.ti_flag & TIF_QUEUED) == 0))
537 UNIARP_TIMER(uap, UNIARP_ARP_RETRY);
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.
552 * ivp pointer to VCC's IPVCC control block
559 uniarp_vcclose(struct ipvcc *ivp)
564 ATM_DEBUG1("uniarp_vcclose: ivp=%p\n", ivp);
567 * Close our CM connection
569 if (ivp->iv_arpconn) {
570 atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
571 ivp->iv_arpconn = NULL;
577 if ((uap = (struct uniarp *)ivp->iv_arpent) == NULL)
584 * If this is the arpserver VCC, then schedule ourselves to
585 * reopen the connection soon
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);
595 * Remove IP VCC from chain
597 UNLINK(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
600 * SVCs and PVCs are handled separately
602 if (ivp->iv_flags & IVF_SVC) {
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
607 if ((uap->ua_flags & (UAF_VALID | UAF_LOCKED)) ||
608 (uap->ua_origin >= UAO_PERM) ||
609 (uap->ua_ivp != NULL)) {
617 if (uap->ua_dstip.s_addr == 0) {
618 UNLINK(uap, struct uniarp, uniarp_nomaptab, ua_next);
624 * Remove entry from pvc table
626 UNLINK(uap, struct uniarp, uniarp_pvctab, ua_next);
632 * Finally, free the entry
634 atm_free((caddr_t)uap);
642 * Process ATMARP VCC Connected Notification
645 * toku owner's connection token (ipvcc protocol block)
652 uniarp_connected(void *toku)
656 * Since we only do atm_cm_addllc()'s on active connections,
657 * we should never get called here...
659 panic("uniarp_connected");
664 * Process ATMARP VCC Cleared Notification
667 * toku owner's connection token (ipvcc protocol block)
668 * cause pointer to cause code
675 uniarp_cleared(void *toku, struct t_atm_cause *cause)
677 struct ipvcc *ivp = toku;
682 * We're done with VCC
684 ivp->iv_arpconn = NULL;
687 * If IP is finished with VCC, then we'll free it
689 if (ivp->iv_state == IPVCC_FREE)
690 atm_free((caddr_t)ivp);