コード例 #1
0
/*
 * Send a RELEASE COMPLETE message
 *
 * Arguments:
 *	usp	pointer to UNISIG protocol instance block
 *	uvp	pointer to VCCB for which the RELEASE is being sent.
 *		NULL indicates that a VCCB wasn't found for a call
 *		reference value.
 *	msg	pointer to the message which triggered the send
 *	cause	the cause code for the message; a value of
 *		T_ATM_ABSENT indicates that the cause code is
 *		in the VCC's ATM attributes block
 *
 * Returns:
 *	0	success
 *	errno	error encountered
 *
 */
int
unisig_send_release_complete(struct unisig *usp, struct unisig_vccb *uvp,
			     struct unisig_msg *msg, int cause)
{
	int			err = 0;
	struct unisig_msg	*rls_cmp;
	struct ie_generic	*cause_ie;

	ATM_DEBUG4("unisig_send_release_complete usp=%p, uvp=%p, msg=%p, cause=%d\n",
			usp, uvp, msg, cause);

	/*
	 * Get memory for a RELEASE COMPLETE message
	 */
	rls_cmp = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
	if (rls_cmp == NULL) {
		return(ENOMEM);
	}
	cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
	if (cause_ie == NULL) {
		atm_free(rls_cmp);
		return(ENOMEM);
	}

	/*
	 * Fill in the RELEASE COMPLETE message
	 */
	if (uvp) {
		rls_cmp->msg_call_ref = uvp->uv_call_ref;
	} else if (msg) {
		rls_cmp->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref);
	} else {
		rls_cmp->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
	}
	rls_cmp->msg_type = UNI_MSG_RLSC;
	rls_cmp->msg_type_flag = 0;
	rls_cmp->msg_type_action = 0;
	rls_cmp->msg_ie_caus = cause_ie;

	/*
	 * Fill out the cause IE
	 */
	cause_ie->ie_ident = UNI_IE_CAUS;
	if (cause == T_ATM_ABSENT) {
		unisig_cause_from_attr(cause_ie,
				&uvp->uv_connvc->cvc_attr);
	} else {
		cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
		unisig_cause_from_msg(cause_ie, msg, cause);
	}

	/*
	 * Send the RELEASE COMPLETE
	 */
	err = unisig_send_msg(usp, rls_cmp);
	unisig_free_msg(rls_cmp);

	return(err);
}
コード例 #2
0
/*
 * Send a RELEASE message
 *
 * Arguments:
 *	usp	pointer to UNISIG protocol instance block
 *	uvp	pointer to VCCB for which the RELEASE is being sent
 *	msg	pointer to UNI signalling message that the RELEASE
 *		responds to (may be NULL)
 *	cause	the reason for the RELEASE; a value of
 *		T_ATM_ABSENT indicates that the cause code is
 *		in the VCC's ATM attributes block
 *
 * Returns:
 *	none
 *
 */
int
unisig_send_release(struct unisig *usp, struct unisig_vccb *uvp,
		    struct unisig_msg *msg, int cause)
{
	int			err = 0;
	struct unisig_msg	*rls_msg;
	struct ie_generic	*cause_ie;

	ATM_DEBUG2("unisig_send_release: usp=%p, uvp=%p\n",
			usp, uvp);

	/*
	 * Get memory for a RELEASE message
	 */
	rls_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
	if (rls_msg == NULL) {
		return(ENOMEM);
	}
	cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
	if (cause_ie == NULL) {
		atm_free(rls_msg);
		return(ENOMEM);
	}

	/*
	 * Fill in the RELEASE message
	 */
	rls_msg->msg_call_ref = uvp->uv_call_ref;
	rls_msg->msg_type = UNI_MSG_RLSE;
	rls_msg->msg_type_flag = 0;
	rls_msg->msg_type_action = 0;
	rls_msg->msg_ie_caus = cause_ie;

	/*
	 * Fill out the cause IE
	 */
	cause_ie->ie_ident = UNI_IE_CAUS;
	if (cause == T_ATM_ABSENT) {
		unisig_cause_from_attr(cause_ie,
				&uvp->uv_connvc->cvc_attr);
	} else {
		cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
		unisig_cause_from_msg(cause_ie, msg, cause);
	}

	/*
	 * Send the RELEASE
	 */
	err = unisig_send_msg(usp, rls_msg);
	unisig_free_msg(rls_msg);

	return(err);
}
コード例 #3
0
ファイル: atm_subr.c プロジェクト: AhmadTux/DragonFlyBSD
/*
 * Queue a Stack Call 
 * 
 * Queues a stack call which must be deferred to the global stack queue.
 * The call parameters are stored in entries which are allocated from the
 * stack queue storage pool.
 *
 * Arguments:
 *	cmd	stack command
 *	func	destination function
 *	token	destination layer's token
 *	cvp	pointer to  connection vcc
 *	arg1	command argument
 *	arg2	command argument
 *
 * Returns:
 *	0 	call queued
 *	errno	call not queued - reason indicated
 *
 */
int
atm_stack_enq(int cmd, void (*func)(int, void *, int, int), void *token,
	      Atm_connvc *cvp, int arg1, int arg2)
{
	struct stackq_entry	*sqp;

	crit_enter();

	/*
	 * Get a new queue entry for this call
	 */
	sqp = (struct stackq_entry *)atm_allocate(&atm_stackq_pool);
	if (sqp == NULL) {
		crit_exit();
		return (ENOMEM);
	}

	/*
	 * Fill in new entry
	 */
	sqp->sq_next = NULL;
	sqp->sq_cmd = cmd;
	sqp->sq_func = func;
	sqp->sq_token = token;
	sqp->sq_arg1 = arg1;
	sqp->sq_arg2 = arg2;
	sqp->sq_connvc = cvp;

	/*
	 * Put new entry at end of queue
	 */
	if (atm_stackq_head == NULL)
		atm_stackq_head = sqp;
	else
		atm_stackq_tail->sq_next = sqp;
	atm_stackq_tail = sqp;

	crit_exit();
	return (0);
}
コード例 #4
0
/*
 * Open a SPANS VCC
 *
 * Called when a user wants to open a VC.  This function will construct
 * a VCCB, create the stack requested by the user, and, if we are
 * opening an SVC, start the SPANS signalling message exchange.  The
 * user will have to wait for a notify event to be sure the SVC is fully
 * open.
 *
 * Must be called from a critical section.
 *
 * Arguments:
 *	spp	pointer to SPANS protocol instance
 *	acp	pointer to PVC's connection parameters
 *
 * Returns:
 *	0	VCC creation successful
 *	errno	VCC setup failed - reason indicated
 *
 */
int
spans_open_vcc(struct spans *spp, Atm_connvc *cvp)
{
	struct atm_pif		*pip = spp->sp_pif;
	struct spans_vccb	*svp;
	Atm_addr_pvc		*pvp;
	spans_aal		aal;
	int			err, pvc, vpi, vci;

	ATM_DEBUG2("spans_open_vcc: spp=%p, cvp=%p\n", spp, cvp);

	/*
	 * Validate user parameters. AAL and encapsulation are
	 * checked by the connection manager.
	 */

	/*
	 * Check called party address(es)
	 */
	if (cvp->cvc_attr.called.tag != T_ATM_PRESENT ||
			cvp->cvc_attr.called.addr.address_format ==
				T_ATM_ABSENT ||
			cvp->cvc_attr.called.subaddr.address_format !=
				T_ATM_ABSENT) {
		return(EINVAL);
	}
	switch (cvp->cvc_attr.called.addr.address_format) {
	case T_ATM_PVC_ADDR:
		/*
		 * Make sure VPI/VCI is valid
		 */
		pvc = 1;
		pvp = (Atm_addr_pvc *)cvp->cvc_attr.called.addr.address;
		vpi = ATM_PVC_GET_VPI(pvp);
		vci = ATM_PVC_GET_VCI(pvp);
		if ((vpi > pip->pif_maxvpi) ||
				(vci == 0) ||
				(vci > pip->pif_maxvci)) {
			return(ERANGE);
		}

		/*
		 * Make sure VPI/VCI is not already in use
		 */
		if (spans_find_vpvc(spp, vpi, vci, 0)) {
			return(EADDRINUSE);
		}
		ATM_DEBUG2("spans_open_vcc: VPI.VCI=%d.%d\n",
				vpi, vci);
		break;

	case T_ATM_SPANS_ADDR:
		pvc = 0;
		vpi = vci = 0;

		/*
		 * Check signalling state
		 */
		if (spp->sp_state != SPANS_ACTIVE) {
			return(ENETDOWN);
		}

		/*
		 *Check destination address length
		 */
		if (cvp->cvc_attr.called.addr.address_length !=
				sizeof(spans_addr)) {
			return(EINVAL);
		}
		break;

	default:
		return(EINVAL);
	}

	/*
	 * Check that this is for the same interface SPANS uses
         */
	if (!cvp->cvc_attr.nif ||
			cvp->cvc_attr.nif->nif_pif != spp->sp_pif) {
		return(EINVAL);
	}

	/*
	 * Check AAL
	 */
	if (!spans_get_spans_aal(cvp->cvc_attr.aal.type, &aal)) {
		return(EINVAL);
	}

#ifdef NOTDEF
	/*
	 * Check encapsulation
	 */
	/* XXX -- How do we check encapsulation? */
	if (cvp->ac_encaps != ATM_ENC_NULL) {
		return(EINVAL);
	}
#endif

	/*
	 * Allocate control block for VCC
	 */
	svp = (struct spans_vccb *)atm_allocate(&spans_vcpool);
	if (svp == NULL) {
		return(ENOMEM);
	}

	/*
	 * Fill in VCCB
	 */
	if (pvc) {
		svp->sv_type = VCC_PVC | VCC_IN | VCC_OUT;
		svp->sv_vpi = vpi;
		svp->sv_vci = vci;
		svp->sv_sstate = (spp->sp_state == SPANS_ACTIVE ?
				SPANS_VC_ACTIVE : SPANS_VC_ACT_DOWN);
		svp->sv_ustate = VCCU_OPEN;
	} else {
		svp->sv_type = VCC_SVC | VCC_OUT;
		spans_addr_copy(cvp->cvc_attr.called.addr.address,
				&svp->sv_conn.con_dst);
		spans_addr_copy(spp->sp_addr.address,
				&svp->sv_conn.con_src);
		svp->sv_conn.con_dsap = SPANS_SAP_IP;
		svp->sv_conn.con_ssap = spans_ephemeral_sap(spp);
		svp->sv_sstate = SPANS_VC_POPEN;
		svp->sv_ustate = VCCU_POPEN;
	}
	svp->sv_proto = ATM_SIG_SPANS;
	svp->sv_pif = spp->sp_pif;
	svp->sv_nif = cvp->cvc_attr.nif;
	svp->sv_connvc = cvp;
	svp->sv_spans_aal = aal;
	svp->sv_tstamp = time_second;

	/*
	 * Put VCCB on SPANS queue
	 */
	ENQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq);

	/*
	 * Link VCCB to VCC connection block
	 */
	cvp->cvc_vcc = (struct vccb *) svp;

	/*
	 * Start the SPANS message exchange if this is an SVC
	 */
	if (!pvc) {
		svp->sv_retry = 0;
		svp->sv_spans_qos.rsc_peak = 1;
		svp->sv_spans_qos.rsc_mean = 1;
		svp->sv_spans_qos.rsc_burst = 1;
		err = spans_send_open_req(spp, svp);
		if (err) {
			/*
			 * On error, delete the VCCB
			 */
			DEQUEUE(svp, struct spans_vccb, sv_sigelem,
					spp->sp_vccq);
			cvp->cvc_vcc = NULL;
			atm_free((caddr_t)svp);
			return(err);
		} else {
コード例 #5
0
ファイル: atm_range.c プロジェクト: gmesser/adeptdp
/*
 * Allocate the memory for an atm_range structure.
 *
 * Allocates the memory for the enclosing structure and for the components.
 *
 * Return:    Pointer to the new instance.
 */
atm_range *atm_range_allocate() {
	atm_range *range = calloc(1, sizeof(atm_range));
	range->begin = atm_allocate();
	range->end = atm_allocate();
	return range;
}
コード例 #6
0
ファイル: spans_proto.c プロジェクト: juanfra684/DragonFlyBSD
/*
 * Process a SPANS timeout
 *
 * Called when a previously scheduled spans control block timer expires.
 * Processing will based on the current SPANS state.
 *
 * Called at splnet.
 *
 * Arguments:
 *	tip	pointer to spans timer control block
 *
 * Returns:
 *	none
 *
 */
void
spans_timer(struct atm_time *tip)
{
    struct spans	*spp;
    spans_msg	*msg;
    Atm_addr_pvc	*pvcp;
    int		err;

    /*
     * Back-off to SPANS control block
     */
    spp = (struct spans *)
          ((caddr_t)tip - (int)(&((struct spans *)0)->sp_time));

    ATM_DEBUG2("spans_timer: spp=%p,state=%d\n",
               spp, spp->sp_state);

    /*
     * Process timeout based on protocol state
     */
    switch (spp->sp_state) {

    case SPANS_INIT:

        /*
         * Open signalling channel
         */
        spans_attr.nif = spp->sp_pif->pif_nif;

        spans_attr.aal.v.aal4.forward_max_SDU_size =
            ATM_NIF_MTU;
        spans_attr.aal.v.aal4.backward_max_SDU_size =
            ATM_NIF_MTU;
        spans_attr.aal.v.aal4.SSCS_type =
            T_ATM_SSCS_SSCOP_UNREL;
        spans_attr.aal.v.aal4.mid_low = 0;
        spans_attr.aal.v.aal4.mid_high = 0;

        spans_attr.called.tag = T_ATM_PRESENT;
        spans_attr.called.addr.address_format = T_ATM_PVC_ADDR;
        spans_attr.called.addr.address_length =
            sizeof(Atm_addr_pvc);
        pvcp = (Atm_addr_pvc *)spans_attr.called.addr.address;
        ATM_PVC_SET_VPI(pvcp, SPANS_SIG_VPI);
        ATM_PVC_SET_VCI(pvcp, SPANS_SIG_VCI);
        spans_attr.called.subaddr.address_format = T_ATM_ABSENT;
        spans_attr.called.subaddr.address_length = 0;

        spans_attr.traffic.v.forward.PCR_all_traffic =
            spp->sp_pif->pif_pcr;
        spans_attr.traffic.v.backward.PCR_all_traffic =
            spp->sp_pif->pif_pcr;

        err = atm_cm_connect(&spans_endpt, spp, &spans_attr,
                             &spp->sp_conn);
        if (err) {
            log(LOG_CRIT, "spans: signalling channel setup failed\n");
            return;
        }

        /*
         * Signalling channel open, start probing
         */
        spp->sp_state = SPANS_PROBE;

    /* FALLTHRU */

    case SPANS_PROBE:
    case SPANS_ACTIVE:

        /*
         * Send out SPANS_STAT_REQ message
         */
        msg = (spans_msg *)atm_allocate(&spans_msgpool);
        if (msg == NULL) {
            /* Retry later if no memory */
            SPANS_TIMER(spp, SPANS_PROBE_ERR_WAIT);
            break;
        }
        msg->sm_vers = SPANS_VERS_1_0;
        msg->sm_type = SPANS_STAT_REQ;
        msg->sm_stat_req.streq_es_epoch = spp->sp_h_epoch;
        if (spans_send_msg(spp, msg)) {
            /* Retry later if send fails */
            SPANS_TIMER(spp, SPANS_PROBE_ERR_WAIT);
            atm_free(msg);
            break;
        }
        atm_free(msg);
        spp->sp_probe_ct++;

        /*
         * Check whether we're getting an answer to our probes
         */
        if (spp->sp_state == SPANS_ACTIVE &&
                spp->sp_probe_ct > SPANS_PROBE_THRESH) {
            /*
             * Interface is down, notify VCC owners
             */
            spans_switch_reset(spp, SPANS_UNI_DOWN);

            /*
             * Set new state and increment host epoch so
             * switch knows we reset everyting.
             */
            spp->sp_state = SPANS_PROBE;
            spp->sp_h_epoch++;
            spp->sp_s_epoch = 0;
        }

        /*
         * Keep sending status requests
         */
        SPANS_TIMER(spp, SPANS_PROBE_INTERVAL);

        break;

    case SPANS_DETACH:
        /*
         * Try to terminate the SPANS signalling PVC
         */
        err = atm_cm_release(spp->sp_conn, &spans_cause);
        if (err) {
            log(LOG_ERR, "spans: can't close signalling channel\n");
        }
        break;

    default:
        log(LOG_ERR, "spans: timer state: spp=%p, state=%d\n",
            spp, spp->sp_state);
    }
}
コード例 #7
0
ファイル: spans_arp.c プロジェクト: AhmadTux/DragonFlyBSD
/*
 * Process a new outgoing SVC requiring SPANS ARP support
 * 
 * This function is called by an endpoint wishing to resolve a destination 
 * IP address to an ATM address in order to open an SVC to that destination.
 * If a valid mapping is already in our cache, then we just tell the caller
 * about it and that's that.  Otherwise, we have to allocate a new arp entry
 * and issue a query for the mapping.
 *
 * Arguments:
 *	ivp	pointer to SVC's IPVCC control block
 *	dst	pointer to destination IP address
 *
 * Returns:
 *	MAP_VALID	- Got the answer, returned via iv_arpent field.
 *	MAP_PROCEEDING	- OK so far, querying for peer's mapping
 *	MAP_FAILED	- error, unable to allocate resources
 *
 */
int
spansarp_svcout(struct ipvcc *ivp, struct in_addr *dst)
{
	struct spanscls	*clp;
	struct spansarp	*sap;

	ivp->iv_arpent = NULL;

	/*
	 * Lookup destination address
	 */
	crit_enter();
	SPANSARP_LOOKUP(dst->s_addr, sap);

	if (sap) {
		/*
		 * Link this vcc to entry queue
		 */
		LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);

		/*
		 * If entry is valid, we're done
		 */
		if (sap->sa_flags & SAF_VALID) {
			ivp->iv_arpent = (struct arpmap *)sap;
			crit_exit();
			return (MAP_VALID);
		}

		/*
		 * We're already looking for this address
		 */
		crit_exit();
		return (MAP_PROCEEDING);
	}

	/*
	 * Need a new arp entry - first, find the cls instance
	 * corresponding to the requestor's IP interface.
	 */
	for (clp = spanscls_head; clp; clp = clp->cls_next) {
		if (clp->cls_ipnif == ivp->iv_ipnif)
			break;
	}
	if (clp == NULL) {
		crit_exit();
		return (MAP_FAILED);
	}

	/*
	 * Now get the new arp entry
	 */
	sap = (struct spansarp *)atm_allocate(&spansarp_pool);
	if (sap == NULL) {
		crit_exit();
		return (MAP_FAILED);
	}

	/*
	 * Get entry set up
	 */
	sap->sa_dstip.s_addr = dst->s_addr;
	sap->sa_dstatm.address_format = T_ATM_ABSENT;
	sap->sa_dstatm.address_length = 0;
	sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
	sap->sa_dstatmsub.address_length = 0;
	sap->sa_cls = clp;
	sap->sa_origin = SAO_LOOKUP;

	/*
	 * Link ipvcc to arp entry for later notification
	 */
	LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);

	/*
	 * Add arp entry to table
	 */
	SPANSARP_ADD(sap);

	/*
	 * Add arp entry to retry list and start retry timer if needed
	 */
	LINK2TAIL(sap, struct spansarp, spansarp_retry_head, sa_rnext);
	if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0)
		atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);

	/*
	 * Issue arp request for this address
	 */
	spansarp_request(sap);

	crit_exit();
	return (MAP_PROCEEDING);
}
コード例 #8
0
ファイル: spans_arp.c プロジェクト: AhmadTux/DragonFlyBSD
/*
 * 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);
}
コード例 #9
0
ファイル: spans_arp.c プロジェクト: AhmadTux/DragonFlyBSD
/*
 * Process a SPANS ARP input packet
 * 
 * Arguments:
 *	clp	pointer to interface CLS control block
 *	m	pointer to input packet buffer chain
 *
 * Returns:
 *	none
 *
 */
void
spansarp_input(struct spanscls *clp, KBuffer *m)
{
	struct spans		*spp = clp->cls_spans;
	struct spanscls_hdr	*chp;
	struct spansarp_hdr	*ahp;
	struct spansarp		*sap;
	struct ip_nif		*inp = clp->cls_ipnif;
	struct in_addr	in_me, in_src, in_targ;
	int		err;

	/*
	 * Make sure IP interface has been activated
	 */
	if (inp == NULL)
		goto free;

	/*
	 * Get the packet together
	 */
	if (KB_LEN(m) < ARP_PACKET_LEN) {
		KB_PULLUP(m, ARP_PACKET_LEN, m);
		if (m == NULL)
			return;
	}
	KB_DATASTART(m, chp, struct spanscls_hdr *);
	ahp = (struct spansarp_hdr *)(chp + 1);

	KM_COPY(ahp->ah_spa, &in_src, sizeof(struct in_addr));
	KM_COPY(ahp->ah_tpa, &in_targ, sizeof(struct in_addr));
	KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), &in_me,
		sizeof(struct in_addr));

	/*
	 * Initial packet verification
	 */
	if ((ahp->ah_hrd != htons(ARP_SPANS)) ||
	    (ahp->ah_pro != htons(ETHERTYPE_IP)))
		goto free;

	/*
	 * Validate source addresses
	 * 	can't be from hardware broadcast
	 *	can't be from me
	 */
	if (!spans_addr_cmp(&ahp->ah_sha, &spans_bcastaddr))
		goto free;
	if (!spans_addr_cmp(&ahp->ah_sha, spp->sp_addr.address))
		goto free;
	if (in_src.s_addr == in_me.s_addr) {
		log(LOG_ERR, 
			"duplicate IP address sent from spans address %s\n",
			spans_addr_print(&ahp->ah_sha));
		in_targ = in_me;
		goto chkop;
	}

	/*
	 * If source IP address is from unspecified or broadcast addresses,
	 * don't bother updating arp table, but answer possible requests
	 */
	if (in_broadcast(in_src, &inp->inf_nif->nif_if))
		goto chkop;

	/*
	 * Update arp table with source address info
	 */
	crit_enter();
	SPANSARP_LOOKUP(in_src.s_addr, sap);
	if (sap) {
		/*
		 * Found an entry for the source, but don't
		 * update permanent entries
		 */
		if (sap->sa_origin != SAO_PERM) {

			/*
			 * Update the entry
			 */
			sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
			sap->sa_dstatm.address_length = sizeof(spans_addr);
			spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
			sap->sa_cls = clp;
			sap->sa_reftime = 0;
			if ((sap->sa_flags & SAF_VALID) == 0) {
				/*
				 * Newly valid entry, notify waiting users
				 */
				struct ipvcc	*ivp, *inext;

				sap->sa_flags |= SAF_VALID;
				for (ivp = sap->sa_ivp; ivp; ivp = inext) {
					inext = ivp->iv_arpnext;

					ivp->iv_arpent = (struct arpmap *)sap;
					(*inp->inf_arpnotify)(ivp, MAP_VALID);
				}

				/*
				 * Remove ourselves from the retry chain
				 */
				UNLINK(sap, struct spansarp,
					spansarp_retry_head, sa_rnext);
			}
		}

	} else if (in_targ.s_addr == in_me.s_addr) {
		/*
		 * Source unknown and we're the target - add new entry
		 */
		sap = (struct spansarp *)atm_allocate(&spansarp_pool);
		if (sap) {
			sap->sa_dstip.s_addr = in_src.s_addr;
			sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
			sap->sa_dstatm.address_length = sizeof(spans_addr);
			spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
			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_LOOKUP;
			SPANSARP_ADD(sap);
		}
	}
	crit_exit();

chkop:
	/*
	 * If this is a request for our address, send a reply 
	 */
	if (ntohs(ahp->ah_op) != ARP_REQUEST)
		goto free;
	if (in_targ.s_addr != in_me.s_addr)
		goto free;

	spans_addr_copy(&chp->ch_src, &chp->ch_dst);
	spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
	ahp->ah_op = htons(ARP_REPLY);
	spans_addr_copy(&ahp->ah_sha, &ahp->ah_tha);
	spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
	KM_COPY(ahp->ah_spa, ahp->ah_tpa, sizeof(struct in_addr));
	KM_COPY(&in_me, ahp->ah_spa, sizeof(struct in_addr));

	err = atm_cm_cpcs_data(clp->cls_conn, m);
	if (err)
		goto free;
	return;

free:
	KB_FREEALL(m);
}
コード例 #10
0
/*
 * Process a SETUP message
 *
 * Arguments:
 *	usp	pointer to UNISIG protocol instance block
 *	msg	pointer to the SETUP message
 *
 * Returns:
 *	none
 *
 */
static void
unisig_rcv_setup(struct unisig *usp, struct unisig_msg *msg)
{
	struct unisig_vccb	*uvp = NULL;
	struct ie_generic	*iep;

	ATM_DEBUG2("unisig_rcv_setup: usp=%p, msg=%p\n", usp, msg);

	/*
	 * If we already have a VCC with the call reference,
	 * ignore the SETUP message
	 */
	uvp = unisig_find_conn(usp, EXTRACT_CREF(msg->msg_call_ref));
	if (uvp)
		return;

	/*
	 * If the call reference flag is incorrectly set, 
	 * ignore the SETUP message
	 */
	if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT)
		return;

	/*
	 * If there are missing mandatory IEs, send a
	 * RELEASE COMPLETE message and ignore the SETUP
	 */
	for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) {
		if (iep->ie_err_cause == UNI_IE_CAUS_MISSING) {
			unisig_send_release_complete(usp,
					uvp, msg, UNI_IE_CAUS_MISSING);
			return;
		}
	}

	/*
	 * If there are mandatory IEs with invalid content, send a
	 * RELEASE COMPLETE message and ignore the SETUP
	 */
	for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) {
		if (iep->ie_err_cause == UNI_IE_CAUS_IECONTENT) {
			unisig_send_release_complete(usp,
					uvp, msg,
					UNI_IE_CAUS_IECONTENT);
			return;
		}
	}

	/*
	 * Get a new VCCB for the connection
	 */
	uvp = (struct unisig_vccb *)atm_allocate(&unisig_vcpool);
	if (uvp == NULL) {
		return;
	}

	/*
	 * Put the VCCB on the UNISIG queue
	 */
	ENQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);

	/*
	 * Set the state and call reference value
	 */
	uvp->uv_sstate = UNI_NULL;
	uvp->uv_call_ref = EXTRACT_CREF(msg->msg_call_ref);

	/*
	 * Pass the VCCB and message to the VC state machine
	 */
	unisig_vc_state(usp, uvp, UNI_VC_SETUP_MSG, msg);

	/*
	 * If the VCCB state is NULL, the open failed and the
	 * VCCB should be released
	 */
	if (uvp->uv_sstate == UNI_NULL) {
		DEQUEUE(uvp, struct unisig_vccb, uv_sigelem,
				usp->us_vccq);
		atm_free(uvp);
	}
コード例 #11
0
/*
 * Process a RESTART message
 *
 * Arguments:
 *	usp	pointer to UNISIG protocol instance block
 *	msg	pointer to the RESTART message
 *
 * Returns:
 *	none
 *
 */
static void
unisig_rcv_restart(struct unisig *usp, struct unisig_msg *msg)
{
	struct unisig_vccb	*uvp, *uvnext;
	struct unisig_msg	*rsta_msg;

	ATM_DEBUG2("unisig_rcv_restart: usp=%p, msg=%p\n",
			usp, msg);

	/*
	 * Check what class of VCCs we're supposed to restart
	 */
	if (msg->msg_ie_rsti->ie_rsti_class == UNI_IE_RSTI_IND_VC) {
		/*
		 * Just restart the indicated VCC
		 */
		if (msg->msg_ie_cnid) {
			uvp = unisig_find_vpvc(usp,
					msg->msg_ie_cnid->ie_cnid_vpci,
					msg->msg_ie_cnid->ie_cnid_vci,
					0);
			if (uvp && uvp->uv_type & VCC_SVC) {
				unisig_clear_vcc(usp, uvp,
						T_ATM_CAUSE_NORMAL_CALL_CLEARING);
			}
		}
	} else {
		/*
		 * Restart all VCCs
		 */
		crit_enter();
		for (uvp=Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
				uvp=uvnext) {
			uvnext = Q_NEXT(uvp, struct unisig_vccb,
					uv_sigelem);
			if (uvp->uv_type & VCC_SVC) {
				unisig_clear_vcc(usp, uvp,
						T_ATM_CAUSE_NORMAL_CALL_CLEARING);
			}
		}
		crit_exit();
	}

	/*
	 * Get memory for a RESTART ACKNOWLEDGE message
	 */
	rsta_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
	if (rsta_msg == NULL) {
		return;
	}

	/*
	 * Fill out the message
	 */
	rsta_msg->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref);
	rsta_msg->msg_type = UNI_MSG_RSTA;
	rsta_msg->msg_type_flag = 0;
	rsta_msg->msg_type_action = 0;
	rsta_msg->msg_ie_rsti = msg->msg_ie_rsti;
	if (msg->msg_ie_cnid) {
		rsta_msg->msg_ie_cnid = msg->msg_ie_cnid;
	}

	/*
	 * Send the message
	 */
	unisig_send_msg(usp, rsta_msg);
	rsta_msg->msg_ie_rsti = NULL;
	rsta_msg->msg_ie_cnid = NULL;
	unisig_free_msg(rsta_msg);

	return;
}
コード例 #12
0
/*
 * Send a STATUS message
 *
 * Arguments:
 *	usp	pointer to UNISIG protocol instance block
 *	uvp	pointer to VCCB for which the STATUS is being sent.
 *		NULL indicates that a VCCB wasn't found for a call
 *		reference value.
 *	msg	pointer to the message which triggered the send
 *	cause	the cause code to include in the message
 *
 * Returns:
 *	none
 *
 */
int
unisig_send_status(struct unisig *usp, struct unisig_vccb *uvp,
		   struct unisig_msg *msg, int cause)
{
	int			err = 0, i;
	struct unisig_msg	*stat_msg;
	struct ie_generic	*cause_ie, *clst_ie, *iep;

	ATM_DEBUG4("unisig_send_status: usp=%p, uvp=%p, msg=%p, cause=%d\n",
			usp, uvp, msg, cause);

	/*
	 * Get memory for a STATUS message
	 */
	stat_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
	if (stat_msg == NULL) {
		return(ENOMEM);
	}
	cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
	if (cause_ie == NULL) {
		atm_free(stat_msg);
		return(ENOMEM);
	}
	clst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
	if (clst_ie == NULL) {
		atm_free(stat_msg);
		atm_free(cause_ie);
		return(ENOMEM);
	}

	/*
	 * Fill in the STATUS message
	 */
	if (uvp) {
		stat_msg->msg_call_ref = uvp->uv_call_ref;
	} else if (msg) {
		stat_msg->msg_call_ref =
				EXTRACT_CREF(msg->msg_call_ref);
	} else {
		stat_msg->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
	}
	stat_msg->msg_type = UNI_MSG_STAT;
	stat_msg->msg_type_flag = 0;
	stat_msg->msg_type_action = 0;
	stat_msg->msg_ie_clst = clst_ie;
	stat_msg->msg_ie_caus = cause_ie;

	/*
	 * Fill out the call state IE
	 */
	clst_ie->ie_ident = UNI_IE_CLST;
	clst_ie->ie_coding = 0;
	clst_ie->ie_flag = 0;
	clst_ie->ie_action = 0;
	if (uvp) {
		clst_ie->ie_clst_state = uvp->uv_sstate;
	} else {
		clst_ie->ie_clst_state = UNI_NULL;
	}

	/*
	 * Fill out the cause IE
	 */
	cause_ie->ie_ident = UNI_IE_CAUS;
	cause_ie->ie_coding = 0;
	cause_ie->ie_flag = 0;
	cause_ie->ie_action = 0;
	cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
	cause_ie->ie_caus_cause = cause;
	switch (cause) {
	case UNI_IE_CAUS_MTEXIST:
	case UNI_IE_CAUS_STATE:
		if (msg) {
			cause_ie->ie_caus_diagnostic[0] = msg->msg_type;
		}
		break;
	case UNI_IE_CAUS_MISSING:
	case UNI_IE_CAUS_IECONTENT:
	case UNI_IE_CAUS_IEEXIST:
		for (i=0, iep=msg->msg_ie_err;
				iep && i<UNI_MSG_IE_CNT;
				i++, iep = iep->ie_next) {
			if (iep->ie_err_cause == cause) {
				cause_ie->ie_caus_diagnostic[i] =
						iep->ie_ident;
			}
		}
	}

	/*
	 * Send the STATUS message
	 */
	err = unisig_send_msg(usp, stat_msg);
	unisig_free_msg(stat_msg);

	return(err);
}
コード例 #13
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);
}