?? q921.c
字號:
/* * libpri: An implementation of Primary Rate ISDN * * Written by Mark Spencer <markster@digium.com> * * Copyright (C) 2001-2005, Digium, Inc. * All Rights Reserved. *//* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include "compat.h"#include "libpri.h"#include "pri_internal.h"#include "pri_q921.h" #include "pri_q931.h"/* * Define RANDOM_DROPS To randomly drop packets in order to simulate loss for testing * retransmission functionality *//*#define RANDOM_DROPS*/#define Q921_INIT(pri, hf) do { \ memset(&(hf),0,sizeof(hf)); \ (hf).h.sapi = (pri)->sapi; \ (hf).h.ea1 = 0; \ (hf).h.ea2 = 1; \ (hf).h.tei = (pri)->tei; \} while(0)static void reschedule_t203(struct pri *pri);static void reschedule_t200(struct pri *pri);static void q921_restart(struct pri *pri, int now);static void q921_tei_release_and_reacquire(struct pri *master);static void q921_discard_retransmissions(struct pri *pri){ struct q921_frame *f, *p; f = pri->txqueue; while(f) { p = f; f = f->next; /* Free frame */ free(p); } pri->txqueue = NULL;}static int q921_transmit(struct pri *pri, q921_h *h, int len) { int res; if (pri->master) pri = pri->master;#ifdef RANDOM_DROPS if (!(random() % 3)) { pri_message(pri, " === Dropping Packet ===\n"); return 0; }#endif #ifdef LIBPRI_COUNTERS pri->q921_txcount++; #endif /* Just send it raw */ if (pri->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW)) q921_dump(pri, h, len, pri->debug & PRI_DEBUG_Q921_RAW, 1); /* Write an extra two bytes for the FCS */ res = pri->write_func ? pri->write_func(pri, h, len + 2) : 0; if (res != (len + 2)) { pri_error(pri, "Short write: %d/%d (%s)\n", res, len + 2, strerror(errno)); return -1; } return 0;}static void q921_send_tei(struct pri *pri, int message, int ri, int ai, int iscommand){ q921_u *f; if (!(f = calloc(1, sizeof(*f) + 5))) return; Q921_INIT(pri, *f); f->h.c_r = (pri->localtype == PRI_NETWORK) ? iscommand : !iscommand; f->ft = Q921_FRAMETYPE_U; f->data[0] = 0x0f; /* Management entity */ f->data[1] = (ri >> 8) & 0xff; f->data[2] = ri & 0xff; f->data[3] = message; f->data[4] = (ai << 1) | 1; if (pri->debug & PRI_DEBUG_Q921_STATE) pri_message(pri, "Sending TEI management message %d, TEI=%d\n", message, ai); q921_transmit(pri, (q921_h *)f, 8); free(f);}static void q921_tei_request(void *vpri){ struct pri *pri = (struct pri *)vpri; if (pri->subchannel) { pri_error(pri, "Cannot request TEI while its already assigned\n"); return; } pri->n202_counter++;#if 0 if (pri->n202_counter > pri->timers[PRI_TIMER_N202]) { pri_error(pri, "Unable to assign TEI from network\n"); return; }#endif pri->ri = random() % 65535; q921_send_tei(pri, Q921_TEI_IDENTITY_REQUEST, pri->ri, Q921_TEI_GROUP, 1); if (pri->t202_timer) pri_schedule_del(pri, pri->t202_timer); pri->t202_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T202], q921_tei_request, pri);}static void q921_send_ua(struct pri *pri, int pfbit){ q921_h h; Q921_INIT(pri, h); h.u.m3 = 3; /* M3 = 3 */ h.u.m2 = 0; /* M2 = 0 */ h.u.p_f = pfbit; /* Final bit on */ h.u.ft = Q921_FRAMETYPE_U; switch(pri->localtype) { case PRI_NETWORK: h.h.c_r = 0; break; case PRI_CPE: h.h.c_r = 1; break; default: pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype); return; } if (pri->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP)) pri_message(pri, "Sending Unnumbered Acknowledgement\n"); q921_transmit(pri, &h, 3);}static void q921_send_sabme_now(void *vpri);static void q921_send_sabme(void *vpri, int now){ struct pri *pri = vpri; q921_h h; pri_schedule_del(pri, pri->sabme_timer); pri->sabme_timer = 0; pri->sabme_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], q921_send_sabme_now, pri); if (!now) return; Q921_INIT(pri, h); h.u.m3 = 3; /* M3 = 3 */ h.u.m2 = 3; /* M2 = 3 */ h.u.p_f = 1; /* Poll bit set */ h.u.ft = Q921_FRAMETYPE_U; switch(pri->localtype) { case PRI_NETWORK: h.h.c_r = 1; break; case PRI_CPE: h.h.c_r = 0; break; default: pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype); return; } if (pri->bri && (pri->state == Q921_AWAITING_ESTABLISH)) { if (pri->sabme_count >= pri->timers[PRI_TIMER_N200]) { pri_schedule_del(pri, pri->sabme_timer); pri->sabme_timer = 0; q921_tei_release_and_reacquire(pri->master); } else { pri->sabme_count++; } } if (pri->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP)) pri_message(pri, "Sending Set Asynchronous Balanced Mode Extended\n"); q921_transmit(pri, &h, 3); if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state != Q921_AWAITING_ESTABLISH) pri_message(pri, DBGHEAD "q921_state now is Q921_AWAITING_ESTABLISH\n", DBGINFO); pri->q921_state = Q921_AWAITING_ESTABLISH;}static void q921_send_sabme_now(void *vpri){ q921_send_sabme(vpri, 1);}static int q921_ack_packet(struct pri *pri, int num){ struct q921_frame *f, *prev = NULL; f = pri->txqueue; while(f) { if (f->h.n_s == num) { /* Cancel each packet as necessary */ /* That's our packet */ if (prev) prev->next = f->next; else pri->txqueue = f->next; if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "-- ACKing packet %d, new txqueue is %d (-1 means empty)\n", f->h.n_s, pri->txqueue ? pri->txqueue->h.n_s : -1); /* Update v_a */ pri->v_a = num; free(f); /* Reset retransmission counter if we actually acked something */ pri->retrans = 0; /* Decrement window size */ pri->windowlen--; return 1; } prev = f; f = f->next; } return 0;}static void t203_expire(void *);static void t200_expire(void *);static pri_event *q921_dchannel_down(struct pri *pri);static void reschedule_t200(struct pri *pri){ if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "-- Restarting T200 timer\n"); if (pri->t200_timer) pri_schedule_del(pri, pri->t200_timer); pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);}static void reschedule_t203(struct pri *pri){ if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "-- Restarting T203 timer\n"); if (pri->t203_timer) pri_schedule_del(pri, pri->t203_timer); pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);}static pri_event *q921_ack_rx(struct pri *pri, int ack, int send_untransmitted_frames){ int x; int cnt=0; pri_event *ev; struct q921_frame *f; /* Make sure the ACK was within our window */ for (x=pri->v_a; (x != pri->v_s) && (x != ack); Q921_INC(x)); if (x != ack) { /* ACK was outside of our window --- ignore */ pri_error(pri, "ACK received for '%d' outside of window of '%d' to '%d', restarting\n", ack, pri->v_a, pri->v_s); ev = q921_dchannel_down(pri); q921_start(pri, 1); pri->schedev = 1; return ev; } /* Cancel each packet as necessary */ if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "-- ACKing all packets from %d to (but not including) %d\n", pri->v_a, ack); for (x=pri->v_a; x != ack; Q921_INC(x)) cnt += q921_ack_packet(pri, x); if (!pri->txqueue) { if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "-- Since there was nothing left, stopping T200 counter\n"); /* Something was ACK'd. Stop T200 counter */ if (pri->t200_timer) { pri_schedule_del(pri, pri->t200_timer); pri->t200_timer = 0; } } if (pri->t203_timer) { if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "-- Stopping T203 counter since we got an ACK\n"); pri_schedule_del(pri, pri->t203_timer); pri->t203_timer = 0; } if (pri->txqueue) { /* Something left to transmit, Start the T200 counter again if we stopped it */ if (!pri->busy && send_untransmitted_frames) { pri->retrans = 0; /* Search for something to send */ f = pri->txqueue; while(f && (pri->windowlen < pri->window)) { if (!f->transmitted) { /* Send it now... */ if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "-- Finally transmitting %d, since window opened up (%d)\n", f->h.n_s, pri->windowlen); f->transmitted++; pri->windowlen++; f->h.n_r = pri->v_r; f->h.p_f = 0; q921_transmit(pri, (q921_h *)(&f->h), f->len); } f = f->next; } } if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "-- Waiting for acknowledge, restarting T200 counter\n"); reschedule_t200(pri); } else { if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "-- Nothing left, starting T203 counter\n"); /* Nothing to transmit, start the T203 counter instead */ pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri); } return NULL;}static void q921_reject(struct pri *pri, int pf){ q921_h h; Q921_INIT(pri, h); h.s.x0 = 0; /* Always 0 */ h.s.ss = 2; /* Reject */ h.s.ft = 1; /* Frametype (01) */ h.s.n_r = pri->v_r; /* Where to start retransmission */ h.s.p_f = pf; switch(pri->localtype) { case PRI_NETWORK: h.h.c_r = 0; break; case PRI_CPE: h.h.c_r = 1; break; default: pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype); return; } if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "Sending Reject (%d)\n", pri->v_r); pri->sentrej = 1; q921_transmit(pri, &h, 4);}static void q921_rr(struct pri *pri, int pbit, int cmd) { q921_h h; Q921_INIT(pri, h); h.s.x0 = 0; /* Always 0 */ h.s.ss = 0; /* Receive Ready */ h.s.ft = 1; /* Frametype (01) */ h.s.n_r = pri->v_r; /* N/R */ h.s.p_f = pbit; /* Poll/Final set appropriately */ switch(pri->localtype) { case PRI_NETWORK: if (cmd) h.h.c_r = 1; else h.h.c_r = 0; break; case PRI_CPE: if (cmd) h.h.c_r = 0; else h.h.c_r = 1; break; default: pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype); return; } pri->v_na = pri->v_r; /* Make a note that we've already acked this */ if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "Sending Receiver Ready (%d)\n", pri->v_r); q921_transmit(pri, &h, 4);}static void t200_expire(void *vpri){ struct pri *pri = vpri; q921_frame *f, *lastframe=NULL; if (pri->txqueue) { /* Retransmit first packet in the queue, setting the poll bit */ if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "-- T200 counter expired, What to do...\n"); pri->solicitfbit = 1; /* Up to three retransmissions */ if (pri->retrans < pri->timers[PRI_TIMER_N200]) { pri->retrans++; /* Reschedule t200_timer */ if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "-- Retransmitting %d bytes\n", pri->txqueue->len); if (pri->busy) q921_rr(pri, 1, 1); else { if (!pri->txqueue->transmitted) pri_error(pri, "!! Not good - head of queue has not been transmitted yet\n"); /*Actually we need to retransmit the last transmitted packet, setting the poll bit */ for (f=pri->txqueue; f; f = f->next) { if (f->transmitted) lastframe = f; } if (lastframe) { /* Force Poll bit */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -