示例#1
0
/*
 * 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);
}
示例#2
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);
}
示例#3
0
/*
 * 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);
}
示例#4
0
/*
 * 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);
}
示例#5
0
/*
 * 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);
}
示例#6
0
/*
 * 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);
}