diff options
Diffstat (limited to 'sys/netatm/ipatm')
-rw-r--r-- | sys/netatm/ipatm/ipatm.h | 55 | ||||
-rw-r--r-- | sys/netatm/ipatm/ipatm_event.c | 454 | ||||
-rw-r--r-- | sys/netatm/ipatm/ipatm_if.c | 335 | ||||
-rw-r--r-- | sys/netatm/ipatm/ipatm_input.c | 210 | ||||
-rw-r--r-- | sys/netatm/ipatm/ipatm_load.c | 878 | ||||
-rw-r--r-- | sys/netatm/ipatm/ipatm_output.c | 216 | ||||
-rw-r--r-- | sys/netatm/ipatm/ipatm_serv.h | 114 | ||||
-rw-r--r-- | sys/netatm/ipatm/ipatm_usrreq.c | 394 | ||||
-rw-r--r-- | sys/netatm/ipatm/ipatm_var.h | 215 | ||||
-rw-r--r-- | sys/netatm/ipatm/ipatm_vcm.c | 1245 |
10 files changed, 4116 insertions, 0 deletions
diff --git a/sys/netatm/ipatm/ipatm.h b/sys/netatm/ipatm/ipatm.h new file mode 100644 index 0000000..b3ce348 --- /dev/null +++ b/sys/netatm/ipatm/ipatm.h @@ -0,0 +1,55 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: ipatm.h,v 1.5 1998/03/24 20:49:49 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Protocol definitions + * + */ + +#ifndef _IPATM_IPATM_H +#define _IPATM_IPATM_H + +/* + * Protocol Variables + */ +#define IPATM_VCIDLE 15 /* VCC idle time (minutes) */ +#define IPATM_ARP_TIME (60 * ATM_HZ) /* Wait for ARP answer */ +#define IPATM_SVC_TIME (60 * ATM_HZ) /* Wait for SVC open answer */ +#define IPATM_IDLE_TIME (60 * ATM_HZ) /* VCC idle timer tick */ + +/* + * IP/ATM LLC/SNAP header + */ +#define IPATM_LLC_LEN 8 +#define IPATM_LLC_HDR {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00} + +#endif /* _IPATM_IPATM_H */ diff --git a/sys/netatm/ipatm/ipatm_event.c b/sys/netatm/ipatm/ipatm_event.c new file mode 100644 index 0000000..048edf9 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_event.c @@ -0,0 +1,454 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: ipatm_event.c,v 1.8 1998/08/06 18:21:13 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * IP VCC event handler + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_event.c,v 1.8 1998/08/06 18:21:13 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Process an IP VCC timeout + * + * Called when a previously scheduled ipvcc control block timer expires. + * Processing will be based on the current ipvcc state. + * + * Called at splnet. + * + * Arguments: + * tip pointer to ipvcc timer control block + * + * Returns: + * none + * + */ +void +ipatm_timeout(tip) + struct atm_time *tip; +{ + struct ipvcc *ivp; + + /* + * Back-off to ipvcc control block + */ + ivp = (struct ipvcc *) + ((caddr_t)tip - (int)(&((struct ipvcc *)0)->iv_time)); + + /* + * Process timeout based on protocol state + */ + switch (ivp->iv_state) { + + case IPVCC_PMAP: + /* + * Give up waiting for arp response + */ + (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE); + break; + + case IPVCC_POPEN: + case IPVCC_PACCEPT: + /* + * Give up waiting for signalling manager response + */ + (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE); + break; + + case IPVCC_ACTPENT: + /* + * Try again to get an ARP entry + */ + switch ((*ivp->iv_ipnif->inf_serv->is_arp_pvcopen)(ivp)) { + + case MAP_PROCEEDING: + /* + * Wait for answer + */ + ivp->iv_state = IPVCC_ACTIVE; + break; + + case MAP_VALID: + /* + * We've got our answer already + */ + ivp->iv_state = IPVCC_ACTIVE; + ivp->iv_flags |= IVF_MAPOK; + ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr; + break; + + case MAP_FAILED: + /* + * Try again later + */ + IPVCC_TIMER(ivp, 5 * ATM_HZ); + break; + + default: + panic("ipatm_timeout: invalid am_pvcopen return"); + } + break; + + default: + log(LOG_ERR, "ipatm: invalid timer state: ivp=0x%x, state=%d\n", + (int)ivp, ivp->iv_state); + } +} + + +/* + * Process IP VCC Connected Notification + * + * Arguments: + * toku owner's connection token (ipvcc protocol block) + * + * Returns: + * none + * + */ +void +ipatm_connected(toku) + void *toku; +{ + struct ipvcc *ivp = (struct ipvcc *)toku; + + /* + * SVC is connected + */ + if ((ivp->iv_state != IPVCC_POPEN) && + (ivp->iv_state != IPVCC_PACCEPT)) { + log(LOG_ERR, "ipatm: invalid CALL_CONNECTED state=%d\n", + ivp->iv_state); + return; + } + + /* + * Verify possible negotiated parameter values + */ + if (ivp->iv_state == IPVCC_POPEN) { + Atm_attributes *ap = &ivp->iv_conn->co_connvc->cvc_attr; + int mtu = (ivp->iv_flags & IVF_LLC) ? + ATM_NIF_MTU + IPATM_LLC_LEN : + ATM_NIF_MTU; + + /* + * Verify final MTU + */ + if (ap->aal.type == ATM_AAL5) { + if ((ap->aal.v.aal5.forward_max_SDU_size < mtu) || + (ap->aal.v.aal5.backward_max_SDU_size > mtu)) { + (void) ipatm_closevc(ivp, + T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED); + return; + } + } else { + if ((ap->aal.v.aal4.forward_max_SDU_size < mtu) || + (ap->aal.v.aal4.backward_max_SDU_size > mtu)) { + (void) ipatm_closevc(ivp, + T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED); + return; + } + } + } + + /* + * Finish up VCC activation + */ + ipatm_activate(ivp); +} + + +/* + * Process IP VCC Cleared Notification + * + * Arguments: + * toku owner's connection token (ipvcc protocol block) + * cause pointer to cause code + * + * Returns: + * none + * + */ +void +ipatm_cleared(toku, cause) + void *toku; + struct t_atm_cause *cause; +{ + struct ipvcc *ivp = (struct ipvcc *)toku; + + + /* + * VCC has been cleared, so figure out what's next + */ + ivp->iv_conn = NULL; + + switch (ivp->iv_state) { + + case IPVCC_POPEN: + /* + * Call setup failed, see if there is another + * set of vcc parameters to try + */ + ivp->iv_state = IPVCC_CLOSED; + if (ipatm_retrysvc(ivp)) { + (void) ipatm_closevc(ivp, cause->cause_value); + } + break; + + case IPVCC_PACCEPT: + case IPVCC_ACTPENT: + case IPVCC_ACTIVE: + ivp->iv_state = IPVCC_CLOSED; + (void) ipatm_closevc(ivp, cause->cause_value); + break; + } +} + + +/* + * Process an ARP Event Notification + * + * Arguments: + * ivp pointer to IP VCC control block + * event ARP event type + * + * Returns: + * none + * + */ +void +ipatm_arpnotify(ivp, event) + struct ipvcc *ivp; + int event; +{ + struct sockaddr_in sin; + struct ifnet *ifp; + + /* + * Process event + */ + switch (event) { + + case MAP_VALID: + switch (ivp->iv_state) { + + case IPVCC_PMAP: + /* + * We've got our destination, however, first we'll + * check to make sure no other VCC to our destination + * has also had it's ARP table entry completed. + * If we don't find a better VCC to use, then we'll + * go ahead and open this SVC. + */ + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ivp->iv_dst.s_addr; + if (ipatm_iptovc(&sin, ivp->iv_ipnif->inf_nif) != ivp) { + /* + * We found a better VCC, so use it and + * get rid of this VCC + */ + if (ivp->iv_queue) { + ifp = (struct ifnet *) + ivp->iv_ipnif->inf_nif; + (void) ipatm_ifoutput(ifp, + ivp->iv_queue, + (struct sockaddr *)&sin); + ivp->iv_queue = NULL; + } + (void) ipatm_closevc(ivp, + T_ATM_CAUSE_UNSPECIFIED_NORMAL); + + } else { + /* + * We like this VCC... + */ + ivp->iv_flags |= IVF_MAPOK; + if (ipatm_opensvc(ivp)) { + (void) ipatm_closevc(ivp, + T_ATM_CAUSE_TEMPORARY_FAILURE); + } + } + break; + + case IPVCC_POPEN: + case IPVCC_PACCEPT: + case IPVCC_ACTIVE: + /* + * Everything looks good, so accept new mapping + */ + ivp->iv_flags |= IVF_MAPOK; + ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr; + + /* + * Send queued packet + */ + if ((ivp->iv_state == IPVCC_ACTIVE) && ivp->iv_queue) { + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ivp->iv_dst.s_addr; + ifp = (struct ifnet *)ivp->iv_ipnif->inf_nif; + (void) ipatm_ifoutput(ifp, ivp->iv_queue, + (struct sockaddr *)&sin); + ivp->iv_queue = NULL; + } + break; + } + break; + + case MAP_INVALID: + switch (ivp->iv_state) { + + case IPVCC_POPEN: + case IPVCC_PACCEPT: + case IPVCC_ACTIVE: + + /* + * Mapping has gone stale, so we cant use this VCC + * until the mapping is refreshed + */ + ivp->iv_flags &= ~IVF_MAPOK; + break; + } + break; + + case MAP_FAILED: + /* + * ARP lookup failed, just trash it all + */ + (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE); + break; + + case MAP_CHANGED: + /* + * ARP mapping has changed + */ + if (ivp->iv_flags & IVF_PVC) { + /* + * For PVCs, just reset lookup cache if needed + */ + if (last_map_ipvcc == ivp) { + last_map_ipdst = 0; + last_map_ipvcc = NULL; + } + } else { + /* + * Close SVC if it has already used this mapping + */ + switch (ivp->iv_state) { + + case IPVCC_POPEN: + case IPVCC_ACTIVE: + (void) ipatm_closevc(ivp, + T_ATM_CAUSE_UNSPECIFIED_NORMAL); + break; + } + } + break; + + default: + log(LOG_ERR, "ipatm: unknown arp event %d, ivp=0x%x\n", + event, (int)ivp); + } +} + + +/* + * Process an IP VCC idle timer tick + * + * This function is called every IPATM_IDLE_TIME seconds, in order to + * scan for idle IP VCC's. If an active VCC reaches the idle time limit, + * then it will be closed. + * + * Called at splnet. + * + * Arguments: + * tip pointer to the VCC idle timer control block + * + * Returns: + * none + * + */ +void +ipatm_itimeout(tip) + struct atm_time *tip; +{ + struct ipvcc *ivp, *inext; + struct ip_nif *inp; + + + /* + * Schedule next timeout + */ + atm_timeout(&ipatm_itimer, IPATM_IDLE_TIME, ipatm_itimeout); + + /* + * Check for disabled idle timeout + */ + if (ipatm_vcidle == 0) + return; + + /* + * Check out all IP VCCs + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; + ivp = inext) { + + inext = Q_NEXT(ivp, struct ipvcc, iv_elem); + + /* + * Looking for active, idle SVCs + */ + if (ivp->iv_flags & (IVF_PVC | IVF_NOIDLE)) + continue; + if (ivp->iv_state != IPVCC_ACTIVE) + continue; + if (++ivp->iv_idle < ipatm_vcidle) + continue; + + /* + * OK, we found one - close the VCC + */ + (void) ipatm_closevc(ivp, + T_ATM_CAUSE_UNSPECIFIED_NORMAL); + } + } +} + diff --git a/sys/netatm/ipatm/ipatm_if.c b/sys/netatm/ipatm/ipatm_if.c new file mode 100644 index 0000000..ede2450 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_if.c @@ -0,0 +1,335 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: ipatm_if.c,v 1.6 1998/03/24 20:51:47 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Interface Manager + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_if.c,v 1.6 1998/03/24 20:51:47 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Local functions + */ +static void ipatm_closenif __P((struct ip_nif *)); + + +/* + * Process Network Interface status change + * + * Called whenever a network interface status change is requested. + * + * Called at splnet. + * + * Arguments: + * cmd command code + * nip pointer to atm network interface control block + * arg command specific parameter + * + * Returns: + * 0 command successful + * errno command failed - reason indicated + * + */ +int +ipatm_nifstat(cmd, nip, arg) + int cmd; + struct atm_nif *nip; + int arg; +{ + struct in_ifaddr *ia; + struct siginst *sip; + struct ip_nif *inp; + int err = 0; + + /* + * Look for corresponding IP interface + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + + /* + * Process command + */ + switch (cmd) { + + case NCM_ATTACH: + /* + * Make sure i/f isn't already attached + */ + if (inp != NULL) { + err = EEXIST; + break; + } + + /* + * Get a new interface block + */ + inp = (struct ip_nif *)atm_allocate(&ipatm_nifpool); + if (inp == NULL) { + err = ENOMEM; + break; + } + inp->inf_nif = nip; + inp->inf_state = IPNIF_ADDR; + inp->inf_arpnotify = ipatm_arpnotify; + inp->inf_ipinput = ipatm_ipinput; + inp->inf_createsvc = ipatm_createsvc; + LINK2TAIL(inp, struct ip_nif, ipatm_nif_head, inf_next); + break; + + case NCM_DETACH: + /* + * Make sure i/f is attached + */ + if (inp == NULL) { + err = ENODEV; + break; + } + + /* + * Validate interface stuff + */ + if (Q_HEAD(inp->inf_vcq, struct ipvcc)) + panic("ipatm_nifstat: ipvcc queue not empty"); + + /* + * If we're active, close all our VCCs and tell the + * interface service about the deactivation + */ + if (inp->inf_state == IPNIF_ACTIVE) { + + ipatm_closenif(inp); + + if (inp->inf_serv) + (void) (*inp->inf_serv->is_ifdact)(inp); + } + + /* + * Clean up and free block + */ + UNLINK(inp, struct ip_nif, ipatm_nif_head, inf_next); + atm_free((caddr_t)inp); + break; + + case NCM_SETADDR: + /* + * We only care about IP addresses + */ +#if (defined(BSD) && (BSD >= 199103)) + if (((struct ifaddr *)arg)->ifa_addr->sa_family != AF_INET) +#else + if (((struct ifaddr *)arg)->ifa_addr.sa_family != AF_INET) +#endif + break; + + /* + * Make sure i/f is there + */ + ia = (struct in_ifaddr *)arg; + if (inp == NULL) + panic("ipatm_nifstat: setaddr missing ip_nif"); + + /* + * Process new address + */ + switch (inp->inf_state) { + + case IPNIF_SIGMGR: + case IPNIF_ADDR: + inp->inf_addr = ia; + + /* + * If signalling manager is not set, wait for it + */ + sip = nip->nif_pif->pif_siginst; + if (sip == NULL) { + inp->inf_state = IPNIF_SIGMGR; + break; + } + + /* + * Otherwise, everything's set + */ + inp->inf_state = IPNIF_ACTIVE; + + /* + * Tell interface service we're around + */ + if (sip->si_ipserv) { + inp->inf_serv = sip->si_ipserv; + err = (*inp->inf_serv->is_ifact)(inp); + } + + /* + * Reset state if there's been a problem + */ + if (err) { + inp->inf_serv = NULL; + inp->inf_addr = NULL; + inp->inf_state = IPNIF_ADDR; + } + break; + + case IPNIF_ACTIVE: + /* + * We dont support an address change + */ + err = EEXIST; + break; + } + break; + + case NCM_SIGATTACH: + /* + * Make sure i/f is attached + */ + if (inp == NULL) { + err = ENODEV; + break; + } + + /* + * Are we waiting for the sigmgr attach?? + */ + if (inp->inf_state != IPNIF_SIGMGR) { + /* + * No, nothing else to do + */ + break; + } + + /* + * OK, everything's set + */ + inp->inf_state = IPNIF_ACTIVE; + + /* + * Tell interface service we're around + */ + sip = nip->nif_pif->pif_siginst; + if (sip->si_ipserv) { + inp->inf_serv = sip->si_ipserv; + err = (*inp->inf_serv->is_ifact)(inp); + } + + /* + * Just report any problems, since a NCM_SIGDETACH will + * be coming down immediately + */ + break; + + case NCM_SIGDETACH: + /* + * Make sure i/f is attached + */ + if (inp == NULL) { + err = ENODEV; + break; + } + + /* + * Are we currently active?? + */ + if (inp->inf_state != IPNIF_ACTIVE) { + /* + * No, nothing else to do + */ + break; + } + + /* + * Close all the IP VCCs for this interface + */ + ipatm_closenif(inp); + + /* + * Tell interface service that i/f has gone down + */ + if (inp->inf_serv) + (void) (*inp->inf_serv->is_ifdact)(inp); + + /* + * Just have to wait for another sigattach + */ + inp->inf_serv = NULL; + inp->inf_state = IPNIF_SIGMGR; + break; + + default: + log(LOG_ERR, "ipatm_nifstat: unknown command %d\n", cmd); + } + + return (err); +} + + +/* + * Close all VCCs on a Network Interface + * + * Called at splnet. + * + * Arguments: + * inp pointer to IP network interface + * + * Returns: + * none + * + */ +static void +ipatm_closenif(inp) + struct ip_nif *inp; +{ + struct ipvcc *ivp, *inext; + + /* + * Close each IP VCC on this interface + */ + for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; ivp = inext) { + + inext = Q_NEXT(ivp, struct ipvcc, iv_elem); + + (void) ipatm_closevc(ivp, T_ATM_CAUSE_UNSPECIFIED_NORMAL); + } +} + diff --git a/sys/netatm/ipatm/ipatm_input.c b/sys/netatm/ipatm/ipatm_input.c new file mode 100644 index 0000000..ca3e3e7 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_input.c @@ -0,0 +1,210 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: ipatm_input.c,v 1.9 1998/04/07 23:03:52 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Process stack and data input + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_input.c,v 1.9 1998/04/07 23:03:52 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Process VCC Input Data + * + * Arguments: + * tok ipatm connection token (pointer to ipvcc) + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +void +ipatm_cpcs_data(tok, m) + void *tok; + KBuffer *m; +{ + struct ipvcc *ivp = tok; + +#ifdef DIAGNOSTIC + if (ipatm_print) { + atm_pdu_print(m, "ipatm_input"); + } +#endif + + /* + * Handle input packet + */ + if (ivp->iv_state != IPVCC_ACTIVE) { + KB_FREEALL(m); + ipatm_stat.ias_rcvstate++; + return; + } + + /* + * IP packet - reset idle timer + */ + ivp->iv_idle = 0; + + /* + * Pass packet to IP + */ + (void) ipatm_ipinput(ivp->iv_ipnif, m); +} + + +/* + * IP Input Packet Handler + * + * All IP packets received from various ATM sources will be sent here + * for final queuing to the IP layer. + * + * Arguments: + * inp pointer to packet's receiving IP network interface + * m pointer to packet buffer chain + * + * Returns: + * 0 packet successfully queued to IP layer + * else error queuing packet, buffer chain freed + * + */ +int +ipatm_ipinput(inp, m) + struct ip_nif *inp; + KBuffer *m; +{ + int s, space; + +#ifdef DIAGNOSTIC + if (ipatm_print) { + atm_pdu_print(m, "ipatm_ipinput"); + } +#endif + +#if defined(BSD) +#if BSD >= 199103 + +#ifdef DIAGNOSTIC + if (!KB_ISPKT(m)) { + panic("ipatm_ipinput: no packet header"); + } + { + int cnt = 0; + KBuffer *m0 = m; + + while (m0) { + cnt += KB_LEN(m0); + m0 = KB_NEXT(m0); + } + if (m->m_pkthdr.len != cnt) { + panic("ipatm_ipinput: packet length incorrect"); + } + } +#endif + /* + * Save the input ifnet pointer in the packet header + */ + m->m_pkthdr.rcvif = (struct ifnet *)inp->inf_nif; + +#else /* ! BSD >= 199103 */ + /* + * Stick ifnet pointer onto front of packet - hopefully + * there'll be room in the first buffer. + */ + KB_HEADROOM(m, space); + if (space < sizeof(struct ifnet *)) { + KBuffer *n; + + /* + * We have to allocate another buffer and tack it + * onto the front of the packet + */ + KB_ALLOCPKT(n, sizeof(struct ifnet *), + KB_F_NOWAIT, KB_T_HEADER); + if (n == 0) { + KB_FREEALL(m); + ipatm_stat.ias_rcvnobuf++; + return (1); + } + KB_LEN(n) = sizeof(struct ifnet *); + KB_LINKHEAD(n, m); + m = n; + } else { + /* + * Header fits, just adjust buffer controls + */ + KB_HEADADJ(m, sizeof(struct ifnet *)); + } + { + struct ifnet **p; + + KB_DATASTART(m, p, struct ifnet **); + *p = (struct ifnet *)inp->inf_nif; + } +#endif /* ! BSD >= 199103 */ + + /* + * Finally, hand packet off to IP. + * + * NB: Since we're already in the softint kernel state, we + * just call IP directly to avoid the extra unnecessary + * kernel scheduling. + */ + s = splimp(); + if (IF_QFULL(&ipintrq)) { + IF_DROP(&ipintrq); + (void) splx(s); + KB_FREEALL(m); + return (1); + } + + IF_ENQUEUE(&ipintrq, m); + (void) splx(s); +#if BSD < 199506 + ipintr(); +#else + schednetisr ( NETISR_IP ); +#endif /* BSD >= 199506 */ +#endif /* defined(BSD) */ + + return (0); +} + diff --git a/sys/netatm/ipatm/ipatm_load.c b/sys/netatm/ipatm/ipatm_load.c new file mode 100644 index 0000000..8caa635 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_load.c @@ -0,0 +1,878 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: ipatm_load.c,v 1.12 1998/07/30 22:23:00 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Support for running as a loadable kernel module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_load.c,v 1.12 1998/07/30 22:23:00 mks Exp $"; +#endif + +#ifndef ATM_IP_MODULE +#include "opt_atm.h" +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Global variables + */ +int ipatm_vccnt = 0; +int ipatm_vcidle = IPATM_VCIDLE; +int ipatm_print = 0; +u_long last_map_ipdst = 0; +struct ipvcc* last_map_ipvcc = NULL; + +struct ip_nif *ipatm_nif_head = NULL; + +struct ipatm_stat ipatm_stat = {0}; + +struct atm_time ipatm_itimer = {0, 0}; /* VCC idle timer */ + +Atm_endpoint ipatm_endpt = { + NULL, + ENDPT_IP, + ipatm_ioctl, + ipatm_getname, + ipatm_connected, + ipatm_cleared, + ipatm_incoming, + NULL, + NULL, + NULL, + ipatm_cpcs_data, + NULL, + NULL, + NULL, + NULL +}; + +struct sp_info ipatm_vcpool = { + "ipatm vcc pool", /* si_name */ + sizeof(struct ipvcc), /* si_blksiz */ + 10, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + +struct sp_info ipatm_nifpool = { + "ipatm nif pool", /* si_name */ + sizeof(struct ip_nif), /* si_blksiz */ + 5, /* si_blkcnt */ + 20 /* si_maxallow */ +}; + + +/* + * Local functions + */ +static int ipatm_start __P((void)); +static int ipatm_stop __P((void)); + + +/* + * Local variables + */ +static struct atm_ncm ipatm_ncm = { + NULL, + AF_INET, + ipatm_ifoutput, + ipatm_nifstat +}; + +static struct ipatm_listener { + Atm_attributes attr; + Atm_connection *conn; +} ipatm_listeners[] = { +{ + { NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL5 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_ANY + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_PRESENT, + T_ATM_ABSENT, + { + { + T_ATM_SIMPLE_ID, + }, + { + T_ATM_ABSENT + } + } + }, + { /* llc */ + T_ATM_PRESENT, + { + T_ATM_LLC_SHARING, + IPATM_LLC_LEN, + IPATM_LLC_HDR + } + }, + { /* called */ + T_ATM_ANY + }, + { /* calling */ + T_ATM_ANY + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ANY + }, + { /* cause */ + T_ATM_ABSENT + }, + }, + NULL +}, +{ + { NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL5 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_ANY + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_ABSENT, + T_ATM_ABSENT + }, + { /* llc */ + T_ATM_ABSENT + }, + { /* called */ + T_ATM_ANY + }, + { /* calling */ + T_ATM_ANY + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ANY + }, + { /* cause */ + T_ATM_ABSENT + }, + }, + NULL +}, +{ + { NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL3_4 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_ANY + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_ABSENT, + T_ATM_ABSENT + }, + { /* llc */ + T_ATM_ABSENT + }, + { /* called */ + T_ATM_ANY + }, + { /* calling */ + T_ATM_ANY + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ANY + }, + { /* cause */ + T_ATM_ABSENT + }, + }, + NULL +}, +}; + +static struct t_atm_cause ipatm_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_UNSPECIFIED_NORMAL, + {0, 0, 0, 0} +}; + + +/* + * Initialize ipatm processing + * + * This will be called during module loading. We'll just register + * ourselves and wait for the packets to start flying. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +static int +ipatm_start() +{ + struct atm_pif *pip; + struct atm_nif *nip; + int err, s, i; + + /* + * Verify software version + */ + if (atm_version != ATM_VERSION) { + log(LOG_ERR, "version mismatch: ipatm=%d.%d kernel=%d.%d\n", + ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION), + ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version)); + return (EINVAL); + } + + /* + * Register ourselves as a network convergence module + */ + err = atm_netconv_register(&ipatm_ncm); + if (err) + goto done; + + /* + * Register ourselves as an ATM endpoint + */ + err = atm_endpoint_register(&ipatm_endpt); + if (err) + goto done; + + /* + * Get current system configuration + */ + s = splnet(); + for (pip = atm_interface_head; pip; pip = pip->pif_next) { + /* + * Process each network interface + */ + for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) { + struct ifnet *ifp = (struct ifnet *)nip; + struct in_ifaddr *ia; + + /* + * Attach interface + */ + err = ipatm_nifstat(NCM_ATTACH, nip, 0); + if (err) { + (void) splx(s); + goto done; + } + + /* + * If IP address has been set, register it + */ + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { + if (ia->ia_ifp == ifp) + break; + } + if (ia) { + err = ipatm_nifstat(NCM_SETADDR, nip, (int)ia); + if (err) { + (void) splx(s); + goto done; + } + } + } + } + (void) splx(s); + + /* + * Fill in union fields + */ + ipatm_aal5llc.aal.v.aal5.forward_max_SDU_size = + ATM_NIF_MTU + IPATM_LLC_LEN; + ipatm_aal5llc.aal.v.aal5.backward_max_SDU_size = + ATM_NIF_MTU + IPATM_LLC_LEN; + ipatm_aal5llc.aal.v.aal5.SSCS_type = T_ATM_NULL; + ipatm_aal5llc.blli.v.layer_2_protocol.ID.simple_ID = T_ATM_BLLI2_I8802; + + ipatm_aal5null.aal.v.aal5.forward_max_SDU_size = ATM_NIF_MTU; + ipatm_aal5null.aal.v.aal5.backward_max_SDU_size = ATM_NIF_MTU; + ipatm_aal5null.aal.v.aal5.SSCS_type = T_ATM_NULL; + + ipatm_aal4null.aal.v.aal4.forward_max_SDU_size = ATM_NIF_MTU; + ipatm_aal4null.aal.v.aal4.backward_max_SDU_size = ATM_NIF_MTU; + ipatm_aal4null.aal.v.aal4.SSCS_type = T_ATM_NULL; + ipatm_aal4null.aal.v.aal4.mid_low = 0; + ipatm_aal4null.aal.v.aal4.mid_high = 1023; + + /* + * Listen for incoming calls + */ + for (i = 0; + i < (sizeof(ipatm_listeners) / sizeof(struct ipatm_listener)); + i++) { + struct attr_aal *aalp = &ipatm_listeners[i].attr.aal; + int maxsdu = ATM_NIF_MTU; + + /* + * Fill in union fields + */ + if (ipatm_listeners[i].attr.blli.tag_l2 == T_ATM_PRESENT) { + struct t_atm_blli *bp = &ipatm_listeners[i].attr.blli.v; + + bp->layer_2_protocol.ID.simple_ID = T_ATM_BLLI2_I8802; + maxsdu += IPATM_LLC_LEN; + } + if (aalp->type == ATM_AAL5) { + aalp->v.aal5.forward_max_SDU_size = maxsdu; + aalp->v.aal5.backward_max_SDU_size = maxsdu; + aalp->v.aal5.SSCS_type = T_ATM_NULL; + } else { + aalp->v.aal4.forward_max_SDU_size = maxsdu; + aalp->v.aal4.backward_max_SDU_size = maxsdu; + aalp->v.aal4.SSCS_type = T_ATM_NULL; + aalp->v.aal4.mid_low = 0; + aalp->v.aal4.mid_high = 1023; + } + + /* + * Now start listening + */ + if (err = atm_cm_listen(&ipatm_endpt, (void *)i, + &ipatm_listeners[i].attr, + &ipatm_listeners[i].conn)) + goto done; + } + + /* + * Start background VCC idle timer + */ + atm_timeout(&ipatm_itimer, IPATM_IDLE_TIME, ipatm_itimeout); + +done: + return (err); +} + + +/* + * Halt ipatm processing + * + * This will be called just prior to unloading the module from + * memory. All IP VCCs must be terminated before the protocol can + * be shutdown. + * + * Arguments: + * none + * + * Returns: + * 0 shutdown was successful + * errno shutdown failed - reason indicated + * + */ +static int +ipatm_stop() +{ + struct ip_nif *inp; + int err = 0, i; + int s = splnet(); + + /* + * Any VCCs still open?? + */ + if (ipatm_vccnt) { + + /* Yes, can't stop now */ + err = EBUSY; + goto done; + } + + /* + * Kill VCC idle timer + */ + (void) atm_untimeout(&ipatm_itimer); + + /* + * Stop listening for incoming calls + */ + for (i = 0; + i < (sizeof(ipatm_listeners) / sizeof(struct ipatm_listener)); + i++) { + if (ipatm_listeners[i].conn != NULL) { + (void) atm_cm_release(ipatm_listeners[i].conn, + &ipatm_cause); + } + } + + /* + * Detach all our interfaces + */ + while (inp = ipatm_nif_head) { + (void) ipatm_nifstat(NCM_DETACH, inp->inf_nif, 0); + } + + /* + * De-register from system + */ + (void) atm_netconv_deregister(&ipatm_ncm); + (void) atm_endpoint_deregister(&ipatm_endpt); + + /* + * Free up our storage pools + */ + atm_release_pool(&ipatm_vcpool); + atm_release_pool(&ipatm_nifpool); + +done: + (void) splx(s); + return (err); +} + + +#ifdef ATM_IP_MODULE +/* + ******************************************************************* + * + * Loadable Module Support + * + ******************************************************************* + */ +static int ipatm_doload __P((void)); +static int ipatm_dounload __P((void)); + +/* + * Generic module load processing + * + * This function is called by an OS-specific function when this + * module is being loaded. + * + * Arguments: + * none + * + * Returns: + * 0 load was successful + * errno load failed - reason indicated + * + */ +static int +ipatm_doload() +{ + int err = 0; + + /* + * Start us up + */ + err = ipatm_start(); + if (err) + /* Problems, clean up */ + (void)ipatm_stop(); + + return (err); +} + + +/* + * Generic module unload processing + * + * This function is called by an OS-specific function when this + * module is being unloaded. + * + * Arguments: + * none + * + * Returns: + * 0 unload was successful + * errno unload failed - reason indicated + * + */ +static int +ipatm_dounload() +{ + int err = 0; + + /* + * OK, try to clean up our mess + */ + err = ipatm_stop(); + + return (err); +} + + +#ifdef sun +/* + * Loadable driver description + */ +struct vdldrv ipatm_drv = { + VDMAGIC_PSEUDO, /* Pseudo Driver */ + "ipatm_mod", /* name */ + NULL, /* dev_ops */ + NULL, /* bdevsw */ + NULL, /* cdevsw */ + 0, /* blockmajor */ + 0 /* charmajor */ +}; + + +/* + * Loadable module support entry point + * + * This is the routine called by the vd driver for all loadable module + * functions for this pseudo driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * cmd vd command code + * vdp pointer to vd driver's structure + * vdi pointer to command-specific vdioctl_* structure + * vds pointer to status structure (VDSTAT only) + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +ipatm_mod(cmd, vdp, vdi, vds) + int cmd; + struct vddrv *vdp; + caddr_t vdi; + struct vdstat *vds; +{ + int err = 0; + + switch (cmd) { + + case VDLOAD: + /* + * Module Load + * + * We dont support any user configuration + */ + err = ipatm_doload(); + if (err == 0) + /* Let vd driver know about us */ + vdp->vdd_vdtab = (struct vdlinkage *)&ipatm_drv; + break; + + case VDUNLOAD: + /* + * Module Unload + */ + err = ipatm_dounload(); + break; + + case VDSTAT: + /* + * Module Status + */ + + /* Not much to say at the moment */ + + break; + + default: + log(LOG_ERR, "ipatm_mod: Unknown vd command 0x%x\n", cmd); + err = EINVAL; + } + + return (err); +} +#endif /* sun */ + +#ifdef __FreeBSD__ + +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/lkm.h> + +/* + * Loadable miscellaneous module description + */ +MOD_MISC(ipatm); + + +/* + * Loadable module support "load" entry point + * + * This is the routine called by the lkm driver whenever the + * modload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +ipatm_load(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(ipatm_doload()); +} + + +/* + * Loadable module support "unload" entry point + * + * This is the routine called by the lkm driver whenever the + * modunload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +ipatm_unload(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(ipatm_dounload()); +} + + +/* + * Loadable module support entry point + * + * This is the routine called by the lkm driver for all loadable module + * functions for this driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * ver lkm version + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +ipatm_mod(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd; + int ver; +{ + MOD_DISPATCH(ipatm, lkmtp, cmd, ver, + ipatm_load, ipatm_unload, lkm_nullcmd); +} +#endif /* __FreeBSD__ */ + +#else /* !ATM_IP_MODULE */ + +/* + ******************************************************************* + * + * Kernel Compiled Module Support + * + ******************************************************************* + */ +static void ipatm_doload __P((void *)); + +SYSINIT(atmipatm, SI_SUB_PROTO_END, SI_ORDER_ANY, ipatm_doload, NULL) + +/* + * Kernel initialization + * + * Arguments: + * arg Not used + * + * Returns: + * none + * + */ +static void +ipatm_doload(void *arg) +{ + int err = 0; + + /* + * Start us up + */ + err = ipatm_start(); + if (err) { + /* Problems, clean up */ + (void)ipatm_stop(); + + log(LOG_ERR, "IP over ATM unable to initialize (%d)!!\n", err); + } + return; +} +#endif /* ATM_IP_MODULE */ + diff --git a/sys/netatm/ipatm/ipatm_output.c b/sys/netatm/ipatm/ipatm_output.c new file mode 100644 index 0000000..7f02f28 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_output.c @@ -0,0 +1,216 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: ipatm_output.c,v 1.6 1998/02/19 20:14:17 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Output IP packets across an ATM VCC + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_output.c,v 1.6 1998/02/19 20:14:17 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Output an IP Packet + * + * All IP packets output to an ATM interface will be directed here via + * the atm_ifoutput() function. If there is an ATM VCC already setup for + * the destination IP address, then we'll just send the packet to that VCC. + * Otherwise we will have to setup a new VCC, ARPing for the corresponding + * destination ATM hardware address along the way. + * + * Arguments: + * ifp pointer to ifnet structure + * m pointer to packet buffer chain to be output + * dst pointer to packet's IP destination address + * + * Returns: + * 0 packet "output" was successful + * errno output failed - reason indicated + * + */ +int +ipatm_ifoutput(ifp, m, dst) + struct ifnet *ifp; + KBuffer *m; + struct sockaddr *dst; +{ + struct ipvcc *ivp; + int err = 0; + +#ifdef DIAGNOSTIC + if (ipatm_print) { + atm_pdu_print(m, "ipatm_ifoutput"); + } +#endif + + /* + * See if we've already got an appropriate VCC + */ + ivp = ipatm_iptovc((struct sockaddr_in *)dst, (struct atm_nif *)ifp); + if (ivp) { + + /* + * Reset idle timer + */ + ivp->iv_idle = 0; + + /* + * Can we use this VCC now?? + */ + if ((ivp->iv_state == IPVCC_ACTIVE) && + (ivp->iv_flags & IVF_MAPOK)) { + + /* + * OK, now send packet + */ + err = atm_cm_cpcs_data(ivp->iv_conn, m); + if (err) { + /* + * Output problem, drop packet + */ + KB_FREEALL(m); + } + } else { + + /* + * VCC is unavailable for data packets. Queue packet + * for now, but only maintain a queue length of one. + */ + if (ivp->iv_queue) + KB_FREEALL(ivp->iv_queue); + + ivp->iv_queue = m; + } + } else { + struct in_ifaddr *ia; +#if (defined(BSD) && (BSD < 199306)) + extern struct ifnet loif; +#endif + + /* + * No VCC to destination + */ + + /* + * Is packet for our interface address? + */ + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { + if (ia->ia_ifp != ifp) + continue; + if (((struct sockaddr_in *)dst)->sin_addr.s_addr == + IA_SIN(ia)->sin_addr.s_addr) { + + /* + * It's for us - hand packet to loopback driver + */ + (void) if_simloop(ifp, m, dst, 0); + goto done; + } + } + + /* + * Is this a broadcast packet ?? + */ +#if (defined(BSD) && (BSD >= 199306)) + if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr, ifp)) { +#else + if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr)) { +#endif + struct ip_nif *inp; + int s; + + /* + * If interface server exists and provides broadcast + * services, then let it deal with this packet + */ + s = splnet(); + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == (struct atm_nif *)ifp) + break; + } + (void) splx(s); + + if ((inp == NULL) || + (inp->inf_serv == NULL) || + (inp->inf_serv->is_bcast_output == NULL)) { + KB_FREEALL(m); + err = EADDRNOTAVAIL; + goto done; + } + + err = (*inp->inf_serv->is_bcast_output)(inp, m); + goto done; + } + + /* + * How about a multicast packet ?? + */ + if (IN_MULTICAST(ntohl(SATOSIN(dst)->sin_addr.s_addr))) { + /* + * Multicast isn't currently supported + */ + KB_FREEALL(m); + err = EADDRNOTAVAIL; + goto done; + } + + /* + * Well, I guess we need to create an SVC to the destination + */ + if ((err = ipatm_createsvc(ifp, AF_INET, + (caddr_t)&((struct sockaddr_in *)dst)->sin_addr, + &ivp)) == 0) { + /* + * SVC open is proceeding, queue packet + */ + ivp->iv_queue = m; + + } else { + /* + * SVC open failed, release buffers and return + */ + KB_FREEALL(m); + } + } + +done: + return (err); +} + diff --git a/sys/netatm/ipatm/ipatm_serv.h b/sys/netatm/ipatm/ipatm_serv.h new file mode 100644 index 0000000..2046213 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_serv.h @@ -0,0 +1,114 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: ipatm_serv.h,v 1.6 1998/02/19 20:14:21 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * IP/ATM service interface definitions + * + */ + +#ifndef _IPATM_IPATM_SERV_H +#define _IPATM_IPATM_SERV_H + + +/* + * Structures specifying VCC parameters and pointers to all of the IP + * services offered by an external IP interface service provider. + */ +struct ip_vccparm { + Aal_t ivc_aal; /* AAL type */ + Encaps_t ivc_encaps; /* VCC encapsulation */ +}; + +#define IPATM_VCCPARMS 4 /* Number of parameter lists */ + +struct ip_serv { +/* Interfaces to IP/ATM interface services */ + int (*is_ifact) /* Interface activation */ + __P((struct ip_nif *)); + int (*is_ifdact) /* Interface deactivation */ + __P((struct ip_nif *)); + int (*is_ioctl) /* Interface ioctl */ + __P((int, caddr_t, caddr_t)); + +/* Interfaces to IP/ATM ARP services */ + int (*is_arp_pvcopen) /* IP creating dynamic PVC */ + __P((struct ipvcc *)); + int (*is_arp_svcout) /* IP creating outgoing SVC */ + __P((struct ipvcc *, struct in_addr *)); + int (*is_arp_svcin) /* IP creating incoming SVC */ + __P((struct ipvcc *, Atm_addr *, Atm_addr *)); + int (*is_arp_svcact) /* IP SVC is active */ + __P((struct ipvcc *)); + void (*is_arp_close) /* IP closing VCC */ + __P((struct ipvcc *)); + +/* Interfaces to IP/ATM broadcast services */ + int (*is_bcast_output) /* IP broadcast packet output */ + __P((struct ip_nif *, KBuffer *)); + +/* Interfaces to IP/ATM multicast services */ + +/* Ordered list of parameters to try for IP/ATM VCC connections */ + struct ip_vccparm is_vccparm[IPATM_VCCPARMS]; /* List of vcc params */ +}; + + +/* + * ARP Interface + * ---------------- + */ + +/* + * Common header for IP/ATM ARP mappings. For each IP VCC created, the + * appropriate IP/ATM ARP server must assign one of these structures to + * indicate the address mapping. This is the only IP-visible ARP structure. + * The servers may embed this structure at the beginning of their + * module-specific mappings. + */ +struct arpmap { + struct in_addr am_dstip; /* Destination IP address */ + Atm_addr am_dstatm; /* Destination ATM address */ + Atm_addr am_dstatmsub; /* Destination ATM subaddress */ +}; + + +/* + * is_arp_[ps]open() return codes and ipatm_arpnotify() event types + */ +#define MAP_PROCEEDING 1 /* Lookup is proceeding (open only) */ +#define MAP_VALID 2 /* Mapping is valid */ +#define MAP_INVALID 3 /* Mapping is invalid */ +#define MAP_CHANGED 4 /* Mapping has changed */ +#define MAP_FAILED 5 /* Mapping request has failed */ + + +#endif /* _IPATM_IPATM_SERV_H */ diff --git a/sys/netatm/ipatm/ipatm_usrreq.c b/sys/netatm/ipatm/ipatm_usrreq.c new file mode 100644 index 0000000..1f1751c --- /dev/null +++ b/sys/netatm/ipatm/ipatm_usrreq.c @@ -0,0 +1,394 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: ipatm_usrreq.c,v 1.6 1998/05/18 19:14:04 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Process user requests + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_usrreq.c,v 1.6 1998/05/18 19:14:04 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Process IP PF_ATM ioctls + * + * Called at splnet. + * + * Arguments: + * code PF_ATM sub-operation code + * data pointer to code specific parameter data area + * arg1 pointer to code specific argument + * + * Returns: + * 0 request procesed + * errno error processing request - reason indicated + * + */ +int +ipatm_ioctl(code, data, arg1) + int code; + caddr_t data; + caddr_t arg1; +{ + struct atmaddreq *aap; + struct atmdelreq *adp; + struct atminfreq *aip; + struct air_ip_vcc_rsp aivr; + struct atm_nif *nip; + struct ip_nif *inp; + struct ipvcc *ivp; + struct vccb *vcp; + struct ipatmpvc pv; + caddr_t cp; + struct in_addr ip; + int space, err = 0; + + + switch (code) { + + case AIOCS_ADD_PVC: + /* + * Add an IP PVC + */ + aap = (struct atmaddreq *)data; + + /* + * Find the IP network interface + */ + if ((nip = atm_nifname(aap->aar_pvc_intf)) == NULL) { + err = ENXIO; + break; + } + + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + if (inp == NULL) { + err = ENXIO; + break; + } + + /* + * Validate PVC params + */ + if (aap->aar_pvc_aal == ATM_AAL5) { + if ((aap->aar_pvc_encaps != ATM_ENC_LLC) && + (aap->aar_pvc_encaps != ATM_ENC_NULL)) { + err = EINVAL; + break; + } + } else if (aap->aar_pvc_aal == ATM_AAL3_4) { + if (aap->aar_pvc_encaps != ATM_ENC_NULL) { + err = EINVAL; + break; + } + } else { + err = EINVAL; + break; + } + + if (aap->aar_pvc_flags & PVC_DYN) { + /* + * For dynamic PVC destination addressing, the + * network interface must have support for this + */ + if ((inp->inf_serv == NULL) || + (inp->inf_serv->is_arp_pvcopen == NULL)) { + err = EDESTADDRREQ; + break; + } + } else { + u_long dst = ((struct sockaddr_in *)&aap->aar_pvc_dst) + ->sin_addr.s_addr; + + if (dst == INADDR_ANY) { + err = EINVAL; + break; + } + } + + /* + * Build connection request + */ + pv.ipp_ipnif = inp; + pv.ipp_vpi = aap->aar_pvc_vpi; + pv.ipp_vci = aap->aar_pvc_vci; + pv.ipp_encaps = aap->aar_pvc_encaps; + pv.ipp_aal = aap->aar_pvc_aal; + if (aap->aar_pvc_flags & PVC_DYN) { + pv.ipp_dst.sin_addr.s_addr = INADDR_ANY; + } else + pv.ipp_dst = *(struct sockaddr_in *)&aap->aar_pvc_dst; + + /* + * Open a new VCC + */ + err = ipatm_openpvc(&pv, &ivp); + break; + + case AIOCS_ADD_ARP: + /* + * Add an ARP mapping + */ + aap = (struct atmaddreq *)data; + + /* + * Validate IP address + */ + if (aap->aar_arp_dst.sa_family != AF_INET) { + err = EAFNOSUPPORT; + break; + } + ip = SATOSIN(&aap->aar_arp_dst)->sin_addr; + + if (aap->aar_arp_intf[0] == '\0') { + /* + * Find the IP network interface associated with + * the supplied IP address + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (ipatm_chknif(ip, inp) == 0) + break; + } + if (inp == NULL) { + err = EADDRNOTAVAIL; + break; + } + } else { + /* + * Find the specified IP network interface + */ + if ((nip = atm_nifname(aap->aar_arp_intf)) == NULL) { + err = ENXIO; + break; + } + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + if (inp == NULL) { + err = ENXIO; + break; + } + } + + if ((ip.s_addr == INADDR_ANY) || +#if (defined(BSD) && (BSD >= 199306)) + in_broadcast(ip, &inp->inf_nif->nif_if) || +#else + in_broadcast(ip) || +#endif + IN_MULTICAST(ntohl(ip.s_addr))) { + err = EADDRNOTAVAIL; + break; + } + + /* + * Notify the responsible ARP service + */ + err = (*inp->inf_serv->is_ioctl)(code, data, inp->inf_isintf); + break; + + case AIOCS_DEL_ARP: + /* + * Delete an ARP mapping + */ + adp = (struct atmdelreq *)data; + + /* + * Validate IP address + */ + if (adp->adr_arp_dst.sa_family != AF_INET) { + err = EAFNOSUPPORT; + break; + } + ip = SATOSIN(&adp->adr_arp_dst)->sin_addr; + + if (adp->adr_arp_intf[0] == '\0') { + /* + * Find the IP network interface associated with + * the supplied IP address + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (ipatm_chknif(ip, inp) == 0) + break; + } + if (inp == NULL) { + err = EADDRNOTAVAIL; + break; + } + } else { + /* + * Find the specified IP network interface + */ + if ((nip = atm_nifname(adp->adr_arp_intf)) == NULL) { + err = ENXIO; + break; + } + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + if (inp == NULL) { + err = ENXIO; + break; + } + } + + if ((ip.s_addr == INADDR_ANY) || +#if (defined(BSD) && (BSD >= 199306)) + in_broadcast(ip, &inp->inf_nif->nif_if) || +#else + in_broadcast(ip) || +#endif + IN_MULTICAST(ntohl(ip.s_addr))) { + err = EADDRNOTAVAIL; + break; + } + + /* + * Notify the responsible ARP service + */ + err = (*inp->inf_serv->is_ioctl)(code, data, inp->inf_isintf); + break; + + case AIOCS_INF_IPM: + /* + * Get IP VCC information + */ + aip = (struct atminfreq *)data; + + if (aip->air_ip_addr.sa_family != AF_INET) + break; + ip = SATOSIN(&aip->air_ip_addr)->sin_addr; + + cp = aip->air_buf_addr; + space = aip->air_buf_len; + + /* + * Loop through all our interfaces + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + /* + * Check out each VCC + */ + for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; + ivp = Q_NEXT(ivp, struct ipvcc, iv_elem)) { + + if ((ip.s_addr != INADDR_ANY) && + (ip.s_addr != ivp->iv_dst.s_addr)) + continue; + + /* + * Make sure there's room in user buffer + */ + if (space < sizeof(aivr)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + KM_ZERO((caddr_t)&aivr, sizeof(aivr)); + SATOSIN(&aivr.aip_dst_addr)->sin_family = + AF_INET; + SATOSIN(&aivr.aip_dst_addr)->sin_addr.s_addr = + ivp->iv_dst.s_addr; + (void) sprintf(aivr.aip_intf, "%s%d", + inp->inf_nif->nif_if.if_name, + inp->inf_nif->nif_if.if_unit); + if ((ivp->iv_conn) && + (ivp->iv_conn->co_connvc) && + (vcp = ivp->iv_conn->co_connvc->cvc_vcc)) { + aivr.aip_vpi = vcp->vc_vpi; + aivr.aip_vci = vcp->vc_vci; + aivr.aip_sig_proto = vcp->vc_proto; + } + aivr.aip_flags = ivp->iv_flags; + aivr.aip_state = ivp->iv_state; + + /* + * Copy data to user buffer and + * update buffer controls + */ + err = copyout((caddr_t)&aivr, cp, sizeof(aivr)); + if (err) + break; + cp += sizeof(aivr); + space -= sizeof(aivr); + } + if (err) + break; + } + + /* + * Update buffer pointer/count + */ + aip->air_buf_addr = cp; + aip->air_buf_len = space; + break; + + default: + err = EOPNOTSUPP; + } + + return (err); +} + + +/* + * Get Connection's Application/Owner Name + * + * Arguments: + * tok ipatm connection token (pointer to ipvcc) + * + * Returns: + * addr pointer to string containing our name + * + */ +caddr_t +ipatm_getname(tok) + void *tok; +{ + return ("IP"); +} + diff --git a/sys/netatm/ipatm/ipatm_var.h b/sys/netatm/ipatm/ipatm_var.h new file mode 100644 index 0000000..6048284 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_var.h @@ -0,0 +1,215 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: ipatm_var.h,v 1.8 1998/03/24 20:56:57 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Protocol control blocks + * + */ + +#ifndef _IPATM_IPATM_VAR_H +#define _IPATM_IPATM_VAR_H + +#ifdef ATM_KERNEL +/* + * Structure containing information for each VCC, both SVC and PVC, which + * supports IP traffic. + */ +struct ipvcc { + Qelem_t iv_elem; /* ip_nif queueing links */ + u_short iv_flags; /* VCC flags (see below) */ + u_char iv_state; /* VCC state (see below) */ + Atm_connection *iv_conn; /* Connection manager token */ + struct in_addr iv_dst; /* Peer's IP address */ + struct ip_nif *iv_ipnif; /* IP network interface */ + struct atm_time iv_time; /* Timer controls */ + short iv_idle; /* VCC idle timer */ + u_char iv_parmx; /* Index into provider's vcc params */ + KBuffer *iv_queue; /* Packet waiting for VCC */ + struct arpmap *iv_arpent; /* ARP entry for VCC */ + struct ipvcc *iv_arpnext; /* ARP link field */ + Atm_connection *iv_arpconn; /* ARP connection manager token */ +}; +#define iv_forw iv_elem.q_forw +#define iv_back iv_elem.q_back +#endif /* ATM_KERNEL */ + +/* + * VCC Flags + */ +#define IVF_PVC 0x0001 /* PVC */ +#define IVF_SVC 0x0002 /* SVC */ +#define IVF_LLC 0x0004 /* VCC uses LLC/SNAP encapsulation */ +#define IVF_MAPOK 0x0008 /* VCC ARP mapping is valid */ +#define IVF_NOIDLE 0x0010 /* Do not idle-timeout this VCC */ + +/* + * VCC States + */ +#define IPVCC_FREE 0 /* No VCC associated with entry */ +#define IPVCC_PMAP 1 /* SVC waiting for ARP mapping */ +#define IPVCC_POPEN 2 /* Pending SVC open completion */ +#define IPVCC_PACCEPT 3 /* Pending SVC accept completion */ +#define IPVCC_ACTPENT 4 /* PVC open - waiting for ARP entry */ +#define IPVCC_ACTIVE 5 /* VCC open - available */ +#define IPVCC_CLOSED 6 /* VCC has been closed */ + + +#ifdef ATM_KERNEL +/* + * Structure containing IP-specific information for each ATM network + * interface in the system. + */ +struct ip_nif { + struct ip_nif *inf_next; /* Next on interface chain */ + struct atm_nif *inf_nif; /* ATM network interface */ + u_short inf_state; /* Interface state (see below) */ + struct in_ifaddr *inf_addr; /* Interface's IP address */ + Queue_t inf_vcq; /* VCC connections queue */ + struct ip_serv *inf_serv; /* Interface service provider */ + +/* For use by IP interface service provider (ie signalling manager) */ + caddr_t inf_isintf; /* Interface control block */ + +/* IP/ATM provided interface services */ + void (*inf_arpnotify)/* ARP event notification */ + __P((struct ipvcc *, int)); + int (*inf_ipinput) /* IP packet input */ + __P((struct ip_nif *, KBuffer *)); + int (*inf_createsvc)/* Create an IP SVC */ + __P((struct ifnet *, u_short, caddr_t, + struct ipvcc **)); +}; + +/* + * Network Interface States + */ +#define IPNIF_ADDR 1 /* Waiting for i/f address */ +#define IPNIF_SIGMGR 2 /* Waiting for sigmgr attach */ +#define IPNIF_ACTIVE 3 /* Active */ + + +/* + * Global IP/ATM Statistics + */ +struct ipatm_stat { + u_long ias_rcvstate; /* Packets received, bad vcc state */ + u_long ias_rcvnobuf; /* Packets received, no buf avail */ +}; + + +/* + * Structure to pass parameters for ipatm_openpvc() + */ +struct ipatmpvc { + struct ip_nif *ipp_ipnif; /* PVC's IP network interface */ + u_short ipp_vpi; /* VPI value */ + u_short ipp_vci; /* VCI value */ + Aal_t ipp_aal; /* AAL type */ + Encaps_t ipp_encaps; /* VCC encapsulation */ + struct sockaddr_in ipp_dst; /* Destination's IP address */ +}; + + +/* + * Timer macros + */ +#define IPVCC_TIMER(s, t) atm_timeout(&(s)->iv_time, (t), ipatm_timeout) +#define IPVCC_CANCEL(s) atm_untimeout(&(s)->iv_time) + +/* + * Misc useful macros + */ +#define SATOSIN(sa) ((struct sockaddr_in *)(sa)) + + +/* + * Global function declarations + */ + /* ipatm_event.c */ +void ipatm_timeout __P((struct atm_time *)); +void ipatm_connected __P((void *)); +void ipatm_cleared __P((void *, struct t_atm_cause *)); +void ipatm_arpnotify __P((struct ipvcc *, int)); +void ipatm_itimeout __P((struct atm_time *)); + + /* ipatm_if.c */ +int ipatm_nifstat __P((int, struct atm_nif *, int)); + + /* ipatm_input.c */ +void ipatm_cpcs_data __P((void *, KBuffer *)); +int ipatm_ipinput __P((struct ip_nif *, KBuffer *)); + + /* ipatm_load.c */ + + /* ipatm_output.c */ +int ipatm_ifoutput __P((struct ifnet *, KBuffer *, + struct sockaddr *)); + + /* ipatm_usrreq.c */ +int ipatm_ioctl __P((int, caddr_t, caddr_t)); +caddr_t ipatm_getname __P((void *)); + + /* ipatm_vcm.c */ +int ipatm_openpvc __P((struct ipatmpvc *, struct ipvcc **)); +int ipatm_createsvc __P((struct ifnet *, u_short, caddr_t, + struct ipvcc **)); +int ipatm_opensvc __P((struct ipvcc *)); +int ipatm_retrysvc __P((struct ipvcc *)); +void ipatm_activate __P((struct ipvcc *)); +int ipatm_incoming __P((void *, Atm_connection *, Atm_attributes *, + void **)); +int ipatm_closevc __P((struct ipvcc *, int)); +int ipatm_chknif __P((struct in_addr, struct ip_nif *)); +struct ipvcc *ipatm_iptovc __P((struct sockaddr_in *, struct atm_nif *)); + + +/* + * External variables + */ +extern int ipatm_vccnt; +extern int ipatm_vcidle; +extern int ipatm_print; +extern u_long last_map_ipdst; +extern struct ipvcc *last_map_ipvcc; +extern struct ip_nif *ipatm_nif_head; +extern struct sp_info ipatm_vcpool; +extern struct sp_info ipatm_nifpool; +extern struct ipatm_stat ipatm_stat; +extern struct atm_time ipatm_itimer; +extern Atm_endpoint ipatm_endpt; +extern Atm_attributes ipatm_aal5llc; +extern Atm_attributes ipatm_aal5null; +extern Atm_attributes ipatm_aal4null; + +#endif /* ATM_KERNEL */ + +#endif /* _IPATM_IPATM_VAR_H */ diff --git a/sys/netatm/ipatm/ipatm_vcm.c b/sys/netatm/ipatm/ipatm_vcm.c new file mode 100644 index 0000000..5d6a7fc --- /dev/null +++ b/sys/netatm/ipatm/ipatm_vcm.c @@ -0,0 +1,1245 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: ipatm_vcm.c,v 1.13 1998/08/06 18:21:14 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Virtual Channel Manager + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_vcm.c,v 1.13 1998/08/06 18:21:14 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +Atm_attributes ipatm_aal5llc = { + NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL5 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_PRESENT, + { + T_ATM_CLASS_X, + T_ATM_NULL, + T_ATM_NULL, + T_NO, + T_ATM_1_TO_1 + } + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_PRESENT, + T_ATM_ABSENT, + { + { + T_ATM_SIMPLE_ID, + }, + { + T_ATM_ABSENT + } + } + }, + { /* llc */ + T_ATM_PRESENT, + { + T_ATM_LLC_SHARING, + IPATM_LLC_LEN, + IPATM_LLC_HDR + } + }, + { /* called */ + T_ATM_PRESENT, + }, + { /* calling */ + T_ATM_ABSENT + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ABSENT + }, + { /* cause */ + T_ATM_ABSENT + } +}; + +Atm_attributes ipatm_aal5null = { + NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + sizeof(struct ifnet *), /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL5 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_PRESENT, + { + T_ATM_CLASS_X, + T_ATM_NULL, + T_ATM_NULL, + T_NO, + T_ATM_1_TO_1 + } + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_ABSENT, + T_ATM_ABSENT + }, + { /* llc */ + T_ATM_ABSENT + }, + { /* called */ + T_ATM_PRESENT, + }, + { /* calling */ + T_ATM_ABSENT + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ABSENT + }, + { /* cause */ + T_ATM_ABSENT + } +}; + +Atm_attributes ipatm_aal4null = { + NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + sizeof(struct ifnet *), /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL3_4 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_PRESENT, + { + T_ATM_CLASS_X, + T_ATM_NULL, + T_ATM_NULL, + T_NO, + T_ATM_1_TO_1 + } + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_ABSENT, + T_ATM_ABSENT + }, + { /* llc */ + T_ATM_ABSENT + }, + { /* called */ + T_ATM_PRESENT, + }, + { /* calling */ + T_ATM_ABSENT + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ABSENT + }, + { /* cause */ + T_ATM_ABSENT + } +}; + +static struct t_atm_cause ipatm_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + 0, + {0, 0, 0, 0} +}; + + +/* + * Open an IP PVC + * + * This function will perform all actions necessary to activate a + * PVC for IP usage. In particular, it will allocate control blocks, + * open the PVC, initialize PVC stack, and initiate whatever ARP + * procedures are required. + * + * Arguments: + * pvp pointer to PVC parameter structure + * sivp address to return pointer to IP PVC control block + * + * Returns: + * 0 PVC was successfully opened + * errno open failed - reason indicated + * + */ +int +ipatm_openpvc(pvp, sivp) + struct ipatmpvc *pvp; + struct ipvcc **sivp; +{ + struct ipvcc *ivp; + Atm_attributes *ap; + Atm_addr_pvc *pvcp; + struct atm_nif *nip; + struct ip_nif *inp; + int s, err = 0; + + inp = pvp->ipp_ipnif; + nip = inp->inf_nif; + + /* + * Make sure interface is ready to go + */ + if (inp->inf_state != IPNIF_ACTIVE) { + err = ENETDOWN; + goto done; + } + + /* + * Validate fixed destination IP address + */ + if (pvp->ipp_dst.sin_addr.s_addr != INADDR_ANY) { +#if (defined(BSD) && (BSD >= 199306)) + if (in_broadcast(pvp->ipp_dst.sin_addr, &nip->nif_if) || +#else + if (in_broadcast(pvp->ipp_dst.sin_addr) || +#endif + IN_MULTICAST(ntohl(pvp->ipp_dst.sin_addr.s_addr)) || + ipatm_chknif(pvp->ipp_dst.sin_addr, inp)) { + err = EINVAL; + goto done; + } + } + + /* + * Allocate IP VCC block + */ + ivp = (struct ipvcc *)atm_allocate(&ipatm_vcpool); + if (ivp == NULL) { + err = ENOMEM; + goto done; + } + + /* + * Initialize the PVC + */ + ivp->iv_flags = IVF_PVC; + if (pvp->ipp_encaps == ATM_ENC_LLC) + ivp->iv_flags |= IVF_LLC; + + /* + * Fill out connection attributes + */ + if (pvp->ipp_aal == ATM_AAL5) { + if (pvp->ipp_encaps == ATM_ENC_LLC) + ap = &ipatm_aal5llc; + else + ap = &ipatm_aal5null; + } else { + ap = &ipatm_aal4null; + } + + ap->nif = nip; + ap->traffic.v.forward.PCR_all_traffic = nip->nif_pif->pif_pcr; + ap->traffic.v.backward.PCR_all_traffic = nip->nif_pif->pif_pcr; + ap->called.addr.address_format = T_ATM_PVC_ADDR; + ap->called.addr.address_length = sizeof(Atm_addr_pvc); + pvcp = (Atm_addr_pvc *)ap->called.addr.address; + ATM_PVC_SET_VPI(pvcp, pvp->ipp_vpi); + ATM_PVC_SET_VCI(pvcp, pvp->ipp_vci); + ap->called.subaddr.address_format = T_ATM_ABSENT; + ap->called.subaddr.address_length = 0; + + /* + * Create PVC + */ + err = atm_cm_connect(&ipatm_endpt, ivp, ap, &ivp->iv_conn); + if (err) { + atm_free((caddr_t)ivp); + goto done; + } + + /* + * Save PVC information and link in VCC + */ + /* ivp->iv_ = ap->headout; */ + + /* + * Queue VCC onto its network interface + */ + s = splnet(); + ipatm_vccnt++; + ENQUEUE(ivp, struct ipvcc, iv_elem, inp->inf_vcq); + ivp->iv_ipnif = inp; + (void) splx(s); + + /* + * Set destination IP address and IPVCC state + */ + if (pvp->ipp_dst.sin_addr.s_addr == INADDR_ANY) { + /* + * Initiate ARP processing + */ + switch ((*inp->inf_serv->is_arp_pvcopen)(ivp)) { + + case MAP_PROCEEDING: + /* + * Wait for answer + */ + ivp->iv_state = IPVCC_ACTIVE; + break; + + case MAP_VALID: + /* + * We've got our answer already + */ + ivp->iv_state = IPVCC_ACTIVE; + ivp->iv_flags |= IVF_MAPOK; + ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr; + break; + + case MAP_FAILED: + /* + * Try again later + */ + ivp->iv_state = IPVCC_ACTPENT; + IPVCC_TIMER(ivp, 1 * ATM_HZ); + break; + + default: + panic("ipatm_openpvc: invalid arp_pvcopen return"); + } + + } else { + /* + * Use configured IP destination + */ + ivp->iv_dst.s_addr = pvp->ipp_dst.sin_addr.s_addr; + ivp->iv_state = IPVCC_ACTIVE; + ivp->iv_flags |= IVF_MAPOK; + } + +done: + if (err) + *sivp = NULL; + else + *sivp = ivp; + return (err); +} + + +/* + * Create an IP SVC + * + * This function will initiate the creation of an IP SVC. The IP VCC + * control block will be initialized and, if required, we will initiate + * ARP processing in order to resolve the destination's ATM address. Once + * the destination ATM address is known, ipatm_opensvc() will be called. + * + * Arguments: + * ifp pointer to destination ifnet structure + * daf destination address family type + * dst pointer to destination address + * sivp address to return pointer to IP SVC control block + * + * Returns: + * 0 SVC creation was successfully initiated + * errno creation failed - reason indicated + * + */ +int +ipatm_createsvc(ifp, daf, dst, sivp) + struct ifnet *ifp; + u_short daf; + caddr_t dst; + struct ipvcc **sivp; +{ + struct atm_nif *nip = (struct atm_nif *)ifp; + struct ip_nif *inp; + struct ipvcc *ivp; + struct in_addr *ip; + Atm_addr *atm; + int s, err = 0; + + /* + * Get IP interface and make sure its ready + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + if (inp == NULL) { + err = ENXIO; + goto done; + } + if (inp->inf_state != IPNIF_ACTIVE) { + err = ENETDOWN; + goto done; + } + + /* + * Validate destination address + */ + if (daf == AF_INET) { + /* + * Destination is IP address + */ + ip = (struct in_addr *)dst; + atm = NULL; + if (ip->s_addr == INADDR_ANY) { + err = EADDRNOTAVAIL; + goto done; + } + } else if (daf == AF_ATM) { + /* + * Destination is ATM address + */ + atm = (Atm_addr *)dst; + ip = NULL; + if (atm->address_format == T_ATM_ABSENT) { + err = EINVAL; + goto done; + } + } else { + err = EINVAL; + goto done; + } + + /* + * Make sure we have services provider and ARP support + */ + if ((inp->inf_serv == NULL) || + (inp->inf_serv->is_arp_svcout == NULL)) { + err = ENETDOWN; + goto done; + } + + /* + * Allocate IP VCC + */ + ivp = (struct ipvcc *)atm_allocate(&ipatm_vcpool); + if (ivp == NULL) { + err = ENOMEM; + goto done; + } + + /* + * Initialize SVC + */ + ivp->iv_flags = IVF_SVC; + ivp->iv_ipnif = inp; + + /* + * Get destination ATM address + */ + if (daf == AF_INET) { + /* + * ARP is the way... + */ + ivp->iv_dst.s_addr = ip->s_addr; + + switch ((*inp->inf_serv->is_arp_svcout)(ivp, ip)) { + + case MAP_PROCEEDING: + /* + * Wait for answer + */ + ivp->iv_state = IPVCC_PMAP; + IPVCC_TIMER(ivp, IPATM_ARP_TIME); + break; + + case MAP_VALID: + /* + * We've got our answer already, so open SVC + */ + ivp->iv_flags |= IVF_MAPOK; + err = ipatm_opensvc(ivp); + if (err) { + (*inp->inf_serv->is_arp_close)(ivp); + atm_free((caddr_t)ivp); + goto done; + } + break; + + case MAP_FAILED: + /* + * So sorry...come again + */ + atm_free((caddr_t)ivp); + err = ENETDOWN; + goto done; + + default: + panic("ipatm_createsvc: invalid arp_svcout return"); + } + } else { + /* + * We were given the ATM address, so open the SVC + * + * Create temporary arp map entry so that opensvc() works. + * Caller must set up a permanent entry immediately! (yuk) + */ + struct arpmap map; + + ATM_ADDR_COPY(atm, &map.am_dstatm); + map.am_dstatmsub.address_format = T_ATM_ABSENT; + map.am_dstatmsub.address_length = 0; + ivp->iv_arpent = ↦ + err = ipatm_opensvc(ivp); + if (err) { + atm_free((caddr_t)ivp); + goto done; + } + ivp->iv_arpent = NULL; + } + + /* + * Queue VCC onto its network interface + */ + s = splnet(); + ipatm_vccnt++; + ENQUEUE(ivp, struct ipvcc, iv_elem, inp->inf_vcq); + (void) splx(s); + +done: + if (err) + *sivp = NULL; + else + *sivp = ivp; + return (err); +} + + +/* + * Open an IP SVC + * + * This function will continue the IP SVC creation process. Here, we + * will issue an SVC open to the signalling manager and then wait for + * the final SVC setup results. + * + * Arguments: + * ivp pointer to IP SVC to open + * + * Returns: + * 0 SVC open was successfully initiated + * errno open failed - reason indicated + * + */ +int +ipatm_opensvc(ivp) + struct ipvcc *ivp; +{ + struct ip_nif *inp = ivp->iv_ipnif; + Atm_attributes *ap; + int err = 0, i; + + /* + * Cancel possible arp timeout + */ + IPVCC_CANCEL(ivp); + + /* + * Fill out connection attributes + */ + i = ivp->iv_parmx; + if (inp->inf_serv->is_vccparm[i].ivc_aal == ATM_AAL5) { + if (inp->inf_serv->is_vccparm[i].ivc_encaps == ATM_ENC_LLC) { + ap = &ipatm_aal5llc; + ivp->iv_flags |= IVF_LLC; + } else { + ap = &ipatm_aal5null; + ivp->iv_flags &= ~IVF_LLC; + } + } else { + ap = &ipatm_aal4null; + ivp->iv_flags &= ~IVF_LLC; + } + + ap->nif = inp->inf_nif; + ap->traffic.v.forward.PCR_all_traffic = inp->inf_nif->nif_pif->pif_pcr; + ap->traffic.v.backward.PCR_all_traffic = inp->inf_nif->nif_pif->pif_pcr; + + ATM_ADDR_COPY(&ivp->iv_arpent->am_dstatm, &ap->called.addr); + ATM_ADDR_COPY(&ivp->iv_arpent->am_dstatmsub, &ap->called.subaddr); + + /* + * Initiate SVC open + */ + err = atm_cm_connect(&ipatm_endpt, ivp, ap, &ivp->iv_conn); + switch (err) { + + case EINPROGRESS: + /* + * Call is progressing + */ + /* ivp->iv_ = ap->headout; */ + + /* + * Now we just wait for a CALL_CONNECTED event + */ + ivp->iv_state = IPVCC_POPEN; + IPVCC_TIMER(ivp, IPATM_SVC_TIME); + err = 0; + break; + + case 0: + /* + * We've been hooked up with a shared VCC + */ + /* ivp->iv_ = ap->headout; */ + ipatm_activate(ivp); + break; + } + + return (err); +} + + +/* + * Retry an IP SVC Open + * + * This function will attempt to retry a failed SVC open request. The IP + * interface service provider specifies a list of possible VCC parameters + * for IP to use. We will try each set of parameters in turn until either + * an open succeeds or we reach the end of the list. + * + * Arguments: + * ivp pointer to IP SVC + * + * Returns: + * 0 SVC (re)open was successfully initiated + * else retry failed + * + */ +int +ipatm_retrysvc(ivp) + struct ipvcc *ivp; +{ + struct ip_nif *inp = ivp->iv_ipnif; + + /* + * If there isn't another set of vcc parameters to try, return + */ + if ((++ivp->iv_parmx >= IPATM_VCCPARMS) || + (inp->inf_serv->is_vccparm[ivp->iv_parmx].ivc_aal == 0)) + return (1); + + /* + * Okay, now initiate open with a new set of parameters + */ + return (ipatm_opensvc(ivp)); +} + + +/* + * Finish IP SVC Activation + * + * Arguments: + * ivp pointer to IP SVC + * + * Returns: + * none + * + */ +void +ipatm_activate(ivp) + struct ipvcc *ivp; +{ + + /* + * Connection is now active + */ + ivp->iv_state = IPVCC_ACTIVE; + IPVCC_CANCEL(ivp); + + /* + * Tell ARP module that connection is active + */ + if ((*ivp->iv_ipnif->inf_serv->is_arp_svcact)(ivp)) { + (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE); + return; + } + + /* + * Send any queued packet + */ + if ((ivp->iv_flags & IVF_MAPOK) && ivp->iv_queue) { + struct sockaddr_in sin; + struct ifnet *ifp; + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ivp->iv_dst.s_addr; + ifp = (struct ifnet *)ivp->iv_ipnif->inf_nif; + (void) ipatm_ifoutput(ifp, ivp->iv_queue, + (struct sockaddr *)&sin); + ivp->iv_queue = NULL; + } +} + + +/* + * Process Incoming Calls + * + * This function will receive control when an incoming call has been matched + * to one of our registered listen parameter blocks. Assuming the call passes + * acceptance criteria and all required resources are available, we will + * create an IP SVC and notify the connection manager of our decision. We + * will then await notification of the final SVC setup results. If any + * problems are encountered, we will just tell the connection manager to + * reject the call. + * + * Called at splnet. + * + * Arguments: + * tok owner's matched listening token + * cop pointer to incoming call's connection block + * ap pointer to incoming call's attributes + * tokp pointer to location to store our connection token + * + * Returns: + * 0 call is accepted + * errno call rejected - reason indicated + * + */ +int +ipatm_incoming(tok, cop, ap, tokp) + void *tok; + Atm_connection *cop; + Atm_attributes *ap; + void **tokp; +{ + struct atm_nif *nip = ap->nif; + struct ip_nif *inp; + struct ipvcc *ivp = NULL; + int err, cause; + int usellc = 0, mtu = ATM_NIF_MTU; + + /* + * Get IP interface and make sure its ready + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + if ((inp == NULL) || (inp->inf_state != IPNIF_ACTIVE)) { + err = ENETUNREACH; + cause = T_ATM_CAUSE_SERVICE_OR_OPTION_UNAVAILABLE; + goto reject; + } + + /* + * Make sure we have services provider and ARP support + */ + if ((inp->inf_serv == NULL) || + (inp->inf_serv->is_arp_svcin == NULL)) { + err = ENETUNREACH; + cause = T_ATM_CAUSE_SERVICE_OR_OPTION_UNAVAILABLE; + goto reject; + } + + /* + * Check for LLC encapsulation + */ + if ((ap->blli.tag_l2 == T_ATM_PRESENT) && + (ap->blli.v.layer_2_protocol.ID_type == T_ATM_SIMPLE_ID) && + (ap->blli.v.layer_2_protocol.ID.simple_ID == T_ATM_BLLI2_I8802)) { + usellc = 1; + mtu += IPATM_LLC_LEN; + } + + /* + * Verify requested MTU + */ + if (ap->aal.type == ATM_AAL5) { + if ((ap->aal.v.aal5.forward_max_SDU_size > mtu) || + (ap->aal.v.aal5.backward_max_SDU_size < mtu)) { + err = ENETUNREACH; + cause = T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED; + goto reject; + } + } else { + if ((ap->aal.v.aal4.forward_max_SDU_size > mtu) || + (ap->aal.v.aal4.backward_max_SDU_size < mtu)) { + err = ENETUNREACH; + cause = T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED; + goto reject; + } + } + + /* + * Allocate IP VCC + */ + ivp = (struct ipvcc *)atm_allocate(&ipatm_vcpool); + if (ivp == NULL) { + err = ENOMEM; + cause = T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE; + goto reject; + } + + /* + * Initialize SVC + */ + ivp->iv_flags = IVF_SVC; + ivp->iv_ipnif = inp; + if (usellc) + ivp->iv_flags |= IVF_LLC; + + /* + * Lookup ARP entry for destination + */ + switch ((*inp->inf_serv->is_arp_svcin) + (ivp, &ap->calling.addr, &ap->calling.subaddr)) { + + case MAP_PROCEEDING: + /* + * We'll be (hopefully) notified later + */ + break; + + case MAP_VALID: + /* + * We've got our answer already + */ + ivp->iv_flags |= IVF_MAPOK; + ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr; + break; + + case MAP_FAILED: + /* + * So sorry...come again + */ + err = ENETUNREACH; + cause = T_ATM_CAUSE_SERVICE_OR_OPTION_UNAVAILABLE; + goto reject; + + default: + panic("ipatm_incoming: invalid arp_svcin return"); + } + + /* + * Accept SVC connection + */ + ivp->iv_state = IPVCC_PACCEPT; + + /* + * Save VCC information + */ + ivp->iv_conn = cop; + *tokp = ivp; + /* ivp->iv_ = ap->headout; */ + + /* + * Queue VCC onto its network interface + */ + ipatm_vccnt++; + ENQUEUE(ivp, struct ipvcc, iv_elem, inp->inf_vcq); + + /* + * Wait for a CALL_CONNECTED event + */ + IPVCC_TIMER(ivp, IPATM_SVC_TIME); + + return (0); + +reject: + /* + * Clean up after call failure + */ + if (ivp) { + (*inp->inf_serv->is_arp_close)(ivp); + atm_free((caddr_t)ivp); + } + ap->cause.tag = T_ATM_PRESENT; + ap->cause.v = ipatm_cause; + ap->cause.v.cause_value = cause; + return (err); +} + + +/* + * Close an IP VCC + * + * This function will close an IP VCC (PVC or SVC), including notifying + * the signalling and ARP subsystems of the VCC's demise and cleaning + * up memory after ourselves. + * + * Arguments: + * ivp pointer to VCC + * code cause code + * + * Returns: + * 0 VCC successfully closed + * errno close failed - reason indicated + * + */ +int +ipatm_closevc(ivp, code) + struct ipvcc *ivp; + int code; +{ + struct ip_nif *inp = ivp->iv_ipnif; + int s, err; + + /* + * Make sure VCC hasn't been through here already + */ + switch (ivp->iv_state) { + + case IPVCC_FREE: + return (EALREADY); + } + + /* + * Reset lookup cache + */ + if (last_map_ipvcc == ivp) { + last_map_ipvcc = NULL; + last_map_ipdst = 0; + } + + /* + * Tell ARP about SVCs and dynamic PVCs + */ + if (inp->inf_serv && + ((ivp->iv_flags & IVF_SVC) || inp->inf_serv->is_arp_pvcopen)) { + (*inp->inf_serv->is_arp_close)(ivp); + } + + /* + * Free queued packets + */ + if (ivp->iv_queue) + KB_FREEALL(ivp->iv_queue); + + /* + * Cancel any timers + */ + IPVCC_CANCEL(ivp); + + /* + * Close VCC + */ + switch (ivp->iv_state) { + + case IPVCC_PMAP: + break; + + case IPVCC_POPEN: + case IPVCC_PACCEPT: + case IPVCC_ACTPENT: + case IPVCC_ACTIVE: + ipatm_cause.cause_value = code; + err = atm_cm_release(ivp->iv_conn, &ipatm_cause); + if (err) { + log(LOG_ERR, + "ipatm_closevc: release fail: err=%d\n", err); + } + break; + + case IPVCC_CLOSED: + break; + + default: + log(LOG_ERR, + "ipatm_closevc: unknown state: ivp=0x%x, state=%d\n", + (int)ivp, ivp->iv_state); + } + + /* + * Remove VCC from network i/f + */ + s = splnet(); + DEQUEUE(ivp, struct ipvcc, iv_elem, inp->inf_vcq); + + /* + * Reset state just to be sure + */ + ivp->iv_state = IPVCC_FREE; + + /* + * If ARP module is done with VCC too, then free it + */ + if (ivp->iv_arpconn == NULL) + atm_free((caddr_t)ivp); + ipatm_vccnt--; + (void) splx(s); + + return (0); +} + + +/* + * Check if IP address is valid on a Network Interface + * + * Checks whether the supplied IP address is allowed to be assigned to + * the supplied IP network interface. + * + * Arguments: + * in IP address + * inp pointer to IP network interface + * + * Returns: + * 0 - OK to assign + * 1 - not valid to assign + * + */ +int +ipatm_chknif(in, inp) + struct in_addr in; + struct ip_nif *inp; +{ + struct in_ifaddr *ia; + u_long i; + + /* + * Make sure there's an interface requested + */ + if (inp == NULL) + return (1); + + /* + * Make sure we have an IP address + */ + i = ntohl(in.s_addr); + if (i == 0) + return (1); + + /* + * Make sure an interface address is set + */ + ia = inp->inf_addr; + if (ia == NULL) + return (1); + + /* + * Make sure we're on the right subnet + */ + if ((i & ia->ia_subnetmask) != ia->ia_subnet) + return (1); + + return (0); +} + + +/* + * Map an IP Address to an IP VCC + * + * Given a destination IP address, this function will return a pointer + * to the appropriate output IP VCC to which to send the packet. + * This is currently implemented using a one-behind cache containing the + * last successful mapping result. If the cache lookup fails, then a + * simple linear search of all IP VCCs on the destination network interface + * is performed. This is obviously an area to look at for performance + * improvements. + * + * Arguments: + * dst pointer to destination IP address + * nip pointer to destination network interface + * + * Returns: + * addr pointer to located IP VCC + * 0 no such mapping exists + * + */ +struct ipvcc * +ipatm_iptovc(dst, nip) + struct sockaddr_in *dst; + struct atm_nif *nip; +{ + struct ip_nif *inp; + struct ipvcc *ivp; + u_long dstip = dst->sin_addr.s_addr; + int s; + + /* + * Look in cache first + */ + if (last_map_ipdst == dstip) + return (last_map_ipvcc); + + /* + * Oh well, we've got to search for it...first find the interface + */ + s = splnet(); + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + if (inp == NULL) { + (void) splx(s); + return (NULL); + } + + /* + * Now home in on the VCC + */ + for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; + ivp = Q_NEXT(ivp, struct ipvcc, iv_elem)) { + if (ivp->iv_dst.s_addr == dstip) + break; + } + + /* + * Update lookup cache + */ + if (ivp) { + last_map_ipdst = dstip; + last_map_ipvcc = ivp; + } + (void) splx(s); + + return (ivp); +} + |