/* * 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); }
/* * 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 {
/* * 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); }