Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/v42.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
| author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> | 
|---|---|
| date | Fri, 25 Jun 2010 15:50:58 +0200 | 
| parents | |
| children | 
   comparison
  equal
  deleted
  inserted
  replaced
| 3:c6c5a16ce2f2 | 4:26cd8f1ef0b1 | 
|---|---|
| 1 /* | |
| 2 * SpanDSP - a series of DSP components for telephony | |
| 3 * | |
| 4 * v42.c | |
| 5 * | |
| 6 * Written by Steve Underwood <steveu@coppice.org> | |
| 7 * | |
| 8 * Copyright (C) 2004 Steve Underwood | |
| 9 * | |
| 10 * All rights reserved. | |
| 11 * | |
| 12 * This program is free software; you can redistribute it and/or modify | |
| 13 * it under the terms of the GNU Lesser General Public License version 2.1, | |
| 14 * as published by the Free Software Foundation. | |
| 15 * | |
| 16 * This program is distributed in the hope that it will be useful, | |
| 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 19 * GNU Lesser General Public License for more details. | |
| 20 * | |
| 21 * You should have received a copy of the GNU Lesser General Public | |
| 22 * License along with this program; if not, write to the Free Software | |
| 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| 24 * | |
| 25 * $Id: v42.c,v 1.51 2009/11/04 15:52:06 steveu Exp $ | |
| 26 */ | |
| 27 | |
| 28 /* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. */ | |
| 29 | |
| 30 /*! \file */ | |
| 31 | |
| 32 #if defined(HAVE_CONFIG_H) | |
| 33 #include "config.h" | |
| 34 #endif | |
| 35 | |
| 36 #include <stdio.h> | |
| 37 #include <stdlib.h> | |
| 38 #include <inttypes.h> | |
| 39 #include <string.h> | |
| 40 #include <errno.h> | |
| 41 | |
| 42 #include "spandsp/telephony.h" | |
| 43 #include "spandsp/logging.h" | |
| 44 #include "spandsp/async.h" | |
| 45 #include "spandsp/hdlc.h" | |
| 46 #include "spandsp/schedule.h" | |
| 47 #include "spandsp/queue.h" | |
| 48 #include "spandsp/v42.h" | |
| 49 | |
| 50 #include "spandsp/private/logging.h" | |
| 51 #include "spandsp/private/schedule.h" | |
| 52 #include "spandsp/private/hdlc.h" | |
| 53 #include "spandsp/private/v42.h" | |
| 54 | |
| 55 #if !defined(FALSE) | |
| 56 #define FALSE 0 | |
| 57 #endif | |
| 58 #if !defined(TRUE) | |
| 59 #define TRUE (!FALSE) | |
| 60 #endif | |
| 61 | |
| 62 #define LAPM_FRAMETYPE_MASK 0x03 | |
| 63 | |
| 64 #define LAPM_FRAMETYPE_I 0x00 | |
| 65 #define LAPM_FRAMETYPE_I_ALT 0x02 | |
| 66 #define LAPM_FRAMETYPE_S 0x01 | |
| 67 #define LAPM_FRAMETYPE_U 0x03 | |
| 68 | |
| 69 /* Timer values */ | |
| 70 | |
| 71 #define T_WAIT_MIN 2000 | |
| 72 #define T_WAIT_MAX 10000 | |
| 73 /* Detection phase timer */ | |
| 74 #define T_400 750000 | |
| 75 /* Acknowledgement timer - 1 second between SABME's */ | |
| 76 #define T_401 1000000 | |
| 77 /* Replay delay timer (optional) */ | |
| 78 #define T_402 1000000 | |
| 79 /* Inactivity timer (optional). No default - use 10 seconds with no packets */ | |
| 80 #define T_403 10000000 | |
| 81 /* Max retries */ | |
| 82 #define N_400 3 | |
| 83 /* Max octets in an information field */ | |
| 84 #define N_401 128 | |
| 85 | |
| 86 #define LAPM_DLCI_DTE_TO_DTE 0 | |
| 87 #define LAPM_DLCI_LAYER2_MANAGEMENT 63 | |
| 88 | |
| 89 static void t401_expired(span_sched_state_t *s, void *user_data); | |
| 90 static void t403_expired(span_sched_state_t *s, void *user_data); | |
| 91 | |
| 92 SPAN_DECLARE(void) lapm_reset(lapm_state_t *s); | |
| 93 SPAN_DECLARE(void) lapm_restart(lapm_state_t *s); | |
| 94 | |
| 95 static void lapm_link_down(lapm_state_t *s); | |
| 96 | |
| 97 static __inline__ void lapm_init_header(uint8_t *frame, int command) | |
| 98 { | |
| 99 /* Data link connection identifier (0) */ | |
| 100 /* Command/response (0 if answerer, 1 if originator) */ | |
| 101 /* Extended address (1) */ | |
| 102 frame[0] = (LAPM_DLCI_DTE_TO_DTE << 2) | ((command) ? 0x02 : 0x00) | 0x01; | |
| 103 } | |
| 104 /*- End of function --------------------------------------------------------*/ | |
| 105 | |
| 106 static int lapm_tx_frame(lapm_state_t *s, uint8_t *frame, int len) | |
| 107 { | |
| 108 if ((s->debug & LAPM_DEBUG_LAPM_DUMP)) | |
| 109 lapm_dump(s, frame, len, s->debug & LAPM_DEBUG_LAPM_RAW, TRUE); | |
| 110 /*endif*/ | |
| 111 hdlc_tx_frame(&s->hdlc_tx, frame, len); | |
| 112 return 0; | |
| 113 } | |
| 114 /*- End of function --------------------------------------------------------*/ | |
| 115 | |
| 116 static void t400_expired(span_sched_state_t *ss, void *user_data) | |
| 117 { | |
| 118 v42_state_t *s; | |
| 119 | |
| 120 /* Give up trying to detect a V.42 capable peer. */ | |
| 121 s = (v42_state_t *) user_data; | |
| 122 s->t400_timer = -1; | |
| 123 s->lapm.state = LAPM_UNSUPPORTED; | |
| 124 if (s->lapm.status_callback) | |
| 125 s->lapm.status_callback(s->lapm.status_callback_user_data, s->lapm.state); | |
| 126 /*endif*/ | |
| 127 } | |
| 128 /*- End of function --------------------------------------------------------*/ | |
| 129 | |
| 130 static void lapm_send_ua(lapm_state_t *s, int pfbit) | |
| 131 { | |
| 132 uint8_t frame[3]; | |
| 133 | |
| 134 lapm_init_header(frame, !s->we_are_originator); | |
| 135 frame[1] = (uint8_t) (0x63 | (pfbit << 4)); | |
| 136 frame[2] = 0; | |
| 137 span_log(&s->logging, SPAN_LOG_FLOW, "Sending unnumbered acknowledgement\n"); | |
| 138 lapm_tx_frame(s, frame, 3); | |
| 139 } | |
| 140 /*- End of function --------------------------------------------------------*/ | |
| 141 | |
| 142 static void lapm_send_sabme(span_sched_state_t *ss, void *user_data) | |
| 143 { | |
| 144 lapm_state_t *s; | |
| 145 uint8_t frame[3]; | |
| 146 | |
| 147 s = (lapm_state_t *) user_data; | |
| 148 if (s->t401_timer >= 0) | |
| 149 { | |
| 150 fprintf(stderr, "Deleting T401 q [%p] %d\n", (void *) s, s->t401_timer); | |
| 151 span_schedule_del(&s->sched, s->t401_timer); | |
| 152 s->t401_timer = -1; | |
| 153 } | |
| 154 /*endif*/ | |
| 155 if (++s->retransmissions > N_400) | |
| 156 { | |
| 157 /* 8.3.2.2 Too many retries */ | |
| 158 s->state = LAPM_RELEASE; | |
| 159 if (s->status_callback) | |
| 160 s->status_callback(s->status_callback_user_data, s->state); | |
| 161 /*endif*/ | |
| 162 return; | |
| 163 } | |
| 164 /*endif*/ | |
| 165 fprintf(stderr, "Setting T401 a1 [%p]\n", (void *) s); | |
| 166 s->t401_timer = span_schedule_event(&s->sched, T_401, lapm_send_sabme, s); | |
| 167 lapm_init_header(frame, s->we_are_originator); | |
| 168 frame[1] = 0x7F; | |
| 169 frame[2] = 0; | |
| 170 span_log(&s->logging, SPAN_LOG_FLOW, "Sending SABME (set asynchronous balanced mode extended)\n"); | |
| 171 lapm_tx_frame(s, frame, 3); | |
| 172 } | |
| 173 /*- End of function --------------------------------------------------------*/ | |
| 174 | |
| 175 static int lapm_ack_packet(lapm_state_t *s, int num) | |
| 176 { | |
| 177 lapm_frame_queue_t *f; | |
| 178 lapm_frame_queue_t *prev; | |
| 179 | |
| 180 for (prev = NULL, f = s->txqueue; f; prev = f, f = f->next) | |
| 181 { | |
| 182 if ((f->frame[1] >> 1) == num) | |
| 183 { | |
| 184 /* Cancel each packet, as necessary */ | |
| 185 if (prev) | |
| 186 prev->next = f->next; | |
| 187 else | |
| 188 s->txqueue = f->next; | |
| 189 /*endif*/ | |
| 190 span_log(&s->logging, | |
| 191 SPAN_LOG_FLOW, | |
| 192 "-- ACKing packet %d. New txqueue is %d (-1 means empty)\n", | |
| 193 (f->frame[1] >> 1), | |
| 194 (s->txqueue) ? (s->txqueue->frame[1] >> 1) : -1); | |
| 195 s->last_frame_peer_acknowledged = num; | |
| 196 free(f); | |
| 197 /* Reset retransmission count if we actually acked something */ | |
| 198 s->retransmissions = 0; | |
| 199 return 1; | |
| 200 } | |
| 201 /*endif*/ | |
| 202 } | |
| 203 /*endfor*/ | |
| 204 return 0; | |
| 205 } | |
| 206 /*- End of function --------------------------------------------------------*/ | |
| 207 | |
| 208 static void lapm_ack_rx(lapm_state_t *s, int ack) | |
| 209 { | |
| 210 int i; | |
| 211 int cnt; | |
| 212 | |
| 213 /* This might not be acking anything new */ | |
| 214 if (s->last_frame_peer_acknowledged == ack) | |
| 215 return; | |
| 216 /*endif*/ | |
| 217 /* It should be acking something that is actually outstanding */ | |
| 218 if ((s->last_frame_peer_acknowledged < s->next_tx_frame && (ack < s->last_frame_peer_acknowledged || ack > s->next_tx_frame)) | |
| 219 || | |
| 220 (s->last_frame_peer_acknowledged > s->next_tx_frame && (ack > s->last_frame_peer_acknowledged || ack < s->next_tx_frame))) | |
| 221 { | |
| 222 /* ACK was outside our window --- ignore */ | |
| 223 span_log(&s->logging, SPAN_LOG_FLOW, "ACK received outside window, ignoring\n"); | |
| 224 return; | |
| 225 } | |
| 226 /*endif*/ | |
| 227 | |
| 228 /* Cancel each packet, as necessary */ | |
| 229 span_log(&s->logging, | |
| 230 SPAN_LOG_FLOW, | |
| 231 "-- ACKing all packets from %d to (but not including) %d\n", | |
| 232 s->last_frame_peer_acknowledged, | |
| 233 ack); | |
| 234 for (cnt = 0, i = s->last_frame_peer_acknowledged; i != ack; i = (i + 1) & 0x7F) | |
| 235 cnt += lapm_ack_packet(s, i); | |
| 236 /*endfor*/ | |
| 237 s->last_frame_peer_acknowledged = ack; | |
| 238 if (s->txqueue == NULL) | |
| 239 { | |
| 240 span_log(&s->logging, SPAN_LOG_FLOW, "-- Since there was nothing left, stopping timer T_401\n"); | |
| 241 /* Something was ACK'd. Stop timer T_401. */ | |
| 242 fprintf(stderr, "T401 a2 is %d [%p]\n", s->t401_timer, (void *) s); | |
| 243 if (s->t401_timer >= 0) | |
| 244 { | |
| 245 fprintf(stderr, "Deleting T401 a3 [%p] %d\n", (void *) s, s->t401_timer); | |
| 246 span_schedule_del(&s->sched, s->t401_timer); | |
| 247 s->t401_timer = -1; | |
| 248 } | |
| 249 /*endif*/ | |
| 250 } | |
| 251 /*endif*/ | |
| 252 if (s->t403_timer >= 0) | |
| 253 { | |
| 254 span_log(&s->logging, SPAN_LOG_FLOW, "-- Stopping timer T_403, since we got an ACK\n"); | |
| 255 if (s->t403_timer >= 0) | |
| 256 { | |
| 257 fprintf(stderr, "Deleting T403 b %d\n", s->t403_timer); | |
| 258 span_schedule_del(&s->sched, s->t403_timer); | |
| 259 s->t403_timer = -1; | |
| 260 } | |
| 261 /*endif*/ | |
| 262 } | |
| 263 /*endif*/ | |
| 264 if (s->txqueue) | |
| 265 { | |
| 266 /* Something left to transmit. Start timer T_401 again if it is stopped */ | |
| 267 span_log(&s->logging, | |
| 268 SPAN_LOG_FLOW, | |
| 269 "-- Something left to transmit (%d). Restarting timer T_401\n", | |
| 270 s->txqueue->frame[1] >> 1); | |
| 271 if (s->t401_timer < 0) | |
| 272 { | |
| 273 fprintf(stderr, "Setting T401 b [%p]\n", (void *) s); | |
| 274 s->t401_timer = span_schedule_event(&s->sched, T_401, t401_expired, s); | |
| 275 } | |
| 276 /*endif*/ | |
| 277 } | |
| 278 else | |
| 279 { | |
| 280 span_log(&s->logging, SPAN_LOG_FLOW, "-- Nothing left, starting timer T_403\n"); | |
| 281 /* Nothing to transmit. Start timer T_403. */ | |
| 282 fprintf(stderr, "Setting T403 c\n"); | |
| 283 s->t403_timer = span_schedule_event(&s->sched, T_403, t403_expired, s); | |
| 284 } | |
| 285 /*endif*/ | |
| 286 } | |
| 287 /*- End of function --------------------------------------------------------*/ | |
| 288 | |
| 289 static void lapm_reject(lapm_state_t *s) | |
| 290 { | |
| 291 uint8_t frame[4]; | |
| 292 | |
| 293 lapm_init_header(frame, !s->we_are_originator); | |
| 294 frame[1] = (uint8_t) (0x00 | 0x08 | LAPM_FRAMETYPE_S); | |
| 295 /* Where to start retransmission */ | |
| 296 frame[2] = (uint8_t) ((s->next_expected_frame << 1) | 0x01); | |
| 297 span_log(&s->logging, SPAN_LOG_FLOW, "Sending REJ (reject (%d)\n", s->next_expected_frame); | |
| 298 lapm_tx_frame(s, frame, 4); | |
| 299 } | |
| 300 /*- End of function --------------------------------------------------------*/ | |
| 301 | |
| 302 static void lapm_rr(lapm_state_t *s, int pfbit) | |
| 303 { | |
| 304 uint8_t frame[4]; | |
| 305 | |
| 306 lapm_init_header(frame, !s->we_are_originator); | |
| 307 frame[1] = (uint8_t) (0x00 | 0x00 | LAPM_FRAMETYPE_S); | |
| 308 frame[2] = (uint8_t) ((s->next_expected_frame << 1) | pfbit); | |
| 309 /* Note that we have already ACKed this */ | |
| 310 s->last_frame_we_acknowledged = s->next_expected_frame; | |
| 311 span_log(&s->logging, SPAN_LOG_FLOW, "Sending RR (receiver ready) (%d)\n", s->next_expected_frame); | |
| 312 lapm_tx_frame(s, frame, 4); | |
| 313 } | |
| 314 /*- End of function --------------------------------------------------------*/ | |
| 315 | |
| 316 static void t401_expired(span_sched_state_t *ss, void *user_data) | |
| 317 { | |
| 318 lapm_state_t *s; | |
| 319 | |
| 320 s = (lapm_state_t *) user_data; | |
| 321 fprintf(stderr, "Expiring T401 a4 [%p]\n", (void *) s); | |
| 322 s->t401_timer = -1; | |
| 323 if (s->txqueue) | |
| 324 { | |
| 325 /* Retransmit first packet in the queue, setting the poll bit */ | |
| 326 span_log(&s->logging, SPAN_LOG_FLOW, "-- Timer T_401 expired, What to do...\n"); | |
| 327 /* Update N(R), and set the poll bit */ | |
| 328 s->txqueue->frame[2] = (uint8_t)((s->next_expected_frame << 1) | 0x01); | |
| 329 s->last_frame_we_acknowledged = s->next_expected_frame; | |
| 330 s->solicit_f_bit = TRUE; | |
| 331 if (++s->retransmissions <= N_400) | |
| 332 { | |
| 333 /* Reschedule timer T401 */ | |
| 334 span_log(&s->logging, SPAN_LOG_FLOW, "-- Retransmitting %d bytes\n", s->txqueue->len); | |
| 335 lapm_tx_frame(s, s->txqueue->frame, s->txqueue->len); | |
| 336 span_log(&s->logging, SPAN_LOG_FLOW, "-- Scheduling retransmission (%d)\n", s->retransmissions); | |
| 337 fprintf(stderr, "Setting T401 d [%p]\n", (void *) s); | |
| 338 s->t401_timer = span_schedule_event(&s->sched, T_401, t401_expired, s); | |
| 339 } | |
| 340 else | |
| 341 { | |
| 342 span_log(&s->logging, SPAN_LOG_FLOW, "-- Timeout occured\n"); | |
| 343 s->state = LAPM_RELEASE; | |
| 344 if (s->status_callback) | |
| 345 s->status_callback(s->status_callback_user_data, s->state); | |
| 346 lapm_link_down(s); | |
| 347 lapm_restart(s); | |
| 348 } | |
| 349 /*endif*/ | |
| 350 } | |
| 351 else | |
| 352 { | |
| 353 span_log(&s->logging, SPAN_LOG_FLOW, "Timer T_401 expired. Nothing to send...\n"); | |
| 354 } | |
| 355 /*endif*/ | |
| 356 } | |
| 357 /*- End of function --------------------------------------------------------*/ | |
| 358 | |
| 359 SPAN_DECLARE(const char *) lapm_status_to_str(int status) | |
| 360 { | |
| 361 switch (status) | |
| 362 { | |
| 363 case LAPM_DETECT: | |
| 364 return "LAPM_DETECT"; | |
| 365 case LAPM_ESTABLISH: | |
| 366 return "LAPM_ESTABLISH"; | |
| 367 case LAPM_DATA: | |
| 368 return "LAPM_DATA"; | |
| 369 case LAPM_RELEASE: | |
| 370 return "LAPM_RELEASE"; | |
| 371 case LAPM_SIGNAL: | |
| 372 return "LAPM_SIGNAL"; | |
| 373 case LAPM_SETPARM: | |
| 374 return "LAPM_SETPARM"; | |
| 375 case LAPM_TEST: | |
| 376 return "LAPM_TEST"; | |
| 377 case LAPM_UNSUPPORTED: | |
| 378 return "LAPM_UNSUPPORTED"; | |
| 379 } | |
| 380 /*endswitch*/ | |
| 381 return "???"; | |
| 382 } | |
| 383 /*- End of function --------------------------------------------------------*/ | |
| 384 | |
| 385 SPAN_DECLARE(int) lapm_tx(lapm_state_t *s, const void *buf, int len) | |
| 386 { | |
| 387 return queue_write(s->tx_queue, buf, len); | |
| 388 } | |
| 389 /*- End of function --------------------------------------------------------*/ | |
| 390 | |
| 391 SPAN_DECLARE(int) lapm_release(lapm_state_t *s) | |
| 392 { | |
| 393 s->state = LAPM_RELEASE; | |
| 394 return 0; | |
| 395 } | |
| 396 /*- End of function --------------------------------------------------------*/ | |
| 397 | |
| 398 SPAN_DECLARE(int) lapm_loopback(lapm_state_t *s, int enable) | |
| 399 { | |
| 400 s->state = LAPM_TEST; | |
| 401 return 0; | |
| 402 } | |
| 403 /*- End of function --------------------------------------------------------*/ | |
| 404 | |
| 405 SPAN_DECLARE(int) lapm_break(lapm_state_t *s, int enable) | |
| 406 { | |
| 407 s->state = LAPM_SIGNAL; | |
| 408 return 0; | |
| 409 } | |
| 410 /*- End of function --------------------------------------------------------*/ | |
| 411 | |
| 412 SPAN_DECLARE(int) lapm_tx_iframe(lapm_state_t *s, const void *buf, int len, int cr) | |
| 413 { | |
| 414 lapm_frame_queue_t *f; | |
| 415 | |
| 416 if ((f = malloc(sizeof(*f) + len + 4)) == NULL) | |
| 417 { | |
| 418 span_log(&s->logging, SPAN_LOG_FLOW, "Out of memory\n"); | |
| 419 return -1; | |
| 420 } | |
| 421 /*endif*/ | |
| 422 | |
| 423 lapm_init_header(f->frame, (s->peer_is_originator) ? cr : !cr); | |
| 424 f->next = NULL; | |
| 425 f->len = len + 4; | |
| 426 f->frame[1] = (uint8_t) (s->next_tx_frame << 1); | |
| 427 f->frame[2] = (uint8_t) (s->next_expected_frame << 1); | |
| 428 memcpy(f->frame + 3, buf, len); | |
| 429 s->next_tx_frame = (s->next_tx_frame + 1) & 0x7F; | |
| 430 s->last_frame_we_acknowledged = s->next_expected_frame; | |
| 431 /* Clear poll bit */ | |
| 432 f->frame[2] &= ~0x01; | |
| 433 if (s->tx_last) | |
| 434 s->tx_last->next = f; | |
| 435 else | |
| 436 s->txqueue = f; | |
| 437 /*endif*/ | |
| 438 s->tx_last = f; | |
| 439 /* Immediately transmit unless we're in a recovery state */ | |
| 440 if (s->retransmissions == 0) | |
| 441 lapm_tx_frame(s, f->frame, f->len); | |
| 442 /*endif*/ | |
| 443 if (s->t403_timer >= 0) | |
| 444 { | |
| 445 span_log(&s->logging, SPAN_LOG_FLOW, "Stopping T_403 timer\n"); | |
| 446 fprintf(stderr, "Deleting T403 c %d\n", s->t403_timer); | |
| 447 span_schedule_del(&s->sched, s->t403_timer); | |
| 448 s->t403_timer = -1; | |
| 449 } | |
| 450 /*endif*/ | |
| 451 if (s->t401_timer < 0) | |
| 452 { | |
| 453 span_log(&s->logging, SPAN_LOG_FLOW, "Starting timer T_401\n"); | |
| 454 s->t401_timer = span_schedule_event(&s->sched, T_401, t401_expired, s); | |
| 455 fprintf(stderr, "Setting T401 e %d [%p]\n", s->t401_timer, (void *) s); | |
| 456 } | |
| 457 else | |
| 458 { | |
| 459 span_log(&s->logging, SPAN_LOG_FLOW, "Timer T_401 already running (%d)\n", s->t401_timer); | |
| 460 } | |
| 461 /*endif*/ | |
| 462 return 0; | |
| 463 } | |
| 464 /*- End of function --------------------------------------------------------*/ | |
| 465 | |
| 466 static void t403_expired(span_sched_state_t *ss, void *user_data) | |
| 467 { | |
| 468 lapm_state_t *s; | |
| 469 | |
| 470 s = (lapm_state_t *) user_data; | |
| 471 span_log(&s->logging, SPAN_LOG_FLOW, "Timer T_403 expired. Sending RR and scheduling T_403 again\n"); | |
| 472 s->t403_timer = -1; | |
| 473 s->retransmissions = 0; | |
| 474 /* Solicit an F-bit in the other end's RR */ | |
| 475 s->solicit_f_bit = TRUE; | |
| 476 lapm_rr(s, 1); | |
| 477 /* Restart ourselves */ | |
| 478 fprintf(stderr, "Setting T403 f\n"); | |
| 479 s->t401_timer = span_schedule_event(&s->sched, T_401, t401_expired, s); | |
| 480 } | |
| 481 /*- End of function --------------------------------------------------------*/ | |
| 482 | |
| 483 SPAN_DECLARE(void) lapm_dump(lapm_state_t *s, const uint8_t *frame, int len, int showraw, int txrx) | |
| 484 { | |
| 485 const char *type; | |
| 486 char direction_tag[2]; | |
| 487 | |
| 488 direction_tag[0] = txrx ? '>' : '<'; | |
| 489 direction_tag[1] = '\0'; | |
| 490 if (showraw) | |
| 491 span_log_buf(&s->logging, SPAN_LOG_FLOW, direction_tag, frame, len); | |
| 492 /*endif*/ | |
| 493 | |
| 494 switch ((frame[1] & LAPM_FRAMETYPE_MASK)) | |
| 495 { | |
| 496 case LAPM_FRAMETYPE_I: | |
| 497 case LAPM_FRAMETYPE_I_ALT: | |
| 498 span_log(&s->logging, SPAN_LOG_FLOW, "%c Information frame:\n", direction_tag[0]); | |
| 499 break; | |
| 500 case LAPM_FRAMETYPE_S: | |
| 501 span_log(&s->logging, SPAN_LOG_FLOW, "%c Supervisory frame:\n", direction_tag[0]); | |
| 502 break; | |
| 503 case LAPM_FRAMETYPE_U: | |
| 504 span_log(&s->logging, SPAN_LOG_FLOW, "%c Unnumbered frame:\n", direction_tag[0]); | |
| 505 break; | |
| 506 } | |
| 507 /*endswitch*/ | |
| 508 | |
| 509 span_log(&s->logging, | |
| 510 SPAN_LOG_FLOW, | |
| 511 "%c DLCI: %2d C/R: %d EA: %d\n", | |
| 512 direction_tag[0], | |
| 513 (frame[0] >> 2), | |
| 514 (frame[0] & 0x02) ? 1 : 0, | |
| 515 (frame[0] & 0x01), | |
| 516 direction_tag[0]); | |
| 517 switch ((frame[1] & LAPM_FRAMETYPE_MASK)) | |
| 518 { | |
| 519 case LAPM_FRAMETYPE_I: | |
| 520 case LAPM_FRAMETYPE_I_ALT: | |
| 521 /* Information frame */ | |
| 522 span_log(&s->logging, | |
| 523 SPAN_LOG_FLOW, | |
| 524 "%c N(S): %03d\n", | |
| 525 direction_tag[0], | |
| 526 (frame[1] >> 1)); | |
| 527 span_log(&s->logging, | |
| 528 SPAN_LOG_FLOW, | |
| 529 "%c N(R): %03d P: %d\n", | |
| 530 direction_tag[0], | |
| 531 (frame[2] >> 1), | |
| 532 (frame[2] & 0x01)); | |
| 533 span_log(&s->logging, | |
| 534 SPAN_LOG_FLOW, | |
| 535 "%c %d bytes of data\n", | |
| 536 direction_tag[0], | |
| 537 len - 4); | |
| 538 break; | |
| 539 case LAPM_FRAMETYPE_S: | |
| 540 /* Supervisory frame */ | |
| 541 switch (frame[1] & 0x0C) | |
| 542 { | |
| 543 case 0x00: | |
| 544 type = "RR (receive ready)"; | |
| 545 break; | |
| 546 case 0x04: | |
| 547 type = "RNR (receive not ready)"; | |
| 548 break; | |
| 549 case 0x08: | |
| 550 type = "REJ (reject)"; | |
| 551 break; | |
| 552 case 0x0C: | |
| 553 type = "SREJ (selective reject)"; | |
| 554 break; | |
| 555 default: | |
| 556 type = "???"; | |
| 557 break; | |
| 558 } | |
| 559 /*endswitch*/ | |
| 560 span_log(&s->logging, | |
| 561 SPAN_LOG_FLOW, | |
| 562 "%c S: %03d [ %s ]\n", | |
| 563 direction_tag[0], | |
| 564 frame[1], | |
| 565 type); | |
| 566 span_log(&s->logging, | |
| 567 SPAN_LOG_FLOW, | |
| 568 "%c N(R): %03d P/F: %d\n", | |
| 569 direction_tag[0], | |
| 570 frame[2] >> 1, | |
| 571 frame[2] & 0x01); | |
| 572 span_log(&s->logging, | |
| 573 SPAN_LOG_FLOW, | |
| 574 "%c %d bytes of data\n", | |
| 575 direction_tag[0], | |
| 576 len - 4); | |
| 577 break; | |
| 578 case LAPM_FRAMETYPE_U: | |
| 579 /* Unnumbered frame */ | |
| 580 switch (frame[1] & 0xEC) | |
| 581 { | |
| 582 case 0x00: | |
| 583 type = "UI (unnumbered information)"; | |
| 584 break; | |
| 585 case 0x0C: | |
| 586 type = "DM (disconnect mode)"; | |
| 587 break; | |
| 588 case 0x40: | |
| 589 type = "DISC (disconnect)"; | |
| 590 break; | |
| 591 case 0x60: | |
| 592 type = "UA (unnumbered acknowledgement)"; | |
| 593 break; | |
| 594 case 0x6C: | |
| 595 type = "SABME (set asynchronous balanced mode extended)"; | |
| 596 break; | |
| 597 case 0x84: | |
| 598 type = "FRMR (frame reject)"; | |
| 599 break; | |
| 600 case 0xAC: | |
| 601 type = "XID (exchange identification)"; | |
| 602 break; | |
| 603 case 0xE0: | |
| 604 type = "TEST (test)"; | |
| 605 break; | |
| 606 default: | |
| 607 type = "???"; | |
| 608 break; | |
| 609 } | |
| 610 /*endswitch*/ | |
| 611 span_log(&s->logging, | |
| 612 SPAN_LOG_FLOW, | |
| 613 "%c M: %03d [ %s ] P/F: %d\n", | |
| 614 direction_tag[0], | |
| 615 frame[1], | |
| 616 type, | |
| 617 (frame[1] >> 4) & 1); | |
| 618 span_log(&s->logging, | |
| 619 SPAN_LOG_FLOW, | |
| 620 "%c %d bytes of data\n", | |
| 621 direction_tag[0], | |
| 622 len - 3); | |
| 623 break; | |
| 624 } | |
| 625 /*endswitch*/ | |
| 626 } | |
| 627 /*- End of function --------------------------------------------------------*/ | |
| 628 | |
| 629 static void lapm_link_up(lapm_state_t *s) | |
| 630 { | |
| 631 uint8_t buf[1024]; | |
| 632 int len; | |
| 633 | |
| 634 lapm_reset(s); | |
| 635 /* Go into connection established state */ | |
| 636 s->state = LAPM_DATA; | |
| 637 if (s->status_callback) | |
| 638 s->status_callback(s->status_callback_user_data, s->state); | |
| 639 /*endif*/ | |
| 640 if (!queue_empty(s->tx_queue)) | |
| 641 { | |
| 642 if ((len = queue_read(s->tx_queue, buf, s->n401)) > 0) | |
| 643 lapm_tx_iframe(s, buf, len, TRUE); | |
| 644 /*endif*/ | |
| 645 } | |
| 646 /*endif*/ | |
| 647 if (s->t401_timer >= 0) | |
| 648 { | |
| 649 fprintf(stderr, "Deleting T401 x [%p] %d\n", (void *) s, s->t401_timer); | |
| 650 span_schedule_del(&s->sched, s->t401_timer); | |
| 651 s->t401_timer = -1; | |
| 652 } | |
| 653 /*endif*/ | |
| 654 /* Start the T403 timer */ | |
| 655 fprintf(stderr, "Setting T403 g\n"); | |
| 656 s->t403_timer = span_schedule_event(&s->sched, T_403, t403_expired, s); | |
| 657 } | |
| 658 /*- End of function --------------------------------------------------------*/ | |
| 659 | |
| 660 static void lapm_link_down(lapm_state_t *s) | |
| 661 { | |
| 662 lapm_reset(s); | |
| 663 | |
| 664 if (s->status_callback) | |
| 665 s->status_callback(s->status_callback_user_data, s->state); | |
| 666 /*endif*/ | |
| 667 } | |
| 668 /*- End of function --------------------------------------------------------*/ | |
| 669 | |
| 670 SPAN_DECLARE(void) lapm_reset(lapm_state_t *s) | |
| 671 { | |
| 672 lapm_frame_queue_t *f; | |
| 673 lapm_frame_queue_t *p; | |
| 674 | |
| 675 /* Having received a SABME, we need to reset our entire state */ | |
| 676 s->next_tx_frame = 0; | |
| 677 s->last_frame_peer_acknowledged = 0; | |
| 678 s->next_expected_frame = 0; | |
| 679 s->last_frame_we_acknowledged = 0; | |
| 680 s->window_size_k = 15; | |
| 681 s->n401 = 128; | |
| 682 if (s->t401_timer >= 0) | |
| 683 { | |
| 684 fprintf(stderr, "Deleting T401 d [%p] %d\n", (void *) s, s->t401_timer); | |
| 685 span_schedule_del(&s->sched, s->t401_timer); | |
| 686 s->t401_timer = -1; | |
| 687 } | |
| 688 /*endif*/ | |
| 689 if (s->t403_timer >= 0) | |
| 690 { | |
| 691 fprintf(stderr, "Deleting T403 e %d\n", s->t403_timer); | |
| 692 span_schedule_del(&s->sched, s->t403_timer); | |
| 693 s->t403_timer = -1; | |
| 694 } | |
| 695 /*endif*/ | |
| 696 s->busy = FALSE; | |
| 697 s->solicit_f_bit = FALSE; | |
| 698 s->state = LAPM_RELEASE; | |
| 699 s->retransmissions = 0; | |
| 700 /* Discard anything waiting to go out */ | |
| 701 for (f = s->txqueue; f; ) | |
| 702 { | |
| 703 p = f; | |
| 704 f = f->next; | |
| 705 free(p); | |
| 706 } | |
| 707 /*endfor*/ | |
| 708 s->txqueue = NULL; | |
| 709 } | |
| 710 /*- End of function --------------------------------------------------------*/ | |
| 711 | |
| 712 SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok) | |
| 713 { | |
| 714 lapm_state_t *s; | |
| 715 lapm_frame_queue_t *f; | |
| 716 int sendnow; | |
| 717 int octet; | |
| 718 int s_field; | |
| 719 int m_field; | |
| 720 | |
| 721 fprintf(stderr, "LAPM receive %d %d\n", ok, len); | |
| 722 if (!ok || len == 0) | |
| 723 return; | |
| 724 /*endif*/ | |
| 725 s = (lapm_state_t *) user_data; | |
| 726 if (len < 0) | |
| 727 { | |
| 728 /* Special conditions */ | |
| 729 span_log(&s->logging, SPAN_LOG_DEBUG, "V.42 rx status is %s (%d)\n", signal_status_to_str(len), len); | |
| 730 return; | |
| 731 } | |
| 732 /*endif*/ | |
| 733 | |
| 734 if ((s->debug & LAPM_DEBUG_LAPM_DUMP)) | |
| 735 lapm_dump(s, frame, len, s->debug & LAPM_DEBUG_LAPM_RAW, FALSE); | |
| 736 /*endif*/ | |
| 737 octet = 0; | |
| 738 /* We do not expect extended addresses */ | |
| 739 if ((frame[octet] & 0x01) == 0) | |
| 740 return; | |
| 741 /*endif*/ | |
| 742 /* Check for DLCIs we do not recognise */ | |
| 743 if ((frame[octet] >> 2) != LAPM_DLCI_DTE_TO_DTE) | |
| 744 return; | |
| 745 /*endif*/ | |
| 746 octet++; | |
| 747 switch (frame[octet] & LAPM_FRAMETYPE_MASK) | |
| 748 { | |
| 749 case LAPM_FRAMETYPE_I: | |
| 750 case LAPM_FRAMETYPE_I_ALT: | |
| 751 if (s->state != LAPM_DATA) | |
| 752 { | |
| 753 span_log(&s->logging, SPAN_LOG_FLOW, "!! Got an I-frame while link state is %d\n", s->state); | |
| 754 break; | |
| 755 } | |
| 756 /*endif*/ | |
| 757 /* Information frame */ | |
| 758 if (len < 4) | |
| 759 { | |
| 760 span_log(&s->logging, SPAN_LOG_FLOW, "!! Received short I-frame (expected 4, got %d)\n", len); | |
| 761 break; | |
| 762 } | |
| 763 /*endif*/ | |
| 764 /* Make sure this is a valid packet */ | |
| 765 if ((frame[1] >> 1) == s->next_expected_frame) | |
| 766 { | |
| 767 /* Increment next expected I-frame */ | |
| 768 s->next_expected_frame = (s->next_expected_frame + 1) & 0x7F; | |
| 769 /* Handle their ACK */ | |
| 770 lapm_ack_rx(s, frame[2] >> 1); | |
| 771 if ((frame[2] & 0x01)) | |
| 772 { | |
| 773 /* If the Poll/Final bit is set, send the RR immediately */ | |
| 774 lapm_rr(s, 1); | |
| 775 } | |
| 776 /*endif*/ | |
| 777 s->iframe_receive(s->iframe_receive_user_data, frame + 3, len - 4); | |
| 778 /* Send an RR if one wasn't sent already */ | |
| 779 if (s->last_frame_we_acknowledged != s->next_expected_frame) | |
| 780 lapm_rr(s, 0); | |
| 781 /*endif*/ | |
| 782 } | |
| 783 else | |
| 784 { | |
| 785 if (((s->next_expected_frame - (frame[1] >> 1)) & 127) < s->window_size_k) | |
| 786 { | |
| 787 /* It's within our window -- send back an RR */ | |
| 788 lapm_rr(s, 0); | |
| 789 } | |
| 790 else | |
| 791 { | |
| 792 lapm_reject(s); | |
| 793 } | |
| 794 /*endif*/ | |
| 795 } | |
| 796 /*endif*/ | |
| 797 break; | |
| 798 case LAPM_FRAMETYPE_S: | |
| 799 if (s->state != LAPM_DATA) | |
| 800 { | |
| 801 span_log(&s->logging, SPAN_LOG_FLOW, "!! Got S-frame while link down\n"); | |
| 802 break; | |
| 803 } | |
| 804 /*endif*/ | |
| 805 if (len < 4) | |
| 806 { | |
| 807 span_log(&s->logging, SPAN_LOG_FLOW, "!! Received short S-frame (expected 4, got %d)\n", len); | |
| 808 break; | |
| 809 } | |
| 810 /*endif*/ | |
| 811 s_field = frame[octet] & 0xEC; | |
| 812 switch (s_field) | |
| 813 { | |
| 814 case 0x00: | |
| 815 /* RR (receive ready) */ | |
| 816 s->busy = FALSE; | |
| 817 /* Acknowledge frames as necessary */ | |
| 818 lapm_ack_rx(s, frame[2] >> 1); | |
| 819 if ((frame[2] & 0x01)) | |
| 820 { | |
| 821 /* If P/F is one, respond with an RR with the P/F bit set */ | |
| 822 if (s->solicit_f_bit) | |
| 823 { | |
| 824 span_log(&s->logging, SPAN_LOG_FLOW, "-- Got RR response to our frame\n"); | |
| 825 } | |
| 826 else | |
| 827 { | |
| 828 span_log(&s->logging, SPAN_LOG_FLOW, "-- Unsolicited RR with P/F bit, responding\n"); | |
| 829 lapm_rr(s, 1); | |
| 830 } | |
| 831 /*endif*/ | |
| 832 s->solicit_f_bit = FALSE; | |
| 833 } | |
| 834 /*endif*/ | |
| 835 break; | |
| 836 case 0x04: | |
| 837 /* RNR (receive not ready) */ | |
| 838 span_log(&s->logging, SPAN_LOG_FLOW, "-- Got receiver not ready\n"); | |
| 839 s->busy = TRUE; | |
| 840 break; | |
| 841 case 0x08: | |
| 842 /* REJ (reject) */ | |
| 843 /* Just retransmit */ | |
| 844 span_log(&s->logging, SPAN_LOG_FLOW, "-- Got reject requesting packet %d... Retransmitting.\n", frame[2] >> 1); | |
| 845 if ((frame[2] & 0x01)) | |
| 846 { | |
| 847 /* If it has the poll bit set, send an appropriate supervisory response */ | |
| 848 lapm_rr(s, 1); | |
| 849 } | |
| 850 /*endif*/ | |
| 851 sendnow = FALSE; | |
| 852 /* Resend the appropriate I-frame */ | |
| 853 for (f = s->txqueue; f; f = f->next) | |
| 854 { | |
| 855 if (sendnow || (f->frame[1] >> 1) == (frame[2] >> 1)) | |
| 856 { | |
| 857 /* Matches the request, or follows in our window */ | |
| 858 sendnow = TRUE; | |
| 859 span_log(&s->logging, | |
| 860 SPAN_LOG_FLOW, | |
| 861 "!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", | |
| 862 frame[2] >> 1, | |
| 863 f->frame[1] >> 1); | |
| 864 f->frame[2] = (uint8_t) (s->next_expected_frame << 1); | |
| 865 lapm_tx_frame(s, f->frame, f->len); | |
| 866 } | |
| 867 /*endif*/ | |
| 868 } | |
| 869 /*endfor*/ | |
| 870 if (!sendnow) | |
| 871 { | |
| 872 if (s->txqueue) | |
| 873 { | |
| 874 /* This should never happen */ | |
| 875 if ((frame[2] & 0x01) == 0 || (frame[2] >> 1)) | |
| 876 { | |
| 877 span_log(&s->logging, | |
| 878 SPAN_LOG_FLOW, | |
| 879 "!! Got reject for frame %d, but we only have others!\n", | |
| 880 frame[2] >> 1); | |
| 881 } | |
| 882 /*endif*/ | |
| 883 } | |
| 884 else | |
| 885 { | |
| 886 /* Hrm, we have nothing to send, but have been REJ'd. Reset last_frame_peer_acknowledged, next_tx_frame, etc */ | |
| 887 span_log(&s->logging, SPAN_LOG_FLOW, "!! Got reject for frame %d, but we have nothing -- resetting!\n", frame[2] >> 1); | |
| 888 s->last_frame_peer_acknowledged = | |
| 889 s->next_tx_frame = frame[2] >> 1; | |
| 890 /* Reset t401 timer if it was somehow going */ | |
| 891 if (s->t401_timer >= 0) | |
| 892 { | |
| 893 fprintf(stderr, "Deleting T401 f [%p] %d\n", (void *) s, s->t401_timer); | |
| 894 span_schedule_del(&s->sched, s->t401_timer); | |
| 895 s->t401_timer = -1; | |
| 896 } | |
| 897 /*endif*/ | |
| 898 /* Reset and restart t403 timer */ | |
| 899 if (s->t403_timer >= 0) | |
| 900 { | |
| 901 fprintf(stderr, "Deleting T403 g %d\n", s->t403_timer); | |
| 902 span_schedule_del(&s->sched, s->t403_timer); | |
| 903 s->t403_timer = -1; | |
| 904 } | |
| 905 /*endif*/ | |
| 906 fprintf(stderr, "Setting T403 h\n"); | |
| 907 s->t403_timer = span_schedule_event(&s->sched, T_403, t403_expired, s); | |
| 908 } | |
| 909 /*endif*/ | |
| 910 } | |
| 911 /*endif*/ | |
| 912 break; | |
| 913 case 0x0C: | |
| 914 /* SREJ (selective reject) */ | |
| 915 break; | |
| 916 default: | |
| 917 span_log(&s->logging, | |
| 918 SPAN_LOG_FLOW, | |
| 919 "!! XXX Unknown Supervisory frame sd=0x%02x,pf=%02xnr=%02x vs=%02x, va=%02x XXX\n", | |
| 920 s_field, | |
| 921 frame[2] & 0x01, | |
| 922 frame[2] >> 1, | |
| 923 s->next_tx_frame, | |
| 924 s->last_frame_peer_acknowledged); | |
| 925 break; | |
| 926 } | |
| 927 /*endswitch*/ | |
| 928 break; | |
| 929 case LAPM_FRAMETYPE_U: | |
| 930 if (len < 3) | |
| 931 { | |
| 932 span_log(&s->logging, SPAN_LOG_FLOW, "!! Received too short unnumbered frame\n"); | |
| 933 break; | |
| 934 } | |
| 935 /*endif*/ | |
| 936 m_field = frame[octet] & 0xEC; | |
| 937 switch (m_field) | |
| 938 { | |
| 939 case 0x00: | |
| 940 /* UI (unnumbered information) */ | |
| 941 switch (frame[++octet] & 0x7F) | |
| 942 { | |
| 943 case 0x40: | |
| 944 /* BRK */ | |
| 945 span_log(&s->logging, SPAN_LOG_FLOW, "BRK - option %d, length %d\n", (frame[octet] >> 5), frame[octet + 1]); | |
| 946 octet += 2; | |
| 947 break; | |
| 948 case 0x60: | |
| 949 /* BRKACK */ | |
| 950 span_log(&s->logging, SPAN_LOG_FLOW, "BRKACK\n"); | |
| 951 break; | |
| 952 default: | |
| 953 /* Unknown */ | |
| 954 span_log(&s->logging, SPAN_LOG_FLOW, "Unknown UI type\n"); | |
| 955 break; | |
| 956 } | |
| 957 /*endswitch*/ | |
| 958 break; | |
| 959 case 0x0C: | |
| 960 /* DM (disconnect mode) */ | |
| 961 if ((frame[octet] & 0x10)) | |
| 962 { | |
| 963 span_log(&s->logging, SPAN_LOG_FLOW, "-- Got Unconnected Mode from peer.\n"); | |
| 964 /* Disconnected mode, try again */ | |
| 965 lapm_link_down(s); | |
| 966 lapm_restart(s); | |
| 967 } | |
| 968 else | |
| 969 { | |
| 970 span_log(&s->logging, SPAN_LOG_FLOW, "-- DM (disconnect mode) requesting SABME, starting.\n"); | |
| 971 /* Requesting that we start */ | |
| 972 lapm_restart(s); | |
| 973 } | |
| 974 /*endif*/ | |
| 975 break; | |
| 976 case 0x40: | |
| 977 /* DISC (disconnect) */ | |
| 978 span_log(&s->logging, SPAN_LOG_FLOW, "-- Got DISC (disconnect) from peer.\n"); | |
| 979 /* Acknowledge */ | |
| 980 lapm_send_ua(s, (frame[octet] & 0x10)); | |
| 981 lapm_link_down(s); | |
| 982 break; | |
| 983 case 0x60: | |
| 984 /* UA (unnumbered acknowledgement) */ | |
| 985 if (s->state == LAPM_ESTABLISH) | |
| 986 { | |
| 987 span_log(&s->logging, SPAN_LOG_FLOW, "-- Got UA (unnumbered acknowledgement) from %s peer. Link up.\n", (frame[0] & 0x02) ? "xxx" : "yyy"); | |
| 988 lapm_link_up(s); | |
| 989 } | |
| 990 else | |
| 991 { | |
| 992 span_log(&s->logging, SPAN_LOG_FLOW, "!! Got a UA (unnumbered acknowledgement) in state %d\n", s->state); | |
| 993 } | |
| 994 /*endif*/ | |
| 995 break; | |
| 996 case 0x6C: | |
| 997 /* SABME (set asynchronous balanced mode extended) */ | |
| 998 span_log(&s->logging, SPAN_LOG_FLOW, "-- Got SABME (set asynchronous balanced mode extended) from %s peer.\n", (frame[0] & 0x02) ? "yyy" : "xxx"); | |
| 999 if ((frame[0] & 0x02)) | |
| 1000 { | |
| 1001 s->peer_is_originator = TRUE; | |
| 1002 if (s->we_are_originator) | |
| 1003 { | |
| 1004 /* We can't both be originators */ | |
| 1005 span_log(&s->logging, SPAN_LOG_FLOW, "We think we are the originator, but they think so too."); | |
| 1006 break; | |
| 1007 } | |
| 1008 /*endif*/ | |
| 1009 } | |
| 1010 else | |
| 1011 { | |
| 1012 s->peer_is_originator = FALSE; | |
| 1013 if (!s->we_are_originator) | |
| 1014 { | |
| 1015 /* We can't both be answerers */ | |
| 1016 span_log(&s->logging, SPAN_LOG_FLOW, "We think we are the answerer, but they think so too.\n"); | |
| 1017 break; | |
| 1018 } | |
| 1019 /*endif*/ | |
| 1020 } | |
| 1021 /*endif*/ | |
| 1022 /* Send unnumbered acknowledgement */ | |
| 1023 lapm_send_ua(s, (frame[octet] & 0x10)); | |
| 1024 lapm_link_up(s); | |
| 1025 break; | |
| 1026 case 0x84: | |
| 1027 /* FRMR (frame reject) */ | |
| 1028 span_log(&s->logging, SPAN_LOG_FLOW, "!! FRMR (frame reject).\n"); | |
| 1029 break; | |
| 1030 case 0xAC: | |
| 1031 /* XID (exchange identification) */ | |
| 1032 span_log(&s->logging, SPAN_LOG_FLOW, "!! XID (exchange identification) frames not supported\n"); | |
| 1033 break; | |
| 1034 case 0xE0: | |
| 1035 /* TEST (test) */ | |
| 1036 span_log(&s->logging, SPAN_LOG_FLOW, "!! TEST (test) frames not supported\n"); | |
| 1037 break; | |
| 1038 default: | |
| 1039 span_log(&s->logging, SPAN_LOG_FLOW, "!! Don't know what to do with M=%X u-frames\n", m_field); | |
| 1040 break; | |
| 1041 } | |
| 1042 /*endswitch*/ | |
| 1043 break; | |
| 1044 } | |
| 1045 /*endswitch*/ | |
| 1046 } | |
| 1047 /*- End of function --------------------------------------------------------*/ | |
| 1048 | |
| 1049 static void lapm_hdlc_underflow(void *user_data) | |
| 1050 { | |
| 1051 lapm_state_t *s; | |
| 1052 uint8_t buf[1024]; | |
| 1053 int len; | |
| 1054 | |
| 1055 s = (lapm_state_t *) user_data; | |
| 1056 span_log(&s->logging, SPAN_LOG_FLOW, "HDLC underflow\n"); | |
| 1057 if (s->state == LAPM_DATA) | |
| 1058 { | |
| 1059 if (!queue_empty(s->tx_queue)) | |
| 1060 { | |
| 1061 if ((len = queue_read(s->tx_queue, buf, s->n401)) > 0) | |
| 1062 lapm_tx_iframe(s, buf, len, TRUE); | |
| 1063 /*endif*/ | |
| 1064 } | |
| 1065 /*endif*/ | |
| 1066 } | |
| 1067 /*endif*/ | |
| 1068 } | |
| 1069 /*- End of function --------------------------------------------------------*/ | |
| 1070 | |
| 1071 SPAN_DECLARE(void) lapm_restart(lapm_state_t *s) | |
| 1072 { | |
| 1073 #if 0 | |
| 1074 if (s->state != LAPM_RELEASE) | |
| 1075 { | |
| 1076 span_log(&s->logging, SPAN_LOG_FLOW, "!! lapm_restart: Not in 'Link Connection Released' state\n"); | |
| 1077 return; | |
| 1078 } | |
| 1079 /*endif*/ | |
| 1080 #endif | |
| 1081 span_log_init(&s->logging, SPAN_LOG_NONE, NULL); | |
| 1082 span_log_set_protocol(&s->logging, "LAP.M"); | |
| 1083 hdlc_tx_init(&s->hdlc_tx, FALSE, 1, TRUE, lapm_hdlc_underflow, s); | |
| 1084 hdlc_rx_init(&s->hdlc_rx, FALSE, FALSE, 1, lapm_receive, s); | |
| 1085 /* TODO: This is a bodge! */ | |
| 1086 s->t401_timer = -1; | |
| 1087 s->t402_timer = -1; | |
| 1088 s->t403_timer = -1; | |
| 1089 lapm_reset(s); | |
| 1090 /* TODO: Maybe we should implement T_WAIT? */ | |
| 1091 lapm_send_sabme(NULL, s); | |
| 1092 } | |
| 1093 /*- End of function --------------------------------------------------------*/ | |
| 1094 | |
| 1095 #if 0 | |
| 1096 static void lapm_init(lapm_state_t *s) | |
| 1097 { | |
| 1098 lapm_restart(s); | |
| 1099 } | |
| 1100 /*- End of function --------------------------------------------------------*/ | |
| 1101 #endif | |
| 1102 | |
| 1103 static void negotiation_rx_bit(v42_state_t *s, int new_bit) | |
| 1104 { | |
| 1105 /* DC1 with even parity, 8-16 ones, DC1 with odd parity, 8-16 ones */ | |
| 1106 //uint8_t odp = "0100010001 11111111 0100010011 11111111"; | |
| 1107 /* V.42 OK E , 8-16 ones, C, 8-16 ones */ | |
| 1108 //uint8_t adp_v42 = "0101000101 11111111 0110000101 11111111"; | |
| 1109 /* V.42 disabled E, 8-16 ones, NULL, 8-16 ones */ | |
| 1110 //uint8_t adp_nov42 = "0101000101 11111111 0000000001 11111111"; | |
| 1111 | |
| 1112 /* There may be no negotiation, so we need to process this data through the | |
| 1113 HDLC receiver as well */ | |
| 1114 if (new_bit < 0) | |
| 1115 { | |
| 1116 /* Special conditions */ | |
| 1117 span_log(&s->logging, SPAN_LOG_DEBUG, "V.42 rx status is %s (%d)\n", signal_status_to_str(new_bit), new_bit); | |
| 1118 return; | |
| 1119 } | |
| 1120 /*endif*/ | |
| 1121 new_bit &= 1; | |
| 1122 s->rxstream = (s->rxstream << 1) | new_bit; | |
| 1123 switch (s->rx_negotiation_step) | |
| 1124 { | |
| 1125 case 0: | |
| 1126 /* Look for some ones */ | |
| 1127 if (new_bit) | |
| 1128 break; | |
| 1129 /*endif*/ | |
| 1130 s->rx_negotiation_step = 1; | |
| 1131 s->rxbits = 0; | |
| 1132 s->rxstream = ~1; | |
| 1133 s->rxoks = 0; | |
| 1134 break; | |
| 1135 case 1: | |
| 1136 /* Look for the first character */ | |
| 1137 if (++s->rxbits < 9) | |
| 1138 break; | |
| 1139 /*endif*/ | |
| 1140 s->rxstream &= 0x3FF; | |
| 1141 if (s->calling_party && s->rxstream == 0x145) | |
| 1142 { | |
| 1143 s->rx_negotiation_step++; | |
| 1144 } | |
| 1145 else if (!s->calling_party && s->rxstream == 0x111) | |
| 1146 { | |
| 1147 s->rx_negotiation_step++; | |
| 1148 } | |
| 1149 else | |
| 1150 { | |
| 1151 s->rx_negotiation_step = 0; | |
| 1152 } | |
| 1153 /*endif*/ | |
| 1154 s->rxbits = 0; | |
| 1155 s->rxstream = ~0; | |
| 1156 break; | |
| 1157 case 2: | |
| 1158 /* Look for 8 to 16 ones */ | |
| 1159 s->rxbits++; | |
| 1160 if (new_bit) | |
| 1161 break; | |
| 1162 /*endif*/ | |
| 1163 if (s->rxbits >= 8 && s->rxbits <= 16) | |
| 1164 s->rx_negotiation_step++; | |
| 1165 else | |
| 1166 s->rx_negotiation_step = 0; | |
| 1167 /*endif*/ | |
| 1168 s->rxbits = 0; | |
| 1169 s->rxstream = ~1; | |
| 1170 break; | |
| 1171 case 3: | |
| 1172 /* Look for the second character */ | |
| 1173 if (++s->rxbits < 9) | |
| 1174 break; | |
| 1175 /*endif*/ | |
| 1176 s->rxstream &= 0x3FF; | |
| 1177 if (s->calling_party && s->rxstream == 0x185) | |
| 1178 { | |
| 1179 s->rx_negotiation_step++; | |
| 1180 } | |
| 1181 else if (s->calling_party && s->rxstream == 0x001) | |
| 1182 { | |
| 1183 s->rx_negotiation_step++; | |
| 1184 } | |
| 1185 else if (!s->calling_party && s->rxstream == 0x113) | |
| 1186 { | |
| 1187 s->rx_negotiation_step++; | |
| 1188 } | |
| 1189 else | |
| 1190 { | |
| 1191 s->rx_negotiation_step = 0; | |
| 1192 } | |
| 1193 /*endif*/ | |
| 1194 s->rxbits = 0; | |
| 1195 s->rxstream = ~0; | |
| 1196 break; | |
| 1197 case 4: | |
| 1198 /* Look for 8 to 16 ones */ | |
| 1199 s->rxbits++; | |
| 1200 if (new_bit) | |
| 1201 break; | |
| 1202 /*endif*/ | |
| 1203 if (s->rxbits >= 8 && s->rxbits <= 16) | |
| 1204 { | |
| 1205 if (++s->rxoks >= 2) | |
| 1206 { | |
| 1207 /* HIT */ | |
| 1208 s->rx_negotiation_step++; | |
| 1209 if (s->calling_party) | |
| 1210 { | |
| 1211 if (s->t400_timer >= 0) | |
| 1212 { | |
| 1213 fprintf(stderr, "Deleting T400 h %d\n", s->t400_timer); | |
| 1214 span_schedule_del(&s->lapm.sched, s->t400_timer); | |
| 1215 s->t400_timer = -1; | |
| 1216 } | |
| 1217 /*endif*/ | |
| 1218 s->lapm.state = LAPM_ESTABLISH; | |
| 1219 if (s->lapm.status_callback) | |
| 1220 s->lapm.status_callback(s->lapm.status_callback_user_data, s->lapm.state); | |
| 1221 /*endif*/ | |
| 1222 } | |
| 1223 else | |
| 1224 { | |
| 1225 s->odp_seen = TRUE; | |
| 1226 } | |
| 1227 /*endif*/ | |
| 1228 break; | |
| 1229 } | |
| 1230 /*endif*/ | |
| 1231 s->rx_negotiation_step = 1; | |
| 1232 s->rxbits = 0; | |
| 1233 s->rxstream = ~1; | |
| 1234 } | |
| 1235 else | |
| 1236 { | |
| 1237 s->rx_negotiation_step = 0; | |
| 1238 s->rxbits = 0; | |
| 1239 s->rxstream = ~0; | |
| 1240 } | |
| 1241 /*endif*/ | |
| 1242 break; | |
| 1243 case 5: | |
| 1244 /* Parked */ | |
| 1245 break; | |
| 1246 } | |
| 1247 /*endswitch*/ | |
| 1248 } | |
| 1249 /*- End of function --------------------------------------------------------*/ | |
| 1250 | |
| 1251 static int v42_support_negotiation_tx_bit(v42_state_t *s) | |
| 1252 { | |
| 1253 int bit; | |
| 1254 | |
| 1255 if (s->calling_party) | |
| 1256 { | |
| 1257 if (s->txbits <= 0) | |
| 1258 { | |
| 1259 s->txstream = 0x3FE22; | |
| 1260 s->txbits = 36; | |
| 1261 } | |
| 1262 else if (s->txbits == 18) | |
| 1263 { | |
| 1264 s->txstream = 0x3FF22; | |
| 1265 } | |
| 1266 /*endif*/ | |
| 1267 bit = s->txstream & 1; | |
| 1268 s->txstream >>= 1; | |
| 1269 s->txbits--; | |
| 1270 } | |
| 1271 else | |
| 1272 { | |
| 1273 if (s->odp_seen && s->txadps < 10) | |
| 1274 { | |
| 1275 if (s->txbits <= 0) | |
| 1276 { | |
| 1277 if (++s->txadps >= 10) | |
| 1278 { | |
| 1279 if (s->t400_timer >= 0) | |
| 1280 { | |
| 1281 fprintf(stderr, "Deleting T400 i %d\n", s->t400_timer); | |
| 1282 span_schedule_del(&s->lapm.sched, s->t400_timer); | |
| 1283 s->t400_timer = -1; | |
| 1284 } | |
| 1285 /*endif*/ | |
| 1286 s->lapm.state = LAPM_ESTABLISH; | |
| 1287 if (s->lapm.status_callback) | |
| 1288 s->lapm.status_callback(s->lapm.status_callback_user_data, s->lapm.state); | |
| 1289 /*endif*/ | |
| 1290 s->txstream = 1; | |
| 1291 } | |
| 1292 else | |
| 1293 { | |
| 1294 s->txstream = 0x3FE8A; | |
| 1295 s->txbits = 36; | |
| 1296 } | |
| 1297 /*endif*/ | |
| 1298 } | |
| 1299 else if (s->txbits == 18) | |
| 1300 { | |
| 1301 s->txstream = 0x3FE86; | |
| 1302 } | |
| 1303 /*endif*/ | |
| 1304 bit = s->txstream & 1; | |
| 1305 s->txstream >>= 1; | |
| 1306 s->txbits--; | |
| 1307 } | |
| 1308 else | |
| 1309 { | |
| 1310 bit = 1; | |
| 1311 } | |
| 1312 /*endif*/ | |
| 1313 } | |
| 1314 /*endif*/ | |
| 1315 return bit; | |
| 1316 } | |
| 1317 /*- End of function --------------------------------------------------------*/ | |
| 1318 | |
| 1319 SPAN_DECLARE(void) v42_rx_bit(void *user_data, int bit) | |
| 1320 { | |
| 1321 v42_state_t *s; | |
| 1322 | |
| 1323 s = (v42_state_t *) user_data; | |
| 1324 if (s->lapm.state == LAPM_DETECT) | |
| 1325 negotiation_rx_bit(s, bit); | |
| 1326 else | |
| 1327 hdlc_rx_put_bit(&s->lapm.hdlc_rx, bit); | |
| 1328 /*endif*/ | |
| 1329 } | |
| 1330 /*- End of function --------------------------------------------------------*/ | |
| 1331 | |
| 1332 SPAN_DECLARE(int) v42_tx_bit(void *user_data) | |
| 1333 { | |
| 1334 v42_state_t *s; | |
| 1335 int bit; | |
| 1336 | |
| 1337 s = (v42_state_t *) user_data; | |
| 1338 if (s->lapm.state == LAPM_DETECT) | |
| 1339 bit = v42_support_negotiation_tx_bit(s); | |
| 1340 else | |
| 1341 bit = hdlc_tx_get_bit(&s->lapm.hdlc_tx); | |
| 1342 /*endif*/ | |
| 1343 return bit; | |
| 1344 } | |
| 1345 /*- End of function --------------------------------------------------------*/ | |
| 1346 | |
| 1347 SPAN_DECLARE(void) v42_set_status_callback(v42_state_t *s, v42_status_func_t callback, void *user_data) | |
| 1348 { | |
| 1349 s->lapm.status_callback = callback; | |
| 1350 s->lapm.status_callback_user_data = user_data; | |
| 1351 } | |
| 1352 /*- End of function --------------------------------------------------------*/ | |
| 1353 | |
| 1354 SPAN_DECLARE(void) v42_restart(v42_state_t *s) | |
| 1355 { | |
| 1356 span_schedule_init(&s->lapm.sched); | |
| 1357 | |
| 1358 s->lapm.we_are_originator = s->calling_party; | |
| 1359 lapm_restart(&s->lapm); | |
| 1360 if (s->detect) | |
| 1361 { | |
| 1362 s->txstream = ~0; | |
| 1363 s->txbits = 0; | |
| 1364 s->rxstream = ~0; | |
| 1365 s->rxbits = 0; | |
| 1366 s->rxoks = 0; | |
| 1367 s->txadps = 0; | |
| 1368 s->rx_negotiation_step = 0; | |
| 1369 s->odp_seen = FALSE; | |
| 1370 fprintf(stderr, "Setting T400 i\n"); | |
| 1371 s->t400_timer = span_schedule_event(&s->lapm.sched, T_400, t400_expired, s); | |
| 1372 s->lapm.state = LAPM_DETECT; | |
| 1373 } | |
| 1374 else | |
| 1375 { | |
| 1376 s->lapm.state = LAPM_ESTABLISH; | |
| 1377 } | |
| 1378 /*endif*/ | |
| 1379 } | |
| 1380 /*- End of function --------------------------------------------------------*/ | |
| 1381 | |
| 1382 SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int calling_party, int detect, v42_frame_handler_t frame_handler, void *user_data) | |
| 1383 { | |
| 1384 int alloced; | |
| 1385 | |
| 1386 if (frame_handler == NULL) | |
| 1387 return NULL; | |
| 1388 /*endif*/ | |
| 1389 alloced = FALSE; | |
| 1390 if (s == NULL) | |
| 1391 { | |
| 1392 if ((s = (v42_state_t *) malloc(sizeof(*s))) == NULL) | |
| 1393 return NULL; | |
| 1394 alloced = TRUE; | |
| 1395 } | |
| 1396 memset(s, 0, sizeof(*s)); | |
| 1397 s->calling_party = calling_party; | |
| 1398 s->detect = detect; | |
| 1399 s->lapm.iframe_receive = frame_handler; | |
| 1400 s->lapm.iframe_receive_user_data = user_data; | |
| 1401 s->lapm.debug |= (LAPM_DEBUG_LAPM_RAW | LAPM_DEBUG_LAPM_DUMP | LAPM_DEBUG_LAPM_STATE); | |
| 1402 s->lapm.t401_timer = | |
| 1403 s->lapm.t402_timer = | |
| 1404 s->lapm.t403_timer = -1; | |
| 1405 | |
| 1406 if ((s->lapm.tx_queue = queue_init(NULL, 16384, 0)) == NULL) | |
| 1407 { | |
| 1408 if (alloced) | |
| 1409 free(s); | |
| 1410 return NULL; | |
| 1411 } | |
| 1412 /*endif*/ | |
| 1413 span_log_init(&s->logging, SPAN_LOG_NONE, NULL); | |
| 1414 span_log_set_protocol(&s->logging, "V.42"); | |
| 1415 v42_restart(s); | |
| 1416 return s; | |
| 1417 } | |
| 1418 /*- End of function --------------------------------------------------------*/ | |
| 1419 | |
| 1420 SPAN_DECLARE(int) v42_release(v42_state_t *s) | |
| 1421 { | |
| 1422 return 0; | |
| 1423 } | |
| 1424 /*- End of function --------------------------------------------------------*/ | |
| 1425 | |
| 1426 SPAN_DECLARE(int) v42_free(v42_state_t *s) | |
| 1427 { | |
| 1428 free(s); | |
| 1429 return 0; | |
| 1430 } | |
| 1431 /*- End of function --------------------------------------------------------*/ | |
| 1432 /*- End of file ------------------------------------------------------------*/ | 
