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