/* * Send a UNISIG signalling message * * Called to send a Q.2931 message. This routine encodes the message * and hands it to SSCF for transmission. * * Arguments: * usp pointer to UNISIG protocol instance block * msg pointer to message * * Returns: * 0 message sent OK * errno error encountered * */ int unisig_send_msg(struct unisig *usp, struct unisig_msg *msg) { int err = 0; struct usfmt usf; ATM_DEBUG2("unisig_send_msg: msg=%p, type=%d\n", msg, msg->msg_type); /* * Make sure the network is up */ if (usp->us_state != UNISIG_ACTIVE) return(ENETDOWN); #ifdef DIAGNOSTIC /* * Print the message we're sending. */ if (unisig_print_msg) usp_print_msg(msg, UNISIG_MSG_OUT); #endif /* * Convert message to network order */ err = usf_init(&usf, usp, NULL, USF_ENCODE, usp->us_headout); if (err) return(err); err = usf_enc_msg(&usf, msg); if (err) { ATM_DEBUG1("unisig_send_msg: encode failed with %d\n", err); KB_FREEALL(usf.usf_m_base); return(EIO); } #ifdef DIAGNOSTIC /* * Print the converted message */ if (unisig_print_msg > 1) unisig_print_mbuf(usf.usf_m_base); #endif /* * Send the message */ err = atm_cm_saal_data(usp->us_conn, usf.usf_m_base); if (err) KB_FREEALL(usf.usf_m_base); return(err); }
/* * RS PDU / SOS_READY Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ static void sscop_rs_ready(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct rs_pdu *rp = (struct rs_pdu *)trlr; int err; /* * If retransmitted RS, just ACK it */ if (sscop_is_rexmit(sop, rp->rs_nsq)) { KB_FREEALL(m); sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; sscop_send_rsak(sop); return; } /* * Stop data transfer timers */ sop->so_timer[SSCOP_T_POLL] = 0; sop->so_timer[SSCOP_T_NORESP] = 0; sop->so_timer[SSCOP_T_IDLE] = 0; sop->so_flags &= ~SOF_KEEPALIVE; /* * Initialize transmit window */ SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr)); /* * Notify user of connection resynchronization */ STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, sop->so_connvc, (int)m, 0, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } /* * Clear out appropriate queues */ q2110_prep_retrieve(sop); /* * Wait for user response */ sop->so_state = SOS_INRESYN; return; }
/* * POLL PDU / SOS_READY Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ static void sscop_poll_ready(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct poll_pdu *pp = (struct poll_pdu *)trlr; sscop_seq nps; pp->poll_ns = ntohl(pp->poll_ns); /* * If the poll sequence number is less than highest number * we've already seen, something's wrong */ if (SEQ_LT(pp->poll_ns, sop->so_rcvhigh, sop->so_rcvnext)) { /* * Record error condition */ sscop_maa_error(sop, 'Q'); /* * Free buffers */ KB_FREEALL(m); /* * Go into recovery mode */ q2110_error_recovery(sop); return; } /* * Set a new "next highest" sequence number expected */ if (SEQ_LT(pp->poll_ns, sop->so_rcvmax, sop->so_rcvnext)) SEQ_SET(sop->so_rcvhigh, pp->poll_ns); else sop->so_rcvhigh = sop->so_rcvmax; /* * Return a STAT PDU to peer */ SEQ_SET(nps, ntohl(pp->poll_nps)); KB_FREEALL(m); sscop_send_stat(sop, nps); return; }
/* * ENDAK PDU / SOS_OUTDISC Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_endak_outdisc(struct sscop *sop, KBuffer *m, caddr_t trlr) { int err; /* * Stop retransmit timer */ sop->so_timer[SSCOP_T_CC] = 0; /* * Release buffers */ KB_FREEALL(m); /* * Notify user of connection termination */ STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, sop->so_toku, sop->so_connvc, 0, 0, err); if (err) { sscop_abort(sop, "stack memory\n"); return; } /* * Back to idle state */ sop->so_state = SOS_IDLE; return; }
/* * SSCOP Upper Stack Command Handler * * This function will receive all of the stack commands issued from the * layer below SSCOP (ie. CPCS). Currently, only incoming PDUs will be * received here. The appropriate processing function will be determined * based on the received PDU type and the current sscop control block state. * * Arguments: * cmd stack command code * tok session token * arg1 command specific argument * arg2 command specific argument * * Returns: * none * */ void sscop_upper(int cmd, void *tok, int arg1, int arg2) { struct sscop *sop = (struct sscop *)tok; void (**ptab) (struct sscop *, KBuffer *, caddr_t); void (*func) (struct sscop *, KBuffer *, caddr_t); caddr_t trlr; int type; ATM_DEBUG5("sscop_upper: cmd=0x%x, sop=%p, state=%d, arg1=0x%x, arg2=0x%x\n", cmd, sop, sop->so_state, arg1, arg2); switch (cmd) { case CPCS_UNITDATA_SIG: /* * Decode/validate received PDU */ trlr = sscop_pdu_receive((KBuffer *)arg1, sop, &type); if (trlr == NULL) { return; } /* * Validate sscop state */ if (sop->so_state > SOS_MAXSTATE) { log(LOG_ERR, "sscop_upper: invalid state sop=%p, state=%d\n", sop, sop->so_state); KB_FREEALL((KBuffer *)arg1); return; } /* * Call event processing function */ ptab = sop->so_vers == SSCOP_VERS_QSAAL ? sscop_qsaal_pdutab[type]: sscop_q2110_pdutab[type]; func = ptab[sop->so_state]; if (func == NULL) { log(LOG_ERR, "sscop_upper: unsupported pdu=%d, state=%d\n", type, sop->so_state); break; } (*func)(sop, (KBuffer *)arg1, trlr); break; default: log(LOG_ERR, "sscop_upper: unknown cmd 0x%x, sop=%p\n", cmd, sop); } return; }
/* * No-op Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_noop(struct sscop *sop, KBuffer *m, caddr_t trlr) { /* * Just free PDU */ KB_FREEALL(m); return; }
/* * BGREJ PDU / SOS_OUTCONN Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_bgrej_outconn(struct sscop *sop, KBuffer *m, caddr_t trlr) { int source, uu, err; /* * Stop retransmit timer */ sop->so_timer[SSCOP_T_CC] = 0; if (sop->so_vers == SSCOP_VERS_QSAAL) { /* * Clear reestablishment flag */ sop->so_flags &= ~SOF_REESTAB; KB_FREEALL(m); m = NULL; uu = SSCOP_UU_NULL; source = SSCOP_SOURCE_SSCOP; } else { uu = (int)m; source = SSCOP_SOURCE_USER; } /* * Notify user of connection failure */ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, sop->so_connvc, uu, source, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } /* * Back to idle state */ sop->so_state = SOS_IDLE; return; }
/* * BGN PDU / SOS_INCONN Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ static void sscop_bgn_inconn(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct bgn_pdu *bp = (struct bgn_pdu *)trlr; int err; /* * If retransmitted BGN, ignore it */ if (sscop_is_rexmit(sop, bp->bgn_nsq)) { KB_FREEALL(m); return; } /* * Initialize transmit window */ SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); /* * First, tell user current connection has been released */ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } /* * Now, tell user of new connection establishment */ STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, sop->so_connvc, (int)m, 0, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } return; }
/* * MD PDU / SOS_* Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_md_all(struct sscop *sop, KBuffer *m, caddr_t trlr) { /* * We don't support MD PDUs */ KB_FREEALL(m); return; }
/* * BGREJ PDU / Protocol Error * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_bgrej_error(struct sscop *sop, KBuffer *m, caddr_t trlr) { /* * Record error condition */ sscop_maa_error(sop, 'D'); KB_FREEALL(m); return; }
/* * No-op Processor (arg1 == buffer) * * Arguments: * sop pointer to sscop connection block * arg1 command-specific argument (buffer pointer) * arg2 command-specific argument * * Returns: * none * */ void sscop_aa_noop_1(struct sscop *sop, int arg1, int arg2) { /* * Just free buffer chain */ if (arg1) KB_FREEALL((KBuffer *)arg1); return; }
/* * UD PDU / SOS_* Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_ud_all(struct sscop *sop, KBuffer *m, caddr_t trlr) { int err; /* * Pass data up to user */ STACK_CALL(SSCOP_UNITDATA_IND, sop->so_upper, sop->so_toku, sop->so_connvc, (int)m, 0, err); if (err) KB_FREEALL(m); return; }
/* * END PDU / SOS_READY Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ static void sscop_end_ready(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct end_pdu *ep = (struct end_pdu *)trlr; int err, source; /* * Stop data transfer timers */ sop->so_timer[SSCOP_T_POLL] = 0; sop->so_timer[SSCOP_T_NORESP] = 0; sop->so_timer[SSCOP_T_IDLE] = 0; sop->so_flags &= ~SOF_KEEPALIVE; /* * Acknowledge END */ sscop_send_endak(sop); /* * Get Source value */ if (ep->end_type & PT_SOURCE_SSCOP) source = SSCOP_SOURCE_SSCOP; else source = SSCOP_SOURCE_USER; /* * Notify user of connection termination */ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, sop->so_connvc, (int)m, source, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } /* * Clear out appropriate queues */ q2110_prep_retrieve(sop); /* * Back to idle state */ sop->so_state = SOS_IDLE; return; }
/* * END PDU / SOS_IDLE Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_end_idle(struct sscop *sop, KBuffer *m, caddr_t trlr) { /* * Free buffers */ KB_FREEALL(m); /* * Return an ENDAK to peer */ sscop_send_endak(sop); return; }
/* * RS PDU / SOS_OUTRECOV Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ static void sscop_rs_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct rs_pdu *rp = (struct rs_pdu *)trlr; int err; /* * If retransmitted RS, report an error */ if (sscop_is_rexmit(sop, rp->rs_nsq)) { sscop_rs_error(sop, m, trlr); return; } /* * Stop retransmit timer */ sop->so_timer[SSCOP_T_CC] = 0; /* * Initialize transmit window */ SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr)); /* * Notify user of connection resynchronization */ STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, sop->so_connvc, (int)m, 0, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } /* * Clear receiver buffer */ sscop_rcvr_drain(sop); /* * Wait for user response */ sop->so_state = SOS_INRESYN; return; }
/* * END PDU / SOS_OUTRECOV Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ static void sscop_end_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct end_pdu *ep = (struct end_pdu *)trlr; int err, source; /* * Stop retransmit timer */ sop->so_timer[SSCOP_T_CC] = 0; /* * Acknowledge END */ sscop_send_endak(sop); /* * Get Source value */ if (ep->end_type & PT_SOURCE_SSCOP) source = SSCOP_SOURCE_SSCOP; else source = SSCOP_SOURCE_USER; /* * Notify user of connection termination */ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, sop->so_connvc, (int)m, source, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } /* * Clear receiver buffer */ sscop_rcvr_drain(sop); /* * Back to idle state */ sop->so_state = SOS_IDLE; return; }
/* * ERAK PDU / SOS_OUTRECOV Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ static void sscop_erak_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct erak_pdu *ep = (struct erak_pdu *)trlr; int err; /* * Stop retransmit timer */ sop->so_timer[SSCOP_T_CC] = 0; /* * Initialize transmit window */ SEQ_SET(sop->so_sendmax, ntohl(ep->erak_nmr)); /* * Free PDU buffers */ KB_FREEALL(m); /* * Deliver any outstanding data to user */ q2110_deliver_data(sop); /* * Notify user of connection recovery */ STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, sop->so_connvc, 0, 0, err); if (err) { sscop_abort(sop, "stack memory\n"); return; } /* * Wait for user response */ sop->so_state = SOS_RECOVRSP; return; }
/* * RS PDU / SOS_INRESYN Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ static void sscop_rs_inresyn(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct rs_pdu *rp = (struct rs_pdu *)trlr; /* * If retransmitted RS, ignore it */ if (sscop_is_rexmit(sop, rp->rs_nsq)) { KB_FREEALL(m); return; } /* * Report error condition */ sscop_rs_error(sop, m, trlr); return; }
/* * ER PDU / SOS_INRECOV Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ static void sscop_er_inrecov(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct er_pdu *ep = (struct er_pdu *)trlr; /* * If retransmitted ER, just ignore it */ if (sscop_is_rexmit(sop, ep->er_nsq)) { KB_FREEALL(m); return; } /* * Report error condition */ sscop_er_error(sop, m, trlr); return; }
/* * Issue an ATMARP NAK PDU * * Arguments: * uip pointer to IP interface * m pointer to ATMARP_REQ buffer chain * ivp pointer to vcc over which to send pdu * * Returns: * 0 PDU was successfully sent * else unable to send PDU * */ int uniarp_arp_nak(struct uniip *uip, KBuffer *m, struct ipvcc *ivp) { struct atmarp_hdr *ahp; int err; /* * Get the fixed fields together */ if (KB_LEN(m) < sizeof(struct atmarp_hdr)) { KB_PULLUP(m, sizeof(struct atmarp_hdr), m); if (m == NULL) return (1); } KB_DATASTART(m, ahp, struct atmarp_hdr *); /* * Set new op-code */ ahp->ah_op = htons(ARP_NAK); /* * Finally, send the pdu to the vcc peer */ if (uniarp_print) uniarp_pdu_print(ivp, m, "send"); err = atm_cm_cpcs_data(ivp->iv_arpconn, m); if (err) { /* * Didn't make it */ KB_FREEALL(m); return (1); } return (0); }
/* * BGN PDU / SOS_IDLE Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_bgn_idle(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct bgn_pdu *bp = (struct bgn_pdu *)trlr; int err, source; if (sop->so_vers == SSCOP_VERS_Q2110) { /* * "Power-up Robustness" option * * Accept BGN regardless of BGN.N(SQ) */ sop->so_rcvconn = bp->bgn_nsq; } else { /* * If retransmitted BGN, reject it */ if (sscop_is_rexmit(sop, bp->bgn_nsq)) { KB_FREEALL(m); sscop_send_bgrej(sop); return; } } if (sop->so_vers == SSCOP_VERS_QSAAL) { /* * Get Source value */ if (bp->bgn_type & PT_SOURCE_SSCOP) source = SSCOP_SOURCE_SSCOP; else source = SSCOP_SOURCE_USER; /* * Reset receiver state variables */ qsaal1_reset_rcvr(sop); } else source = 0; /* * Set initial transmit window */ SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); /* * Pass connection request up to user */ STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, sop->so_connvc, (int)m, source, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } /* * Wait for user's response */ sop->so_state = SOS_INCONN; return; }
/* * SSCOP Lower Stack Command Handler * * This function will receive all of the stack commands issued from the * layer above SSCOP (ie. using the SSCOP SAP). The appropriate processing * function will be determined based on the received stack command and the * current sscop control block state. * * Arguments: * cmd stack command code * tok session token * arg1 command specific argument * arg2 command specific argument * * Returns: * none * */ void sscop_lower(int cmd, void *tok, int arg1, int arg2) { struct sscop *sop = (struct sscop *)tok; void (**stab) (struct sscop *, int, int); void (*func) (struct sscop *, int, int); int val; ATM_DEBUG5("sscop_lower: cmd=0x%x, sop=%p, state=%d, arg1=0x%x, arg2=0x%x\n", cmd, sop, sop->so_state, arg1, arg2); /* * Validate stack command */ val = cmd & STKCMD_VAL_MASK; if (((u_int)cmd < (u_int)SSCOP_CMD_MIN) || ((u_int)cmd > (u_int)SSCOP_CMD_MAX) || ((stab = (sop->so_vers == SSCOP_VERS_QSAAL ? sscop_qsaal_aatab[val] : sscop_q2110_aatab[val])) == NULL)) { log(LOG_ERR, "sscop_lower: unknown cmd 0x%x, sop=%p\n", cmd, sop); return; } /* * Validate sscop state */ if (sop->so_state > SOS_MAXSTATE) { log(LOG_ERR, "sscop_lower: invalid state sop=%p, state=%d\n", sop, sop->so_state); /* * Release possible buffer */ if (sscop_buf1[val]) { if (arg1) KB_FREEALL((KBuffer *)arg1); } return; } /* * Validate command/state combination */ func = stab[sop->so_state]; if (func == NULL) { log(LOG_ERR, "sscop_lower: invalid cmd/state: sop=%p, cmd=0x%x, state=%d\n", sop, cmd, sop->so_state); /* * Release possible buffer */ if (sscop_buf1[val]) { if (arg1) KB_FREEALL((KBuffer *)arg1); } return; } /* * Call event processing function */ (*func)(sop, arg1, arg2); return; }
/* * Supply Strategy 1 Large Buffers to CP * * May be called in interrupt state. * Must be called with interrupts locked out. * * Arguments: * fup pointer to device unit structure * * Returns: * none */ static void fore_buf_supply_1l(Fore_unit *fup) { H_buf_queue *hbp; Buf_queue *cqp; Buf_descr *bdp; Buf_handle *bhp; KBuffer *m; int nvcc, nbuf, i; /* * Figure out how many buffers we should be giving to the CP. * We're basing this calculation on the current number of open * VCCs thru this device, with certain minimum and maximum values * enforced. This will then allow us to figure out how many more * buffers we need to supply to the CP. This will be rounded up * to fill a supply queue entry. */ nvcc = MAX(fup->fu_open_vcc, BUF_MIN_VCC); nbuf = nvcc * 4 * RECV_MAX_SEGS; nbuf = MIN(nbuf, BUF1_LG_CPPOOL); nbuf -= fup->fu_buf1l_cnt; nbuf = roundup(nbuf, BUF1_LG_ENTSIZE); /* * OK, now supply the buffers to the CP */ while (nbuf > 0) { /* * Acquire a supply queue entry */ hbp = fup->fu_buf1l_tail; if (!((*hbp->hbq_status) & QSTAT_FREE)) break; bdp = hbp->hbq_descr; /* * Get a buffer for each descriptor in the queue entry */ for (i = 0; i < BUF1_LG_ENTSIZE; i++, bdp++) { caddr_t cp; /* * Get a cluster buffer */ KB_ALLOCEXT(m, BUF1_LG_SIZE, KB_F_NOWAIT, KB_T_DATA); if (m == NULL) { break; } KB_HEADSET(m, BUF1_LG_DOFF); /* * Point to buffer handle structure */ bhp = (Buf_handle *)((caddr_t)m + BUF1_LG_HOFF); bhp->bh_type = BHT_S1_LARGE; /* * Setup buffer descriptor */ bdp->bsd_handle = bhp; KB_DATASTART(m, cp, caddr_t); bhp->bh_dma = bdp->bsd_buffer = (H_dma) DMA_GET_ADDR( cp, BUF1_LG_SIZE, BUF_DATA_ALIGN, 0); if (bdp->bsd_buffer == 0) { /* * Unable to assign dma address - free up * this descriptor's buffer */ fup->fu_stats->st_drv.drv_bf_segdma++; KB_FREEALL(m); break; } /* * All set, so queue buffer (handle) */ ENQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq); } /* * If we we're not able to fill all the descriptors for * an entry, free up what's been partially built */ if (i != BUF1_LG_ENTSIZE) { caddr_t cp; /* * Clean up each used descriptor */ for (bdp = hbp->hbq_descr; i; i--, bdp++) { bhp = bdp->bsd_handle; DEQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq); m = (KBuffer *) ((caddr_t)bhp - BUF1_LG_HOFF); KB_DATASTART(m, cp, caddr_t); DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_LG_SIZE, 0); KB_FREEALL(m); } break; } /* * Finally, we've got an entry ready for the CP. * So claim the host queue entry and setup the CP-resident * queue entry. The CP will (potentially) grab the supplied * buffers when the descriptor pointer is set. */ fup->fu_buf1l_tail = hbp->hbq_next; (*hbp->hbq_status) = QSTAT_PENDING; cqp = hbp->hbq_cpelem; cqp->cq_descr = (CP_dma) CP_WRITE((u_long)hbp->hbq_descr_dma); /* * Update counters, etc for supplied buffers */ fup->fu_buf1l_cnt += BUF1_LG_ENTSIZE; nbuf -= BUF1_LG_ENTSIZE; } return; }
/* * BGAK PDU / SOS_OUTCONN Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_bgak_outconn(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct bgak_pdu *bp = (struct bgak_pdu *)trlr; int err; /* * Stop retransmit timer */ sop->so_timer[SSCOP_T_CC] = 0; /* * Initialize transmit window */ SEQ_SET(sop->so_sendmax, ntohl(bp->bgak_nmr)); /* * Notify user of connection establishment */ if (sop->so_flags & SOF_REESTAB) { KB_FREEALL(m); STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); if (err) { sscop_abort(sop, "stack memory\n"); return; } sop->so_flags &= ~SOF_REESTAB; } else { STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku, sop->so_connvc, (int)m, 0, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } } if (sop->so_vers == SSCOP_VERS_QSAAL) { /* * Reset receiver variables */ qsaal1_reset_rcvr(sop); /* * Start polling timer */ sscop_set_poll(sop); /* * Start lost poll/stat timer */ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; } else { /* * Initialize state variables */ q2110_init_state(sop); /* * Start data transfer timers */ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; } /* * OK, we're ready for data */ sop->so_state = SOS_READY; /* * See if transmit queues need servicing */ if (sop->so_flags & SOF_XMITSRVC) sscop_service_xmit(sop); return; }
/* * BGN PDU / SOS_INRESYN Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_bgn_inresyn(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct bgn_pdu *bp = (struct bgn_pdu *)trlr; int err, source; /* * If retransmitted BGN, oops */ if (sscop_is_rexmit(sop, bp->bgn_nsq)) { KB_FREEALL(m); sscop_maa_error(sop, 'B'); return; } /* * Stop data transfer timers */ sop->so_timer[SSCOP_T_POLL] = 0; sop->so_timer[SSCOP_T_NORESP] = 0; sop->so_timer[SSCOP_T_IDLE] = 0; sop->so_flags &= ~SOF_KEEPALIVE; /* * Initialize transmit window */ SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); if (sop->so_vers == SSCOP_VERS_QSAAL) { /* * Get (possible) Source value */ if (bp->bgn_type & PT_SOURCE_SSCOP) source = SSCOP_SOURCE_SSCOP; else source = SSCOP_SOURCE_USER; /* * Reset receiver variables */ qsaal1_reset_rcvr(sop); } else { /* * Stop possible retransmit timer */ sop->so_timer[SSCOP_T_CC] = 0; /* * Drain receiver queues */ sscop_rcvr_drain(sop); /* * Tell user current connection has been released */ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } source = 0; } /* * Tell user of incoming connection */ STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, sop->so_connvc, (int)m, source, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } /* * Wait for user's response */ sop->so_state = SOS_INCONN; return; }
/* * BGN PDU / SOS_OUTRESYN Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_bgn_outresyn(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct bgn_pdu *bp = (struct bgn_pdu *)trlr; int err, source; /* * If retransmitted BGN, ACK it and send new RS */ if (sscop_is_rexmit(sop, bp->bgn_nsq)) { KB_FREEALL(m); sscop_send_bgak(sop); sscop_send_rs(sop); return; } /* * Stop retransmit timer */ sop->so_timer[SSCOP_T_CC] = 0; /* * Initialize transmit window */ SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); if (sop->so_vers == SSCOP_VERS_QSAAL) { /* * Get (possible) Source value */ if (bp->bgn_type & PT_SOURCE_SSCOP) source = SSCOP_SOURCE_SSCOP; else source = SSCOP_SOURCE_USER; /* * Reset receiver variables */ qsaal1_reset_rcvr(sop); } else source = SSCOP_SOURCE_USER; /* * Notify user of connection termination */ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, sop->so_connvc, SSCOP_UU_NULL, source, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } /* * Now tell user of a "new" incoming connection */ STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, sop->so_connvc, (int)m, source, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } /* * Wait for user's response */ sop->so_state = SOS_INCONN; return; }
/* * RSAK PDU / SOS_OUTRESYN Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_rsak_outresyn(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct rsak_q2110_pdu *rp = (struct rsak_q2110_pdu *)trlr; int err; /* * Stop retransmit timer */ sop->so_timer[SSCOP_T_CC] = 0; /* * Notify user of resynchronization completion */ STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku, sop->so_connvc, 0, 0, err); if (err) { KB_FREEALL(m); sscop_abort(sop, "stack memory\n"); return; } if (sop->so_vers == SSCOP_VERS_QSAAL) { /* * Start the polling timer */ sscop_set_poll(sop); /* * Start lost poll/stat timer */ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; } else { /* * Initialize state variables */ SEQ_SET(sop->so_sendmax, ntohl(rp->rsak_nmr)); q2110_init_state(sop); /* * Start data transfer timers */ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; } /* * Free buffers */ KB_FREEALL(m); /* * Now go back to data transfer state */ sop->so_state = SOS_READY; /* * See if transmit queues need servicing */ if (sop->so_flags & SOF_XMITSRVC) sscop_service_xmit(sop); return; }
/* * USTAT PDU / SOS_READY Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_ustat_ready(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct ustat_pdu *up = (struct ustat_pdu *)trlr; struct pdu_hdr *php; sscop_seq seq1, seq2; up->ustat_nmr = ntohl(up->ustat_nmr); up->ustat_nr = ntohl(up->ustat_nr); /* * Validate peer's current receive data sequence number */ if (SEQ_GT(sop->so_ack, up->ustat_nr, sop->so_ack) || SEQ_GEQ(up->ustat_nr, sop->so_send, sop->so_ack)) { /* * Bad data sequence number */ goto goterr; } /* * Free acknowledged PDUs */ for (seq1 = sop->so_ack, SEQ_SET(seq2, up->ustat_nr); SEQ_LT(seq1, seq2, sop->so_ack); SEQ_INCR(seq1, 1)) { sscop_pack_free(sop, seq1); } /* * Update transmit state variables */ sop->so_ack = seq2; SEQ_SET(sop->so_sendmax, up->ustat_nmr); /* * Get USTAT list elements */ SEQ_SET(seq1, ntohl(up->ustat_le1)); SEQ_SET(seq2, ntohl(up->ustat_le2)); /* * Validate elements */ if (SEQ_GT(sop->so_ack, seq1, sop->so_ack) || SEQ_GEQ(seq1, seq2, sop->so_ack) || SEQ_GEQ(seq2, sop->so_send, sop->so_ack)) { /* * Bad element sequence number */ goto goterr; } /* * Process each missing sequence number in this gap */ while (SEQ_LT(seq1, seq2, sop->so_ack)) { /* * Find corresponding SD PDU on pending ack queue */ php = sscop_pack_locate(sop, seq1); if (php == NULL) { goto goterr; } /* * Retransmit this SD PDU if it's not * already scheduled for retranmission. */ if ((php->ph_rexmit_lk == NULL) && (sop->so_rexmit_tl != php)) { /* * Put PDU on retransmit queue and schedule * transmit servicing */ sscop_rexmit_insert(sop, php); sop->so_flags |= SOF_XMITSRVC; } /* * Bump to next sequence number */ SEQ_INCR(seq1, 1); } /* * Report retransmitted PDUs */ sscop_maa_error(sop, 'V'); /* * Free PDU buffer chain */ KB_FREEALL(m); /* * See if transmit queues need servicing */ if (sop->so_flags & SOF_XMITSRVC) sscop_service_xmit(sop); return; goterr: /* * Protocol/parameter error encountered */ sscop_maa_error(sop, 'T'); /* * Free PDU buffer chain */ KB_FREEALL(m); if (sop->so_vers == SSCOP_VERS_QSAAL) /* * Reestablish a new connection */ qsaal1_reestablish(sop); else /* * Initiate error recovery */ q2110_error_recovery(sop); return; }
/* * Free Buffer Supply Queue Data Structures * * Arguments: * fup pointer to device unit structure * * Returns: * none */ void fore_buf_free(Fore_unit *fup) { Buf_handle *bhp; KBuffer *m; /* * Free any previously supplied and not returned buffers */ if (fup->fu_flags & CUF_INITED) { /* * Run through Strategy 1 Small queue */ while ((bhp = Q_HEAD(fup->fu_buf1s_bq, Buf_handle)) != NULL) { caddr_t cp; /* * Back off to buffer */ m = (KBuffer *)((caddr_t)bhp - BUF1_SM_HOFF); /* * Dequeue handle and free buffer */ DEQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1s_bq); KB_DATASTART(m, cp, caddr_t); DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_SM_SIZE, 0); KB_FREEALL(m); } /* * Run through Strategy 1 Large queue */ while ((bhp = Q_HEAD(fup->fu_buf1l_bq, Buf_handle)) != NULL) { caddr_t cp; /* * Back off to buffer */ m = (KBuffer *)((caddr_t)bhp - BUF1_LG_HOFF); /* * Dequeue handle and free buffer */ DEQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq); KB_DATASTART(m, cp, caddr_t); DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_LG_SIZE, 0); KB_FREEALL(m); } } /* * Free the status words */ if (fup->fu_buf1s_stat) { if (fup->fu_buf1s_statd) { DMA_FREE_ADDR(fup->fu_buf1s_stat, fup->fu_buf1s_statd, sizeof(Q_status) * (BUF1_SM_QUELEN + BUF1_LG_QUELEN), ATM_DEV_NONCACHE); } atm_dev_free((volatile void *)fup->fu_buf1s_stat); fup->fu_buf1s_stat = NULL; fup->fu_buf1s_statd = NULL; fup->fu_buf1l_stat = NULL; fup->fu_buf1l_statd = NULL; } /* * Free the transmit descriptors */ if (fup->fu_buf1s_desc) { if (fup->fu_buf1s_descd) { DMA_FREE_ADDR(fup->fu_buf1s_desc, fup->fu_buf1s_descd, sizeof(Buf_descr) * ((BUF1_SM_QUELEN * BUF1_SM_ENTSIZE) + (BUF1_LG_QUELEN * BUF1_LG_ENTSIZE)), 0); } atm_dev_free(fup->fu_buf1s_desc); fup->fu_buf1s_desc = NULL; fup->fu_buf1s_descd = NULL; fup->fu_buf1l_desc = NULL; fup->fu_buf1l_descd = NULL; } return; }
/* * STAT PDU / SOS_READY Processor * * Arguments: * sop pointer to sscop connection block * m pointer to PDU buffer (without trailer) * trlr pointer to PDU trailer * * Returns: * none * */ void sscop_stat_ready(struct sscop *sop, KBuffer *m, caddr_t trlr) { struct stat_pdu *sp = (struct stat_pdu *)trlr; struct pdu_hdr *php; KBuffer *m0 = m; sscop_seq seq1, seq2, opa; int cnt = 0; sp->stat_nps = ntohl(sp->stat_nps); sp->stat_nmr = ntohl(sp->stat_nmr); sp->stat_nr = ntohl(sp->stat_nr); /* * Validate peer's received poll sequence number */ if (SEQ_GT(sop->so_pollack, sp->stat_nps, sop->so_pollack) || SEQ_GT(sp->stat_nps, sop->so_pollsend, sop->so_pollack)) { /* * Bad poll sequence number */ sscop_maa_error(sop, 'R'); goto goterr; } /* * Validate peer's current receive data sequence number */ if (SEQ_GT(sop->so_ack, sp->stat_nr, sop->so_ack) || SEQ_GT(sp->stat_nr, sop->so_send, sop->so_ack)) { /* * Bad data sequence number */ sscop_maa_error(sop, 'S'); goto goterr; } /* * Free acknowledged PDUs */ for (seq1 = sop->so_ack, SEQ_SET(seq2, sp->stat_nr); SEQ_LT(seq1, seq2, sop->so_ack); SEQ_INCR(seq1, 1)) { sscop_pack_free(sop, seq1); } /* * Update transmit state variables */ opa = sop->so_pollack; sop->so_ack = seq2; SEQ_SET(sop->so_pollack, sp->stat_nps); SEQ_SET(sop->so_sendmax, sp->stat_nmr); /* * Get first element in STAT list */ while (m && (KB_LEN(m) == 0)) m = KB_NEXT(m); if (m == NULL) goto done; m = sscop_stat_getelem(m, &seq1); /* * Make sure there's a second element too */ if (m == NULL) goto done; /* * Validate first element (start of missing pdus) */ if (SEQ_GT(sop->so_ack, seq1, sop->so_ack) || SEQ_GEQ(seq1, sop->so_send, sop->so_ack)) { /* * Bad element sequence number */ sscop_maa_error(sop, 'S'); goto goterr; } /* * Loop thru all STAT elements in list */ while (m) { /* * Get next even element (start of received pdus) */ m = sscop_stat_getelem(m, &seq2); /* * Validate seqence number */ if (SEQ_GEQ(seq1, seq2, sop->so_ack) || SEQ_GT(seq2, sop->so_send, sop->so_ack)) { /* * Bad element sequence number */ sscop_maa_error(sop, 'S'); goto goterr; } /* * Process each missing sequence number in this gap */ while (SEQ_LT(seq1, seq2, sop->so_ack)) { /* * Find corresponding SD PDU on pending ack queue */ php = sscop_pack_locate(sop, seq1); if (php == NULL) { sscop_maa_error(sop, 'S'); goto goterr; } /* * Retransmit this SD PDU only if it was last sent * during an earlier poll sequence and it's not * already scheduled for retranmission. */ if (SEQ_LT(php->ph_nps, sp->stat_nps, opa) && (php->ph_rexmit_lk == NULL) && (sop->so_rexmit_tl != php)) { /* * Put PDU on retransmit queue and schedule * transmit servicing */ sscop_rexmit_insert(sop, php); sop->so_flags |= SOF_XMITSRVC; cnt++; } /* * Bump to next sequence number */ SEQ_INCR(seq1, 1); } /* * Now process series of acknowledged PDUs * * Get next odd element (start of missing pdus), * but make sure there is one and that it's valid */ if (m == NULL) goto done; m = sscop_stat_getelem(m, &seq2); if (SEQ_GEQ(seq1, seq2, sop->so_ack) || SEQ_GT(seq2, sop->so_send, sop->so_ack)) { /* * Bad element sequence number */ sscop_maa_error(sop, 'S'); goto goterr; } /* * Process each acked sequence number */ while (SEQ_LT(seq1, seq2, sop->so_ack)) { /* * Can we clear transmit buffers ?? */ if ((sop->so_flags & SOF_NOCLRBUF) == 0) { /* * Yes, free acked buffers */ sscop_pack_free(sop, seq1); } /* * Bump to next sequence number */ SEQ_INCR(seq1, 1); } } done: /* * Free PDU buffer chain */ KB_FREEALL(m0); /* * Report retransmitted PDUs */ if (cnt) sscop_maa_error(sop, 'V'); /* * Record transmit window closed transitions */ if (SEQ_LT(sop->so_send, sop->so_sendmax, sop->so_ack)) { if (sop->so_flags & SOF_NOCREDIT) { sop->so_flags &= ~SOF_NOCREDIT; sscop_maa_error(sop, 'X'); } } else { if ((sop->so_flags & SOF_NOCREDIT) == 0) { sop->so_flags |= SOF_NOCREDIT; sscop_maa_error(sop, 'W'); } } if (sop->so_vers == SSCOP_VERS_QSAAL) /* * Restart lost poll/stat timer */ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; else { /* * Determine new polling phase */ if ((sop->so_timer[SSCOP_T_POLL] != 0) && ((sop->so_flags & SOF_KEEPALIVE) == 0)) { /* * Remain in active phase - reset NO-RESPONSE timer */ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; } else if (sop->so_timer[SSCOP_T_IDLE] == 0) { /* * Go from transient to idle phase */ sop->so_timer[SSCOP_T_POLL] = 0; sop->so_flags &= ~SOF_KEEPALIVE; sop->so_timer[SSCOP_T_NORESP] = 0; sop->so_timer[SSCOP_T_IDLE] = sop->so_parm.sp_timeidle; } } /* * See if transmit queues need servicing */ if (sop->so_flags & SOF_XMITSRVC) sscop_service_xmit(sop); return; goterr: /* * Protocol/parameter error encountered */ /* * Free PDU buffer chain */ KB_FREEALL(m0); if (sop->so_vers == SSCOP_VERS_QSAAL) /* * Reestablish a new connection */ qsaal1_reestablish(sop); else /* * Initiate error recovery */ q2110_error_recovery(sop); return; }