http://gimel.esc.cam.ac.uk/james/rpld/src/rpld-1.7.tar.gz
[rpld.git] / rpl.c
1 /*************************************************
2 *     rpld - an IBM style RIPL server            *
3 *************************************************/
4
5 /* Copyright (c) 1999,2000, James McKenzie.
6  *                      All rights reserved
7  * Copyright (c) 1998,2000, Christopher Lightfoot.
8  *                      All rights reserved
9  *
10  * By using this file, you agree to the terms and conditions set
11  * forth in the LICENCE file which can be found at the top level of
12  * the rpld distribution.
13  *
14  * IBM is a trademark of IBM corp.
15  *
16  */
17
18
19
20 static char rcsid[] = "$Id: rpl.c,v 1.12 2000/09/26 01:39:17 root Exp $";
21
22 /*
23  * $Log: rpl.c,v $
24  * Revision 1.12  2000/09/26 01:39:17  root
25  * #
26  *
27  * Revision 1.11  2000/09/26 01:03:19  root
28  * #
29  *
30  * Revision 1.10  2000/07/17 10:43:34  root
31  * #
32  *
33  * Revision 1.9  2000/07/16 14:05:28  root
34  * #
35  *
36  * Revision 1.8  2000/07/16 13:18:10  root
37  * #
38  *
39  * Revision 1.1  2000/07/16 13:16:33  root
40  * #
41  *
42  * Revision 1.7  1999/09/13 11:17:35  root
43  * \#
44  *
45  * Revision 1.6  1999/09/13 11:08:34  root
46  * \#
47  *
48  * Revision 1.5  1999/09/13 11:05:27  root
49  * \#
50  *
51  * Revision 1.4  1999/09/13 11:04:13  root
52  * \#
53  *
54  */
55
56 #include "project.h"
57
58 /* Code for recursively disembling packets */
59
60 static void
61 rpl_token (struct rpl_packet *p, int s, unsigned char *pp, int pl)
62 {
63   int i;
64   switch (s)
65     {
66     case RPL_TK_TMZ:
67       if (pl < 4)
68         return;
69       p->flags |= RPL_FL_TMZ;
70       p->themightyzero = ntohl (*(u32 *) pp);
71       return;
72     case RPL_TK_MYMAC:
73       if (pl < ETH_ALEN)
74         return;
75       p->flags |= RPL_FL_MYMAC;
76       bcopy (pp, p->mymac, ETH_ALEN);
77       return;
78     case RPL_TK_SAP:
79       /*FIXME: */
80       p->flags |= RPL_FL_SAP;
81       return;
82     case RPL_TK_FRAMELEN:
83       if (pl < 2)
84         return;
85       p->flags |= RPL_FL_FRAMELEN;
86       p->framelen = ntohs (*(u16 *) pp);
87       return;
88     case RPL_TK_WHOAMI:
89       if (pl < 2)
90         return;
91       p->flags |= RPL_FL_WHOAMI;
92       p->whoami = ntohs (*(u16 *) pp);
93       return;
94     case RPL_TK_TSZ:
95       if (pl < 1)
96         return;
97       p->flags |= RPL_FL_TSZ;
98       p->thesmallzero = *pp;
99       return;
100     case RPL_TK_YOUMAC:
101       if (pl < ETH_ALEN)
102         return;
103       p->flags |= RPL_FL_YOUMAC;
104       bcopy (pp, p->youmac, ETH_ALEN);
105       return;
106     case RPL_TK_BLOCK:
107       if (pl < 4)
108         return;
109       p->flags |= RPL_FL_BLOCK;
110       p->block = ntohl (*(u32 *) pp);
111       return;
112     case RPL_TK_DATA:
113       if (NOTINRANGE (1, pl, MAX_DATA_LEN))
114         return;
115       p->flags |= RPL_FL_DATA;
116       bcopy (pp, p->data, pl);
117       p->datalen = pl;
118       return;
119     case RPL_TK_IDENT:
120       if (NOTINRANGE (1, pl, MAX_IDENT_LEN))
121         return;
122       p->flags |= RPL_FL_IDENT;
123       bcopy (pp, p->ident, pl);
124       p->identlen = pl;
125       return;
126     case RPL_FL_ADDR:
127       if (pl < 9)
128         return;
129       p->flags |= RPL_FL_ADDR;
130       p->addr.load = ntohl (*(u32 *) pp);
131       p->addr.run = ntohl (*(u32 *) (pp + 4));
132       p->addr.flags = pp[8];
133       return;
134     default:
135       syslog (LOG_ERR, "Unknown token: 0x%04x", s);
136     }
137
138 }
139
140 static void
141 rpl_frag (struct rpl_packet *p, unsigned char *pp, int pl)
142 {
143   int s;
144
145   while (pl > 0)
146     {
147
148       if (pl < 2)
149         return;
150       s = ntohs (*(u16 *) pp);
151
152       if (!s)
153         {
154           syslog (LOG_ERR, "Unexpected end of packet", s);
155           return;
156
157         }
158       if (RPL_IS_TOKEN (s))
159         {
160           rpl_token (p, s, pp + 2, pl - 2);
161           return;
162         }
163       else
164         {
165           rpl_frag (p, pp + 2, s - 2);
166           pp += s;
167           pl -= s;
168         }
169
170     }
171
172 }
173
174 /* Code for assembling packets */
175 int
176 write_char (unsigned char *ptr, u8 v)
177 {
178   *ptr = v;
179   return (1);
180 }
181
182 int
183 write_short (unsigned char *ptr, u16 v)
184 {
185   *((u16 *) ptr) = htons (v);
186   return (2);
187 }
188
189 int
190 write_long (unsigned char *ptr, u32 v)
191 {
192   *((u32 *) ptr) = htonl (v);
193   return (4);
194 }
195
196 int
197 put_char (unsigned char *ptr, u16 token, u8 value)
198 {
199   int len = 0, i;
200   i = write_short (ptr, 0x2 + 0x2 + 0x1);
201   ptr += i;
202   len += i;
203   i = write_short (ptr, token);
204   ptr += i;
205   len += i;
206   i = write_char (ptr, value);
207   ptr += i;
208   len += i;
209   return (len);
210 }
211
212 int
213 put_short (unsigned char *ptr, u16 token, u16 value)
214 {
215   int len = 0, i;
216   i = write_short (ptr, 0x2 + 0x2 + 0x2);
217   ptr += i;
218   len += i;
219   i = write_short (ptr, token);
220   ptr += i;
221   len += i;
222   i = write_short (ptr, value);
223   ptr += i;
224   len += i;
225   return (len);
226 }
227
228 int
229 put_long (unsigned char *ptr, u16 token, u32 value)
230 {
231   int len = 0, i;
232   i = write_short (ptr, 0x2 + 0x2 + 0x4);
233   ptr += i;
234   len += i;
235   i = write_short (ptr, token);
236   ptr += i;
237   len += i;
238   i = write_long (ptr, value);
239   ptr += i;
240   len += i;
241   return (len);
242 }
243
244 int
245 put_mac (unsigned char *ptr, u16 token, unsigned char *mac)
246 {
247   int len = 0, i;
248   i = write_short (ptr, 0x2 + 0x2 + 0x6);
249   ptr += i;
250   len += i;
251   i = write_short (ptr, token);
252   ptr += i;
253   len += i;
254   bcopy (mac, ptr, ETH_ALEN);
255   ptr += ETH_ALEN;
256   len += ETH_ALEN;
257   return (len);
258 }
259
260 static void
261 send_found_frame (struct llcdrv *lld, unsigned char *dmac,
262                   struct rpl_packet *out)
263 {
264   unsigned char buf[MAX_FRAME_LEN], *ptr;
265   int len, i;
266
267   if (out->flags != RPL_FOUND_FLAGS)
268     {
269
270       syslog (LOG_ERR, "FOUND packet: doesn't match RE case %x!=%x",
271               out->flags, RPL_FOUND_FLAGS);
272       return;
273     }
274
275   ptr = buf;
276   len = 0;
277
278   i = write_short (ptr, 0x0);
279   ptr += i;
280   len += i;                     /*length */
281   i = write_short (ptr, out->type);
282   ptr += i;
283   len += i;                     /*type */
284
285   i = put_long (ptr, RPL_TK_TMZ, out->themightyzero);
286   ptr += i;
287   len += i;
288   i = put_char (ptr, RPL_TK_TSZ, out->thesmallzero);
289   ptr += i;
290   len += i;
291   i = put_mac (ptr, RPL_TK_YOUMAC, out->youmac);
292   ptr += i;
293   len += i;
294   i = put_mac (ptr, RPL_TK_MYMAC, out->mymac);
295   ptr += i;
296   len += i;
297   i = write_short (ptr, 0x10);
298   ptr += i;
299   len += i;
300   i = write_short (ptr, 0x08);
301   ptr += i;
302   len += i;
303   i = put_short (ptr, RPL_TK_FRAMELEN, out->framelen);
304   ptr += i;
305   len += i;
306   i = put_short (ptr, RPL_TK_WHOAMI, out->whoami);
307   ptr += i;
308   len += i;
309   i = put_char (ptr, RPL_TK_SAP, out->sap);
310   ptr += i;
311   len += i;
312
313   ptr = buf;
314   write_short (ptr, len);       /*length */
315
316   lld->send (lld, dmac, rpl_sap, buf, len);
317
318
319 }
320
321
322 static void
323 send_file_data_frame (struct llcdrv *lld, unsigned char *dmac,
324                       struct rpl_packet *out)
325 {
326   unsigned char buf[MAX_FRAME_LEN], *ptr;
327   int len, i;
328
329   if (out->flags != RPL_FILE_DATA_FLAGS)
330     {
331       syslog (LOG_ERR, "FILE.DATA packet: doesn't match RE case %x!=%x",
332               out->flags, RPL_FILE_DATA_FLAGS);
333       return;
334     }
335
336   ptr = buf;
337   len = 0;
338
339   i = write_short (ptr, 0x0);
340   ptr += i;
341   len += i;                     /*length */
342   i = write_short (ptr, out->type);
343   ptr += i;
344   len += i;                     /*type */
345
346   i = put_long (ptr, RPL_TK_BLOCK, out->block);
347   ptr += i;
348   len += i;
349
350   i = write_short (ptr, 0x2 + 0x2 + 0x9);
351   ptr += i;
352   len += i;
353   i = write_short (ptr, RPL_TK_ADDR);
354   ptr += i;
355   len += i;
356   i = write_long (ptr, out->addr.load);
357   ptr += i;
358   len += i;
359   i = write_long (ptr, out->addr.run);
360   ptr += i;
361   len += i;
362   i = write_char (ptr, out->addr.flags);
363   ptr += i;
364   len += i;
365
366   i = write_short (ptr, 0x2 + 0x2 + out->datalen);
367   ptr += i;
368   len += i;
369   i = write_short (ptr, RPL_TK_DATA);
370   ptr += i;
371   len += i;
372   bcopy (out->data, ptr, out->datalen);
373   ptr += out->datalen;
374   len += out->datalen;
375
376
377   ptr = buf;
378   write_short (ptr, len);       /*length */
379
380   lld->send (lld, dmac, rpl_sap, buf, len);
381
382
383 }
384
385 void
386 rpl_send_packet (struct llcdrv *lld, unsigned char *d, struct rpl_packet *p)
387 {
388
389   switch (p->type)
390     {
391     case RPL_PK_FOUND:
392       send_found_frame (lld, d, p);
393       break;
394     case RPL_PK_FILEDATA:
395       send_file_data_frame (lld, d, p);
396       break;
397     default:
398       syslog (LOG_ERR, "rpl_send_packet: unknown packet type 0x%04x",
399               p->type);
400     }
401 }
402
403 /* This code is called for every valid rpl packet */
404 void
405 rpl_packet_recvd (struct llcdrv *lld, unsigned char *pptr, int plen)
406 {
407
408   struct rpl_packet p;
409   int elen;
410
411   if (plen < 6)
412     return;
413
414   elen = ntohs (*(u16 *) pptr);
415
416   if (elen != plen)
417     {
418       syslog (LOG_ERR, "received lengths disagree %d vs %d", elen, plen);
419     }
420
421   if (elen > plen)
422     elen = plen;
423
424   pptr += 2;                    /*Length */
425   elen -= 2;
426
427   if (elen < 2)
428     return;
429   p.type = ntohs (*(u16 *) pptr);
430
431   pptr += 2;
432   elen -= 2;
433
434   p.flags = 0;
435
436   rpl_frag (&p, pptr, elen);    /*Analyse the packet */
437
438   rpl_packet_recvd_callback (lld, &p); /*Pass it up to the protocol layer */
439
440 }