/* * Check whether an interface is up and ready for service * * Arguments: * aip pointer to network interface block * * Returns: * 0 interface not ready, errno has reason * 1 interface is ready to go (interface block is updated) * */ int atmarp_if_ready(Atmarp_intf *aip) { int i, len, mtu, rc, sel; Atmarp *aap = NULL; struct atminfreq air; struct air_netif_rsp *netif_rsp = NULL; struct air_int_rsp *intf_rsp = NULL; struct sockaddr_in *ip_addr; struct sockaddr_in subnet_mask; Atm_addr_nsap *anp; /* * Get the IP address and physical interface name * associated with the network interface */ UM_ZERO(&air, sizeof(struct atminfreq)); air.air_opcode = AIOCS_INF_NIF; strcpy(air.air_netif_intf, aip->ai_intf); len = do_info_ioctl(&air, sizeof(struct air_netif_rsp)); if (len <= 0) { goto if_ready_fail; } netif_rsp = (struct air_netif_rsp *)air.air_buf_addr; ip_addr = (struct sockaddr_in *)&netif_rsp->anp_proto_addr; if (ip_addr->sin_family != AF_INET || ip_addr->sin_addr.s_addr == 0) { errno = EAFNOSUPPORT; goto if_ready_fail; } /* * Get the MTU for the network interface */ mtu = get_mtu(aip->ai_intf); if (mtu < 0) { goto if_ready_fail; } /* * Get the subnet mask associated with the * network interface */ rc = get_subnet_mask(aip->ai_intf, &subnet_mask); if (rc || subnet_mask.sin_family != AF_INET) { goto if_ready_fail; } /* * Get physical interface information */ UM_ZERO(&air, sizeof(struct atminfreq)); air.air_opcode = AIOCS_INF_INT; strcpy(air.air_int_intf, netif_rsp->anp_phy_intf); len = do_info_ioctl(&air, sizeof(struct air_int_rsp)); if (len <= 0) { goto if_ready_fail; } intf_rsp = (struct air_int_rsp *)air.air_buf_addr; /* * Check the signalling manager */ if (intf_rsp->anp_sig_proto != ATM_SIG_UNI30 && intf_rsp->anp_sig_proto != ATM_SIG_UNI31 && intf_rsp->anp_sig_proto != ATM_SIG_UNI40) { errno = EINVAL; goto if_ready_fail; } /* * Check the interface state */ if (intf_rsp->anp_sig_state != UNISIG_ACTIVE) { errno = EINVAL; goto if_ready_fail; } /* * Check the address format */ if (intf_rsp->anp_addr.address_format != T_ATM_ENDSYS_ADDR && !(intf_rsp->anp_addr.address_format == T_ATM_E164_ADDR && intf_rsp->anp_subaddr.address_format == T_ATM_ENDSYS_ADDR)) { errno = EINVAL; goto if_ready_fail; } /* * Find the selector byte value for the interface */ for (i=0; i<strlen(aip->ai_intf); i++) { if (aip->ai_intf[i] >= '0' && aip->ai_intf[i] <= '9') break; } sel = atoi(&aip->ai_intf[i]); /* * Make sure we're the server for this interface's LIS */ if (!atmarp_is_server(aip)) { rc = EINVAL; goto if_ready_fail; } /* * If we already have the interface active and the address * hasn't changed, return */ if (aip->ai_state != AI_STATE_NULL && bcmp((caddr_t) &((struct sockaddr_in *) &netif_rsp->anp_proto_addr)->sin_addr, (caddr_t)&aip->ai_ip_addr, sizeof(aip->ai_ip_addr)) == 0 && ATM_ADDR_EQUAL(&intf_rsp->anp_addr, &aip->ai_atm_addr) && ATM_ADDR_EQUAL(&intf_rsp->anp_subaddr, &aip->ai_atm_subaddr)) { return(1); } /* * Delete any existing ATMARP cache entry for this interface */ ATMARP_LOOKUP(aip, aip->ai_ip_addr.s_addr, aap); if (aap) { ATMARP_DELETE(aip, aap); UM_FREE(aap); } /* * Update the interface entry */ aip->ai_ip_addr = ((struct sockaddr_in *) &netif_rsp->anp_proto_addr)->sin_addr; aip->ai_subnet_mask = subnet_mask.sin_addr; aip->ai_mtu = mtu + 8; ATM_ADDR_COPY(&intf_rsp->anp_addr, &aip->ai_atm_addr); ATM_ADDR_COPY(&intf_rsp->anp_subaddr, &aip->ai_atm_subaddr); anp = (Atm_addr_nsap *)aip->ai_atm_addr.address; if (aip->ai_atm_addr.address_format == T_ATM_ENDSYS_ADDR) { anp->aan_sel = sel; } else if (aip->ai_atm_addr.address_format == T_ATM_E164_ADDR && aip->ai_atm_subaddr.address_format == T_ATM_ENDSYS_ADDR) { anp->aan_sel = sel; } /* * Get a new ATMARP cache for the interface */ aap = (Atmarp *)UM_ALLOC(sizeof(Atmarp)); if (!aap) { atmarp_mem_err("atmarp_if_ready: sizeof(Atmarp)"); } UM_ZERO(aap, sizeof(Atmarp)); /* * Fill out the entry */ aap->aa_dstip = aip->ai_ip_addr; ATM_ADDR_COPY(&intf_rsp->anp_addr, &aap->aa_dstatm); ATM_ADDR_COPY(&intf_rsp->anp_subaddr, &aap->aa_dstatmsub); aap->aa_key.key_len = SCSP_ATMARP_KEY_LEN; scsp_cache_key(&aap->aa_dstatm, &aap->aa_dstip, SCSP_ATMARP_KEY_LEN, aap->aa_key.key); aap->aa_oid.id_len = SCSP_ATMARP_ID_LEN; aap->aa_seq = SCSP_CSA_SEQ_MIN; UM_COPY(&aap->aa_dstip.s_addr, aap->aa_oid.id, SCSP_ATMARP_ID_LEN); aap->aa_intf = aip; aap->aa_flags = AAF_SERVER; aap->aa_origin = UAO_LOCAL; /* * Add the entry to the cache */ ATMARP_ADD(aip, aap); /* * Free dynamic data */ UM_FREE(netif_rsp); UM_FREE(intf_rsp); return(1); if_ready_fail: if (netif_rsp) UM_FREE(netif_rsp); if (intf_rsp) UM_FREE(intf_rsp); return(0); }
/* * Send the cache for a LIS to SCSP * * * Arguments: * aip pointer to interface block * * Returns: * 0 cache sent to SCSP OK * errno reason for failure * */ int atmarp_scsp_cache(Atmarp_intf *aip, Scsp_if_msg *msg) { int i, len, rc = 0; Atmarp *aap; Scsp_if_msg *smp = NULL; Scsp_atmarp_msg *sap; /* * Figure out how big the message needs to be */ len = sizeof(Scsp_if_msg_hdr); for (i = 0; i < ATMARP_HASHSIZ; i++) { for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) { len += sizeof(Scsp_atmarp_msg); } } /* * Get memory for the cache message */ smp = (Scsp_if_msg *)UM_ALLOC(len); if (!smp) { atmarp_mem_err("atmarp_scsp_cache: len"); } UM_ZERO(smp, len); /* * Set header fields in SCSP message */ smp->si_type = SCSP_CACHE_RSP; smp->si_proto = SCSP_PROTO_ATMARP; smp->si_len = len; smp->si_tok = msg->si_tok; /* * Loop through the cache, adding each entry to the SCSP * Cache Response message */ sap = &smp->si_atmarp; for (i = 0; i < ATMARP_HASHSIZ; i++) { for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) { sap->sa_state = SCSP_ASTATE_NEW; sap->sa_cpa = aap->aa_dstip; ATM_ADDR_COPY(&aap->aa_dstatm, &sap->sa_cha); ATM_ADDR_COPY(&aap->aa_dstatmsub, &sap->sa_csa); sap->sa_key = aap->aa_key; sap->sa_oid = aap->aa_oid; sap->sa_seq = aap->aa_seq; sap++; } } /* * Send the message to SCSP */ rc = atmarp_scsp_out(aip, (char *)smp, len); /* * Free the message */ if (smp) UM_FREE(smp); return(rc); }
/* * Answer a reqeust for information about a cache entry * * Arguments: * aap pointer to entry * state entry's new state * * Returns: * 0 success * errno reason for failure * */ int atmarp_scsp_solicit(Atmarp_intf *aip, Scsp_if_msg *smp) { int i, rc = 0; Atmarp *aap; Scsp_if_msg *rsp = NULL; /* * Search the interface's ATMARP cache for an entry with * the specified cache key and origin ID */ for (i = 0; i < ATMARP_HASHSIZ; i++) { for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) { if (KEY_EQUAL(&aap->aa_key, &smp->si_sum.ss_key) && OID_EQUAL(&aap->aa_oid, &smp->si_sum.ss_oid)) break; } if (aap) break; } /* * Get storage for a Solicit Response */ rsp = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg)); if (!rsp) { atmarp_mem_err("atmarp_scsp_solicit: sizeof(Scsp_if_msg)"); } UM_ZERO(rsp, sizeof(Scsp_if_msg)); /* * Fill out the Solicit Rsp */ rsp->si_type = SCSP_SOLICIT_RSP; rsp->si_proto = smp->si_proto; rsp->si_tok = smp->si_tok; if (aap) { /* * Copy fields from the ATMARP entry to the SCSP * Update Request message */ rsp->si_rc = SCSP_RSP_OK; rsp->si_len = sizeof(Scsp_if_msg_hdr) + sizeof(Scsp_atmarp_msg); rsp->si_atmarp.sa_state = SCSP_ASTATE_UPD; rsp->si_atmarp.sa_cpa = aap->aa_dstip; ATM_ADDR_COPY(&aap->aa_dstatm, &rsp->si_atmarp.sa_cha); ATM_ADDR_COPY(&aap->aa_dstatmsub, &rsp->si_atmarp.sa_csa); rsp->si_atmarp.sa_key = aap->aa_key; rsp->si_atmarp.sa_oid = aap->aa_oid; rsp->si_atmarp.sa_seq = aap->aa_seq; } else { /* * Entry not found--set return code */ rsp->si_rc = SCSP_RSP_NOT_FOUND; rsp->si_len = smp->si_len; rsp->si_sum = smp->si_sum; } /* * Send the message to SCSP */ rc = atmarp_scsp_out(aip, (char *)rsp, rsp->si_len); UM_FREE(rsp); return(rc); }
/* * SPANS ARP IOCTL support * * Function will be called from a critical section. * * 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 spansarp_ioctl(int code, caddr_t data, caddr_t arg1) { struct atmaddreq *aap; struct atmdelreq *adp; struct atminfreq *aip; struct spans *spp; struct spanscls *clp; struct spansarp *sap; struct air_arp_rsp aar; struct ip_nif *inp; struct ipvcc *ivp, *inext; struct in_addr ip; u_long dst; int err = 0, i, buf_len; caddr_t buf_addr; switch (code) { case AIOCS_ADD_ARP: /* * Add a permanent ARP mapping */ aap = (struct atmaddreq *)data; clp = (struct spanscls *)arg1; inp = clp->cls_ipnif; if ((aap->aar_arp_addr.address_format != T_ATM_SPANS_ADDR) || (aap->aar_arp_origin != ARP_ORIG_PERM)) { err = EINVAL; break; } ip = SATOSIN(&aap->aar_arp_dst)->sin_addr; /* * See if we already have an entry for this IP address */ SPANSARP_LOOKUP(ip.s_addr, sap); if (sap == NULL) { /* * No, get a new arp entry */ sap = (struct spansarp *)atm_allocate(&spansarp_pool); if (sap == NULL) { err = ENOMEM; break; } /* * Get entry set up */ sap->sa_dstip = ip; ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm); sap->sa_dstatmsub.address_format = T_ATM_ABSENT; sap->sa_dstatmsub.address_length = 0; sap->sa_cls = clp; sap->sa_flags |= SAF_VALID; sap->sa_origin = SAO_PERM; /* * Add entry to table */ SPANSARP_ADD(sap); break; } /* * See if we're attempting to change the ATM address for * this cached entry */ if ((sap->sa_dstatm.address_format != T_ATM_ABSENT) && (!ATM_ADDR_EQUAL(&aap->aar_arp_addr, &sap->sa_dstatm) || (clp != sap->sa_cls))) { /* * Yes, notify IP/ATM that a mapping change has * occurred. IP/ATM will close any VCC's which * aren't waiting for this map. */ sap->sa_flags |= SAF_LOCKED; for (ivp = sap->sa_ivp; ivp; ivp = inext) { inext = ivp->iv_arpnext; (*inp->inf_arpnotify)(ivp, MAP_CHANGED); } sap->sa_flags &= ~SAF_LOCKED; } /* * Update the cached entry with the new data */ ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm); sap->sa_cls = clp; /* * If this entry isn't valid, notify anyone who might * be interested */ if ((sap->sa_flags & SAF_VALID) == 0) { sap->sa_flags |= SAF_LOCKED; for (ivp = sap->sa_ivp; ivp; ivp = inext) { inext = ivp->iv_arpnext; (*inp->inf_arpnotify)(ivp, MAP_VALID); } sap->sa_flags &= ~SAF_LOCKED; } /* * Remove this entry from the retry chain */ UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext); /* * Mark the entry as permanent */ sap->sa_flags |= SAF_VALID; sap->sa_origin = SAO_PERM; break; case AIOCS_DEL_ARP: /* * Delete an ARP mapping */ adp = (struct atmdelreq *)data; clp = (struct spanscls *)arg1; ip = SATOSIN(&adp->adr_arp_dst)->sin_addr; /* * Now find the entry to be deleted */ SPANSARP_LOOKUP(ip.s_addr, sap); if (sap == NULL) { err = ENOENT; break; } /* * Notify all VCCs using this entry that they must finish * up now. */ sap->sa_flags |= SAF_LOCKED; for (ivp = sap->sa_ivp; ivp; ivp = inext) { inext = ivp->iv_arpnext; (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED); } /* * Now free up the entry */ UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext); SPANSARP_DELETE(sap); atm_free((caddr_t)sap); break; case AIOCS_INF_ARP: /* * Get ARP table information */ aip = (struct atminfreq *)data; spp = (struct spans *)arg1; if (aip->air_arp_addr.sa_family != AF_INET) break; dst = SATOSIN(&aip->air_arp_addr)->sin_addr.s_addr; buf_addr = aip->air_buf_addr; buf_len = aip->air_buf_len; if ((clp = spp->sp_cls) == NULL) break; /* * Run through entire arp table */ for (i = 0; i < SPANSARP_HASHSIZ; i++) { for (sap = spansarp_arptab[i]; sap; sap = sap->sa_next) { /* * We only want entries learned * from the supplied interface. */ if (sap->sa_cls != clp) continue; if ((dst != INADDR_ANY) && (dst != sap->sa_dstip.s_addr)) continue; /* * Make sure there's room in the user's buffer */ if (buf_len < sizeof(aar)) { err = ENOSPC; break; } /* * Fill in info to be returned */ SATOSIN(&aar.aap_arp_addr)->sin_family = AF_INET; SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr = sap->sa_dstip.s_addr; strlcpy(aar.aap_intf, clp->cls_ipnif->inf_nif->nif_if.if_xname, sizeof(aar.aap_intf)); aar.aap_flags = sap->sa_flags; aar.aap_origin = sap->sa_origin; if (sap->sa_flags & SAF_VALID) aar.aap_age = SPANSARP_MAXAGE - sap->sa_reftime; else aar.aap_age = 0; ATM_ADDR_COPY(&sap->sa_dstatm, &aar.aap_addr); ATM_ADDR_COPY(&sap->sa_dstatmsub, &aar.aap_subaddr); /* * Copy the response into the user's buffer */ if ((err = copyout((caddr_t)&aar, buf_addr, sizeof(aar))) != 0) break; buf_addr += sizeof(aar); buf_len -= sizeof(aar); } if (err) break; } /* * Update the buffer pointer and length */ aip->air_buf_addr = buf_addr; aip->air_buf_len = buf_len; break; case AIOCS_INF_ASV: /* * Get ARP server information */ /* SPANS doesn't have an ARP server */ break; default: err = EOPNOTSUPP; } return (err); }
/* * Send a SETUP request * * Build and send a Q.2931 SETUP message. * * Arguments: * usp pointer to UNISIG protocol instance block * uvp pointer to VCCB for which the request is being sent * * Returns: * none * */ int unisig_send_setup(struct unisig *usp, struct unisig_vccb *uvp) { int err = 0; struct unisig_msg *setup; Atm_attributes *ap = &uvp->uv_connvc->cvc_attr; ATM_DEBUG1("unisig_send_setup: uvp=%p\n", uvp); /* * Make sure required connection attriutes are set */ if (ap->aal.tag != T_ATM_PRESENT || ap->traffic.tag != T_ATM_PRESENT || ap->bearer.tag != T_ATM_PRESENT || ap->called.tag != T_ATM_PRESENT || ap->qos.tag != T_ATM_PRESENT) { err = EINVAL; setup = NULL; goto done; } /* * Get memory for a SETUP message */ setup = (struct unisig_msg *)atm_allocate(&unisig_msgpool); if (setup == NULL) { err = ENOMEM; goto done; } /* * Fill in the SETUP message */ if (!uvp->uv_call_ref) uvp->uv_call_ref = unisig_alloc_call_ref(usp); setup->msg_call_ref = uvp->uv_call_ref; setup->msg_type = UNI_MSG_SETU; /* * Set IEs from connection attributes */ err = unisig_set_attrs(usp, setup, ap); if (err) goto done; /* * Attach a Calling Party Number IE if the user didn't * specify one in the attribute block */ if (ap->calling.tag != T_ATM_PRESENT) { setup->msg_ie_cgad = (struct ie_generic *) atm_allocate(&unisig_iepool); if (setup->msg_ie_cgad == NULL) { err = ENOMEM; goto done; } setup->msg_ie_cgad->ie_ident = UNI_IE_CGAD; ATM_ADDR_COPY(&usp->us_addr, &setup->msg_ie_cgad->ie_cgad_addr); ATM_ADDR_SEL_COPY(&usp->us_addr, uvp->uv_nif ? uvp->uv_nif->nif_sel : 0, &setup->msg_ie_cgad->ie_cgad_addr); } /* * Send the SETUP message */ err = unisig_send_msg(usp, setup); done: if (setup) unisig_free_msg(setup); return(err); }
/* * Get informtion about a server from the kernel * * Arguments: * ssp pointer to the server block * * Returns: * 0 server info is OK * errno server is not ready * */ int scsp_get_server_info(Scsp_server *ssp) { int i, len, mtu, rc, sel; struct atminfreq air; struct air_netif_rsp *netif_rsp = NULL; struct air_int_rsp *intf_rsp = NULL; struct air_cfg_rsp *cfg_rsp = NULL; struct sockaddr_in *ip_addr; Atm_addr_nsap *anp; /* * Make sure we're the server for the interface */ if (!scsp_is_atmarp_server(ssp->ss_intf)) { rc = EINVAL; goto server_info_done; } /* * Get the IP address and physical interface name * associated with the network interface */ UM_ZERO(&air, sizeof(struct atminfreq)); air.air_opcode = AIOCS_INF_NIF; strcpy(air.air_netif_intf, ssp->ss_intf); len = do_info_ioctl(&air, sizeof(struct air_netif_rsp)); if (len <= 0) { rc = EIO; goto server_info_done; } netif_rsp = (struct air_netif_rsp *)air.air_buf_addr; ip_addr = (struct sockaddr_in *)&netif_rsp->anp_proto_addr; if (ip_addr->sin_family != AF_INET || ip_addr->sin_addr.s_addr == 0) { rc = EADDRNOTAVAIL; goto server_info_done; } /* * Get the MTU for the network interface */ mtu = get_mtu(ssp->ss_intf); if (mtu < 0) { rc = EIO; goto server_info_done; } /* * Get the ATM address associated with the * physical interface */ UM_ZERO(&air, sizeof(struct atminfreq)); air.air_opcode = AIOCS_INF_INT; strcpy(air.air_int_intf, netif_rsp->anp_phy_intf); len = do_info_ioctl(&air, sizeof(struct air_int_rsp)); if (len <= 0) { rc = EIO; goto server_info_done; } intf_rsp = (struct air_int_rsp *)air.air_buf_addr; /* * Make sure we're running UNI signalling */ if (intf_rsp->anp_sig_proto != ATM_SIG_UNI30 && intf_rsp->anp_sig_proto != ATM_SIG_UNI31 && intf_rsp->anp_sig_proto != ATM_SIG_UNI40) { rc = EINVAL; goto server_info_done; } /* * Check the physical interface's state */ if (intf_rsp->anp_sig_state != UNISIG_ACTIVE) { rc = EHOSTDOWN; goto server_info_done; } /* * Make sure the interface's address is valid */ if (intf_rsp->anp_addr.address_format != T_ATM_ENDSYS_ADDR && !(intf_rsp->anp_addr.address_format == T_ATM_E164_ADDR && intf_rsp->anp_subaddr.address_format == T_ATM_ENDSYS_ADDR)) { rc = EINVAL; goto server_info_done; } /* * Find the selector byte value for the interface */ for (i=0; i<strlen(ssp->ss_intf); i++) { if (ssp->ss_intf[i] >= '0' && ssp->ss_intf[i] <= '9') break; } sel = atoi(&ssp->ss_intf[i]); /* * Get configuration information associated with the * physical interface */ UM_ZERO(&air, sizeof(struct atminfreq)); air.air_opcode = AIOCS_INF_CFG; strcpy(air.air_int_intf, netif_rsp->anp_phy_intf); len = do_info_ioctl(&air, sizeof(struct air_cfg_rsp)); if (len <= 0) { rc = EIO; goto server_info_done; } cfg_rsp = (struct air_cfg_rsp *)air.air_buf_addr; /* * Update the server entry */ UM_COPY(&ip_addr->sin_addr, ssp->ss_lsid.id, ssp->ss_id_len); ssp->ss_lsid.id_len = ssp->ss_id_len; ssp->ss_mtu = mtu + 8; ATM_ADDR_COPY(&intf_rsp->anp_addr, &ssp->ss_addr); ATM_ADDR_COPY(&intf_rsp->anp_subaddr, &ssp->ss_subaddr); if (ssp->ss_addr.address_format == T_ATM_ENDSYS_ADDR) { anp = (Atm_addr_nsap *)ssp->ss_addr.address; anp->aan_sel = sel; } else if (ssp->ss_addr.address_format == T_ATM_E164_ADDR && ssp->ss_subaddr.address_format == T_ATM_ENDSYS_ADDR) { anp = (Atm_addr_nsap *)ssp->ss_subaddr.address; anp->aan_sel = sel; } ssp->ss_media = cfg_rsp->acp_cfg.ac_media; rc = 0; /* * Free dynamic data */ server_info_done: if (netif_rsp) UM_FREE(netif_rsp); if (intf_rsp) UM_FREE(intf_rsp); if (cfg_rsp) UM_FREE(cfg_rsp); return(rc); }