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