1 /*
2 * mangler module
3 *
4 * Copyright (C) 2001-2003 FhG Fokus
5 *
6 * This file is part of Kamailio, a free SIP server.
7 *
8 * Kamailio 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 * Kamailio 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include "contact_ops.h"
24 #include "utils.h"
25 #include "common.h"
26 #include "../../core/mem/mem.h"
27 #include "../../core/data_lump.h"
28 #include "../../core/parser/hf.h"
29 #include "../../core/parser/parse_uri.h"
30 #include "../../core/parser/contact/parse_contact.h"
31 #include "../../core/ut.h"
32 #include "../../core/dset.h"
33
34 #include <stdio.h>
35 #include <string.h>
36
37 #define SIP_SCH "sip:"
38 #define SIP_SCH_LEN (sizeof(SIP_SCH)-1)
39
40
41 int
encode_contact(struct sip_msg * msg,char * encoding_prefix,char * public_ip)42 encode_contact (struct sip_msg *msg, char *encoding_prefix,char *public_ip)
43 {
44
45 contact_body_t *cb;
46 contact_t *c;
47 str* uri;
48 str newUri;
49 int res;
50 char separator;
51
52
53
54 /*
55 * I have a list of contacts in contact->parsed which is of type contact_body_t
56 * inside i have a contact->parsed->contact which is the head of the list of contacts
57 * inside it is a
58 * str uri;
59 * struct contact *next;
60 * I just have to visit each uri and encode each uri according to a scheme
61 */
62
63 if ((msg->contact == NULL)&&((parse_headers(msg,HDR_CONTACT_F,0) == -1) ||
64 (msg->contact == NULL) ))
65 {
66 LOG(L_ERR,"ERROR: encode_contact: no Contact header present\n");
67 return -1;
68 }
69
70
71 separator = DEFAULT_SEPARATOR[0];
72 if (contact_flds_separator != NULL)
73 if (strlen(contact_flds_separator)>=1)
74 separator = contact_flds_separator[0];
75
76 if (msg->contact->parsed == NULL) {
77 if(parse_contact (msg->contact)<0) {
78 LM_DBG("failed to parse contact\n");
79 }
80 }
81 if (msg->contact->parsed != NULL)
82 {
83 cb = (contact_body_t *) msg->contact->parsed;
84 c = cb->contacts;
85 /* we visit each contact */
86 if (c != NULL)
87 {
88 uri = &c->uri;
89 res = encode_uri(msg, uri, encoding_prefix, public_ip,
90 separator, &newUri);
91
92 if (res != 0)
93 {
94 LOG (L_ERR,"ERROR: encode_contact: Failed encoding contact.Code %d\n", res);
95 return res;
96 }
97 else
98 if (patch (msg, uri->s, uri->len, newUri.s, newUri.len) < 0)
99 {
100 LOG (L_ERR,"ERROR: encode_contact: lumping failed in mangling port \n");
101 return -2;
102 }
103
104 /* encoding next contacts too?*/
105 #ifdef ENCODE_ALL_CONTACTS
106 while (c->next != NULL)
107 {
108 c = c->next;
109 uri = &c->uri;
110
111 res = encode_uri (msg, uri, encoding_prefix, public_ip,
112 separator, &newUri);
113 if (res != 0)
114 {
115 LOG(L_ERR,"ERROR: encode_contact: Failed encode_uri.Code %d\n",res);
116 #ifdef STRICT_CHECK
117 return res;
118 #endif
119 }
120 else
121 if (patch (msg, uri->s, uri->len, newUri.s, newUri.len)< 0)
122 {
123 LOG (L_ERR,"ERROR: encode_contact: lumping failed in mangling port \n");
124 return -3;
125 }
126 } /* while */
127 #endif /* ENCODE_ALL_CONTACTS */
128 } /* if c != NULL */
129
130 } /* end if */
131 else /* after parsing still NULL */
132 {
133 LOG(L_ERR,"ERROR: encode_contact: Unable to parse Contact header\n");
134 #ifdef EXTRA_DEBUG
135 printf("ERROR: encode_contact: Unable to parse Contact header\n");
136 #endif
137 return -4;
138 }
139 #ifdef EXTRA_DEBUG
140 fprintf (stdout,"---END--------ENCODE CONTACT-----------------\n");
141 #endif
142 return 1;
143 }
144
145 int
decode_contact(struct sip_msg * msg,char * unused1,char * unused2)146 decode_contact (struct sip_msg *msg,char *unused1,char *unused2)
147 {
148
149 str* uri;
150 str newUri;
151 str dst_uri;
152 char separator;
153 int res;
154
155
156 separator = DEFAULT_SEPARATOR[0];
157 if (contact_flds_separator != NULL)
158 if (strlen(contact_flds_separator)>=1)
159 separator = contact_flds_separator[0];
160
161 if ((msg->new_uri.s == NULL) || (msg->new_uri.len == 0)) {
162 uri = &msg->first_line.u.request.uri;
163 }else{
164 uri = &msg->new_uri;
165 }
166
167 res = decode_uri (uri, separator, &newUri, &dst_uri);
168
169 if (res != 0) {
170 LOG (L_ERR,"ERROR: decode_contact:Failed decoding contact."
171 "Code %d\n", res);
172 return res;
173 } else {
174 /* we do not modify the original first line */
175 if (msg->new_uri.s)
176 pkg_free(msg->new_uri.s);
177 msg->new_uri = newUri;
178 msg->parsed_uri_ok=0;
179 msg->dst_uri = dst_uri;
180 ruri_mark_new();
181 }
182 return 1;
183 }
184
185 int
decode_contact_header(struct sip_msg * msg,char * unused1,char * unused2)186 decode_contact_header (struct sip_msg *msg,char *unused1,char *unused2)
187 {
188
189 contact_body_t *cb;
190 contact_t *c;
191 str* uri;
192 str newUri;
193 char separator;
194 int res;
195
196 if ((msg->contact == NULL)&&((parse_headers(msg,HDR_CONTACT_F,0) == -1) ||
197 (msg->contact== NULL) ))
198 {
199 LOG(L_ERR,"ERROR: decode_contact_header: no Contact header present\n");
200 return -1;
201 }
202
203 separator = DEFAULT_SEPARATOR[0];
204 if (contact_flds_separator != NULL)
205 if (strlen(contact_flds_separator)>=1)
206 separator = contact_flds_separator[0];
207
208 if (msg->contact->parsed == NULL) {
209 if(parse_contact (msg->contact)<0) {
210 LM_DBG("failed to parse contact\n");
211 }
212 }
213 if (msg->contact->parsed != NULL)
214 {
215 cb = (contact_body_t *) msg->contact->parsed;
216 c = cb->contacts;
217 // we visit each contact
218 if (c != NULL)
219 {
220 uri = &c->uri;
221
222 res = decode_uri (uri, separator, &newUri, 0);
223 if (res != 0)
224 {
225 LOG (L_ERR,"ERROR: decode_contact_header:Failed decoding contact.Code %d\n", res);
226 #ifdef STRICT_CHECK
227 return res;
228 #endif
229 }
230 else
231 if (patch (msg, uri->s, uri->len, newUri.s, newUri.len) < 0)
232 {
233 LOG (L_ERR,"ERROR: decode_contact:lumping failed in mangling port \n");
234 return -2;
235 }
236
237 #ifdef DECODE_ALL_CONTACTS
238 while (c->next != NULL)
239 {
240 c = c->next;
241 uri = &c->uri;
242
243 res = decode_uri (uri, separator, &newUri, 0);
244 if (res != 0)
245 {
246 LOG (L_ERR,"ERROR: decode_contact: Failed decoding contact.Code %d\n",res);
247 #ifdef STRICT_CHECK
248 return res;
249 #endif
250 }
251 else
252 if (patch (msg, uri->s, uri->len, newUri.s, newUri.len) < 0)
253 {
254 LOG (L_ERR,"ERROR: decode_contact:lumping failed in mangling port \n");
255 return -3;
256 }
257 } // end while
258 #endif
259 } // if c!= NULL
260 } // end if
261 else // after parsing still NULL
262 {
263 LOG(L_ERR,"ERROR: decode_contact: Unable to parse Contact header\n");
264 return -4;
265 }
266 return 1;
267 }
268
269
270 static str s_tcp = STR_STATIC_INIT("tcp");
271 static str s_tls = STR_STATIC_INIT("tls");
272 static str s_sctp = STR_STATIC_INIT("sctp");
273
274
275
276 int
encode2format(struct sip_msg * msg,str * uri,struct uri_format * format)277 encode2format (struct sip_msg* msg, str* uri, struct uri_format *format)
278 {
279 int foo;
280 char *string, *pos, *start, *end;
281 struct sip_uri sipUri;
282 int scheme_len;
283
284
285 if (uri->s == NULL)
286 return -1;
287 string = uri->s;
288
289
290 pos = q_memchr (string, '<', uri->len);
291 if (pos != NULL) /* we are only interested of chars inside <> */
292 {
293 start = q_memchr (string, ':', uri->len);
294 if (start == NULL) return -2;
295 if (start - pos < 4) return -3;
296 if ((*(start-1)|0x20)=='s' && (start-pos)>4)
297 /* if it ends in s: it is a sips or tels uri */
298 scheme_len=4;
299 else
300 scheme_len=3;
301 start-=scheme_len;
302 end = strchr (start, '>');
303 if (end == NULL)
304 return -4; /* must be a match to < */
305 }
306 else /* we do not have <> */
307 {
308 pos=string;
309 start = q_memchr (string, ':', uri->len);
310 if (start == NULL)
311 return -5;
312 if (start - pos < 3)
313 return -6;
314 if ((*(start-1)|0x20)=='s' && (start-pos)>3)
315 /* if it ends in s: it is a sips or tels uri */
316 scheme_len=4;
317 else
318 scheme_len=3;
319 start = start - scheme_len;
320 end = string + uri->len;
321 }
322 memset(format,0,sizeof(struct uri_format));
323 format->first = start - string + scheme_len+1 /* ':' */;
324 format->second = end - string;
325 /* --------------------------testing ------------------------------- */
326 /* sip:gva@pass@10.0.0.1;;transport=udp>;expires=2 INCORECT BEHAVIOR OF parse_uri,myfunction works good */
327 foo = parse_uri (start, end - start, &sipUri);
328 if (foo != 0)
329 {
330 LOG(L_ERR,"ERROR: encode2format: parse_uri failed on [%.*s]."
331 "Code %d \n", uri->len, uri->s, foo);
332 return foo-10;
333 }
334
335
336 format->username = sipUri.user;
337 format->password = sipUri.passwd;
338 format->ip = sipUri.host;
339 format->port = sipUri.port;
340 format->protocol = sipUri.transport_val;
341 format->transport=sipUri.transport; /* the whole transport header */
342 format->rest.s = sipUri.port.s?(sipUri.port.s+sipUri.port.len):
343 (sipUri.host.s+sipUri.host.len);
344 format->rest.len = (int)(end-format->rest.s);
345 format->rcv_ip.s=ip_addr2a(&msg->rcv.src_ip);
346 format->rcv_ip.len=strlen(format->rcv_ip.s);
347 if (msg->rcv.src_port!=SIP_PORT){
348 format->rcv_port.s=
349 int2str(msg->rcv.src_port, &format->rcv_port.len);
350 }else{
351 format->rcv_port.s=0;
352 format->rcv_port.len=0;
353 }
354 if (msg->rcv.proto!=PROTO_UDP){
355 switch(msg->rcv.proto){
356 case PROTO_TCP:
357 format->rcv_proto=s_tcp;
358 break;
359 case PROTO_TLS:
360 format->rcv_proto=s_tls;
361 break;
362 case PROTO_SCTP:
363 format->rcv_proto=s_sctp;
364 break;
365 default:
366 BUG("unknown proto %d\n", msg->rcv.proto);
367 }
368 }else{
369 format->rcv_proto.s=0;
370 format->rcv_proto.len=0;
371 }
372
373 #ifdef EXTRA_DEBUG
374 fprintf (stdout, "transport=[%.*s] transportval=[%.*s]\n", sipUri.transport.len,sipUri.transport.s,sipUri.transport_val.len,sipUri.transport_val.s);
375 fprintf(stdout,"First %d,second %d\n",format->first,format->second);
376 #endif
377
378 return 0;
379
380 }
381
382
383 int
encode_uri(struct sip_msg * msg,str * uri,char * encoding_prefix,char * public_ip,char separator,str * result)384 encode_uri (struct sip_msg* msg, str* uri, char *encoding_prefix,
385 char *public_ip,char separator, str * result)
386 {
387 struct uri_format format;
388 char *pos;
389 int foo,res;
390
391
392 result->s = NULL;
393 result->len = 0;
394 if (uri->len <= 1)
395 return -1; /* no contact or an invalid one */
396 if (public_ip == NULL)
397 {
398 LOG(L_ERR,"ERROR: encode_uri: Invalid NULL value for public_ip parameter\n");
399 return -2;
400 }
401 foo = encode2format (msg, uri, &format);
402 if (foo < 0)
403 {
404 LOG(L_ERR,"ERROR: encode_uri: Unable to encode Contact URI"
405 " [%.*s].Return code %d\n",uri->len, uri->s, foo);
406 return foo - 20;
407 }
408
409 /* a complete uri would be sip:username@ip:port;transport=protocol goes to
410 * sip:enc_pref*username*ip*port*protocol@public_ip
411 */
412
413 foo = 1; /*strlen(separator); */
414 result->len = format.first + uri->s+uri->len - format.rest.s +
415 strlen (encoding_prefix) + foo +
416 format.username.len + foo +
417 format.password.len + foo +
418 format.ip.len + foo + format.port.len + foo +
419 format.protocol.len + foo + format.rcv_ip.len + foo +
420 format.rcv_port.len + foo + format.rcv_proto.len +
421 1 + strlen (public_ip);
422 /* adding one comes from @ */
423 result->s = pkg_malloc (result->len);
424 pos = result->s;
425 if (pos == NULL)
426 {
427 LOG(L_ERR,"ERROR: encode_uri:Unable to alloc memory\n");
428 return -3;
429 }
430
431 res = snprintf(pos,result->len,"%.*s%s%c%.*s%c%.*s%c%.*s%c%.*s%c%.*s%c"
432 "%.*s%c%.*s%c%.*s@",
433 format.first, uri->s,encoding_prefix,separator,
434 format.username.len,format.username.s,separator,
435 format.password.len,format.password.s,
436 separator,format.ip.len,format.ip.s,separator,format.port.len,
437 format.port.s,separator,format.protocol.len,format.protocol.s,
438 separator, format.rcv_ip.len, format.rcv_ip.s, separator,
439 format.rcv_port.len, format.rcv_port.s, separator,
440 format.rcv_proto.len, format.rcv_proto.s
441 );
442
443 if ((res < 0 )||(res>result->len))
444 {
445 LOG(L_ERR,"ERROR: encode_uri: Unable to construct new uri.\n");
446 if (result->s != NULL) pkg_free(result->s);
447 return -4;
448 }
449 pos = pos + res ;/* overwriting the \0 from snprintf */
450 memcpy (pos, public_ip, strlen (public_ip));
451 pos = pos + strlen (public_ip);
452 /* copy the rest of the parameters and the rest of uri line*/
453 memcpy (pos, format.rest.s, uri->s+uri->len - format.rest.s);
454 /*memcpy (pos, uri.s + format.second, uri.len - format.second);*/
455
456 /* Because called parse_uri format contains pointers to the inside of msg,
457 * must not deallocate */
458
459 return 0;
460 }
461
462
463 int
decode2format(str * uri,char separator,struct uri_format * format)464 decode2format (str* uri, char separator, struct uri_format *format)
465 {
466 char *start, *end, *pos,*lastpos;
467 str tmp;
468 enum {EX_PREFIX=0,EX_USER,EX_PASS,EX_IP,EX_PORT,EX_PROT, EX_RCVIP,
469 EX_RCVPORT, EX_RCVPROTO, EX_FINAL} state;
470
471 memset (format, 0, sizeof(struct uri_format));
472
473 if (uri->s == NULL)
474 {
475 LOG(L_ERR,"ERROR: decode2format: Invalid parameter uri.It is NULL\n");
476 return -1;
477 }
478 /* sip:enc_pref*username*password*ip*port*protocol@public_ip */
479
480 start = q_memchr (uri->s, ':', uri->len);
481 if (start == NULL)
482 {
483 LOG(L_ERR,"ERROR: decode2format: Invalid SIP uri.Missing :\n");
484 return -2;
485 } /* invalid uri */
486 start = start + 1;
487 if (start >= (uri->s+uri->len)){
488 LOG(L_ERR, "ERROR: decode2format> Invalid sip uri: too short: %.*s\n",
489 uri->len, uri->s);
490 return -2;
491 }
492 format->first = start - uri->s;
493
494 /* start */
495
496 end = q_memchr(start,'@',uri->len-(start-uri->s));
497 if (end == NULL)
498 {
499 LOG(L_ERR,"ERROR: decode2format: Invalid SIP uri.Missing @\n");
500 return -3;/* no host address found */
501 }
502
503 #ifdef EXTRA_DEBUG
504 fprintf (stdout, "Decoding %.*s\n",(int)(long)(end-start), start);
505 #endif
506
507 state = EX_PREFIX;
508 lastpos = start;
509
510 for (pos = start;pos<end;pos++)
511 {
512 if (*pos == separator)
513 {
514 /* we copy between lastpos and pos */
515 tmp.len = pos - lastpos;
516 if (tmp.len>0) tmp.s = lastpos;
517 else tmp.s = NULL;
518 switch (state)
519 {
520 case EX_PREFIX: state = EX_USER;break;
521 case EX_USER:format->username = tmp;state = EX_PASS;break;
522 case EX_PASS:format->password = tmp;state = EX_IP;break;
523 case EX_IP:format->ip = tmp;state = EX_PORT;break;
524 case EX_PORT:format->port = tmp;state = EX_PROT;break;
525 case EX_PROT:
526 format->protocol=tmp;
527 state=EX_RCVIP;
528 break;
529 case EX_RCVIP:
530 format->rcv_ip=tmp;
531 state=EX_RCVPORT;
532 break;
533 case EX_RCVPORT:
534 format->rcv_port=tmp;
535 state=EX_RCVPROTO;
536 break;
537 default:
538 {
539 /* this should not happen, we should find @ not separator */
540 return -4;
541 break;
542 }
543 }
544
545 lastpos = pos+1;
546
547 }
548 else
549 if (((*pos) == '>')||(*pos == ';'))
550 {
551 /* invalid chars inside username part */
552 return -5;
553 }
554 }
555
556
557 /* we must be in state EX_RCVPROTO and protocol is between lastpos and
558 * end@ */
559 if (state != EX_RCVPROTO) return -6;
560 format->rcv_proto.len = end - lastpos;
561 if (format->rcv_proto.len>0) format->rcv_proto.s = lastpos;
562 /* I should check perhaps that after @ there is something */
563
564 /* looking for the end of public ip */
565 start = end;/*we are now at @ */
566 for(pos = start;pos<(uri->s+uri->len);pos++)
567 {
568 if ((*pos == ';')||(*pos == '>'))
569 {
570 /* found end */
571 format->second = pos - uri->s;
572 return 0;
573 }
574 }
575 /* if we are here we did not find > or ; */
576 format->second = uri->len;
577 return 0;
578
579 }
580
581
582 int
decode_uri(str * uri,char separator,str * result,str * dst_uri)583 decode_uri (str* uri, char separator, str * result, str* dst_uri)
584 {
585 char *pos;
586 struct uri_format format;
587 int foo;
588
589 result->s = NULL;
590 result->len = 0;
591 if (dst_uri){
592 dst_uri->s=0;
593 dst_uri->len=0;
594 }
595
596 if ((uri->len <= 0) || (uri->s == NULL))
597 {
598 LOG(L_ERR,"ERROR: decode_uri: Invalid value for uri\n");
599 return -1;
600 }
601
602 foo = decode2format (uri, separator, &format);
603 if (foo < 0)
604 {
605 LOG(L_ERR,"ERROR: decode_uri: Error decoding Contact uri .Error code %d\n",foo);
606 return foo - 20;
607 }
608 /* sanity check */
609 if (format.ip.len <= 0)
610 {
611 LOG(L_ERR,"ERROR: decode_uri: Unable to decode host address \n");
612 return -2;/* should I quit or ignore ? */
613 }
614
615 if ((format.password.len > 0) && (format.username.len <= 0))
616 {
617 LOG(L_ERR,"ERROR: decode_uri: Password decoded but no username available\n");
618 return -3;
619 }
620
621 /* a complete uri would be sip:username:password@ip:port;transport=protocol goes to
622 * sip:enc_pref#username#password#ip#port#protocol@public_ip
623 */
624 result->len = format.first + (uri->len - format.second); /* not NULL terminated */
625 if (format.username.len > 0) result->len += format.username.len + 1; //: or @
626 if (format.password.len > 0) result->len += format.password.len + 1; //@
627
628 /* if (format.ip.len > 0) */ result->len += format.ip.len;
629
630 if (format.port.len > 0) result->len += 1 + format.port.len; //:
631 if (format.protocol.len > 0) result->len += 1 + 10 + format.protocol.len; //;transport=
632
633 /* adding one comes from * */
634 result->s = pkg_malloc (result->len + 1); /* NULL termination */
635 if (result->s == NULL)
636 {
637 LOG(L_ERR,"ERROR: decode_contact: Unable to allocate memory\n");
638 return -4;
639 }
640 pos = result->s;
641 memcpy (pos, uri->s, format.first); /* till sip: */
642 pos = pos + format.first;
643
644 if (format.username.len > 0)
645 {
646 memcpy (pos, format.username.s, format.username.len);
647 pos = pos + format.username.len;
648 if (format.password.len > 0)
649 memcpy (pos, ":", 1);
650 else
651 memcpy (pos, "@", 1);
652 pos = pos + 1;
653 }
654 if (format.password.len > 0)
655 {
656 memcpy (pos, format.password.s, format.password.len);
657 pos = pos + format.password.len;
658 memcpy (pos, "@", 1);
659 pos = pos + 1;
660 }
661 /* if (format.ip.len > 0) */
662
663 memcpy (pos, format.ip.s, format.ip.len);
664 pos = pos + format.ip.len;
665
666 if (format.port.len > 0)
667 {
668 memcpy (pos, ":", 1);
669 pos = pos + 1;
670 memcpy (pos, format.port.s, format.port.len);
671 pos = pos + format.port.len;
672 }
673 if (format.protocol.len > 0)
674 {
675 memcpy (pos, ";transport=", 11);
676 pos = pos + 11;
677 memcpy (pos, format.protocol.s, format.protocol.len);
678 pos = pos + format.protocol.len;
679 }
680
681 memcpy (pos, uri->s + format.second, uri->len - format.second); /* till end: */
682
683 result->s[result->len] = '\0';
684
685 /* dst_uri */
686 if (dst_uri && format.rcv_ip.s){
687 dst_uri->len=4 /* sip: */ + format.rcv_ip.len;
688 if (format.rcv_port.len){
689 dst_uri->len+=1 /* : */+format.rcv_port.len;
690 }
691 if (format.rcv_proto.len){
692 dst_uri->len+=TRANSPORT_PARAM_LEN+format.rcv_proto.len;
693 }
694 dst_uri->s=pkg_malloc(dst_uri->len);
695 if (dst_uri->s==0){
696 LOG(L_ERR,"ERROR: decode_contact: dst_uri: memory allocation"
697 " failed\n");
698 dst_uri->len=0;
699 pkg_free(result->s);
700 result->s=0;
701 result->len=0;
702 return -4;
703 }
704 pos=dst_uri->s;
705 memcpy(pos, SIP_SCH, SIP_SCH_LEN);
706 pos+=SIP_SCH_LEN;
707 memcpy(pos, format.rcv_ip.s, format.rcv_ip.len);
708 pos+=format.rcv_ip.len;
709 if (format.rcv_port.len){
710 *pos=':';
711 pos++;
712 memcpy(pos, format.rcv_port.s, format.rcv_port.len);
713 pos+=format.rcv_port.len;
714 }
715 if (format.rcv_proto.len){
716 memcpy(pos, TRANSPORT_PARAM, TRANSPORT_PARAM_LEN);
717 pos+=TRANSPORT_PARAM_LEN;
718 memcpy(pos, format.rcv_proto.s, format.rcv_proto.len);
719 }
720 }
721 return 0;
722 }
723
724