capi.c revision 452bca1bde500b8a6d830d232c2e3fe27cbe72b6
1/*
2 *
3 *  Bluetooth packet analyzer - CAPI parser
4 *
5 *  Copyright (C) 2004-2005  Marcel Holtmann <marcel@holtmann.org>
6 *
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation; either version 2 of the License, or
11 *  (at your option) any later version.
12 *
13 *  This program is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *  GNU General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this program; if not, write to the Free Software
20 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 *
22 *
23 *  $Id$
24 */
25
26#include <stdio.h>
27#include <errno.h>
28#include <ctype.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include <string.h>
32
33#include <sys/types.h>
34#include <netinet/in.h>
35
36#include <bluetooth/bluetooth.h>
37
38#include "parser.h"
39
40#define CAPI_U8(frm)  (get_u8(frm))
41#define CAPI_U16(frm) (btohs(htons(get_u16(frm))))
42#define CAPI_U32(frm) (btohl(htonl(get_u32(frm))))
43
44static char *cmd2str(uint8_t cmd)
45{
46	switch (cmd) {
47	case 0x01:
48		return "ALERT";
49	case 0x02:
50		return "CONNECT";
51	case 0x03:
52		return "CONNECT_ACTIVE";
53	case 0x04:
54		return "DISCONNECT";
55	case 0x05:
56		return "LISTEN";
57	case 0x08:
58		return "INFO";
59	case 0x20:
60		return "INTEROPERABILITY";
61	case 0x41:
62		return "SELECT_B_PROTOCOL";
63	case 0x80:
64		return "FACILITY";
65	case 0x82:
66		return "CONNECT_B3";
67	case 0x83:
68		return "CONNECT_B3_ACTIVE";
69	case 0x84:
70		return "DISCONNECT_B3";
71	case 0x86:
72		return "DATA_B3";
73	case 0x87:
74		return "RESET_B3";
75	case 0x88:
76		return "CONNECT_B3_T90_ACTIVE";
77	case 0xff:
78		return "MANUFACTURER";
79	default:
80		return "UNKNOWN";
81	}
82}
83
84static char *subcmd2str(uint8_t subcmd)
85{
86	switch (subcmd) {
87	case 0x80:
88		return "REQ";
89	case 0x81:
90		return "CONF";
91	case 0x82:
92		return "IND";
93	case 0x83:
94		return "RESP";
95	default:
96		return "UNKN";
97	}
98}
99
100static char *interopsel2str(uint16_t sel)
101{
102	switch (sel) {
103	case 0x0000:
104		return "USB Device Management";
105	case 0x0001:
106		return "Bluetooth Device Management";
107	default:
108		return "Unknown";
109	}
110}
111
112static char *func2str(uint16_t func)
113{
114	switch (func) {
115	case 0:
116		return "Register";
117	case 1:
118		return "Release";
119	case 2:
120		return "Get_Profile";
121	case 3:
122		return "Get_Manufacturer";
123	case 4:
124		return "Get_Version";
125	case 5:
126		return "Get_Serial_Number";
127	case 6:
128		return "Manufacturer";
129	case 7:
130		return "Echo_Loopback";
131	default:
132		return "Unknown";
133	}
134}
135
136static char *facilitysel2str(uint16_t sel)
137{
138	switch (sel) {
139	case 0x0000:
140		return "Handset";
141	case 0x0001:
142		return "DTMF";
143	case 0x0002:
144		return "V.42 bis";
145	case 0x0003:
146		return "Supplementary Services";
147	case 0x0004:
148		return "Power management wakeup";
149	case 0x0005:
150		return "Line Interconnect";
151	case 0x0006:
152		return "DTMF";
153	default:
154		return "Unknown";
155	}
156}
157
158static char *info2str(uint16_t info)
159{
160	switch (info) {
161	case 0x0000:
162		return "No error";
163	case 0x0001:
164		return "NCPI not supported by current protocol, NCPI ignored";
165	case 0x0002:
166		return "Flags not supported by current protocol, flags ignored";
167	case 0x2001:
168		return "Message not supported in current state";
169	case 0x2002:
170		return "Incorrect Controller/PLCI/NCCI";
171	case 0x2003:
172		return "No PLCI available";
173	case 0x2004:
174		return "No NCCI available";
175	case 0x2005:
176		return "No Listen resources available";
177	case 0x2007:
178		return "Illegal message parameter coding";
179	case 0x2008:
180		return "No interconnection resources available";
181	case 0x3001:
182		return "B1 protocol not supported";
183	case 0x3002:
184		return "B2 protocol not supported";
185	case 0x3003:
186		return "B3 protocol not supported";
187	case 0x3004:
188		return "B1 protocol parameter not supported";
189	case 0x3005:
190		return "B2 protocol parameter not supported";
191	case 0x3006:
192		return "B3 protocol parameter not supported";
193	case 0x3007:
194		return "B protocol combination not supported";
195	case 0x3008:
196		return "NCPI not supported";
197	case 0x3009:
198		return "CIP Value unknown";
199	case 0x300A:
200		return "Flags not supported (reserved bits)";
201	case 0x300B:
202		return "Facility not supported";
203	case 0x300C:
204		return "Data length not supported by current protocol";
205	case 0x300D:
206		return "Reset procedure not supported by current protocol";
207	case 0x300F:
208		return "Unsupported interoperability";
209	case 0x3011:
210		return "Facility specific function not supported";
211	case 0x3301:
212		return "Protocol error, Layer 1";
213	case 0x3302:
214		return "Protocol error, Layer 2";
215	case 0x3303:
216		return "Protocol error, Layer 3";
217	case 0x3304:
218		return "Another application got that call";
219	case 0x3305:
220		return "Cleared by Call Control Supervision";
221	case 0x3400:
222		/* The cause value received from the network in a cause
223		 * information element (Octet 4) is indicated in the field 00 */
224		return "Disconnect cause from the network in accordance with Q.850/ETS 300 102-1";
225	default:
226		return "Unknown";
227	}
228}
229
230static void profile(int level, struct frame *frm)
231{
232	uint16_t nctr, nchn;
233	uint32_t value;
234
235	nctr = CAPI_U16(frm);
236	nchn = CAPI_U16(frm);
237
238	if (nchn > 0) {
239		p_indent(level, frm);
240		printf("Controller: %d\n", nctr);
241		p_indent(level, frm);
242		printf("Number of B-channels: %d\n", nchn);
243
244		value = CAPI_U32(frm);
245		p_indent(level, frm);
246		printf("Global options: 0x%04x\n", value);
247		value = CAPI_U32(frm);
248		p_indent(level, frm);
249		printf("B1 protocol support: 0x%08x\n", value);
250		value = CAPI_U32(frm);
251		p_indent(level, frm);
252		printf("B2 protocol support: 0x%08x\n", value);
253		value = CAPI_U32(frm);
254		p_indent(level, frm);
255		printf("B3 protocol support: 0x%08x\n", value);
256
257		frm->ptr += 24;
258		frm->len -= 24;
259
260		p_indent(level, frm);
261		printf("Manufacturer-specific information:\n");
262		hex_dump(level, frm, 20);
263	} else {
264		p_indent(level, frm);
265		printf("Number of controllers: %d\n", nctr);
266	}
267}
268
269static void cmd_common(int level, uint8_t subcmd, struct frame *frm)
270{
271	uint32_t val;
272	uint16_t info, ncci;
273	uint8_t ctr, plci;
274
275	val = CAPI_U32(frm);
276	ctr = val & 0xff;
277	plci = (val & 0xff00) >> 8;
278	ncci = (val & 0xffff0000) >> 16;
279
280	p_indent(level, frm);
281	printf("Controller: %d %s\n", ctr & 0x7f, ctr & 0x80 ? "Ext." : "Int.");
282
283	if (plci > 0) {
284		p_indent(level, frm);
285		printf("PLCI: 0x%02x\n", plci);
286	}
287
288	if (ncci > 0) {
289		p_indent(level, frm);
290		printf("NCCI: 0x%04x\n", ncci);
291	}
292
293	if (subcmd == 0x81) {
294		info = CAPI_U16(frm);
295		p_indent(level, frm);
296		printf("Info: 0x%04x (%s)\n", info, info2str(info));
297	}
298}
299
300static void cmd_alert(int level, uint8_t subcmd, struct frame *frm)
301{
302	uint8_t len;
303
304	cmd_common(level, subcmd, frm);
305
306	if (subcmd == 0x80) {
307		len = CAPI_U8(frm);
308		if (len > 0) {
309			p_indent(level, frm);
310			printf("Additional info:\n");
311			hex_dump(level, frm, len);
312		}
313	}
314}
315
316static void cmd_connect(int level, uint8_t subcmd, struct frame *frm)
317{
318	uint16_t cip;
319	uint8_t len;
320
321	cmd_common(level, subcmd, frm);
322
323	if (subcmd == 0x81)
324		return;
325
326	cip = CAPI_U16(frm);
327	p_indent(level, frm);
328	printf("CIP value: 0x%04x\n", cip);
329
330	len = CAPI_U8(frm);
331	frm->ptr += len;
332	frm->len -= len;
333	len = CAPI_U8(frm);
334	frm->ptr += len;
335	frm->len -= len;
336	len = CAPI_U8(frm);
337	frm->ptr += len;
338	frm->len -= len;
339	len = CAPI_U8(frm);
340	frm->ptr += len;
341	frm->len -= len;
342
343	raw_dump(level, frm);
344}
345
346static void cmd_disconnect(int level, uint8_t subcmd, struct frame *frm)
347{
348	uint16_t reason;
349	uint8_t len;
350
351	cmd_common(level, subcmd, frm);
352
353	if (subcmd == 0x80) {
354		len = CAPI_U8(frm);
355		if (len > 0) {
356			p_indent(level, frm);
357			printf("Additional info:\n");
358			hex_dump(level, frm, len);
359		}
360	}
361
362	if (subcmd == 0x82) {
363		reason = CAPI_U16(frm);
364		p_indent(level, frm);
365		printf("Reason: 0x%04x (%s)\n", reason, info2str(reason));
366	}
367}
368
369static void cmd_connect_active(int level, uint8_t subcmd, struct frame *frm)
370{
371	uint8_t len;
372
373	cmd_common(level, subcmd, frm);
374
375	if (subcmd == 0x82) {
376		len = CAPI_U8(frm);
377		if (len > 0) {
378			p_indent(level, frm);
379			printf("Connected number:\n");
380			hex_dump(level, frm, len);
381		}
382
383		len = CAPI_U8(frm);
384		if (len > 0) {
385			p_indent(level, frm);
386			printf("Connected subaddress:\n");
387			hex_dump(level, frm, len);
388		}
389
390		len = CAPI_U8(frm);
391		if (len > 0) {
392			p_indent(level, frm);
393			printf("LLC:\n");
394			hex_dump(level, frm, len);
395		}
396	}
397}
398
399static void cmd_listen(int level, uint8_t subcmd, struct frame *frm)
400{
401	uint32_t mask;
402	uint8_t len;
403
404	cmd_common(level, subcmd, frm);
405
406	if (subcmd == 0x80) {
407		mask = CAPI_U32(frm);
408		p_indent(level, frm);
409		printf("Info mask: 0x%08x\n", mask);
410
411		mask = CAPI_U32(frm);
412		p_indent(level, frm);
413		printf("CIP mask:  0x%08x", mask);
414
415		mask = CAPI_U32(frm);
416		if (mask > 0)
417			printf(" 0x%08x\n", mask);
418		else
419			printf("\n");
420
421		len = CAPI_U8(frm);
422		if (len > 0) {
423			p_indent(level, frm);
424			printf("Calling party number:\n");
425			hex_dump(level, frm, len);
426		}
427		frm->ptr += len;
428		frm->len -= len;
429
430		len = CAPI_U8(frm);
431		if (len > 0) {
432			p_indent(level, frm);
433			printf("Calling party subaddress:\n");
434			hex_dump(level, frm, len);
435		}
436		frm->ptr += len;
437		frm->len -= len;
438	}
439}
440
441static void cmd_info(int level, uint8_t subcmd, struct frame *frm)
442{
443	uint8_t len;
444	uint16_t info;
445
446	cmd_common(level, subcmd, frm);
447
448	switch (subcmd) {
449	case 0x80:
450		len = CAPI_U8(frm);
451		if (len > 0) {
452			p_indent(level, frm);
453			printf("Called party number:\n");
454			hex_dump(level, frm, len);
455		}
456		frm->ptr += len;
457		frm->len -= len;
458
459		len = CAPI_U8(frm);
460		if (len > 0) {
461			p_indent(level, frm);
462			printf("Additional info:\n");
463			hex_dump(level, frm, len);
464		}
465		break;
466
467	case 0x82:
468		info = CAPI_U16(frm);
469		p_indent(level, frm);
470		printf("Info number: %d\n", info);
471
472		len = CAPI_U8(frm);
473		if (len > 0) {
474			p_indent(level, frm);
475			printf("Info element:\n");
476			hex_dump(level, frm, len);
477		}
478		break;
479	}
480}
481
482static void cmd_interoperability(int level, uint8_t subcmd, struct frame *frm)
483{
484	uint16_t sel, func, info;
485	uint16_t nconn, datablkcnt, datablklen;
486	uint32_t ctr, value, major, minor;
487
488	info = (subcmd == 0x81) ? CAPI_U16(frm) : 0;
489	sel = CAPI_U16(frm);
490	CAPI_U8(frm);
491	if (subcmd != 0x83) {
492		func = CAPI_U16(frm);
493		CAPI_U8(frm);
494	} else
495		func = 0;
496
497	p_indent(level, frm);
498	printf("Selector: 0x%04x (%s)\n", sel, interopsel2str(sel));
499
500	switch (sel) {
501	case 0x0001:
502		p_indent(level, frm);
503		printf("Function: %d (%s)\n", func, func2str(func));
504
505		switch (subcmd) {
506		case 0x80:
507			switch (func) {
508			case 0:
509				nconn = CAPI_U16(frm);
510				p_indent(level + 1, frm);
511				printf("maxLogicalConnections: %d\n", nconn);
512				datablkcnt = CAPI_U16(frm);
513				p_indent(level + 1, frm);
514				printf("maxBDataBlocks: %d\n", datablkcnt);
515				datablklen = CAPI_U16(frm);
516				p_indent(level + 1, frm);
517				printf("maxBDataLen: %d\n", datablklen);
518				break;
519			case 2:
520			case 3:
521			case 4:
522			case 5:
523				ctr = CAPI_U32(frm);
524				p_indent(level + 1, frm);
525				printf("Controller: %d\n", ctr);
526				break;
527			default:
528				raw_dump(level + 1, frm);
529				break;
530			}
531			break;
532
533		case 0x81:
534			switch (func) {
535			case 0:
536			case 1:
537				info = CAPI_U16(frm);
538				p_indent(level + 1, frm);
539				printf("Info: 0x%04x (%s)\n", info, info2str(info));
540				break;
541			case 2:
542				info = CAPI_U16(frm);
543				p_indent(level + 1, frm);
544				printf("Info: 0x%04x (%s)\n", info, info2str(info));
545				CAPI_U8(frm);
546				profile(level + 1, frm);
547				break;
548			case 3:
549				info = CAPI_U16(frm);
550				p_indent(level + 1, frm);
551				printf("Info: 0x%04x (%s)\n", info, info2str(info));
552				ctr = CAPI_U32(frm);
553				p_indent(level + 1, frm);
554				printf("Controller: %d\n", ctr);
555				CAPI_U8(frm);
556				p_indent(level + 1, frm);
557				printf("Identification: \"%s\"\n", (char *) frm->ptr);
558				break;
559			case 4:
560				value = CAPI_U32(frm);
561				p_indent(level + 1, frm);
562				printf("Return value: 0x%04x\n", value);
563				ctr = CAPI_U32(frm);
564				p_indent(level + 1, frm);
565				printf("Controller: %d\n", ctr);
566				p_indent(level + 1, frm);
567				major = CAPI_U32(frm);
568				minor = CAPI_U32(frm);
569				printf("CAPI: %d.%d\n", major, minor);
570				major = CAPI_U32(frm);
571				minor = CAPI_U32(frm);
572				p_indent(level + 1, frm);
573				printf("Manufacture: %u.%01x%01x-%02u (%d.%d)\n",
574					(major & 0xf0) >> 4, (major & 0x0f) << 4,
575					(minor & 0xf0) >> 4, minor & 0x0f,
576					major, minor);
577				break;
578			case 5:
579				value = CAPI_U32(frm);
580				p_indent(level + 1, frm);
581				printf("Return value: 0x%04x\n", value);
582				ctr = CAPI_U32(frm);
583				p_indent(level + 1, frm);
584				printf("Controller: %d\n", ctr);
585				CAPI_U8(frm);
586				p_indent(level + 1, frm);
587				printf("Serial number: %.7s\n", (char *) frm->ptr);
588				break;
589			default:
590				raw_dump(level + 1, frm);
591				break;
592			}
593			break;
594
595		default:
596			raw_dump(level, frm);
597			break;
598		}
599		break;
600
601	default:
602		p_indent(level, frm);
603		printf("Function: %d\n", func);
604		if (subcmd == 0x81) {
605			p_indent(level, frm);
606			printf("Info: 0x%04x (%s)\n", info, info2str(info));
607		}
608		raw_dump(level + 1, frm);
609		break;
610	}
611}
612
613static void cmd_facility(int level, uint8_t subcmd, struct frame *frm)
614{
615	uint16_t sel;
616
617	cmd_common(level, subcmd, frm);
618
619	sel = CAPI_U16(frm);
620	CAPI_U8(frm);
621
622	p_indent(level, frm);
623	printf("Selector: 0x%04x (%s)\n", sel, facilitysel2str(sel));
624
625	raw_dump(level, frm);
626}
627
628static void cmd_connect_b3(int level, uint8_t subcmd, struct frame *frm)
629{
630	uint16_t reject;
631	uint8_t len;
632
633	cmd_common(level, subcmd, frm);
634
635	if (subcmd == 0x81)
636		return;
637
638	if (subcmd == 0x83) {
639		reject = CAPI_U16(frm);
640		p_indent(level, frm);
641		printf("Reject: 0x%04x (%s)\n", reject, info2str(reject));
642	}
643
644	len = CAPI_U8(frm);
645	if (len > 0) {
646		p_indent(level, frm);
647		printf("NCPI:\n");
648		hex_dump(level, frm, len);
649	}
650}
651
652static void cmd_connect_b3_active(int level, uint8_t subcmd, struct frame *frm)
653{
654	uint8_t len;
655
656	cmd_common(level, subcmd, frm);
657
658	if (subcmd == 0x82) {
659		len = CAPI_U8(frm);
660		if (len > 0) {
661			p_indent(level, frm);
662			printf("NCPI:\n");
663			hex_dump(level, frm, len);
664		}
665	}
666}
667
668static void cmd_disconnect_b3(int level, uint8_t subcmd, struct frame *frm)
669{
670	uint16_t reason;
671	uint8_t len;
672
673	cmd_common(level, subcmd, frm);
674
675	if (subcmd == 0x82) {
676		reason = CAPI_U16(frm);
677		p_indent(level, frm);
678		printf("Reason: 0x%04x (%s)\n", reason, info2str(reason));
679	}
680
681	if (subcmd == 0x80 || subcmd == 0x82) {
682		len = CAPI_U8(frm);
683		if (len > 0) {
684			p_indent(level, frm);
685			printf("NCPI:\n");
686			hex_dump(level, frm, len);
687		}
688	}
689}
690
691static void cmd_data_b3(int level, uint8_t subcmd, struct frame *frm)
692{
693	uint32_t data;
694	uint64_t data64;
695	uint16_t length, handle, flags, info;
696
697	cmd_common(level, 0x00, frm);
698
699	if (subcmd == 0x81 || subcmd == 0x83) {
700		handle = CAPI_U16(frm);
701		p_indent(level, frm);
702		printf("Data handle: 0x%04x\n", handle);
703
704		if (subcmd == 0x81) {
705			info = CAPI_U16(frm);
706			p_indent(level, frm);
707			printf("Info: 0x%04x (%s)\n", info, info2str(info));
708		}
709	} else {
710		data = CAPI_U32(frm);
711
712		length = CAPI_U16(frm);
713		p_indent(level, frm);
714		printf("Data length: 0x%04x (%d bytes)\n", length, length);
715
716		handle = CAPI_U16(frm);
717		p_indent(level, frm);
718		printf("Data handle: 0x%04x\n", handle);
719
720		flags = CAPI_U16(frm);
721		p_indent(level, frm);
722		printf("Flags: 0x%04x\n", flags);
723
724		if (data == 0)
725			data64 = get_u64(frm);
726
727		raw_dump(level, frm);
728	}
729}
730
731static void cmd_reset_b3(int level, uint8_t subcmd, struct frame *frm)
732{
733	uint8_t len;
734
735	cmd_common(level, subcmd, frm);
736
737	if (subcmd == 0x80 || subcmd == 0x82) {
738		len = CAPI_U8(frm);
739		if (len > 0) {
740			p_indent(level, frm);
741			printf("NCPI:\n");
742			hex_dump(level, frm, len);
743		}
744	}
745}
746
747static void cmd_manufacturer(int level, uint8_t subcmd, struct frame *frm)
748{
749	uint32_t ctr, class, func;
750	uint16_t len;
751	unsigned char *id;
752
753	ctr = CAPI_U32(frm);
754	p_indent(level, frm);
755	printf("Controller: %d\n", ctr);
756
757	id = (unsigned char *) frm->ptr;
758	p_indent(level, frm);
759	if (isprint(id[0]) && isprint(id[1]) && isprint(id[2]) && isprint(id[3]))
760		printf("Manufacturer: %.4s", id);
761	else
762		printf("Manufacturer: 0x%02x 0x%02x 0x%02x 0x%02x",
763						id[0], id[1], id[2], id[3]);
764	frm->ptr += 4;
765	frm->len -= 4;
766
767	if (!strncmp((char *) id, "AVM!", 4)) {
768		class = CAPI_U32(frm);
769		func = CAPI_U32(frm);
770		len = CAPI_U8(frm);
771		if (len == 0xff)
772			len = CAPI_U16(frm);
773
774		printf(" [class %d func %d len %d]\n", class, func, len);
775	} else
776		printf("\n");
777
778	raw_dump(level, frm);
779}
780
781void capi_dump(int level, struct frame *frm)
782{
783	uint16_t len, appl, msgnum;
784	uint8_t cmd, subcmd;
785
786	len = CAPI_U16(frm) - 8;
787	appl = CAPI_U16(frm);
788	cmd = CAPI_U8(frm);
789	subcmd = CAPI_U8(frm);
790	msgnum = CAPI_U16(frm);
791
792	p_indent(level, frm);
793
794	printf("CAPI_%s_%s: appl %d msgnum %d len %d\n",
795			cmd2str(cmd), subcmd2str(subcmd), appl, msgnum, len);
796
797	switch (cmd) {
798	case 0x01:
799		cmd_alert(level + 1, subcmd, frm);
800		break;
801	case 0x02:
802		cmd_connect(level + 1, subcmd, frm);
803		break;
804	case 0x03:
805		cmd_connect_active(level + 1, subcmd, frm);
806		break;
807	case 0x04:
808		cmd_disconnect(level + 1, subcmd, frm);
809		break;
810	case 0x05:
811		cmd_listen(level + 1, subcmd, frm);
812		break;
813	case 0x08:
814		cmd_info(level + 1, subcmd, frm);
815		break;
816	case 0x20:
817		cmd_interoperability(level + 1, subcmd, frm);
818		break;
819	case 0x80:
820		cmd_facility(level + 1, subcmd, frm);
821		break;
822	case 0x82:
823		cmd_connect_b3(level + 1, subcmd, frm);
824		break;
825	case 0x83:
826	case 0x88:
827		cmd_connect_b3_active(level + 1, subcmd, frm);
828		break;
829	case 0x84:
830		cmd_disconnect_b3(level + 1, subcmd, frm);
831		break;
832	case 0x86:
833		cmd_data_b3(level + 1, subcmd, frm);
834		break;
835	case 0x87:
836		cmd_reset_b3(level + 1, subcmd, frm);
837		break;
838	case 0xff:
839		cmd_manufacturer(level + 1, subcmd, frm);
840		break;
841	default:
842		raw_dump(level, frm);
843		frm->ptr += len;
844		frm->len -= len;
845		break;
846	}
847}
848