more changes on original files
[linux-2.4.git] / net / 802 / llc_macinit.c
1 /*
2  * NET          An implementation of the IEEE 802.2 LLC protocol for the
3  *              LINUX operating system.  LLC is implemented as a set of
4  *              state machines and callbacks for higher networking layers.
5  *
6  *              Code for initialization, termination, registration and
7  *              MAC layer glue.
8  *
9  *              Written by Tim Alpaerts, Tim_Alpaerts@toyota-motor-europe.com
10  *
11  *              This program is free software; you can redistribute it and/or
12  *              modify it under the terms of the GNU General Public License
13  *              as published by the Free Software Foundation; either version
14  *              2 of the License, or (at your option) any later version.
15  *
16  *      Changes
17  *              Alan Cox        :       Chainsawed to Linux format
18  *                                      Added llc_ to names
19  *                                      Started restructuring handlers
20  *
21  *              Horst von Brand :      Add #include <linux/string.h>
22  */
23
24 #include <linux/module.h>
25 #include <linux/version.h>
26 #include <linux/kernel.h>
27 #include <linux/slab.h>
28 #include <linux/unistd.h>
29 #include <linux/string.h>
30 #include <linux/netdevice.h>
31 #include <linux/init.h>
32 #include <net/p8022.h>
33
34 #include <asm/byteorder.h>
35
36 #include <net/llc_frame.h>
37 #include <net/llc.h>
38
39 /*
40  *      All incoming frames pass thru mac_data_indicate().
41  *      On entry the llc structure related to the frame is passed as parameter. 
42  *      The received sk_buffs with pdus other than I_CMD and I_RSP
43  *      are freed by mac_data_indicate() after processing,
44  *      the I pdu buffers are freed by the cl2llc client when it no longer needs
45  *      the skb.
46 */
47
48 int llc_mac_data_indicate(llcptr lp, struct sk_buff *skb)
49 {
50         int ll;                 /* logical length == 802.3 length field */
51         unsigned char p_flag;
52         unsigned char type;
53         frameptr fr;
54         int free=1;
55
56         lp->inc_skb=NULL;
57         
58         /*
59          *      Truncate buffer to true 802.3 length
60          *      [FIXME: move to 802.2 demux]
61          */
62
63         ll = *(skb->data -2) * 256 + *(skb->data -1);
64         skb_trim( skb, ll );
65
66         fr = (frameptr) skb->data;
67         type = llc_decode_frametype( fr );
68
69
70         if (type <= FRMR_RSP)
71         {
72                 /*
73                  *      PDU is of the type 2 set
74                  */
75                 if ((lp->llc_mode == MODE_ABM)||(type == SABME_CMD))
76                         llc_process_otype2_frame(lp, skb, type);
77
78         }
79         else
80         {
81                 /*
82                  *      PDU belongs to type 1 set
83                  */
84                 p_flag = fr->u_hdr.u_pflag;
85                 switch(type)
86                 {
87                         case TEST_CMD:
88                                 llc_sendpdu(lp, TEST_RSP, 0,ll -3,
89                                         fr->u_hdr.u_info);
90                                 break;
91                         case TEST_RSP:
92                                 lp->llc_callbacks|=LLC_TEST_INDICATION;
93                                 lp->inc_skb=skb;
94                                 free=0;
95                                 break;
96                         case XID_CMD:
97                                 /*
98                                  *      Basic format XID is handled by LLC itself
99                                  *      Doc 5.4.1.1.2 p 48/49
100                                  */
101
102                                 if ((ll == 6)&&(fr->u_hdr.u_info[0] == 0x81))
103                                 {
104                                         lp->k = fr->u_hdr.u_info[2];
105                                         llc_sendpdu(lp, XID_RSP,
106                                                 fr->u_hdr.u_pflag, ll -3,
107                                                 fr->u_hdr.u_info);
108                                 }
109                                 break;
110
111                         case XID_RSP:
112                                 if( ll == 6 && fr->u_hdr.u_info[0] == 0x81 )
113                                 {
114                                         lp->k = fr->u_hdr.u_info[2];
115                                 }
116                                 lp->llc_callbacks|=LLC_XID_INDICATION;
117                                 lp->inc_skb=skb;
118                                 free=0;
119                                 break;
120
121                         case UI_CMD:
122                                 lp->llc_callbacks|=LLC_UI_DATA;
123                                 skb_pull(skb,3);
124                                 lp->inc_skb=skb;
125                                 free=0;
126                                 break;
127
128                         default:;
129                                 /*
130                                  *      All other type 1 pdus ignored for now
131                                  */
132                 }
133         }
134
135         if (free&&(!(IS_IFRAME(fr))))
136         {
137                 /*
138                  *      No auto free for I pdus
139                  */
140                 skb->sk = NULL;
141                 kfree_skb(skb);
142         }
143
144         if(lp->llc_callbacks)
145         {
146                 if ( lp->llc_event != NULL ) lp->llc_event(lp);
147                 lp->llc_callbacks=0;
148         }
149         return 0;
150 }
151
152
153 /*
154  *      Create an LLC client. As it is the job of the caller to clean up
155  *      LLC's on device down, the device list must be locked before this call.
156  */
157
158 int register_cl2llc_client(llcptr lp, const char *device, void (*event)(llcptr), u8 *rmac, u8 ssap, u8 dsap)
159 {
160         char eye_init[] = "LLC\0";
161
162         memset(lp, 0, sizeof(*lp));
163         lp->dev = __dev_get_by_name(device);
164         if(lp->dev == NULL)
165                 return -ENODEV;
166         memcpy(lp->eye, eye_init, sizeof(lp->eye));
167         lp->rw = 1;
168         lp->k = 127;
169         lp->n1 = 1490;
170         lp->n2 = 10;
171         lp->timer_interval[P_TIMER] = HZ;    /* 1 sec */
172         lp->timer_interval[REJ_TIMER] = HZ/8;
173         lp->timer_interval[ACK_TIMER] = HZ/8;
174         lp->timer_interval[BUSY_TIMER] = HZ*2;
175         lp->local_sap = ssap;
176         lp->llc_event = event;
177         memcpy(lp->remote_mac, rmac, sizeof(lp->remote_mac));
178         lp->state = 0;
179         lp->llc_mode = MODE_ADM;
180         lp->remote_sap = dsap;
181         skb_queue_head_init(&lp->atq);
182         skb_queue_head_init(&lp->rtq);
183         MOD_INC_USE_COUNT;
184         return 0;
185 }
186
187
188 void unregister_cl2llc_client(llcptr lp)
189 {
190         llc_cancel_timers(lp);
191         MOD_DEC_USE_COUNT;
192         kfree(lp);
193 }
194
195
196 EXPORT_SYMBOL(register_cl2llc_client);
197 EXPORT_SYMBOL(unregister_cl2llc_client);
198 EXPORT_SYMBOL(llc_data_request);
199 EXPORT_SYMBOL(llc_unit_data_request);
200 EXPORT_SYMBOL(llc_test_request);
201 EXPORT_SYMBOL(llc_xid_request);
202 EXPORT_SYMBOL(llc_mac_data_indicate);
203 EXPORT_SYMBOL(llc_cancel_timers);
204
205 #define ALL_TYPES_8022 0
206
207 static int __init llc_init(void)
208 {
209         printk(KERN_NOTICE "IEEE 802.2 LLC for Linux 2.1 (c) 1996 Tim Alpaerts\n");
210         return 0;
211 }
212
213
214 module_init(llc_init);