kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / netproto / atm / spans / spans_cls.c
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: src/sys/netatm/spans/spans_cls.c,v 1.6 1999/08/28 00:48:49 peter Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/spans/spans_cls.c,v 1.4 2003/08/07 21:54:34 dillon Exp $
28  */
29
30 /*
31  * SPANS Signalling Manager
32  * ---------------------------
33  *
34  * SPANS Connectionless Datagram Service (CLS) module
35  *
36  */
37
38 #include <netproto/atm/kern_include.h>
39
40 #include <netproto/atm/ipatm/ipatm_var.h>
41 #include <netproto/atm/ipatm/ipatm_serv.h>
42 #include "spans_xdr.h"
43 #include "spans_var.h"
44 #include "spans_cls.h"
45
46 /*
47  * Global variables
48  */
49 int     spanscls_print = 0;
50
51 struct spanscls *spanscls_head = NULL;
52
53 struct spans_addr       spans_bcastaddr = {
54         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
55 };
56
57 struct spanscls_hdr     spanscls_hdr = {
58         { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, /* dst */
59         { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, /* src */
60         0x00, 0x00, 0,
61         0xaa, 0xaa, 0x03, { 0x00, 0x00, 0x00 }, 0               /* LLC SNAP */
62 };
63
64
65 /*
66  * Local functions
67  */
68 static int      spanscls_ipact __P((struct ip_nif *));
69 static int      spanscls_ipdact __P((struct ip_nif *));
70 static int      spanscls_bcast_output __P((struct ip_nif *, KBuffer *));
71 static void     spanscls_cpcs_data __P((void *, KBuffer *));
72 static void     spanscls_connected __P((void *));
73 static void     spanscls_cleared __P((void *, struct t_atm_cause *));
74 static caddr_t  spanscls_getname __P((void *));
75 static void     spanscls_pdu_print __P((struct spanscls *, KBuffer *,
76                         char *));
77
78 /*
79  * Local variables
80  */
81 static struct sp_info  spanscls_pool = {
82         "spans cls pool",               /* si_name */
83         sizeof(struct spanscls),        /* si_blksiz */
84         2,                              /* si_blkcnt */
85         100                             /* si_maxallow */
86 };
87
88 static struct ip_serv   spanscls_ipserv = {
89         spanscls_ipact,
90         spanscls_ipdact,
91         spansarp_ioctl,
92         NULL,
93         spansarp_svcout,
94         spansarp_svcin,
95         spansarp_svcactive,
96         spansarp_vcclose,
97         spanscls_bcast_output,
98         {
99                 {ATM_AAL5, ATM_ENC_NULL},
100                 {ATM_AAL3_4, ATM_ENC_NULL}
101         }
102 };
103
104 static u_char   spanscls_bridged[] = {
105         0x00, 0x00, 0x00, 0x00,
106         0xaa, 0xaa, 0x03, 0x00, 0x80, 0xc2      /* LLC SNAP */
107 };
108
109 static Atm_endpoint     spanscls_endpt = {
110         NULL,
111         ENDPT_SPANS_CLS,
112         NULL,
113         spanscls_getname,
114         spanscls_connected,
115         spanscls_cleared,
116         NULL,
117         NULL,
118         NULL,
119         NULL,
120         spanscls_cpcs_data,
121         NULL,
122         NULL,
123         NULL,
124         NULL
125 };
126
127 static Atm_attributes   spanscls_attr = {
128         NULL,                   /* nif */
129         CMAPI_CPCS,             /* api */
130         0,                      /* api_init */
131         0,                      /* headin */
132         0,                      /* headout */
133         {                       /* aal */
134                 T_ATM_PRESENT,
135                 ATM_AAL3_4
136         },
137         {                       /* traffic */
138                 T_ATM_PRESENT,
139                 {
140                         {
141                                 T_ATM_ABSENT,
142                                 0,
143                                 T_ATM_ABSENT,
144                                 T_ATM_ABSENT,
145                                 T_ATM_ABSENT,
146                                 T_ATM_ABSENT,
147                                 T_NO
148                         },
149                         {
150                                 T_ATM_ABSENT,
151                                 0,
152                                 T_ATM_ABSENT,
153                                 T_ATM_ABSENT,
154                                 T_ATM_ABSENT,
155                                 T_ATM_ABSENT,
156                                 T_NO
157                         },
158                         T_YES
159                 },
160         },
161         {                       /* bearer */
162                 T_ATM_PRESENT,
163                 {
164                         T_ATM_CLASS_X,
165                         T_ATM_NULL,
166                         T_ATM_NULL,
167                         T_NO,
168                         T_ATM_1_TO_1
169                 }
170         },
171         {                       /* bhli */
172                 T_ATM_ABSENT
173         },
174         {                       /* blli */
175                 T_ATM_ABSENT,
176                 T_ATM_ABSENT
177         },
178         {                       /* llc */
179                 T_ATM_ABSENT
180         },
181         {                       /* called */
182                 T_ATM_PRESENT,
183         },
184         {                       /* calling */
185                 T_ATM_ABSENT
186         },
187         {                       /* qos */
188                 T_ATM_PRESENT,
189                 {
190                         T_ATM_NETWORK_CODING,
191                         {
192                                 T_ATM_QOS_CLASS_0,
193                         },
194                         {
195                                 T_ATM_QOS_CLASS_0
196                         }
197                 }
198         },
199         {                       /* transit */
200                 T_ATM_ABSENT
201         },
202         {                       /* cause */
203                 T_ATM_ABSENT
204         }
205 };
206
207 static struct t_atm_cause       spanscls_cause = {
208         T_ATM_ITU_CODING,
209         T_ATM_LOC_USER,
210         T_ATM_CAUSE_UNSPECIFIED_NORMAL,
211         {0, 0, 0, 0}
212 };
213
214
215 /*
216  * Process module loading
217  * 
218  * Called whenever the spans module is initializing.  
219  *
220  * Arguments:
221  *      none
222  *
223  * Returns:
224  *      0       initialization successful
225  *      errno   initialization failed - reason indicated
226  *
227  */
228 int
229 spanscls_start()
230 {
231         int     err;
232
233         /*
234          * Fill in union fields
235          */
236         spanscls_attr.aal.v.aal4.forward_max_SDU_size = ATM_NIF_MTU;
237         spanscls_attr.aal.v.aal4.backward_max_SDU_size = ATM_NIF_MTU;
238         spanscls_attr.aal.v.aal4.SSCS_type = T_ATM_NULL;
239         spanscls_attr.aal.v.aal4.mid_low = 0;
240         spanscls_attr.aal.v.aal4.mid_high = 1023;
241
242         /*
243          * Register our endpoint
244          */
245         err = atm_endpoint_register(&spanscls_endpt);
246
247         return (err);
248 }
249
250
251 /*
252  * Process module unloading notification
253  * 
254  * Called whenever the spans module is about to be unloaded.  All signalling
255  * instances will have been previously detached.  All spanscls resources
256  * must be freed now.
257  *
258  * Arguments:
259  *      none
260  *
261  * Returns:
262  *      none
263  *
264  */
265 void
266 spanscls_stop()
267 {
268         int     s = splnet();
269
270         /*
271          * Tell ARP to stop
272          */
273         spansarp_stop();
274
275         /*
276          * Nothing should be left here...
277          */
278         if (spanscls_head) {
279                 panic("spanscls_stop: bad state");
280         }
281         (void) splx(s);
282
283         /*
284          * De-register ourselves
285          */
286         (void) atm_endpoint_deregister(&spanscls_endpt);
287
288         /*
289          * Free our storage pools
290          */
291         atm_release_pool(&spanscls_pool);
292 }
293
294
295 /*
296  * Process signalling interface attach
297  * 
298  * This function is called whenever a physical interface has been attached
299  * to spans.  We will open the CLS PVC and await further events.
300  *
301  * Called at splnet.
302  *
303  * Arguments:
304  *      spp     pointer to spans signalling protocol instance
305  *
306  * Returns:
307  *      0       attach successful
308  *      errno   attach failed - reason indicated
309  *
310  */
311 int
312 spanscls_attach(spp)
313         struct spans    *spp;
314 {
315         struct spanscls *clp;
316         Atm_addr_pvc    *pvcp;
317         int     err;
318
319         /*
320          * Get a new cls control block
321          */
322         clp = (struct spanscls *)atm_allocate(&spanscls_pool);
323         if (clp == NULL)
324                 return (ENOMEM);
325
326         /*
327          * Initialize some stuff
328          */
329         clp->cls_state = CLS_CLOSED;
330         clp->cls_spans = spp;
331         spp->sp_ipserv = &spanscls_ipserv;
332
333         /*
334          * Fill out connection attributes
335          */
336         spanscls_attr.nif = spp->sp_pif->pif_nif;
337         spanscls_attr.traffic.v.forward.PCR_all_traffic = spp->sp_pif->pif_pcr;
338         spanscls_attr.traffic.v.backward.PCR_all_traffic = spp->sp_pif->pif_pcr;
339         spanscls_attr.called.addr.address_format = T_ATM_PVC_ADDR;
340         spanscls_attr.called.addr.address_length = sizeof(Atm_addr_pvc);
341         pvcp = (Atm_addr_pvc *)spanscls_attr.called.addr.address;
342         ATM_PVC_SET_VPI(pvcp, SPANS_CLS_VPI);
343         ATM_PVC_SET_VCI(pvcp, SPANS_CLS_VCI);
344         spanscls_attr.called.subaddr.address_format = T_ATM_ABSENT;
345         spanscls_attr.called.subaddr.address_length = 0;
346
347         /*
348          * Create SPANS Connectionless Service (CLS) PVC
349          */
350         err = atm_cm_connect(&spanscls_endpt, clp, &spanscls_attr,
351                         &clp->cls_conn);
352         if (err) {
353                 atm_free((caddr_t)clp);
354                 return (err);
355         }
356
357         /*
358          * Set new state and link instance
359          */
360         clp->cls_state = CLS_OPEN;
361         LINK2TAIL(clp, struct spanscls, spanscls_head, cls_next);
362         spp->sp_cls = clp;
363
364         return (0);
365 }
366
367
368 /*
369  * Process signalling interface detach
370  * 
371  * This function is called whenever a physical interface has been detached
372  * from spans.  We will close the CLS PVC and clean up everything.
373  *
374  * Called at splnet.
375  *
376  * Arguments:
377  *      spp     pointer to spans signalling protocol instance
378  *
379  * Returns:
380  *      none
381  *
382  */
383 void
384 spanscls_detach(spp)
385         struct spans    *spp;
386 {
387         struct spanscls *clp;
388
389         /*
390          * Get our control block
391          */
392         clp = spp->sp_cls;
393         if (clp == NULL)
394                 return;
395
396         /*
397          * Just checking up on things...
398          */
399         if (clp->cls_ipnif)
400                 panic("spanscls_detach: IP interface still active");
401
402         /*
403          * Close CLS PVC
404          */
405         spanscls_closevc(clp, &spanscls_cause);
406
407         /*
408          * Sever links and free server block, if possible
409          */
410         clp->cls_spans = NULL;
411         spp->sp_cls = NULL;
412         if (clp->cls_state == CLS_CLOSED) {
413                 UNLINK(clp, struct spanscls, spanscls_head, cls_next);
414                 atm_free((caddr_t)clp);
415         }
416 }
417
418
419 /*
420  * Process IP Network Interface Activation
421  * 
422  * Called whenever an IP network interface becomes active.
423  *
424  * Called at splnet.
425  *
426  * Arguments:
427  *      inp     pointer to IP network interface
428  *
429  * Returns:
430  *      0       command successful
431  *      errno   command failed - reason indicated
432  *
433  */
434 static int
435 spanscls_ipact(inp)
436         struct ip_nif   *inp;
437 {
438         struct spans            *spp;
439         struct spanscls         *clp;
440
441         /*
442          * Get corresponding cls instance
443          */
444         spp = (struct spans *)inp->inf_nif->nif_pif->pif_siginst;
445         if ((spp == NULL) || ((clp = spp->sp_cls) == NULL))
446                 return (ENXIO);
447
448         /*
449          * Make sure it's not already activated
450          */
451         if (clp->cls_ipnif)
452                 return (EEXIST);
453
454         /*
455          * Set two-way links with IP world
456          */
457         clp->cls_ipnif = inp;
458         inp->inf_isintf = (caddr_t)clp;
459
460         /*
461          * Tell arp about new interface
462          */
463         spansarp_ipact(clp);
464
465         return (0);
466 }
467
468
469 /*
470  * Process IP Network Interface Deactivation
471  * 
472  * Called whenever an IP network interface becomes inactive.
473  *
474  * Called at splnet.
475  *
476  * Arguments:
477  *      inp     pointer to IP network interface
478  *
479  * Returns:
480  *      0       command successful
481  *      errno   command failed - reason indicated
482  *
483  */
484 static int
485 spanscls_ipdact(inp)
486         struct ip_nif   *inp;
487 {
488         struct spanscls         *clp;
489
490         /*
491          * Get cls instance and make sure it's been activated
492          */
493         clp = (struct spanscls *)inp->inf_isintf;
494         if ((clp == NULL) || (clp->cls_ipnif == NULL))
495                 return (ENXIO);
496
497         /*
498          * Let arp know about this
499          */
500         spansarp_ipdact(clp);
501
502         /*
503          * Clear IP interface pointer
504          */
505         clp->cls_ipnif = NULL;
506         return (0);
507 }
508
509
510 /*
511  * Output IP Broadcast Packet
512  * 
513  * Called whenever an IP broadcast packet is sent to this interface.
514  *
515  * Arguments:
516  *      inp     pointer to IP network interface
517  *      m       pointer to packet buffer chain
518  *
519  * Returns:
520  *      0       packet sent successfully
521  *      errno   send failed - reason indicated
522  *
523  */
524 static int
525 spanscls_bcast_output(inp, m)
526         struct ip_nif   *inp;
527         KBuffer         *m;
528 {
529         struct spans            *spp;
530         struct spanscls         *clp;
531         struct spanscls_hdr     *chp;
532         int                     err, space;
533
534         /*
535          * Get cls instance and make sure it's been activated
536          */
537         clp = (struct spanscls *)inp->inf_isintf;
538         if ((clp == NULL) || (clp->cls_ipnif == NULL)) {
539                 KB_FREEALL(m);
540                 return (ENETDOWN);
541         }
542
543         /*
544          * Make sure that we know our addresses
545          */
546         spp = clp->cls_spans;
547         if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR) {
548                 KB_FREEALL(m);
549                 return (ENETDOWN);
550         }
551
552         /*
553          * See if there's room to add CLS header to front of packet.
554          */
555         KB_HEADROOM(m, space);
556         if (space < sizeof(struct spanscls_hdr)) {
557                 KBuffer         *n;
558
559                 /*
560                  * We have to allocate another buffer and tack it
561                  * onto the front of the packet
562                  */
563                 KB_ALLOCPKT(n, sizeof(struct spanscls_hdr),
564                         KB_F_NOWAIT, KB_T_HEADER);
565                 if (n == 0) {
566                         KB_FREEALL(m);
567                         return (ENOBUFS);
568                 }
569                 KB_TAILALIGN(n, sizeof(struct spanscls_hdr));
570                 KB_LINKHEAD(n, m);
571                 m = n;
572         } else {
573                 /*
574                  * Header fits, just adjust buffer controls
575                  */
576                 KB_HEADADJ(m, sizeof(struct spanscls_hdr));
577         }
578
579         /*
580          * Now, build the CLS header
581          */
582         KB_DATASTART(m, chp, struct spanscls_hdr *);
583         spans_addr_copy(&spans_bcastaddr, &chp->ch_dst);
584         spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
585         *(u_int *)&chp->ch_proto = *(u_int *)&spanscls_hdr.ch_proto;
586         *(u_int *)&chp->ch_dsap = *(u_int *)&spanscls_hdr.ch_dsap;
587         *(u_short *)&chp->ch_oui[1] = *(u_short *)&spanscls_hdr.ch_oui[1];
588         chp->ch_pid = htons(ETHERTYPE_IP);
589
590 #ifdef DIAGNOSTIC
591         if (spanscls_print)
592                 spanscls_pdu_print(clp, m, "output");
593 #endif
594
595         /*
596          * Finally, send the pdu via the CLS service
597          */
598         err = atm_cm_cpcs_data(clp->cls_conn, m);
599         if (err) {
600                 KB_FREEALL(m);
601                 return (ENOBUFS);
602         }
603
604         return (0);
605 }
606
607
608 /*
609  * Process VCC Input Data
610  * 
611  * All input packets received from CLS VCC lower layers are processed here.
612  *
613  * Arguments:
614  *      tok     connection token (pointer to CLS VCC control block)
615  *      m       pointer to input packet buffer chain
616  *
617  * Returns:
618  *      none
619  *
620  */
621 static void
622 spanscls_cpcs_data(tok, m)
623         void            *tok;
624         KBuffer         *m;
625 {
626         struct spanscls *clp = tok;
627         struct spans    *spp = clp->cls_spans;
628         struct spanscls_hdr     *chp;
629         struct ip_nif   *inp;
630
631         /*
632          * Make sure we're ready
633          */
634         if ((clp->cls_state != CLS_OPEN) || (spp->sp_state != SPANS_ACTIVE)) {
635                 KB_FREEALL(m);
636                 return;
637         }
638
639 #ifdef DIAGNOSTIC
640         if (spanscls_print)
641                 spanscls_pdu_print(clp, m, "input");
642 #endif
643
644         /*
645          * Get CLS header into buffer
646          */
647         if (KB_LEN(m) < sizeof(struct spanscls_hdr)) {
648                 KB_PULLUP(m, sizeof(struct spanscls_hdr), m);
649                 if (m == 0)
650                         return;
651         }
652         KB_DATASTART(m, chp, struct spanscls_hdr *);
653
654         /*
655          * Verify packet information
656          */
657         if ((*(u_int *)&chp->ch_proto != *(u_int *)&spanscls_hdr.ch_proto) ||
658             (*(u_int *)&chp->ch_dsap != *(u_int *)&spanscls_hdr.ch_dsap) ||
659             (*(u_short *)&chp->ch_oui[1] != 
660                                 *(u_short *)&spanscls_hdr.ch_oui[1])) {
661
662                 /*
663                  * Check for bridged PDU
664                  */
665                 if (bcmp((char *)&chp->ch_proto, (char *)spanscls_bridged, 
666                                 sizeof(spanscls_bridged))) {
667                         log(LOG_ERR, "spanscls_input: bad format\n");
668 #ifdef DIAGNOSTIC
669                         spanscls_pdu_print(clp, m, "input error"); 
670 #endif
671                 }
672
673                 KB_FREEALL(m);
674                 return;
675         }
676
677         /*
678          * Make sure packet is for us
679          */
680         if (spans_addr_cmp(&chp->ch_dst, spp->sp_addr.address) &&
681             spans_addr_cmp(&chp->ch_dst, &spans_bcastaddr)) {
682                 KB_FREEALL(m);
683                 return;
684         }
685
686         /*
687          * Do protocol processing
688          */
689         switch (ntohs(chp->ch_pid)) {
690
691         case ETHERTYPE_IP:
692                 /*
693                  * Drop CLS header
694                  */
695                 KB_HEADADJ(m, -sizeof(struct spanscls_hdr));
696                 KB_PLENADJ(m, -sizeof(struct spanscls_hdr));
697
698                 /*
699                  * Packet is ready for input to IP
700                  */
701                 if ((inp = clp->cls_ipnif) != NULL)
702                         (void) (*inp->inf_ipinput)(inp, m);
703                 else
704                         KB_FREEALL(m);
705                 break;
706
707         case ETHERTYPE_ARP:
708                 spansarp_input(clp, m);
709                 break;
710
711         default:
712                 log(LOG_ERR, "spanscls_input: unknown protocol 0x%x\n",
713                         chp->ch_pid);
714                 KB_FREEALL(m);
715                 return;
716         }
717 }
718
719
720 /*
721  * Close a SPANS CLS VCC
722  * 
723  * This function will close a SPANS CLS VCC.
724  *
725  * Arguments:
726  *      clp     pointer to CLS instance
727  *      cause   pointer to cause code
728  *
729  * Returns:
730  *      none
731  *
732  */
733 void
734 spanscls_closevc(clp, cause)
735         struct spanscls *clp;
736         struct t_atm_cause      *cause;
737 {
738         int     err;
739
740         /*
741          * Close VCC
742          */
743         if (clp->cls_conn) {
744                 err = atm_cm_release(clp->cls_conn, cause);
745                 if (err) {
746                         log(LOG_ERR, "spanscls_closevc: release err=%d\n", err);
747                 }
748                 clp->cls_conn = NULL;
749         }
750
751         clp->cls_state = CLS_CLOSED;
752 }
753
754
755 /*
756  * Process CLS VCC Connected Notification
757  * 
758  * Arguments:
759  *      toku    user's connection token (spanscls protocol block)
760  *
761  * Returns:
762  *      none
763  *
764  */
765 static void
766 spanscls_connected(toku)
767         void            *toku;
768 {
769         /*
770          * We should never get one of these
771          */
772         log(LOG_ERR, "spanscls: unexpected connected event\n");
773 }
774
775
776 /*
777  * Process CLS VCC Cleared Notification
778  * 
779  * Arguments:
780  *      toku    user's connection token (spanscls protocol block)
781  *      cause   pointer to cause code
782  *
783  * Returns:
784  *      none
785  *
786  */
787 static void
788 spanscls_cleared(toku, cause)
789         void            *toku;
790         struct t_atm_cause      *cause;
791 {
792         struct spanscls *clp = (struct spanscls *)toku;
793
794         /*
795          * CLS VCC has been closed, so clean up our side
796          */
797         clp->cls_conn = NULL;
798         spanscls_closevc(clp, cause);
799 }
800
801
802 /*
803  * Get Connection's Application/Owner Name
804  * 
805  * Arguments:
806  *      tok     spanscls connection token
807  *
808  * Returns:
809  *      addr    pointer to string containing our name
810  *
811  */
812 static caddr_t
813 spanscls_getname(tok)
814         void            *tok;
815 {
816         return ("SPANSCLS");
817 }
818
819
820 /*
821  * Print a SPANS CLS PDU
822  * 
823  * Arguments:
824  *      clp     pointer to cls instance
825  *      m       pointer to pdu buffer chain
826  *      msg     pointer to message string
827  *
828  * Returns:
829  *      none
830  *
831  */
832 static void
833 spanscls_pdu_print(clp, m, msg)
834         struct spanscls *clp;
835         KBuffer         *m;
836         char            *msg;
837 {
838         char            buf[128];
839
840         snprintf(buf, sizeof(buf), "spanscls %s:\n", msg);
841         atm_pdu_print(m, buf);
842 }
843