1 /*
2 *
3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
6 *
7 *
8 * This Host ATM Research Platform ("HARP") file (the "Software") is
9 * made available by Network Computing Services, Inc. ("NetworkCS")
10 * "AS IS". NetworkCS does not provide maintenance, improvements or
11 * support of any kind.
12 *
13 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17 * In no event shall NetworkCS be responsible for any damages, including
18 * but not limited to consequential damages, arising from or relating to
19 * any use of the Software or related support.
20 *
21 * Copyright 1994-1998 Network Computing Services, Inc.
22 *
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
25 *
26 * @(#) $FreeBSD: releng/5.0/sys/netatm/atm_socket.c 97658 2002-05-31 11:52:35Z tanimura $
27 *
28 */
29
30 /*
31 * Core ATM Services
32 * -----------------
33 *
34 * ATM common socket protocol processing
35 *
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/syslog.h>
44 #include <net/if.h>
45 #include <netatm/port.h>
46 #include <netatm/queue.h>
47 #include <netatm/atm.h>
48 #include <netatm/atm_sys.h>
49 #include <netatm/atm_sap.h>
50 #include <netatm/atm_cm.h>
51 #include <netatm/atm_if.h>
52 #include <netatm/atm_sigmgr.h>
53 #include <netatm/atm_stack.h>
54 #include <netatm/atm_pcb.h>
55 #include <netatm/atm_var.h>
56
57 #ifndef lint
58 __RCSID("@(#) $FreeBSD: releng/5.0/sys/netatm/atm_socket.c 97658 2002-05-31 11:52:35Z tanimura $");
59 #endif
60
61
62 /*
63 * Local functions
64 */
65
66
67 /*
68 * Local variables
69 */
70 static uma_zone_t atm_pcb_zone;
71
72 static struct t_atm_cause atm_sock_cause = {
73 T_ATM_ITU_CODING,
74 T_ATM_LOC_USER,
75 T_ATM_CAUSE_UNSPECIFIED_NORMAL,
76 {0, 0, 0, 0}
77 };
78
79 void
80 atm_sock_init(void)
81 {
82
83 atm_pcb_zone = uma_zcreate("atm pcb", sizeof(Atm_pcb), NULL, NULL,
84 NULL, NULL, UMA_ALIGN_PTR, 0);
85 if (atm_pcb_zone == NULL)
86 panic("atm_sock_init: unable to initialize atm_pcb_zone");
87 uma_zone_set_max(atm_pcb_zone, 100);
88 }
89
90 /*
91 * Allocate resources for a new ATM socket
92 *
93 * Called at splnet.
94 *
95 * Arguments:
96 * so pointer to socket
97 * send socket send buffer maximum
98 * recv socket receive buffer maximum
99 *
100 * Returns:
101 * 0 attach successful
102 * errno attach failed - reason indicated
103 *
104 */
105 int
106 atm_sock_attach(so, send, recv)
107 struct socket *so;
108 u_long send;
109 u_long recv;
110 {
111 Atm_pcb *atp = sotoatmpcb(so);
112 int err;
113
114 /*
115 * Make sure initialization has happened
116 */
117 if (!atm_init)
118 atm_initialize();
119
120 /*
121 * Make sure we're not already attached
122 */
123 if (atp)
124 return (EISCONN);
125
126 /*
127 * Reserve socket buffer space, if not already done
128 */
129 if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) {
130 err = soreserve(so, send, recv);
131 if (err)
132 return (err);
133 }
134
135 /*
136 * Allocate and initialize our control block
137 */
138 atp = uma_zalloc(atm_pcb_zone, M_ZERO | M_NOWAIT);
139 if (atp == NULL)
140 return (ENOMEM);
141
142 atp->atp_socket = so;
143 so->so_pcb = (caddr_t)atp;
144 return (0);
145 }
146
147
148 /*
149 * Detach from socket and free resources
150 *
151 * Called at splnet.
152 *
153 * Arguments:
154 * so pointer to socket
155 *
156 * Returns:
157 * 0 detach successful
158 * errno detach failed - reason indicated
159 *
160 */
161 int
162 atm_sock_detach(so)
163 struct socket *so;
164 {
165 Atm_pcb *atp = sotoatmpcb(so);
166
167 /*
168 * Make sure we're still attached
169 */
170 if (atp == NULL)
171 return (ENOTCONN);
172
173 /*
174 * Terminate any (possibly pending) connection
175 */
176 if (atp->atp_conn) {
177 (void) atm_sock_disconnect(so);
178 }
179
180 /*
181 * Break links and free control blocks
182 */
183 so->so_pcb = NULL;
184 sotryfree(so);
185
186 uma_zfree(atm_pcb_zone, atp);
187
188 return (0);
189 }
190
191
192 /*
193 * Bind local address to socket
194 *
195 * Called at splnet.
196 *
197 * Arguments:
198 * so pointer to socket
199 * addr pointer to protocol address
200 *
201 * Returns:
202 * 0 request processed
203 * errno error processing request - reason indicated
204 *
205 */
206 int
207 atm_sock_bind(so, addr)
208 struct socket *so;
209 struct sockaddr *addr;
210 {
211 Atm_pcb *atp = sotoatmpcb(so);
212 Atm_attributes attr;
213 struct sockaddr_atm *satm;
214 struct t_atm_sap_addr *sapadr;
215 struct t_atm_sap_layer2 *sapl2;
216 struct t_atm_sap_layer3 *sapl3;
217 struct t_atm_sap_appl *sapapl;
218
219 /*
220 * Make sure we're still attached
221 */
222 if (atp == NULL)
223 return (ENOTCONN);
224
225 /*
226 * Can't change local address once we've started connection process
227 */
228 if (atp->atp_conn != NULL)
229 return (EADDRNOTAVAIL);
230
231 /*
232 * Validate requested local address
233 */
234 satm = (struct sockaddr_atm *)addr;
235 if (satm->satm_family != AF_ATM)
236 return (EAFNOSUPPORT);
237
238 sapadr = &satm->satm_addr.t_atm_sap_addr;
239 if (sapadr->SVE_tag_addr == T_ATM_PRESENT) {
240 if (sapadr->address_format == T_ATM_ENDSYS_ADDR) {
241 if (sapadr->SVE_tag_selector != T_ATM_PRESENT)
242 return (EINVAL);
243 } else if (sapadr->address_format == T_ATM_E164_ADDR) {
244 if (sapadr->SVE_tag_selector != T_ATM_ABSENT)
245 return (EINVAL);
246 } else
247 return (EINVAL);
248 } else if ((sapadr->SVE_tag_addr != T_ATM_ABSENT) &&
249 (sapadr->SVE_tag_addr != T_ATM_ANY))
250 return (EINVAL);
251 if (sapadr->address_length > ATM_ADDR_LEN)
252 return (EINVAL);
253
254 sapl2 = &satm->satm_addr.t_atm_sap_layer2;
255 if (sapl2->SVE_tag == T_ATM_PRESENT) {
256 if ((sapl2->ID_type != T_ATM_SIMPLE_ID) &&
257 (sapl2->ID_type != T_ATM_USER_ID))
258 return (EINVAL);
259 } else if ((sapl2->SVE_tag != T_ATM_ABSENT) &&
260 (sapl2->SVE_tag != T_ATM_ANY))
261 return (EINVAL);
262
263 sapl3 = &satm->satm_addr.t_atm_sap_layer3;
264 if (sapl3->SVE_tag == T_ATM_PRESENT) {
265 if ((sapl3->ID_type != T_ATM_SIMPLE_ID) &&
266 (sapl3->ID_type != T_ATM_IPI_ID) &&
267 (sapl3->ID_type != T_ATM_SNAP_ID) &&
268 (sapl3->ID_type != T_ATM_USER_ID))
269 return (EINVAL);
270 } else if ((sapl3->SVE_tag != T_ATM_ABSENT) &&
271 (sapl3->SVE_tag != T_ATM_ANY))
272 return (EINVAL);
273
274 sapapl = &satm->satm_addr.t_atm_sap_appl;
275 if (sapapl->SVE_tag == T_ATM_PRESENT) {
276 if ((sapapl->ID_type != T_ATM_ISO_APP_ID) &&
277 (sapapl->ID_type != T_ATM_USER_APP_ID) &&
278 (sapapl->ID_type != T_ATM_VENDOR_APP_ID))
279 return (EINVAL);
280 } else if ((sapapl->SVE_tag != T_ATM_ABSENT) &&
281 (sapapl->SVE_tag != T_ATM_ANY))
282 return (EINVAL);
283
284 /*
285 * Create temporary attributes list so that we can check out the
286 * new bind parameters before we modify the socket's values;
287 */
288 attr = atp->atp_attr;
289 attr.called.tag = sapadr->SVE_tag_addr;
290 bcopy(&sapadr->address_format, &attr.called.addr, sizeof(Atm_addr));
291
292 attr.blli.tag_l2 = sapl2->SVE_tag;
293 if (sapl2->SVE_tag == T_ATM_PRESENT) {
294 attr.blli.v.layer_2_protocol.ID_type = sapl2->ID_type;
295 bcopy(&sapl2->ID, &attr.blli.v.layer_2_protocol.ID,
296 sizeof(attr.blli.v.layer_2_protocol.ID));
297 }
298
299 attr.blli.tag_l3 = sapl3->SVE_tag;
300 if (sapl3->SVE_tag == T_ATM_PRESENT) {
301 attr.blli.v.layer_3_protocol.ID_type = sapl3->ID_type;
302 bcopy(&sapl3->ID, &attr.blli.v.layer_3_protocol.ID,
303 sizeof(attr.blli.v.layer_3_protocol.ID));
304 }
305
306 attr.bhli.tag = sapapl->SVE_tag;
307 if (sapapl->SVE_tag == T_ATM_PRESENT) {
308 attr.bhli.v.ID_type = sapapl->ID_type;
309 bcopy(&sapapl->ID, &attr.bhli.v.ID,
310 sizeof(attr.bhli.v.ID));
311 }
312
313 /*
314 * Make sure we have unique listening attributes
315 */
316 if (atm_cm_match(&attr, NULL) != NULL)
317 return (EADDRINUSE);
318
319 /*
320 * Looks good, save new attributes
321 */
322 atp->atp_attr = attr;
323
324 return (0);
325 }
326
327
328 /*
329 * Listen for incoming connections
330 *
331 * Called at splnet.
332 *
333 * Arguments:
334 * so pointer to socket
335 * epp pointer to endpoint definition structure
336 *
337 * Returns:
338 * 0 request processed
339 * errno error processing request - reason indicated
340 *
341 */
342 int
343 atm_sock_listen(so, epp)
344 struct socket *so;
345 Atm_endpoint *epp;
346 {
347 Atm_pcb *atp = sotoatmpcb(so);
348
349 /*
350 * Make sure we're still attached
351 */
352 if (atp == NULL)
353 return (ENOTCONN);
354
355 /*
356 * Start listening for incoming calls
357 */
358 return (atm_cm_listen(epp, atp, &atp->atp_attr, &atp->atp_conn));
359 }
360
361
362 /*
363 * Connect socket to peer
364 *
365 * Called at splnet.
366 *
367 * Arguments:
368 * so pointer to socket
369 * addr pointer to protocol address
370 * epp pointer to endpoint definition structure
371 *
372 * Returns:
373 * 0 request processed
374 * errno error processing request - reason indicated
375 *
376 */
377 int
378 atm_sock_connect(so, addr, epp)
379 struct socket *so;
380 struct sockaddr *addr;
381 Atm_endpoint *epp;
382 {
383 Atm_pcb *atp = sotoatmpcb(so);
384 struct sockaddr_atm *satm;
385 struct t_atm_sap_addr *sapadr;
386 struct t_atm_sap_layer2 *sapl2;
387 struct t_atm_sap_layer3 *sapl3;
388 struct t_atm_sap_appl *sapapl;
389 int err;
390
391 /*
392 * Make sure we're still attached
393 */
394 if (atp == NULL)
395 return (ENOTCONN);
396
397 /*
398 * Validate requested peer address
399 */
400 satm = (struct sockaddr_atm *)addr;
401 if (satm->satm_family != AF_ATM)
402 return (EAFNOSUPPORT);
403
404 sapadr = &satm->satm_addr.t_atm_sap_addr;
405 if (sapadr->SVE_tag_addr != T_ATM_PRESENT)
406 return (EINVAL);
407 if (sapadr->address_format == T_ATM_ENDSYS_ADDR) {
408 if (sapadr->SVE_tag_selector != T_ATM_PRESENT)
409 return (EINVAL);
410 } else if (sapadr->address_format == T_ATM_E164_ADDR) {
411 if (sapadr->SVE_tag_selector != T_ATM_ABSENT)
412 return (EINVAL);
413 } else if (sapadr->address_format == T_ATM_PVC_ADDR) {
414 if (sapadr->SVE_tag_selector != T_ATM_ABSENT)
415 return (EINVAL);
416 } else
417 return (EINVAL);
418 if (sapadr->address_length > ATM_ADDR_LEN)
419 return (EINVAL);
420
421 sapl2 = &satm->satm_addr.t_atm_sap_layer2;
422 if (sapl2->SVE_tag == T_ATM_PRESENT) {
423 if ((sapl2->ID_type != T_ATM_SIMPLE_ID) &&
424 (sapl2->ID_type != T_ATM_USER_ID))
425 return (EINVAL);
426 } else if (sapl2->SVE_tag != T_ATM_ABSENT)
427 return (EINVAL);
428
429 sapl3 = &satm->satm_addr.t_atm_sap_layer3;
430 if (sapl3->SVE_tag == T_ATM_PRESENT) {
431 if ((sapl3->ID_type != T_ATM_SIMPLE_ID) &&
432 (sapl3->ID_type != T_ATM_IPI_ID) &&
433 (sapl3->ID_type != T_ATM_SNAP_ID) &&
434 (sapl3->ID_type != T_ATM_USER_ID))
435 return (EINVAL);
436 } else if (sapl3->SVE_tag != T_ATM_ABSENT)
437 return (EINVAL);
438
439 sapapl = &satm->satm_addr.t_atm_sap_appl;
440 if (sapapl->SVE_tag == T_ATM_PRESENT) {
441 if ((sapapl->ID_type != T_ATM_ISO_APP_ID) &&
442 (sapapl->ID_type != T_ATM_USER_APP_ID) &&
443 (sapapl->ID_type != T_ATM_VENDOR_APP_ID))
444 return (EINVAL);
445 } else if (sapapl->SVE_tag != T_ATM_ABSENT)
446 return (EINVAL);
447
448 /*
449 * Select an outgoing network interface
450 */
451 if (atp->atp_attr.nif == NULL) {
452 struct atm_pif *pip;
453
454 for (pip = atm_interface_head; pip != NULL;
455 pip = pip->pif_next) {
456 if (pip->pif_nif != NULL) {
457 atp->atp_attr.nif = pip->pif_nif;
458 break;
459 }
460 }
461 if (atp->atp_attr.nif == NULL)
462 return (ENXIO);
463 }
464
465 /*
466 * Set supplied connection attributes
467 */
468 atp->atp_attr.called.tag = T_ATM_PRESENT;
469 bcopy(&sapadr->address_format, &atp->atp_attr.called.addr,
470 sizeof(Atm_addr));
471
472 atp->atp_attr.blli.tag_l2 = sapl2->SVE_tag;
473 if (sapl2->SVE_tag == T_ATM_PRESENT) {
474 atp->atp_attr.blli.v.layer_2_protocol.ID_type = sapl2->ID_type;
475 bcopy(&sapl2->ID, &atp->atp_attr.blli.v.layer_2_protocol.ID,
476 sizeof(atp->atp_attr.blli.v.layer_2_protocol.ID));
477 }
478
479 atp->atp_attr.blli.tag_l3 = sapl3->SVE_tag;
480 if (sapl3->SVE_tag == T_ATM_PRESENT) {
481 atp->atp_attr.blli.v.layer_3_protocol.ID_type = sapl3->ID_type;
482 bcopy(&sapl3->ID, &atp->atp_attr.blli.v.layer_3_protocol.ID,
483 sizeof(atp->atp_attr.blli.v.layer_3_protocol.ID));
484 }
485
486 atp->atp_attr.bhli.tag = sapapl->SVE_tag;
487 if (sapapl->SVE_tag == T_ATM_PRESENT) {
488 atp->atp_attr.bhli.v.ID_type = sapapl->ID_type;
489 bcopy(&sapapl->ID, &atp->atp_attr.bhli.v.ID,
490 sizeof(atp->atp_attr.bhli.v.ID));
491 }
492
493 /*
494 * We're finally ready to initiate the ATM connection
495 */
496 soisconnecting(so);
497 atm_sock_stat.as_connreq[atp->atp_type]++;
498 err = atm_cm_connect(epp, atp, &atp->atp_attr, &atp->atp_conn);
499 if (err == 0) {
500 /*
501 * Connection is setup
502 */
503 atm_sock_stat.as_conncomp[atp->atp_type]++;
504 soisconnected(so);
505
506 } else if (err == EINPROGRESS) {
507 /*
508 * We've got to wait for a connected event
509 */
510 err = 0;
511
512 } else {
513 /*
514 * Call failed...
515 */
516 atm_sock_stat.as_connfail[atp->atp_type]++;
517 soisdisconnected(so);
518 }
519
520 return (err);
521 }
522
523
524 /*
525 * Disconnect connected socket
526 *
527 * Called at splnet.
528 *
529 * Arguments:
530 * so pointer to socket
531 *
532 * Returns:
533 * 0 request processed
534 * errno error processing request - reason indicated
535 *
536 */
537 int
538 atm_sock_disconnect(so)
539 struct socket *so;
540 {
541 Atm_pcb *atp = sotoatmpcb(so);
542 struct t_atm_cause *cause;
543 int err;
544
545 /*
546 * Make sure we're still attached
547 */
548 if (atp == NULL)
549 return (ENOTCONN);
550
551 /*
552 * Release the ATM connection
553 */
554 if (atp->atp_conn) {
555 if (atp->atp_attr.cause.tag == T_ATM_PRESENT)
556 cause = &atp->atp_attr.cause.v;
557 else
558 cause = &atm_sock_cause;
559 err = atm_cm_release(atp->atp_conn, cause);
560 if (err)
561 log(LOG_ERR, "atm_sock_disconnect: release fail (%d)\n",
562 err);
563 atm_sock_stat.as_connrel[atp->atp_type]++;
564 atp->atp_conn = NULL;
565 }
566
567 soisdisconnected(so);
568
569 return (0);
570 }
571
572
573 /*
574 * Retrieve local socket address
575 *
576 * Called at splnet.
577 *
578 * Arguments:
579 * so pointer to socket
580 * addr pointer to pointer to contain protocol address
581 *
582 * Returns:
583 * 0 request processed
584 * errno error processing request - reason indicated
585 *
586 */
587 int
588 atm_sock_sockaddr(so, addr)
589 struct socket *so;
590 struct sockaddr **addr;
591 {
592 struct sockaddr_atm *satm;
593 struct t_atm_sap_addr *saddr;
594 Atm_pcb *atp = sotoatmpcb(so);
595
596 /*
597 * Return local interface address, if known
598 */
599 satm = malloc(sizeof(*satm), M_SONAME, M_WAITOK | M_ZERO);
600 if (satm == NULL)
601 return (ENOMEM);
602
603 satm->satm_family = AF_ATM;
604 satm->satm_len = sizeof(*satm);
605
606 saddr = &satm->satm_addr.t_atm_sap_addr;
607 if (atp->atp_attr.nif && atp->atp_attr.nif->nif_pif->pif_siginst) {
608 saddr->SVE_tag_addr = T_ATM_PRESENT;
609 ATM_ADDR_SEL_COPY(
610 &atp->atp_attr.nif->nif_pif->pif_siginst->si_addr,
611 atp->atp_attr.nif->nif_sel, saddr);
612 if (saddr->address_format == T_ATM_ENDSYS_ADDR)
613 saddr->SVE_tag_selector = T_ATM_PRESENT;
614 else
615 saddr->SVE_tag_selector = T_ATM_ABSENT;
616 } else {
617 saddr->SVE_tag_addr = T_ATM_ABSENT;
618 saddr->SVE_tag_selector = T_ATM_ABSENT;
619 saddr->address_format = T_ATM_ABSENT;
620 }
621 satm->satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_ABSENT;
622 satm->satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
623 satm->satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
624
625 *addr = (struct sockaddr *)satm;
626 return (0);
627 }
628
629
630 /*
631 * Retrieve peer socket address
632 *
633 * Called at splnet.
634 *
635 * Arguments:
636 * so pointer to socket
637 * addr pointer to pointer to contain protocol address
638 *
639 * Returns:
640 * 0 request processed
641 * errno error processing request - reason indicated
642 *
643 */
644 int
645 atm_sock_peeraddr(so, addr)
646 struct socket *so;
647 struct sockaddr **addr;
648 {
649 struct sockaddr_atm *satm;
650 struct t_atm_sap_addr *saddr;
651 Atm_pcb *atp = sotoatmpcb(so);
652 Atm_connvc *cvp;
653
654 /*
655 * Return remote address, if known
656 */
657 satm = malloc(sizeof(*satm), M_SONAME, M_WAITOK | M_ZERO);
658 if (satm == NULL)
659 return (ENOMEM);
660
661 satm->satm_family = AF_ATM;
662 satm->satm_len = sizeof(*satm);
663 saddr = &satm->satm_addr.t_atm_sap_addr;
664 if (so->so_state & SS_ISCONNECTED) {
665 cvp = atp->atp_conn->co_connvc;
666 saddr->SVE_tag_addr = T_ATM_PRESENT;
667 if (cvp->cvc_flags & CVCF_CALLER) {
668 ATM_ADDR_COPY(&cvp->cvc_attr.called.addr, saddr);
669 } else {
670 if (cvp->cvc_attr.calling.tag == T_ATM_PRESENT) {
671 ATM_ADDR_COPY(&cvp->cvc_attr.calling.addr,
672 saddr);
673 } else {
674 saddr->SVE_tag_addr = T_ATM_ABSENT;
675 saddr->address_format = T_ATM_ABSENT;
676 }
677 }
678 if (saddr->address_format == T_ATM_ENDSYS_ADDR)
679 saddr->SVE_tag_selector = T_ATM_PRESENT;
680 else
681 saddr->SVE_tag_selector = T_ATM_ABSENT;
682 } else {
683 saddr->SVE_tag_addr = T_ATM_ABSENT;
684 saddr->SVE_tag_selector = T_ATM_ABSENT;
685 saddr->address_format = T_ATM_ABSENT;
686 }
687 satm->satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_ABSENT;
688 satm->satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
689 satm->satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
690
691 *addr = (struct sockaddr *)satm;
692 return (0);
693 }
694
695
696 /*
697 * Common setsockopt processing
698 *
699 * Called at splnet.
700 *
701 * Arguments:
702 * so pointer to socket
703 * sopt pointer to socket option info
704 * atp pointer to ATM PCB
705 *
706 * Returns:
707 * 0 request processed
708 * errno error processing request - reason indicated
709 *
710 */
711 int
712 atm_sock_setopt(so, sopt, atp)
713 struct socket *so;
714 struct sockopt *sopt;
715 Atm_pcb *atp;
716 {
717 int err = 0;
718 union {
719 struct t_atm_aal5 aal5;
720 struct t_atm_traffic trf;
721 struct t_atm_bearer brr;
722 struct t_atm_bhli bhl;
723 struct t_atm_blli bll;
724 Atm_addr addr;
725 struct t_atm_cause cau;
726 struct t_atm_qos qos;
727 struct t_atm_transit trn;
728 struct t_atm_net_intf nif;
729 struct t_atm_llc llc;
730 struct t_atm_app_name appn;
731 } p;
732
733 #define MAXVAL(bits) ((1 << bits) - 1)
734 #define MAXMASK(bits) (~MAXVAL(bits))
735
736 switch (sopt->sopt_name) {
737
738 case T_ATM_AAL5:
739 err = sooptcopyin(sopt, &p.aal5, sizeof p.aal5, sizeof p.aal5);
740 if (err)
741 break;
742 if ((p.aal5.forward_max_SDU_size != T_ATM_ABSENT) &&
743 (p.aal5.forward_max_SDU_size & MAXMASK(16)))
744 return (EINVAL);
745 if ((p.aal5.backward_max_SDU_size != T_ATM_ABSENT) &&
746 (p.aal5.backward_max_SDU_size & MAXMASK(16)))
747 return (EINVAL);
748 if ((p.aal5.SSCS_type != T_ATM_ABSENT) &&
749 (p.aal5.SSCS_type != T_ATM_NULL) &&
750 (p.aal5.SSCS_type != T_ATM_SSCS_SSCOP_REL) &&
751 (p.aal5.SSCS_type != T_ATM_SSCS_SSCOP_UNREL) &&
752 (p.aal5.SSCS_type != T_ATM_SSCS_FR))
753 return (EINVAL);
754
755 if ((p.aal5.forward_max_SDU_size == T_ATM_ABSENT) &&
756 (p.aal5.backward_max_SDU_size == T_ATM_ABSENT) &&
757 (p.aal5.SSCS_type == T_ATM_ABSENT))
758 atp->atp_attr.aal.tag = T_ATM_ABSENT;
759 else {
760 atp->atp_attr.aal.tag = T_ATM_PRESENT;
761 atp->atp_attr.aal.type = ATM_AAL5;
762 atp->atp_attr.aal.v.aal5 = p.aal5;
763 }
764 break;
765
766 case T_ATM_TRAFFIC:
767 err = sooptcopyin(sopt, &p.trf, sizeof p.trf, sizeof p.trf);
768 if (err)
769 break;
770 if ((p.trf.forward.PCR_high_priority != T_ATM_ABSENT) &&
771 (p.trf.forward.PCR_high_priority & MAXMASK(24)))
772 return (EINVAL);
773 if (p.trf.forward.PCR_all_traffic & MAXMASK(24))
774 return (EINVAL);
775 if ((p.trf.forward.SCR_high_priority != T_ATM_ABSENT) &&
776 (p.trf.forward.SCR_high_priority & MAXMASK(24)))
777 return (EINVAL);
778 if ((p.trf.forward.SCR_all_traffic != T_ATM_ABSENT) &&
779 (p.trf.forward.SCR_all_traffic & MAXMASK(24)))
780 return (EINVAL);
781 if ((p.trf.forward.MBS_high_priority != T_ATM_ABSENT) &&
782 (p.trf.forward.MBS_high_priority & MAXMASK(24)))
783 return (EINVAL);
784 if ((p.trf.forward.MBS_all_traffic != T_ATM_ABSENT) &&
785 (p.trf.forward.MBS_all_traffic & MAXMASK(24)))
786 return (EINVAL);
787 if ((p.trf.forward.tagging != T_YES) &&
788 (p.trf.forward.tagging != T_NO))
789 return (EINVAL);
790
791 if ((p.trf.backward.PCR_high_priority != T_ATM_ABSENT) &&
792 (p.trf.backward.PCR_high_priority & MAXMASK(24)))
793 return (EINVAL);
794 if (p.trf.backward.PCR_all_traffic & MAXMASK(24))
795 return (EINVAL);
796 if ((p.trf.backward.SCR_high_priority != T_ATM_ABSENT) &&
797 (p.trf.backward.SCR_high_priority & MAXMASK(24)))
798 return (EINVAL);
799 if ((p.trf.backward.SCR_all_traffic != T_ATM_ABSENT) &&
800 (p.trf.backward.SCR_all_traffic & MAXMASK(24)))
801 return (EINVAL);
802 if ((p.trf.backward.MBS_high_priority != T_ATM_ABSENT) &&
803 (p.trf.backward.MBS_high_priority & MAXMASK(24)))
804 return (EINVAL);
805 if ((p.trf.backward.MBS_all_traffic != T_ATM_ABSENT) &&
806 (p.trf.backward.MBS_all_traffic & MAXMASK(24)))
807 return (EINVAL);
808 if ((p.trf.backward.tagging != T_YES) &&
809 (p.trf.backward.tagging != T_NO))
810 return (EINVAL);
811 if ((p.trf.best_effort != T_YES) &&
812 (p.trf.best_effort != T_NO))
813 return (EINVAL);
814
815 atp->atp_attr.traffic.tag = T_ATM_PRESENT;
816 atp->atp_attr.traffic.v = p.trf;
817 break;
818
819 case T_ATM_BEARER_CAP:
820 err = sooptcopyin(sopt, &p.brr, sizeof p.brr, sizeof p.brr);
821 if (err)
822 break;
823 if ((p.brr.bearer_class != T_ATM_CLASS_A) &&
824 (p.brr.bearer_class != T_ATM_CLASS_C) &&
825 (p.brr.bearer_class != T_ATM_CLASS_X))
826 return (EINVAL);
827 if ((p.brr.traffic_type != T_ATM_NULL) &&
828 (p.brr.traffic_type != T_ATM_CBR) &&
829 (p.brr.traffic_type != T_ATM_VBR))
830 return (EINVAL);
831 if ((p.brr.timing_requirements != T_ATM_NULL) &&
832 (p.brr.timing_requirements != T_ATM_END_TO_END) &&
833 (p.brr.timing_requirements != T_ATM_NO_END_TO_END))
834 return (EINVAL);
835 if ((p.brr.clipping_susceptibility != T_NO) &&
836 (p.brr.clipping_susceptibility != T_YES))
837 return (EINVAL);
838 if ((p.brr.connection_configuration != T_ATM_1_TO_1) &&
839 (p.brr.connection_configuration != T_ATM_1_TO_MANY))
840 return (EINVAL);
841
842 atp->atp_attr.bearer.tag = T_ATM_PRESENT;
843 atp->atp_attr.bearer.v = p.brr;
844 break;
845
846 case T_ATM_BHLI:
847 err = sooptcopyin(sopt, &p.bhl, sizeof p.bhl, sizeof p.bhl);
848 if (err)
849 break;
850 if ((p.bhl.ID_type != T_ATM_ABSENT) &&
851 (p.bhl.ID_type != T_ATM_ISO_APP_ID) &&
852 (p.bhl.ID_type != T_ATM_USER_APP_ID) &&
853 (p.bhl.ID_type != T_ATM_VENDOR_APP_ID))
854 return (EINVAL);
855
856 if (p.bhl.ID_type == T_ATM_ABSENT)
857 atp->atp_attr.bhli.tag = T_ATM_ABSENT;
858 else {
859 atp->atp_attr.bhli.tag = T_ATM_PRESENT;
860 atp->atp_attr.bhli.v = p.bhl;
861 }
862 break;
863
864 case T_ATM_BLLI:
865 err = sooptcopyin(sopt, &p.bll, sizeof p.bll, sizeof p.bll);
866 if (err)
867 break;
868 if ((p.bll.layer_2_protocol.ID_type != T_ATM_ABSENT) &&
869 (p.bll.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) &&
870 (p.bll.layer_2_protocol.ID_type != T_ATM_USER_ID))
871 return (EINVAL);
872 if ((p.bll.layer_2_protocol.mode != T_ATM_ABSENT) &&
873 (p.bll.layer_2_protocol.mode != T_ATM_BLLI_NORMAL_MODE) &&
874 (p.bll.layer_2_protocol.mode != T_ATM_BLLI_EXTENDED_MODE))
875 return (EINVAL);
876 if ((p.bll.layer_2_protocol.window_size != T_ATM_ABSENT) &&
877 (p.bll.layer_2_protocol.window_size < 1))
878 return (EINVAL);
879
880 if ((p.bll.layer_3_protocol.ID_type != T_ATM_ABSENT) &&
881 (p.bll.layer_3_protocol.ID_type != T_ATM_SIMPLE_ID) &&
882 (p.bll.layer_3_protocol.ID_type != T_ATM_IPI_ID) &&
883 (p.bll.layer_3_protocol.ID_type != T_ATM_SNAP_ID) &&
884 (p.bll.layer_3_protocol.ID_type != T_ATM_USER_ID))
885 return (EINVAL);
886 if ((p.bll.layer_3_protocol.mode != T_ATM_ABSENT) &&
887 (p.bll.layer_3_protocol.mode != T_ATM_BLLI_NORMAL_MODE) &&
888 (p.bll.layer_3_protocol.mode != T_ATM_BLLI_EXTENDED_MODE))
889 return (EINVAL);
890 if ((p.bll.layer_3_protocol.packet_size != T_ATM_ABSENT) &&
891 (p.bll.layer_3_protocol.packet_size & MAXMASK(4)))
892 return (EINVAL);
893 if ((p.bll.layer_3_protocol.window_size != T_ATM_ABSENT) &&
894 (p.bll.layer_3_protocol.window_size < 1))
895 return (EINVAL);
896
897 if (p.bll.layer_2_protocol.ID_type == T_ATM_ABSENT)
898 atp->atp_attr.blli.tag_l2 = T_ATM_ABSENT;
899 else
900 atp->atp_attr.blli.tag_l2 = T_ATM_PRESENT;
901
902 if (p.bll.layer_3_protocol.ID_type == T_ATM_ABSENT)
903 atp->atp_attr.blli.tag_l3 = T_ATM_ABSENT;
904 else
905 atp->atp_attr.blli.tag_l3 = T_ATM_PRESENT;
906
907 if ((atp->atp_attr.blli.tag_l2 == T_ATM_PRESENT) ||
908 (atp->atp_attr.blli.tag_l3 == T_ATM_PRESENT))
909 atp->atp_attr.blli.v = p.bll;
910 break;
911
912 case T_ATM_DEST_ADDR:
913 err = sooptcopyin(sopt, &p.addr, sizeof p.addr, sizeof p.addr);
914 if (err)
915 break;
916 if ((p.addr.address_format != T_ATM_ENDSYS_ADDR) &&
917 (p.addr.address_format != T_ATM_E164_ADDR))
918 return (EINVAL);
919 if (p.addr.address_length > ATM_ADDR_LEN)
920 return (EINVAL);
921
922 atp->atp_attr.called.tag = T_ATM_PRESENT;
923 atp->atp_attr.called.addr = p.addr;
924 break;
925
926 case T_ATM_DEST_SUB:
927 err = sooptcopyin(sopt, &p.addr, sizeof p.addr, sizeof p.addr);
928 if (err)
929 break;
930 if ((p.addr.address_format != T_ATM_ABSENT) &&
931 (p.addr.address_format != T_ATM_NSAP_ADDR))
932 return (EINVAL);
933 if (p.addr.address_length > ATM_ADDR_LEN)
934 return (EINVAL);
935
936 /* T_ATM_DEST_ADDR controls tag */
937 atp->atp_attr.called.subaddr = p.addr;
938 break;
939
940 case T_ATM_ORIG_ADDR:
941 return (EACCES);
942
943 case T_ATM_ORIG_SUB:
944 return (EACCES);
945
946 case T_ATM_CALLER_ID:
947 return (EACCES);
948
949 case T_ATM_CAUSE:
950 err = sooptcopyin(sopt, &p.cau, sizeof p.cau, sizeof p.cau);
951 if (err)
952 break;
953 if ((p.cau.coding_standard != T_ATM_ABSENT) &&
954 (p.cau.coding_standard != T_ATM_ITU_CODING) &&
955 (p.cau.coding_standard != T_ATM_NETWORK_CODING))
956 return (EINVAL);
957 if ((p.cau.location != T_ATM_LOC_USER) &&
958 (p.cau.location != T_ATM_LOC_LOCAL_PRIVATE_NET) &&
959 (p.cau.location != T_ATM_LOC_LOCAL_PUBLIC_NET) &&
960 (p.cau.location != T_ATM_LOC_TRANSIT_NET) &&
961 (p.cau.location != T_ATM_LOC_REMOTE_PUBLIC_NET) &&
962 (p.cau.location != T_ATM_LOC_REMOTE_PRIVATE_NET) &&
963 (p.cau.location != T_ATM_LOC_INTERNATIONAL_NET) &&
964 (p.cau.location != T_ATM_LOC_BEYOND_INTERWORKING))
965 return (EINVAL);
966
967 if (p.cau.coding_standard == T_ATM_ABSENT)
968 atp->atp_attr.cause.tag = T_ATM_ABSENT;
969 else {
970 atp->atp_attr.cause.tag = T_ATM_PRESENT;
971 atp->atp_attr.cause.v = p.cau;
972 }
973 break;
974
975 case T_ATM_QOS:
976 err = sooptcopyin(sopt, &p.qos, sizeof p.qos, sizeof p.qos);
977 if (err)
978 break;
979 if ((p.qos.coding_standard != T_ATM_ABSENT) &&
980 (p.qos.coding_standard != T_ATM_ITU_CODING) &&
981 (p.qos.coding_standard != T_ATM_NETWORK_CODING))
982 return (EINVAL);
983 if ((p.qos.forward.qos_class != T_ATM_QOS_CLASS_0) &&
984 (p.qos.forward.qos_class != T_ATM_QOS_CLASS_1) &&
985 (p.qos.forward.qos_class != T_ATM_QOS_CLASS_2) &&
986 (p.qos.forward.qos_class != T_ATM_QOS_CLASS_3) &&
987 (p.qos.forward.qos_class != T_ATM_QOS_CLASS_4))
988 return (EINVAL);
989 if ((p.qos.backward.qos_class != T_ATM_QOS_CLASS_0) &&
990 (p.qos.backward.qos_class != T_ATM_QOS_CLASS_1) &&
991 (p.qos.backward.qos_class != T_ATM_QOS_CLASS_2) &&
992 (p.qos.backward.qos_class != T_ATM_QOS_CLASS_3) &&
993 (p.qos.backward.qos_class != T_ATM_QOS_CLASS_4))
994 return (EINVAL);
995
996 if (p.qos.coding_standard == T_ATM_ABSENT)
997 atp->atp_attr.qos.tag = T_ATM_ABSENT;
998 else {
999 atp->atp_attr.qos.tag = T_ATM_PRESENT;
1000 atp->atp_attr.qos.v = p.qos;
1001 }
1002 break;
1003
1004 case T_ATM_TRANSIT:
1005 err = sooptcopyin(sopt, &p.trn, sizeof p.trn, sizeof p.trn);
1006 if (err)
1007 break;
1008 if (p.trn.length > T_ATM_MAX_NET_ID)
1009 return (EINVAL);
1010
1011 if (p.trn.length == 0)
1012 atp->atp_attr.transit.tag = T_ATM_ABSENT;
1013 else {
1014 atp->atp_attr.transit.tag = T_ATM_PRESENT;
1015 atp->atp_attr.transit.v = p.trn;
1016 }
1017 break;
1018
1019 case T_ATM_ADD_LEAF:
1020 return (EPROTONOSUPPORT); /* XXX */
1021
1022 case T_ATM_DROP_LEAF:
1023 return (EPROTONOSUPPORT); /* XXX */
1024
1025 case T_ATM_NET_INTF:
1026 err = sooptcopyin(sopt, &p.nif, sizeof p.nif, sizeof p.nif);
1027 if (err)
1028 break;
1029
1030 atp->atp_attr.nif = atm_nifname(p.nif.net_intf);
1031 if (atp->atp_attr.nif == NULL)
1032 return (ENXIO);
1033 break;
1034
1035 case T_ATM_LLC:
1036 err = sooptcopyin(sopt, &p.llc, sizeof p.llc, sizeof p.llc);
1037 if (err)
1038 break;
1039 if ((p.llc.llc_len < T_ATM_LLC_MIN_LEN) ||
1040 (p.llc.llc_len > T_ATM_LLC_MAX_LEN))
1041 return (EINVAL);
1042
1043 atp->atp_attr.llc.tag = T_ATM_PRESENT;
1044 atp->atp_attr.llc.v = p.llc;
1045 break;
1046
1047 case T_ATM_APP_NAME:
1048 err = sooptcopyin(sopt, &p.appn, sizeof p.appn, sizeof p.appn);
1049 if (err)
1050 break;
1051
1052 strncpy(atp->atp_name, p.appn.app_name, T_ATM_APP_NAME_LEN);
1053 break;
1054
1055 default:
1056 return (ENOPROTOOPT);
1057 }
1058
1059 return (err);
1060 }
1061
1062
1063 /*
1064 * Common getsockopt processing
1065 *
1066 * Called at splnet.
1067 *
1068 * Arguments:
1069 * so pointer to socket
1070 * sopt pointer to socket option info
1071 * atp pointer to ATM PCB
1072 *
1073 * Returns:
1074 * 0 request processed
1075 * errno error processing request - reason indicated
1076 *
1077 */
1078 int
1079 atm_sock_getopt(so, sopt, atp)
1080 struct socket *so;
1081 struct sockopt *sopt;
1082 Atm_pcb *atp;
1083 {
1084 Atm_attributes *ap;
1085
1086 /*
1087 * If socket is connected, return attributes for the VCC in use,
1088 * otherwise just return what the user has setup so far.
1089 */
1090 if (so->so_state & SS_ISCONNECTED)
1091 ap = &atp->atp_conn->co_connvc->cvc_attr;
1092 else
1093 ap = &atp->atp_attr;
1094
1095 switch (sopt->sopt_name) {
1096
1097 case T_ATM_AAL5:
1098 if ((ap->aal.tag == T_ATM_PRESENT) &&
1099 (ap->aal.type == ATM_AAL5)) {
1100 return (sooptcopyout(sopt, &ap->aal.v.aal5,
1101 sizeof ap->aal.v.aal5));
1102 } else {
1103 return (ENOENT);
1104 }
1105 break;
1106
1107 case T_ATM_TRAFFIC:
1108 if (ap->traffic.tag == T_ATM_PRESENT) {
1109 return (sooptcopyout(sopt, &ap->traffic.v,
1110 sizeof ap->traffic.v));
1111 } else {
1112 return (ENOENT);
1113 }
1114 break;
1115
1116 case T_ATM_BEARER_CAP:
1117 if (ap->bearer.tag == T_ATM_PRESENT) {
1118 return (sooptcopyout(sopt, &ap->bearer.v,
1119 sizeof ap->bearer.v));
1120 } else {
1121 return (ENOENT);
1122 }
1123 break;
1124
1125 case T_ATM_BHLI:
1126 if (ap->bhli.tag == T_ATM_PRESENT) {
1127 return (sooptcopyout(sopt, &ap->bhli.v,
1128 sizeof ap->bhli.v));
1129 } else {
1130 return (ENOENT);
1131 }
1132 break;
1133
1134 case T_ATM_BLLI:
1135 if ((ap->blli.tag_l2 == T_ATM_PRESENT) ||
1136 (ap->blli.tag_l3 == T_ATM_PRESENT)) {
1137 return (sooptcopyout(sopt, &ap->blli.v,
1138 sizeof ap->blli.v));
1139 } else {
1140 return (ENOENT);
1141 }
1142 break;
1143
1144 case T_ATM_DEST_ADDR:
1145 if (ap->called.tag == T_ATM_PRESENT) {
1146 return (sooptcopyout(sopt, &ap->called.addr,
1147 sizeof ap->called.addr));
1148 } else {
1149 return (ENOENT);
1150 }
1151 break;
1152
1153 case T_ATM_DEST_SUB:
1154 if (ap->called.tag == T_ATM_PRESENT) {
1155 return (sooptcopyout(sopt, &ap->called.subaddr,
1156 sizeof ap->called.subaddr));
1157 } else {
1158 return (ENOENT);
1159 }
1160 break;
1161
1162 case T_ATM_ORIG_ADDR:
1163 if (ap->calling.tag == T_ATM_PRESENT) {
1164 return (sooptcopyout(sopt, &ap->calling.addr,
1165 sizeof ap->calling.addr));
1166 } else {
1167 return (ENOENT);
1168 }
1169 break;
1170
1171 case T_ATM_ORIG_SUB:
1172 if (ap->calling.tag == T_ATM_PRESENT) {
1173 return (sooptcopyout(sopt, &ap->calling.subaddr,
1174 sizeof ap->calling.subaddr));
1175 } else {
1176 return (ENOENT);
1177 }
1178 break;
1179
1180 case T_ATM_CALLER_ID:
1181 if (ap->calling.tag == T_ATM_PRESENT) {
1182 return (sooptcopyout(sopt, &ap->calling.cid,
1183 sizeof ap->calling.cid));
1184 } else {
1185 return (ENOENT);
1186 }
1187 break;
1188
1189 case T_ATM_CAUSE:
1190 if (ap->cause.tag == T_ATM_PRESENT) {
1191 return (sooptcopyout(sopt, &ap->cause.v,
1192 sizeof ap->cause.v));
1193 } else {
1194 return (ENOENT);
1195 }
1196 break;
1197
1198 case T_ATM_QOS:
1199 if (ap->qos.tag == T_ATM_PRESENT) {
1200 return (sooptcopyout(sopt, &ap->qos.v,
1201 sizeof ap->qos.v));
1202 } else {
1203 return (ENOENT);
1204 }
1205 break;
1206
1207 case T_ATM_TRANSIT:
1208 if (ap->transit.tag == T_ATM_PRESENT) {
1209 return (sooptcopyout(sopt, &ap->transit.v,
1210 sizeof ap->transit.v));
1211 } else {
1212 return (ENOENT);
1213 }
1214 break;
1215
1216 case T_ATM_LEAF_IND:
1217 return (EPROTONOSUPPORT); /* XXX */
1218
1219 case T_ATM_NET_INTF:
1220 if (ap->nif) {
1221 struct t_atm_net_intf netif;
1222 struct ifnet *ifp;
1223
1224 ifp = &ap->nif->nif_if;
1225 (void) snprintf(netif.net_intf, sizeof(netif.net_intf),
1226 "%s%d", ifp->if_name, ifp->if_unit);
1227 return (sooptcopyout(sopt, &netif,
1228 sizeof netif));
1229 } else {
1230 return (ENOENT);
1231 }
1232 break;
1233
1234 case T_ATM_LLC:
1235 if (ap->llc.tag == T_ATM_PRESENT) {
1236 return (sooptcopyout(sopt, &ap->llc.v,
1237 sizeof ap->llc.v));
1238 } else {
1239 return (ENOENT);
1240 }
1241 break;
1242
1243 default:
1244 return (ENOPROTOOPT);
1245 }
1246
1247 return (0);
1248 }
1249
1250
1251 /*
1252 * Process Socket VCC Connected Notification
1253 *
1254 * Arguments:
1255 * toku owner's connection token (atm_pcb protocol block)
1256 *
1257 * Returns:
1258 * none
1259 *
1260 */
1261 void
1262 atm_sock_connected(toku)
1263 void *toku;
1264 {
1265 Atm_pcb *atp = (Atm_pcb *)toku;
1266
1267 /*
1268 * Connection is setup
1269 */
1270 atm_sock_stat.as_conncomp[atp->atp_type]++;
1271 soisconnected(atp->atp_socket);
1272 }
1273
1274
1275 /*
1276 * Process Socket VCC Cleared Notification
1277 *
1278 * Arguments:
1279 * toku owner's connection token (atm_pcb protocol block)
1280 * cause pointer to cause code
1281 *
1282 * Returns:
1283 * none
1284 *
1285 */
1286 void
1287 atm_sock_cleared(toku, cause)
1288 void *toku;
1289 struct t_atm_cause *cause;
1290 {
1291 Atm_pcb *atp = (Atm_pcb *)toku;
1292 struct socket *so;
1293
1294 so = atp->atp_socket;
1295
1296 /*
1297 * Save call clearing cause
1298 */
1299 atp->atp_attr.cause.tag = T_ATM_PRESENT;
1300 atp->atp_attr.cause.v = *cause;
1301
1302 /*
1303 * Set user error code
1304 */
1305 if (so->so_state & SS_ISCONNECTED) {
1306 so->so_error = ECONNRESET;
1307 atm_sock_stat.as_connclr[atp->atp_type]++;
1308 } else {
1309 so->so_error = ECONNREFUSED;
1310 atm_sock_stat.as_connfail[atp->atp_type]++;
1311 }
1312
1313 /*
1314 * Connection is gone
1315 */
1316 atp->atp_conn = NULL;
1317 soisdisconnected(so);
1318
1319 /*
1320 * Cleanup failed incoming connection setup
1321 */
1322 if (so->so_state & SS_NOFDREF) {
1323 (void) atm_sock_detach(so);
1324 }
1325 }
1326
Cache object: aa32fc40e371f878d99bdb9f43f14c04
|