/* * HS X.25 Protocol Stack. Developed by Hillstone Software (http://www.hillstone-software.com) */ #include #include "list.h" #include "hsdl.h" #include "hsx25core.h" #include "hsx25api.h" /* * Initialise HS X.25 Protocol */ extern int HsX25Init(hs_x25_init_t *init) { int iplen; if (!init) return HS_X25_RC_INV_PAR; memcpy(&x25.api, &init->api, sizeof (hs_x25_api_t)); ListInit(&x25.links); x25.dl_api.usr_event = hs_x25_l2_event_handler; x25.dl_api.options = init->opt; x25.dl_api.trc_fn = init->trc_fn; x25.is_dce = init->is_dce; x25.cfg.hi_incoming_lcn = x25.dl_api.hi_incoming_lcn = init->hi_incoming_lcn; x25.cfg.lo_incoming_lcn = x25.dl_api.lo_incoming_lcn = init->lo_incoming_lcn; x25.cfg.t10_val = HS_X25_T10; x25.cfg.t11_val = HS_X25_T11; x25.cfg.t12_val = HS_X25_T12; x25.cfg.t20_val = HS_X25_T20; x25.cfg.t21_val = HS_X25_T21; x25.cfg.t22_val = HS_X25_T22; x25.cfg.t22_val = HS_X25_T23; x25.cfg.support_dbit = init->support_dbit; switch (init->pktsize) { case 0: x25.cfg.pktsize = HS_X25_DEFAULT_PKT_SIZE; break; case 128: case 256: case 512: case 1024: x25.cfg.pktsize = init->pktsize; break; default: return HS_X25_RC_INV_PKTSIZE; } if (init->wsize > 7) return HS_X25_RC_INV_WSIZE; x25.cfg.wsize = (!init->wsize) ? HS_X25_DEFAULT_WSIZE : init->wsize; if (init->is_rfc1613) { x25.dl_api.options = HS_DL_INIT_OPT_RFC1613; if (init->rfc1613_peer_ip) { iplen = strlen(init->rfc1613_peer_ip); if (iplen < sizeof (x25.dl_api.rfc1613_peer_ip)) memcpy(x25.dl_api.rfc1613_peer_ip, init->rfc1613_peer_ip, iplen); else return HS_X25_RC_INV_PAR; } } if (HsDlInit(&x25.dl_api) != HS_DL_RC_OK) { return HS_X25_RC_DL_INIT_FAIL; } return HS_X25_RC_OK; } /* * Configure X.25 Stack */ extern int HsX25Config(hs_x25_cfg_t *cfg) { memcpy(&x25.cfg, cfg, sizeof (hs_x25_cfg_t)); if (x25.cfg.t21_val == 0) x25.cfg.t21_val = HS_X25_T21; HsX25CoreRestartLayer2(); return HS_X25_RC_OK; } /* * Send RNR (signal receiver not ready) */ extern int HsX25Rnr(long handle, int on) { hs_x25_vc_t *pVc = (hs_x25_vc_t *)handle; if (!handle) return HS_X25_RC_INV_PAR; pVc->vc_fsm(handle, HS_X25_RNR_CONDITON, on, 0); return HS_X25_RC_OK; } /* * Initiate outgoing X.25 call */ extern int HsX25Connect(hs_x25_conn_t *conn, long *handle, int *lci) { hs_x25_link_t *pLink; long vc_han; int pktlen, addlen; hs_x25_vc_t *pVc; int cld_len; if ((!conn) || (!handle) || (!lci)) return HS_X25_RC_INV_PAR; cld_len = strlen(conn->called); if (!cld_len) return HS_X25_RC_INV_PAR; addlen = (cld_len + strlen(conn->calling)); if (addlen % 2) addlen = (addlen / 2) + 1; else addlen = (addlen / 2); pktlen = X25_HDR_SZ + 1 + addlen + 1 + conn->facility_len + conn->cud_len; if (pktlen > HS_X25_MAX_CR_LEN) return HS_X25_RC_TOO_LONG; pLink = hs_x25_find_link(conn->l2_addr); if ((!pLink) || (x25.dl_api.options == HS_X25_OPT_L2_LOOP)) pLink = hs_x25_alloc_link(conn->l2_addr); if (!pLink) return HS_X25_RC_NOLINK; vc_han = pLink->pkt_layer_fsm((long)pLink, HS_X25_CONNECT, (long)conn, 0); if (!vc_han) return HS_X25_RC_NO_VC; pVc = (hs_x25_vc_t *)vc_han; *lci = (int)pVc->lci; *handle = vc_han; return HS_X25_RC_OK; } /* * Submit a listen request for incoming X.25 call */ extern int HsX25Listen(hs_x25_listen_t *listen) { hs_x25_link_t *pLink = hs_x25_find_link(listen->l2_addr); if (!listen) return HS_X25_RC_INV_PAR; if (!pLink) pLink = hs_x25_alloc_link(listen->l2_addr); if (!pLink) return HS_X25_RC_NOLINK; if ((!listen->take_any_call) && ((listen->called_len > HS_MAX_NUA) || (listen->calling_len > HS_MAX_NUA))) return HS_X25_RC_INV_PAR; if ((!listen->take_any_call) && (listen->called_len == 0)) return HS_X25_RC_INV_PAR; hs_x25_asc2bin(listen->called, listen->called_len); hs_x25_asc2bin(listen->calling, listen->calling_len); if (pLink->pkt_layer_fsm((long)pLink, HS_X25_LISTEN, (long)listen, 0) == -1) return HS_X25_RC_DL_LIS_FAIL; return HS_X25_RC_OK; } /* * Flush listen queue */ extern int HsX25FlushListenQueue(long l2_addr) { hs_x25_link_t *pLink = hs_x25_find_link(l2_addr); if (!pLink) return HS_X25_RC_NOLINK; hs_x25_flush_listenq(pLink); return HS_X25_RC_OK; } /* * Clear X.25 Call */ extern int HsX25Clear(long handle) { hs_x25_vc_t *pVc = (hs_x25_vc_t *)handle; pVc->vc_fsm(handle, HS_X25_DISCONNECT, 0, 0); return HS_X25_RC_OK; } /* * Send DATA sequence over established vitrual circuit */ extern int HsX25Data(long handle, unsigned char *buf, int len, int qbit) { hs_x25_vc_t *pVc = (hs_x25_vc_t *)handle; hs_x25_data_t x25data = {0}; long rc; if ((!buf) || (!len) || (!handle)) return HS_X25_RC_INV_PAR; x25data.buf = buf; x25data.len = len; x25data.qbit = qbit; rc = pVc->vc_fsm(handle, HS_X25_DATA, (long)&x25data, 0); return (int)rc; } /* * Send expedited data (Interrupt) */ extern int HsX25DataExp(long handle, unsigned char *buf, int len) { hs_x25_vc_t *pVc = (hs_x25_vc_t *)handle; pVc->vc_fsm(handle, HS_X25_DATA_EXP, (long)buf, len); return HS_X25_RC_OK; } /* * Must be called periodically as often as possible. * This function services transmit queue and provides a "tick" for Data Link */ extern int HsX25Tick(void) { HsDlTick(); HsX25CoreTick(); return HS_X25_RC_OK; } /* * Close all interfaces */ extern void HsX25ShutDown(void) { hs_x25_release_all_links(); HsDlShutDown(); } /* * Get VC statistics */ void HsX25GetStats(long handle, hs_x25_stats_t *stats) { hs_x25_vc_t *pVc = (hs_x25_vc_t *)handle; if (!handle) return; if (!stats) return; HsX25CoreGetStats(pVc, stats); } /* Decode packet, return error code and PTI */ int HsX25DecodePkt(unsigned char *pkt, int len, int *ev, hs_x25_pkt_info_t *info, int need_name) { if (len < 3) return HS_X25_RC_DECODE_SHORT; if (len > (HS_X25_MAX_PKT + 3)) return HS_X25_RC_DECODE_LONG; info->lci = PKT8_LCI(pkt); info->pti = PKT8_PTI(pkt); info->pkt = pkt; info->len = len; info->pktname = 0; // DATA if ((info->pti & 0x01) == 0) { if (info->lci == 0) return HS_X25_RC_DECODE_LCI_UNASSIGN; info->Pr = ((info->pti >> 5) & 0x07); info->Ps = ((info->pti >> 1) & 0x07); *ev = HS_X25_DAT; if (need_name) hs_get_packet_pame(&info->pktname, PTI_DAT); return HS_X25_RC_DECODE_OK; } // RR else if ((info->pti & 0x1f) == 0x01) { if (info->lci == 0) return HS_X25_RC_DECODE_LCI_UNASSIGN; info->Pr = ((info->pti >> 5) & 0x07); *ev = HS_X25_RR; if (need_name) hs_get_packet_pame(&info->pktname, PTI_RR); return HS_X25_RC_DECODE_OK; } // RNR else if ((info->pti & 0x1f) == 0x05) { if (info->lci == 0) return HS_X25_RC_DECODE_LCI_UNASSIGN; info->Pr = ((info->pti >> 5) & 0x07); *ev = HS_X25_RNR; if (need_name) hs_get_packet_pame(&info->pktname, PTI_RNR); return HS_X25_RC_DECODE_OK; } switch (info->pti) { case PTI_RST: case PTI_RSTC: if (info->lci != 0) return HS_X25_RC_DECODE_UNSPEC; break; case PTI_CALL: case PTI_ACC: case PTI_CLRC: case PTI_CLR: case PTI_INT: case PTI_INTC: case PTI_RES: case PTI_RESC: if (info->lci == 0) return HS_X25_RC_DECODE_LCI_UNASSIGN; break; } switch (info->pti) { case PTI_ACC: *ev = HS_X25_CALL_ACCEPTED; break; case PTI_CALL: *ev = HS_X25_CALL_REQ; break; case PTI_RST: *ev = HS_X25_RESTART_REQ; break; case PTI_RSTC: *ev = HS_X25_RESTART_CNF; break; case PTI_CLRC: *ev = HS_X25_CLEAR_CNF; break; case PTI_CLR: *ev = HS_X25_CLEAR_REQ; break; case PTI_INTC: *ev = HS_X25_INT_CNF; break; case PTI_INT: *ev = HS_X25_INT_REQ; break; case PTI_RES: *ev = HS_X25_RESET_REQ; break; case PTI_RESC: *ev = HS_X25_RESET_CNF; break; default: return HS_X25_RC_DECODE_INV_GFI; } if (need_name) hs_get_packet_pame(&info->pktname, info->pti); return HS_X25_RC_DECODE_OK; }