void create_test_times() { time_t tnow; // Create a time_t that is 10:30:30 on July 15th of this year. tnow = time(0); atm *at = atm_create_from_time_t(&tnow); at->loc->tm_hour = 10; at->loc->tm_min = 30; at->loc->tm_sec = 30; at->loc->tm_mon = 6; at->loc->tm_mday = 15; atm *at2 = atm_create_from_loctime(at->loc); tnow = at2->time; at = atm_free(at); at2 = atm_free(at2); tsecless = tnow - 1; tminless = tnow - 60; thourless = tnow - (60 * 60); tdayless = tnow - (60 * 60 * 24); tmonless = tnow - (60 * 60 * 24 * 31); tyearless = tnow - (60 * 60 * 24 * 366); atnow = atm_create_from_time_t(&tnow); atnow2 = atm_create_from_time_t(&tnow); atsecless = atm_create_from_time_t(&tsecless); atminless = atm_create_from_time_t(&tminless); athourless = atm_create_from_time_t(&thourless); atdayless = atm_create_from_time_t(&tdayless); atmonless = atm_create_from_time_t(&tmonless); atyearless = atm_create_from_time_t(&tyearless); }
void test_free() { time_t t = time(0); atm *at = atm_create_from_time_t(&t); aut_assert("test_free_created", at != NULL); at = atm_free(at); aut_assert("test_free_freed", at == NULL); at = atm_free(at); aut_assert("test_free_freed", at == NULL); }
/* * Free the memory that was allocated for an atm_range structure. * * Parameter: The time range to be freed. * Return: NULL pointer. */ atm_range *atm_range_free(atm_range *range) { if(range != NULL) { if(range->begin != NULL) { range->begin = atm_free(range->begin); } if(range->end != NULL) { range->end = atm_free(range->end); } free(range); } return NULL; }
void test_atm_create_now() { atm *at1 = atm_create_now(); aut_assert("test atm_create_now", at1 != NULL); // printf("\nCreated from now...\n"); // print_atm(at1); at1 = atm_free(at1); }
/* * SSCOP_TERM / SOS_* Command Processor * * Arguments: * sop pointer to sscop connection block * arg1 command specific argument * arg2 command specific argument * * Returns: * none * */ void sscop_term_all(struct sscop *sop, int arg1, int arg2) { int err; /* * Set termination state */ sop->so_state = SOS_TERM; /* * Pass the TERM down the stack */ STACK_CALL(CPCS_TERM, sop->so_lower, sop->so_tokl, sop->so_connvc, 0, 0, err); if (err) { /* * Should never happen */ sscop_abort(sop, "sscop: TERM failure\n"); return; } /* * Unlink and free the connection block */ UNLINK(sop, struct sscop, sscop_head, so_next); atm_free((caddr_t)sop); sscop_vccnt--; return; }
/* * 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); }
void test_atm_create_from_time_t() { time_t t1 = time(0); atm *at1 = atm_create_from_time_t(&t1); aut_assert("test_atm_create_from_time_t", at1 != NULL); // printf("\nCreated from time_t...\n"); // print_atm(at1); at1 = atm_free(at1); }
void free_test_times() { atnow = atm_free(atnow); atnow2 = atm_free(atnow2); atsecless = atm_free(atsecless); atminless = atm_free(atminless); athourless = atm_free(athourless); atdayless = atm_free(atdayless); atmonless = atm_free(atmonless); atyearless = atm_free(atyearless); }
void test_atm_create_from_loctime() { time_t t1 = time(0); struct tm *tm1 = localtime(&t1); atm *at1 = atm_create_from_loctime(tm1); aut_assert("test_atm_create_from_loctime", at1 != NULL); // printf("\nCreated from localtime...\n"); // print_atm(at1); at1 = atm_free(at1); }
/* * 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); }
void test_atm_set_original() { atm *at = atm_create_now(); aut_assert("test atm_set_original 1", at != NULL && at->original == at->time); time_t orit = at->original; time_t newt = at->time + 600; atm_set_from_time_t(at, &newt); aut_assert("test atm_set_original 2", at != NULL && at->original == orit && at->time == newt); atm_set_original(at); aut_assert("test atm_set_original 3", at != NULL && at->original == at->time && at->time == orit); // printf("\nCreated from now...\n"); // print_atm(at); at = atm_free(at); }
/* * Process IP Network Interface Deactivation * * Called whenever an IP network interface becomes inactive. * * Called from a critical section. * * Arguments: * clp pointer to CLS interface * * Returns: * none * */ void spansarp_ipdact(struct spanscls *clp) { struct spanscls *clp2; struct spansarp *sap, *snext; int i; /* * Delete all interface entries */ for (i = 0; i < SPANSARP_HASHSIZ; i++) { for (sap = spansarp_arptab[i]; sap; sap = snext) { snext = sap->sa_next; /* * Clean up entries for this interface */ if (sap->sa_cls != clp) continue; /* * All VCCs better be gone by now */ if (sap->sa_ivp) panic("spansarp_ipdact: entry not empty"); /* * Remove entry from the retry chain */ UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext); /* * Delete entry from arp table */ SPANSARP_DELETE(sap); atm_free((caddr_t)sap); } } /* * Stop aging timer if this is the last active interface */ for (clp2 = spanscls_head; clp2; clp2 = clp2->cls_next) { if ((clp != clp2) && (clp2->cls_ipnif)) break; } if (clp2 == NULL) atm_untimeout(&spansarp_timer); }
/* * SPANS ARP supported VCC is closing * * This function is called just prior to a user closing a VCC which * supports SPANS ARP. We'll sever our links to the VCC and then * figure out how much more cleanup we need to do for now. * * Arguments: * ivp pointer to VCC's IPVCC control block * * Returns: * none * */ void spansarp_vcclose(struct ipvcc *ivp) { struct spansarp *sap; crit_enter(); /* * Get spansarp entry */ SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap); if (sap == NULL) { crit_exit(); return; } /* * Remove IP VCC from chain */ UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext); ivp->iv_arpent = NULL; /* * If entry is currently valid or in use, not much else for us to do */ if ((sap->sa_flags & (SAF_VALID | SAF_LOCKED)) || (sap->sa_origin >= SAO_PERM)) { crit_exit(); return; } /* * If there are still other VCCs waiting, exit */ if (sap->sa_ivp) { crit_exit(); return; } /* * Noone else waiting, so remove entry from the retry chain */ UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext); /* * Free entry */ SPANSARP_DELETE(sap); atm_free((caddr_t)sap); crit_exit(); }
void test_atm_to_string() { atm *at = atm_create_now(); aut_assert("test atm_to_string", at != NULL); char *atstr = atm_to_string(at); aut_assert("test atm_to_string not null", atstr != NULL); // print_atm(at); // printf("%s\n", atstr); char teststr[41]; snprintf(teststr, 41, "%lu", at->time); aut_assert("test atm_to_string length", strlen(atstr) == strlen(teststr)); aut_assert("test atm_to_string content", strcmp(atstr, teststr) == 0); at = atm_free(at); }
int main(int arg, char **argv) { char user_input[1000]; if (arg != 2) { printf("Error opening atm initialization file\n"); return 64; } char *token; char argv_cp[1024]; strcpy(argv_cp, argv[1]); strtok(argv_cp, "."); token = strtok(NULL, "."); if (strcmp(token, "atm") != 0) { printf("Error opening atm initialization file\n"); return 64; } ATM *atm = atm_create(); //Check for command line arguements FILE *fp; fp = fopen(argv[1],"r"); if(fp ==NULL) { printf("Error opening atm initialization file\n"); return 64; } strcpy(atm->symm_key, argv[1]); fclose(fp); printf("%s", prompt); fflush(stdout); while (fgets(user_input, 10000,stdin) != NULL) { atm_process_command(atm, user_input); if(atm->session == 1) { printf("ATM (%s): ",atm->username); } else { printf("%s", prompt); } fflush(stdout); } atm_free(atm); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { char user_input[1000]; FILE *atm_file; if(argc != 2) { printf("Usage: atm <filename>\n"); exit(62); } if(strncmp(argv[1]+strlen(argv[1])-4, ".atm", 4) != 0) { printf("Error opening ATM initialization file\n"); exit(64); } atm_file = fopen(argv[1], "r"); if(!atm_file) { printf("Error opening ATM initialization file\n"); exit(64); } ATM *atm = atm_create(); fread(atm->key, sizeof(char), BLOCK_SIZE, atm_file); fread(atm->iv, sizeof(char), BLOCK_SIZE, atm_file); printf("%s", prompt); fflush(stdout); while (fgets(user_input, 10000,stdin) != NULL) { if(strlen(user_input) > 0 && strcmp(user_input, "\n") == 0) continue; atm_process_command(atm, user_input); if(atm->session) { printf("ATM (<%s>): ", atm->cur_user); } else { printf("%s", prompt); } fflush(stdout); } atm_free(atm); return EXIT_SUCCESS; }
/* * 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); } }
/* * 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); }
/* * 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); }
/* * Process a SPANS ARP aging timer tick * * This function is called every SPANSARP_AGING seconds, in order to age * all the arp table entries. * * Called from a critical section. * * Arguments: * tip pointer to spansarp aging timer control block * * Returns: * none * */ static void spansarp_aging(struct atm_time *tip) { struct spansarp *sap, *snext; struct ipvcc *ivp, *inext; int i; /* * Schedule next timeout */ atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging); /* * Run through arp table bumping each entry's aging timer. */ for (i = 0; i < SPANSARP_HASHSIZ; i++) { for (sap = spansarp_arptab[i]; sap; sap = snext) { snext = sap->sa_next; /* * Permanent (manually installed) entries aren't aged */ if (sap->sa_origin == SAO_PERM) continue; /* * See if entry is valid and over-aged */ if ((sap->sa_flags & SAF_VALID) == 0) continue; if (++sap->sa_reftime < SPANSARP_MAXAGE) continue; /* * Entry is now invalid, tell IP/ATM about it */ sap->sa_flags |= SAF_LOCKED; for (ivp = sap->sa_ivp; ivp; ivp = inext) { inext = ivp->iv_arpnext; (*ivp->iv_ipnif->inf_arpnotify) (ivp, MAP_INVALID); } sap->sa_flags &= ~(SAF_LOCKED | SAF_VALID); if (sap->sa_ivp != NULL) { /* * Somebody still cares, so add the arp * entry to the retry list. */ 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); } else { /* * Delete unused entry */ SPANSARP_DELETE(sap); atm_free((caddr_t)sap); } } } }
/* * 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); }
/* * 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 {
/* * Drain the Stack Queue * * Dequeues and processes entries from the global stack queue. * * Arguments: * none * * Returns: * none * */ void atm_stack_drain(void) { struct stackq_entry *sqp, *qprev, *qnext; int cnt; crit_enter(); /* * Loop thru entire queue until queue is empty * (but panic rather loop forever) */ do { cnt = 0; qprev = NULL; for (sqp = atm_stackq_head; sqp; ) { /* * Got an eligible entry, do STACK_CALL stuff */ if (sqp->sq_cmd & STKCMD_UP) { if (sqp->sq_connvc->cvc_downcnt) { /* * Cant process now, skip it */ qprev = sqp; sqp = sqp->sq_next; continue; } /* * OK, dispatch the call */ sqp->sq_connvc->cvc_upcnt++; (*sqp->sq_func)(sqp->sq_cmd, sqp->sq_token, sqp->sq_arg1, sqp->sq_arg2); sqp->sq_connvc->cvc_upcnt--; } else { if (sqp->sq_connvc->cvc_upcnt) { /* * Cant process now, skip it */ qprev = sqp; sqp = sqp->sq_next; continue; } /* * OK, dispatch the call */ sqp->sq_connvc->cvc_downcnt++; (*sqp->sq_func)(sqp->sq_cmd, sqp->sq_token, sqp->sq_arg1, sqp->sq_arg2); sqp->sq_connvc->cvc_downcnt--; } /* * Dequeue processed entry and free it */ cnt++; qnext = sqp->sq_next; if (qprev) qprev->sq_next = qnext; else atm_stackq_head = qnext; if (qnext == NULL) atm_stackq_tail = qprev; atm_free((caddr_t)sqp); sqp = qnext; } } while (cnt > 0); /* * Make sure entire queue was drained */ if (atm_stackq_head != NULL) panic("atm_stack_drain: Queue not emptied"); crit_exit(); }