carp: add carp_group_demote_adj()
[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.8 2006/12/20 18:14:43 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 (struct ip_nif *);
69 static int      spanscls_ipdact (struct ip_nif *);
70 static int      spanscls_bcast_output (struct ip_nif *, KBuffer *);
71 static void     spanscls_cpcs_data (void *, KBuffer *);
72 static void     spanscls_connected (void *);
73 static void     spanscls_cleared (void *, struct t_atm_cause *);
74 static caddr_t  spanscls_getname (void *);
75 static void     spanscls_pdu_print (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(void)
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(void)
267 {
268         crit_enter();
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         crit_exit();
282
283         /*
284          * De-register ourselves
285          */
286         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 from a critical section.
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(struct spans *spp)
313 {
314         struct spanscls *clp;
315         Atm_addr_pvc    *pvcp;
316         int     err;
317
318         /*
319          * Get a new cls control block
320          */
321         clp = (struct spanscls *)atm_allocate(&spanscls_pool);
322         if (clp == NULL)
323                 return (ENOMEM);
324
325         /*
326          * Initialize some stuff
327          */
328         clp->cls_state = CLS_CLOSED;
329         clp->cls_spans = spp;
330         spp->sp_ipserv = &spanscls_ipserv;
331
332         /*
333          * Fill out connection attributes
334          */
335         spanscls_attr.nif = spp->sp_pif->pif_nif;
336         spanscls_attr.traffic.v.forward.PCR_all_traffic = spp->sp_pif->pif_pcr;
337         spanscls_attr.traffic.v.backward.PCR_all_traffic = spp->sp_pif->pif_pcr;
338         spanscls_attr.called.addr.address_format = T_ATM_PVC_ADDR;
339         spanscls_attr.called.addr.address_length = sizeof(Atm_addr_pvc);
340         pvcp = (Atm_addr_pvc *)spanscls_attr.called.addr.address;
341         ATM_PVC_SET_VPI(pvcp, SPANS_CLS_VPI);
342         ATM_PVC_SET_VCI(pvcp, SPANS_CLS_VCI);
343         spanscls_attr.called.subaddr.address_format = T_ATM_ABSENT;
344         spanscls_attr.called.subaddr.address_length = 0;
345
346         /*
347          * Create SPANS Connectionless Service (CLS) PVC
348          */
349         err = atm_cm_connect(&spanscls_endpt, clp, &spanscls_attr,
350                         &clp->cls_conn);
351         if (err) {
352                 atm_free((caddr_t)clp);
353                 return (err);
354         }
355
356         /*
357          * Set new state and link instance
358          */
359         clp->cls_state = CLS_OPEN;
360         LINK2TAIL(clp, struct spanscls, spanscls_head, cls_next);
361         spp->sp_cls = clp;
362
363         return (0);
364 }
365
366
367 /*
368  * Process signalling interface detach
369  * 
370  * This function is called whenever a physical interface has been detached
371  * from spans.  We will close the CLS PVC and clean up everything.
372  *
373  * Called from a critical section.
374  *
375  * Arguments:
376  *      spp     pointer to spans signalling protocol instance
377  *
378  * Returns:
379  *      none
380  *
381  */
382 void
383 spanscls_detach(struct spans *spp)
384 {
385         struct spanscls *clp;
386
387         /*
388          * Get our control block
389          */
390         clp = spp->sp_cls;
391         if (clp == NULL)
392                 return;
393
394         /*
395          * Just checking up on things...
396          */
397         if (clp->cls_ipnif)
398                 panic("spanscls_detach: IP interface still active");
399
400         /*
401          * Close CLS PVC
402          */
403         spanscls_closevc(clp, &spanscls_cause);
404
405         /*
406          * Sever links and free server block, if possible
407          */
408         clp->cls_spans = NULL;
409         spp->sp_cls = NULL;
410         if (clp->cls_state == CLS_CLOSED) {
411                 UNLINK(clp, struct spanscls, spanscls_head, cls_next);
412                 atm_free((caddr_t)clp);
413         }
414 }
415
416
417 /*
418  * Process IP Network Interface Activation
419  * 
420  * Called whenever an IP network interface becomes active.
421  *
422  * Called from a critical section.
423  *
424  * Arguments:
425  *      inp     pointer to IP network interface
426  *
427  * Returns:
428  *      0       command successful
429  *      errno   command failed - reason indicated
430  *
431  */
432 static int
433 spanscls_ipact(struct ip_nif *inp)
434 {
435         struct spans            *spp;
436         struct spanscls         *clp;
437
438         /*
439          * Get corresponding cls instance
440          */
441         spp = (struct spans *)inp->inf_nif->nif_pif->pif_siginst;
442         if ((spp == NULL) || ((clp = spp->sp_cls) == NULL))
443                 return (ENXIO);
444
445         /*
446          * Make sure it's not already activated
447          */
448         if (clp->cls_ipnif)
449                 return (EEXIST);
450
451         /*
452          * Set two-way links with IP world
453          */
454         clp->cls_ipnif = inp;
455         inp->inf_isintf = (caddr_t)clp;
456
457         /*
458          * Tell arp about new interface
459          */
460         spansarp_ipact(clp);
461
462         return (0);
463 }
464
465
466 /*
467  * Process IP Network Interface Deactivation
468  * 
469  * Called whenever an IP network interface becomes inactive.
470  *
471  * Called from a critical section.
472  *
473  * Arguments:
474  *      inp     pointer to IP network interface
475  *
476  * Returns:
477  *      0       command successful
478  *      errno   command failed - reason indicated
479  *
480  */
481 static int
482 spanscls_ipdact(struct ip_nif *inp)
483 {
484         struct spanscls         *clp;
485
486         /*
487          * Get cls instance and make sure it's been activated
488          */
489         clp = (struct spanscls *)inp->inf_isintf;
490         if ((clp == NULL) || (clp->cls_ipnif == NULL))
491                 return (ENXIO);
492
493         /*
494          * Let arp know about this
495          */
496         spansarp_ipdact(clp);
497
498         /*
499          * Clear IP interface pointer
500          */
501         clp->cls_ipnif = NULL;
502         return (0);
503 }
504
505
506 /*
507  * Output IP Broadcast Packet
508  * 
509  * Called whenever an IP broadcast packet is sent to this interface.
510  *
511  * Arguments:
512  *      inp     pointer to IP network interface
513  *      m       pointer to packet buffer chain
514  *
515  * Returns:
516  *      0       packet sent successfully
517  *      errno   send failed - reason indicated
518  *
519  */
520 static int
521 spanscls_bcast_output(struct ip_nif *inp, KBuffer *m)
522 {
523         struct spans            *spp;
524         struct spanscls         *clp;
525         struct spanscls_hdr     *chp;
526         int                     err, space;
527
528         /*
529          * Get cls instance and make sure it's been activated
530          */
531         clp = (struct spanscls *)inp->inf_isintf;
532         if ((clp == NULL) || (clp->cls_ipnif == NULL)) {
533                 KB_FREEALL(m);
534                 return (ENETDOWN);
535         }
536
537         /*
538          * Make sure that we know our addresses
539          */
540         spp = clp->cls_spans;
541         if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR) {
542                 KB_FREEALL(m);
543                 return (ENETDOWN);
544         }
545
546         /*
547          * See if there's room to add CLS header to front of packet.
548          */
549         KB_HEADROOM(m, space);
550         if (space < sizeof(struct spanscls_hdr)) {
551                 KBuffer         *n;
552
553                 /*
554                  * We have to allocate another buffer and tack it
555                  * onto the front of the packet
556                  */
557                 KB_ALLOCPKT(n, sizeof(struct spanscls_hdr),
558                         KB_F_NOWAIT, KB_T_HEADER);
559                 if (n == 0) {
560                         KB_FREEALL(m);
561                         return (ENOBUFS);
562                 }
563                 KB_TAILALIGN(n, sizeof(struct spanscls_hdr));
564                 KB_LINKHEAD(n, m);
565                 m = n;
566         } else {
567                 /*
568                  * Header fits, just adjust buffer controls
569                  */
570                 KB_HEADADJ(m, sizeof(struct spanscls_hdr));
571         }
572
573         /*
574          * Now, build the CLS header
575          */
576         KB_DATASTART(m, chp, struct spanscls_hdr *);
577         spans_addr_copy(&spans_bcastaddr, &chp->ch_dst);
578         spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
579         *(u_int *)&chp->ch_proto = *(u_int *)&spanscls_hdr.ch_proto;
580         *(u_int *)&chp->ch_dsap = *(u_int *)&spanscls_hdr.ch_dsap;
581         *(u_short *)&chp->ch_oui[1] = *(u_short *)&spanscls_hdr.ch_oui[1];
582         chp->ch_pid = htons(ETHERTYPE_IP);
583
584 #ifdef DIAGNOSTIC
585         if (spanscls_print)
586                 spanscls_pdu_print(clp, m, "output");
587 #endif
588
589         /*
590          * Finally, send the pdu via the CLS service
591          */
592         err = atm_cm_cpcs_data(clp->cls_conn, m);
593         if (err) {
594                 KB_FREEALL(m);
595                 return (ENOBUFS);
596         }
597
598         return (0);
599 }
600
601
602 /*
603  * Process VCC Input Data
604  * 
605  * All input packets received from CLS VCC lower layers are processed here.
606  *
607  * Arguments:
608  *      tok     connection token (pointer to CLS VCC control block)
609  *      m       pointer to input packet buffer chain
610  *
611  * Returns:
612  *      none
613  *
614  */
615 static void
616 spanscls_cpcs_data(void *tok, KBuffer *m)
617 {
618         struct spanscls *clp = tok;
619         struct spans    *spp = clp->cls_spans;
620         struct spanscls_hdr     *chp;
621         struct ip_nif   *inp;
622
623         /*
624          * Make sure we're ready
625          */
626         if ((clp->cls_state != CLS_OPEN) || (spp->sp_state != SPANS_ACTIVE)) {
627                 KB_FREEALL(m);
628                 return;
629         }
630
631 #ifdef DIAGNOSTIC
632         if (spanscls_print)
633                 spanscls_pdu_print(clp, m, "input");
634 #endif
635
636         /*
637          * Get CLS header into buffer
638          */
639         if (KB_LEN(m) < sizeof(struct spanscls_hdr)) {
640                 KB_PULLUP(m, sizeof(struct spanscls_hdr), m);
641                 if (m == 0)
642                         return;
643         }
644         KB_DATASTART(m, chp, struct spanscls_hdr *);
645
646         /*
647          * Verify packet information
648          */
649         if ((*(u_int *)&chp->ch_proto != *(u_int *)&spanscls_hdr.ch_proto) ||
650             (*(u_int *)&chp->ch_dsap != *(u_int *)&spanscls_hdr.ch_dsap) ||
651             (*(u_short *)&chp->ch_oui[1] != 
652                                 *(u_short *)&spanscls_hdr.ch_oui[1])) {
653
654                 /*
655                  * Check for bridged PDU
656                  */
657                 if (bcmp((char *)&chp->ch_proto, (char *)spanscls_bridged, 
658                                 sizeof(spanscls_bridged))) {
659                         log(LOG_ERR, "spanscls_input: bad format\n");
660 #ifdef DIAGNOSTIC
661                         spanscls_pdu_print(clp, m, "input error"); 
662 #endif
663                 }
664
665                 KB_FREEALL(m);
666                 return;
667         }
668
669         /*
670          * Make sure packet is for us
671          */
672         if (spans_addr_cmp(&chp->ch_dst, spp->sp_addr.address) &&
673             spans_addr_cmp(&chp->ch_dst, &spans_bcastaddr)) {
674                 KB_FREEALL(m);
675                 return;
676         }
677
678         /*
679          * Do protocol processing
680          */
681         switch (ntohs(chp->ch_pid)) {
682
683         case ETHERTYPE_IP:
684                 /*
685                  * Drop CLS header
686                  */
687                 KB_HEADADJ(m, -sizeof(struct spanscls_hdr));
688                 KB_PLENADJ(m, -sizeof(struct spanscls_hdr));
689
690                 /*
691                  * Packet is ready for input to IP
692                  */
693                 if ((inp = clp->cls_ipnif) != NULL)
694                         (*inp->inf_ipinput)(inp, m);
695                 else
696                         KB_FREEALL(m);
697                 break;
698
699         case ETHERTYPE_ARP:
700                 spansarp_input(clp, m);
701                 break;
702
703         default:
704                 log(LOG_ERR, "spanscls_input: unknown protocol 0x%x\n",
705                         chp->ch_pid);
706                 KB_FREEALL(m);
707                 return;
708         }
709 }
710
711
712 /*
713  * Close a SPANS CLS VCC
714  * 
715  * This function will close a SPANS CLS VCC.
716  *
717  * Arguments:
718  *      clp     pointer to CLS instance
719  *      cause   pointer to cause code
720  *
721  * Returns:
722  *      none
723  *
724  */
725 void
726 spanscls_closevc(struct spanscls *clp, struct t_atm_cause *cause)
727 {
728         int     err;
729
730         /*
731          * Close VCC
732          */
733         if (clp->cls_conn) {
734                 err = atm_cm_release(clp->cls_conn, cause);
735                 if (err) {
736                         log(LOG_ERR, "spanscls_closevc: release err=%d\n", err);
737                 }
738                 clp->cls_conn = NULL;
739         }
740
741         clp->cls_state = CLS_CLOSED;
742 }
743
744
745 /*
746  * Process CLS VCC Connected Notification
747  * 
748  * Arguments:
749  *      toku    user's connection token (spanscls protocol block)
750  *
751  * Returns:
752  *      none
753  *
754  */
755 static void
756 spanscls_connected(void *toku)
757 {
758         /*
759          * We should never get one of these
760          */
761         log(LOG_ERR, "spanscls: unexpected connected event\n");
762 }
763
764
765 /*
766  * Process CLS VCC Cleared Notification
767  * 
768  * Arguments:
769  *      toku    user's connection token (spanscls protocol block)
770  *      cause   pointer to cause code
771  *
772  * Returns:
773  *      none
774  *
775  */
776 static void
777 spanscls_cleared(void *toku, struct t_atm_cause *cause)
778 {
779         struct spanscls *clp = (struct spanscls *)toku;
780
781         /*
782          * CLS VCC has been closed, so clean up our side
783          */
784         clp->cls_conn = NULL;
785         spanscls_closevc(clp, cause);
786 }
787
788
789 /*
790  * Get Connection's Application/Owner Name
791  * 
792  * Arguments:
793  *      tok     spanscls connection token
794  *
795  * Returns:
796  *      addr    pointer to string containing our name
797  *
798  */
799 static caddr_t
800 spanscls_getname(void *tok)
801 {
802         return ("SPANSCLS");
803 }
804
805
806 /*
807  * Print a SPANS CLS PDU
808  * 
809  * Arguments:
810  *      clp     pointer to cls instance
811  *      m       pointer to pdu buffer chain
812  *      msg     pointer to message string
813  *
814  * Returns:
815  *      none
816  *
817  */
818 static void
819 spanscls_pdu_print(struct spanscls *clp, KBuffer *m, char *msg)
820 {
821         char            buf[128];
822
823         ksnprintf(buf, sizeof(buf), "spanscls %s:\n", msg);
824         atm_pdu_print(m, buf);
825 }
826