Пример #1
0
/*
 * 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);
}
Пример #2
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 {
Пример #3
0
/*
 * Issue a SPANS ARP request packet
 * 
 * Arguments:
 *	sap	pointer to arp table entry
 *
 * Returns:
 *	0	packet was successfully sent
 *	else	unable to send packet
 *
 */
static int
spansarp_request(struct spansarp *sap)
{
	struct spanscls		*clp;
	struct spans		*spp;
	struct spanscls_hdr	*chp;
	struct spansarp_hdr	*ahp;
	KBuffer			*m;
	struct ip_nif		*inp;
	int			err;

	clp = sap->sa_cls;
	spp = clp->cls_spans;
	inp = clp->cls_ipnif;

	/*
	 * Make sure CLS VCC is open and that we know our addresses
	 */
	if (clp->cls_state != CLS_OPEN)
		return (1);
	if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR)
		return (1);
	if (inp == NULL)
		return (1);

	/*
	 * Get a buffer for pdu
	 */
	KB_ALLOCPKT(m, ARP_PACKET_LEN, KB_F_NOWAIT, KB_T_DATA);
	if (m == NULL)
		return (1);

	/*
	 * Place pdu at end of buffer
	 */
	KB_PLENSET(m, ARP_PACKET_LEN);
	KB_TAILALIGN(m, ARP_PACKET_LEN);
	KB_DATASTART(m, chp, struct spanscls_hdr *);
	ahp = (struct spansarp_hdr *)(chp + 1);

	/*
	 * Build headers
	 */
	spans_addr_copy(&spans_bcastaddr, &chp->ch_dst);
	spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
	*(u_int *)&chp->ch_proto = *(u_int *)&spanscls_hdr.ch_proto;
	*(u_int *)&chp->ch_dsap = *(u_int *)&spanscls_hdr.ch_dsap;
	*(u_short *)&chp->ch_oui[1] = *(u_short *)&spanscls_hdr.ch_oui[1];
	chp->ch_pid = htons(ETHERTYPE_ARP);


	/*
	 * Build ARP packet
	 */
	ahp->ah_hrd = htons(ARP_SPANS);
	ahp->ah_pro = htons(ETHERTYPE_IP);
	ahp->ah_hln = sizeof(spans_addr);
	ahp->ah_pln = sizeof(struct in_addr);
	ahp->ah_op = htons(ARP_REQUEST);
	spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
	KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), ahp->ah_spa,
		sizeof(struct in_addr));
	KM_COPY(&sap->sa_dstip, ahp->ah_tpa, sizeof(struct in_addr));

	/*
	 * Now, send the pdu via the CLS service
	 */
	err = atm_cm_cpcs_data(clp->cls_conn, m);
	if (err) {
		KB_FREEALL(m);
		return (1);
	}

	return (0);
}