1 /*
2                                   NETWIB
3                              Network library
4                 Copyright(c) 1999-2010 Laurent Constantin
5                                   -----
6 
7   Main server   : http://www.laurentconstantin.com/
8   Backup server : http://laurentconstantin.free.fr/
9   [my current email address is on the web servers]
10 
11                                   -----
12   This file is part of Netwib.
13 
14   Netwib is free software: you can redistribute it and/or modify
15   it under the terms of the GNU General Public License version 3
16   as published by the Free Software Foundation.
17 
18   Netwib is distributed in the hope that it will be useful,
19   but WITHOUT ANY WARRANTY; without even the implied warranty of
20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21   GNU General Public License for more details (http://www.gnu.org/).
22 
23 ------------------------------------------------------------------------
24 */
25 
26 #include <netwib/inc/maininc.h>
27 
28 /*-------------------------------------------------------------*/
netwib_linkhdr_initdefault(netwib_device_dlttype type,netwib_linkhdr * plinkhdr)29 netwib_err netwib_linkhdr_initdefault(netwib_device_dlttype type,
30                                       netwib_linkhdr *plinkhdr)
31 {
32 
33   if (plinkhdr != NULL) {
34     plinkhdr->type = type;
35     switch(type) {
36     case NETWIB_DEVICE_DLTTYPE_ETHER :
37     case NETWIB_DEVICE_DLTTYPE_NULL :
38     case NETWIB_DEVICE_DLTTYPE_LOOP :
39     case NETWIB_DEVICE_DLTTYPE_RAW :
40     case NETWIB_DEVICE_DLTTYPE_RAW4 :
41     case NETWIB_DEVICE_DLTTYPE_RAW6 :
42       break;
43     case NETWIB_DEVICE_DLTTYPE_PPP :
44       /* is this correct to set nothing ??? */
45       break;
46     case NETWIB_DEVICE_DLTTYPE_LINUX_SLL :
47       plinkhdr->hdr.linuxsll.pkttype = NETWIB_LINUXSLLHDRPKTTYPE_HOST;
48       plinkhdr->hdr.linuxsll.hatype = NETWIB_LINUXSLLHDRHATYPE_ETHER;
49       plinkhdr->hdr.linuxsll.halen = NETWIB_ETH_LEN;
50       break;
51     default :
52       return(NETWIB_ERR_LONOTIMPLEMENTED);
53       break;
54     }
55   }
56 
57   return(NETWIB_ERR_OK);
58 }
59 
60 /*-------------------------------------------------------------*/
netwib_pkt_append_etherhdr(netwib_constetherhdr * petherhdr,netwib_buf * ppkt)61 static netwib_err netwib_pkt_append_etherhdr(netwib_constetherhdr *petherhdr,
62                                              netwib_buf *ppkt)
63 {
64   netwib_data data;
65 
66   netwib_er(netwib_buf_wantspace(ppkt, NETWIB_ETHERHDR_LEN, &data));
67 
68   netwib_c_memcpy(data, petherhdr->dst.b, NETWIB_ETH_LEN);
69   data += NETWIB_ETH_LEN;
70   netwib_c_memcpy(data, petherhdr->src.b, NETWIB_ETH_LEN);
71   data += NETWIB_ETH_LEN;
72   netwib__data_append_uint16(data, petherhdr->type);
73 
74   ppkt->endoffset += NETWIB_ETHERHDR_LEN;
75 
76   return(NETWIB_ERR_OK);
77 }
78 
79 /*-------------------------------------------------------------*/
netwib_pkt_decode_etherhdr(netwib_constbuf * ppkt,netwib_etherhdr * petherhdr,netwib_uint32 * pskipsize)80 static netwib_err netwib_pkt_decode_etherhdr(netwib_constbuf *ppkt,
81                                              netwib_etherhdr *petherhdr,
82                                              netwib_uint32 *pskipsize)
83 {
84   netwib_data data;
85   netwib_uint32 datasize;
86 
87   if (pskipsize != NULL) *pskipsize = NETWIB_ETHERHDR_LEN;
88 
89   datasize = netwib__buf_ref_data_size(ppkt);
90   if (datasize < NETWIB_ETHERHDR_LEN) {
91     return(NETWIB_ERR_DATAMISSING);
92   }
93 
94   if (petherhdr != NULL) {
95     data = netwib__buf_ref_data_ptr(ppkt);
96     netwib_c_memcpy(petherhdr->dst.b, data, NETWIB_ETH_LEN);
97     data += NETWIB_ETH_LEN;
98     netwib_c_memcpy(petherhdr->src.b, data, NETWIB_ETH_LEN);
99     data += NETWIB_ETH_LEN;
100     netwib__data_decode_uint16t(data, petherhdr->type, netwib_etherhdrtype);
101   }
102 
103   return(NETWIB_ERR_OK);
104 }
105 
106 /*-------------------------------------------------------------*/
107 /*-------------------------------------------------------------*/
netwib_pkt_append_nullhdr(netwib_constnullhdr * pnullhdr,netwib_buf * ppkt)108 static netwib_err netwib_pkt_append_nullhdr(netwib_constnullhdr *pnullhdr,
109                                             netwib_buf *ppkt)
110 {
111   netwib_data data;
112 
113   netwib_er(netwib_buf_wantspace(ppkt, NETWIB_NULLHDR_LEN, &data));
114 
115   netwib__data_append_uint32(data, pnullhdr->type);
116 
117   ppkt->endoffset += NETWIB_NULLHDR_LEN;
118   return(NETWIB_ERR_OK);
119 }
120 
121 /*-------------------------------------------------------------*/
netwib_pkt_decode_nullhdr(netwib_constbuf * ppkt,netwib_nullhdr * pnullhdr,netwib_uint32 * pskipsize)122 static netwib_err netwib_pkt_decode_nullhdr(netwib_constbuf *ppkt,
123                                             netwib_nullhdr *pnullhdr,
124                                             netwib_uint32 *pskipsize)
125 {
126   netwib_data data;
127   netwib_uint32 datasize;
128 
129   if (pskipsize != NULL) *pskipsize = NETWIB_NULLHDR_LEN;
130 
131   datasize = netwib__buf_ref_data_size(ppkt);
132   if (datasize < NETWIB_NULLHDR_LEN) {
133     return(NETWIB_ERR_DATAMISSING);
134   }
135 
136   if (pnullhdr != NULL) {
137     data = netwib__buf_ref_data_ptr(ppkt);
138     netwib__data_decode_uint32t(data, pnullhdr->type, netwib_etherhdrtype);
139     if ((pnullhdr->type & 0xFFFF) == 0) {
140       /* swap */
141       pnullhdr->type = (netwib_etherhdrtype)(((pnullhdr->type>>8)&0xFFFF) |
142                                              (pnullhdr->type>>24));
143     }
144     /* under BSD, this field can also contain AF_xyz */
145     switch(pnullhdr->type) {
146       case AF_INET :
147         pnullhdr->type = NETWIB_ETHERHDRTYPE_IP4;
148         break;
149 #if NETWIBDEF_HAVEVAR_AF_INET6 == 1
150       case AF_INET6 :
151         pnullhdr->type = NETWIB_ETHERHDRTYPE_IP6;
152         break;
153 #endif
154       default :
155         /* do not change */
156         break;
157     }
158   }
159 
160   return(NETWIB_ERR_OK);
161 }
162 
163 /*-------------------------------------------------------------*/
164 /*-------------------------------------------------------------*/
netwib_pkt_append_loophdr(netwib_constloophdr * ploophdr,netwib_buf * ppkt)165 static netwib_err netwib_pkt_append_loophdr(netwib_constloophdr *ploophdr,
166                                             netwib_buf *ppkt)
167 {
168   netwib_data data;
169 
170   netwib_er(netwib_buf_wantspace(ppkt, NETWIB_LOOPHDR_LEN, &data));
171 
172   netwib__data_append_uint32(data, ploophdr->type);
173 
174   ppkt->endoffset += NETWIB_LOOPHDR_LEN;
175 
176   return(NETWIB_ERR_OK);
177 }
178 
179 /*-------------------------------------------------------------*/
netwib_pkt_decode_loophdr(netwib_constbuf * ppkt,netwib_loophdr * ploophdr,netwib_uint32 * pskipsize)180 static netwib_err netwib_pkt_decode_loophdr(netwib_constbuf *ppkt,
181                                             netwib_loophdr *ploophdr,
182                                             netwib_uint32 *pskipsize)
183 {
184   netwib_data data;
185   netwib_uint32 datasize;
186 
187   if (pskipsize != NULL) *pskipsize = NETWIB_LOOPHDR_LEN;
188 
189   datasize = netwib__buf_ref_data_size(ppkt);
190   if (datasize < NETWIB_LOOPHDR_LEN) {
191     return(NETWIB_ERR_DATAMISSING);
192   }
193 
194   if (ploophdr != NULL) {
195     data = netwib__buf_ref_data_ptr(ppkt);
196     netwib__data_decode_uint32t(data, ploophdr->type, netwib_etherhdrtype);
197     /* under BSD, this field can contain AF_xyz */
198     switch(ploophdr->type) {
199       case AF_INET :
200         ploophdr->type = NETWIB_ETHERHDRTYPE_IP4;
201         break;
202 #if NETWIBDEF_HAVEVAR_AF_INET6 == 1
203       case AF_INET6 :
204         ploophdr->type = NETWIB_ETHERHDRTYPE_IP6;
205         break;
206 #endif
207       default :
208         /* do not change */
209         break;
210     }
211   }
212 
213   return(NETWIB_ERR_OK);
214 }
215 
216 
217 /*-------------------------------------------------------------*/
218 /*-------------------------------------------------------------*/
netwib_pkt_append_ppphdr(netwib_constppphdr * pppphdr,netwib_buf * ppkt)219 static netwib_err netwib_pkt_append_ppphdr(netwib_constppphdr *pppphdr,
220                                            netwib_buf *ppkt)
221 {
222   netwib_data data;
223 
224   netwib_er(netwib_buf_wantspace(ppkt, NETWIB_PPPHDR_LEN, &data));
225 
226   netwib__data_append_uint8(data, pppphdr->address);
227   netwib__data_append_uint8(data, pppphdr->control);
228   netwib__data_append_uint16(data, pppphdr->protocol);
229 
230   ppkt->endoffset += NETWIB_PPPHDR_LEN;
231 
232   return(NETWIB_ERR_OK);
233 }
234 
235 /*-------------------------------------------------------------*/
netwib_pkt_decode_ppphdr(netwib_constbuf * ppkt,netwib_ppphdr * pppphdr,netwib_uint32 * pskipsize)236 static netwib_err netwib_pkt_decode_ppphdr(netwib_constbuf *ppkt,
237                                            netwib_ppphdr *pppphdr,
238                                            netwib_uint32 *pskipsize)
239 {
240   netwib_data data;
241   netwib_uint32 datasize;
242 
243   if (pskipsize != NULL) *pskipsize = NETWIB_PPPHDR_LEN;
244 
245   datasize = netwib__buf_ref_data_size(ppkt);
246   if (datasize < NETWIB_PPPHDR_LEN) {
247     return(NETWIB_ERR_DATAMISSING);
248   }
249 
250   if (pppphdr != NULL) {
251     data = netwib__buf_ref_data_ptr(ppkt);
252     netwib__data_decode_uint8(data, pppphdr->address);
253     netwib__data_decode_uint8(data, pppphdr->control);
254     netwib__data_decode_uint16t(data, pppphdr->protocol, netwib_ppphdrproto);
255   }
256 
257   return(NETWIB_ERR_OK);
258 }
259 
260 /*-------------------------------------------------------------*/
261 /*-------------------------------------------------------------*/
netwib_pkt_append_linuxsllhdr(netwib_constlinuxsllhdr * plinuxsllhdr,netwib_buf * ppkt)262 static netwib_err netwib_pkt_append_linuxsllhdr(netwib_constlinuxsllhdr *plinuxsllhdr,
263                                                 netwib_buf *ppkt)
264 {
265   netwib_data data;
266 
267   netwib_er(netwib_buf_wantspace(ppkt, NETWIB_LINUXSLLHDR_LEN, &data));
268 
269   netwib__data_append_uint16(data, plinuxsllhdr->pkttype);
270   netwib__data_append_uint16(data, plinuxsllhdr->hatype);
271   netwib__data_append_uint16(data, plinuxsllhdr->halen);
272   if (plinuxsllhdr->halen >= 8 ) {
273     netwib_c_memcpy(data, plinuxsllhdr->srcaddr, 8);
274     data += 8;
275   } else {
276     netwib_c_memcpy(data, plinuxsllhdr->srcaddr, plinuxsllhdr->halen);
277     data += plinuxsllhdr->halen;
278     netwib_c_memset(data, 0, 8-plinuxsllhdr->halen);
279     data += 8-plinuxsllhdr->halen;
280   }
281   netwib__data_append_uint16(data, plinuxsllhdr->protocol);
282 
283   ppkt->endoffset += NETWIB_LINUXSLLHDR_LEN;
284 
285   return(NETWIB_ERR_OK);
286 }
287 
288 /*-------------------------------------------------------------*/
netwib_pkt_decode_linuxsllhdr(netwib_constbuf * ppkt,netwib_linuxsllhdr * plinuxsllhdr,netwib_uint32 * pskipsize)289 static netwib_err netwib_pkt_decode_linuxsllhdr(netwib_constbuf *ppkt,
290                                                 netwib_linuxsllhdr *plinuxsllhdr,
291                                                 netwib_uint32 *pskipsize)
292 {
293   netwib_data data;
294   netwib_uint32 datasize;
295 
296   if (pskipsize != NULL) *pskipsize = NETWIB_LINUXSLLHDR_LEN;
297 
298   datasize = netwib__buf_ref_data_size(ppkt);
299   if (datasize < NETWIB_LINUXSLLHDR_LEN) {
300     return(NETWIB_ERR_DATAMISSING);
301   }
302 
303   if (plinuxsllhdr != NULL) {
304     data = netwib__buf_ref_data_ptr(ppkt);
305     netwib__data_decode_uint16t(data, plinuxsllhdr->pkttype,
306                               netwib_linuxsllhdrpkttype);
307     netwib__data_decode_uint16t(data, plinuxsllhdr->hatype,
308                               netwib_linuxsllhdrhatype);
309     netwib__data_decode_uint16(data, plinuxsllhdr->halen);
310     if (plinuxsllhdr->halen >= 8 ) {
311       netwib_c_memcpy(plinuxsllhdr->srcaddr, data, 8);
312     } else {
313       netwib_c_memcpy(plinuxsllhdr->srcaddr, data, plinuxsllhdr->halen);
314       netwib_c_memset(plinuxsllhdr->srcaddr+plinuxsllhdr->halen, 0,
315                       8-plinuxsllhdr->halen);
316     }
317     data += 8;
318     netwib__data_decode_uint16t(data, plinuxsllhdr->protocol,
319                                 netwib_etherhdrtype);
320   }
321 
322   return(NETWIB_ERR_OK);
323 }
324 
325 
326 /*-------------------------------------------------------------*/
327 /*-------------------------------------------------------------*/
328 
329 /*-------------------------------------------------------------*/
netwib_pkt_append_linkhdr(netwib_constlinkhdr * plinkhdr,netwib_buf * ppkt)330 netwib_err netwib_pkt_append_linkhdr(netwib_constlinkhdr *plinkhdr,
331                                      netwib_buf *ppkt)
332 {
333   switch(plinkhdr->type) {
334     case NETWIB_DEVICE_DLTTYPE_EN10MB :
335       netwib_er(netwib_pkt_append_etherhdr(&plinkhdr->hdr.ether, ppkt));
336       break;
337     case NETWIB_DEVICE_DLTTYPE_NULL :
338       netwib_er(netwib_pkt_append_nullhdr(&plinkhdr->hdr.null, ppkt));
339       break;
340     case NETWIB_DEVICE_DLTTYPE_LOOP :
341       netwib_er(netwib_pkt_append_loophdr(&plinkhdr->hdr.loop, ppkt));
342       break;
343     case NETWIB_DEVICE_DLTTYPE_RAW :
344     case NETWIB_DEVICE_DLTTYPE_RAW4 :
345     case NETWIB_DEVICE_DLTTYPE_RAW6 :
346       /* nothing to append */
347       break;
348     case NETWIB_DEVICE_DLTTYPE_PPP :
349       netwib_er(netwib_pkt_append_ppphdr(&plinkhdr->hdr.ppp, ppkt));
350       break;
351     case NETWIB_DEVICE_DLTTYPE_LINUX_SLL :
352       netwib_er(netwib_pkt_append_linuxsllhdr(&plinkhdr->hdr.linuxsll, ppkt));
353       break;
354     default :
355       return(NETWIB_ERR_LONOTIMPLEMENTED);
356       break;
357   }
358   return(NETWIB_ERR_OK);
359 }
360 
361 /*-------------------------------------------------------------*/
netwib_pkt_prepend_linkhdr(netwib_constlinkhdr * plinkhdr,netwib_buf * ppkt)362 netwib_err netwib_pkt_prepend_linkhdr(netwib_constlinkhdr *plinkhdr,
363                                       netwib_buf *ppkt)
364 {
365   netwib_byte array[NETWIB_LINKHDR_MAXLEN];
366   netwib_buf buf;
367   netwib_err ret;
368 
369   netwib_er(netwib_buf_init_ext_arrayempty(array, NETWIB_LINKHDR_MAXLEN,
370                                            &buf));
371   ret = netwib_pkt_append_linkhdr(plinkhdr, &buf);
372   if (ret == NETWIB_ERR_OK) {
373     ret = netwib_buf_prepend_buf(&buf, ppkt);
374   }
375 
376   return(ret);
377 }
378 
379 /*-------------------------------------------------------------*/
netwib_pkt_decode_linkhdr(netwib_device_dlttype dlttype,netwib_constbuf * ppkt,netwib_linkhdr * plinkhdr,netwib_uint32 * pskipsize)380 netwib_err netwib_pkt_decode_linkhdr(netwib_device_dlttype dlttype,
381                                      netwib_constbuf *ppkt,
382                                      netwib_linkhdr *plinkhdr,
383                                      netwib_uint32 *pskipsize)
384 {
385   netwib_iptype iptype;
386 
387   switch(dlttype) {
388     case NETWIB_DEVICE_DLTTYPE_EN10MB :
389       netwib_er(netwib_pkt_decode_etherhdr(ppkt,
390                                  (plinkhdr==NULL)?NULL:&plinkhdr->hdr.ether,
391                                            pskipsize));
392       break;
393     case NETWIB_DEVICE_DLTTYPE_NULL :
394       netwib_er(netwib_pkt_decode_nullhdr(ppkt,
395                                  (plinkhdr==NULL)?NULL:&plinkhdr->hdr.null,
396                                           pskipsize));
397       break;
398     case NETWIB_DEVICE_DLTTYPE_LOOP :
399       netwib_er(netwib_pkt_decode_loophdr(ppkt,
400                                  (plinkhdr==NULL)?NULL:&plinkhdr->hdr.loop,
401                                           pskipsize));
402       break;
403     case NETWIB_DEVICE_DLTTYPE_RAW :
404       netwib_er(netwib_priv_ippkt_decode_iptype(ppkt, &iptype));
405       switch(iptype) {
406       case NETWIB_IPTYPE_IP4 :
407         dlttype = NETWIB_DEVICE_DLTTYPE_RAW4;
408         break;
409       case NETWIB_IPTYPE_IP6 :
410         dlttype = NETWIB_DEVICE_DLTTYPE_RAW6;
411         break;
412       default :
413         break;
414       }
415       /* no break */
416     case NETWIB_DEVICE_DLTTYPE_RAW4 :
417     case NETWIB_DEVICE_DLTTYPE_RAW6 :
418       if (pskipsize != NULL) *pskipsize = NETWIB_RAWHDR_LEN;
419       break;
420     case NETWIB_DEVICE_DLTTYPE_PPP :
421       netwib_er(netwib_pkt_decode_ppphdr(ppkt,
422                                  (plinkhdr==NULL)?NULL:&plinkhdr->hdr.ppp,
423                                          pskipsize));
424       break;
425     case NETWIB_DEVICE_DLTTYPE_LINUX_SLL :
426       netwib_er(netwib_pkt_decode_linuxsllhdr(ppkt,
427                                  (plinkhdr==NULL)?NULL:&plinkhdr->hdr.linuxsll,
428                                               pskipsize));
429       break;
430     default :
431       return(NETWIB_ERR_LONOTIMPLEMENTED);
432       break;
433   }
434 
435   if (plinkhdr != NULL) plinkhdr->type = dlttype;
436 
437   return(NETWIB_ERR_OK);
438 }
439 
440 /*-------------------------------------------------------------*/
netwib_linkhdr_set_proto(netwib_linkhdr * plinkhdr,netwib_linkhdrproto linkhdrproto)441 netwib_err netwib_linkhdr_set_proto(netwib_linkhdr *plinkhdr,
442                                     netwib_linkhdrproto linkhdrproto)
443 {
444   netwib_etherhdrtype etherhdrtype = (netwib_etherhdrtype)0;
445   netwib_ppphdrproto ppphdrproto = (netwib_ppphdrproto)0;
446 
447   switch(linkhdrproto) {
448     case NETWIB_LINKHDRPROTO_IP4 :
449       etherhdrtype = NETWIB_ETHERHDRTYPE_IP4;
450       ppphdrproto = NETWIB_PPPHDRPROTO_IP4;
451       break;
452     case NETWIB_LINKHDRPROTO_IP6 :
453       etherhdrtype = NETWIB_ETHERHDRTYPE_IP6;
454       ppphdrproto = NETWIB_PPPHDRPROTO_IP6;
455       break;
456     case NETWIB_LINKHDRPROTO_ARP :
457       etherhdrtype = NETWIB_ETHERHDRTYPE_ARP;
458       ppphdrproto = (netwib_ppphdrproto)0;
459       break;
460     case NETWIB_LINKHDRPROTO_RARP :
461       etherhdrtype = NETWIB_ETHERHDRTYPE_RARP;
462       ppphdrproto = (netwib_ppphdrproto)0;
463       break;
464     case NETWIB_LINKHDRPROTO_IPX :
465       etherhdrtype = NETWIB_ETHERHDRTYPE_IPX;
466       ppphdrproto = NETWIB_PPPHDRPROTO_IPX;
467       break;
468     default :
469       return(NETWIB_ERR_LONOTIMPLEMENTED);
470       break;
471   }
472 
473   switch(plinkhdr->type) {
474     case NETWIB_DEVICE_DLTTYPE_EN10MB :
475       plinkhdr->hdr.ether.type = etherhdrtype;
476       break;
477     case NETWIB_DEVICE_DLTTYPE_NULL :
478       plinkhdr->hdr.null.type = etherhdrtype;
479       break;
480     case NETWIB_DEVICE_DLTTYPE_LOOP :
481       plinkhdr->hdr.loop.type = etherhdrtype;
482       break;
483     case NETWIB_DEVICE_DLTTYPE_RAW :
484     case NETWIB_DEVICE_DLTTYPE_RAW4 :
485     case NETWIB_DEVICE_DLTTYPE_RAW6 :
486       /* nothing to store */
487       break;
488     case NETWIB_DEVICE_DLTTYPE_PPP :
489       if (ppphdrproto == 0) {
490         return(NETWIB_ERR_LONOTIMPLEMENTED);
491       }
492       plinkhdr->hdr.ppp.protocol = ppphdrproto;
493       break;
494     case NETWIB_DEVICE_DLTTYPE_LINUX_SLL :
495       plinkhdr->hdr.linuxsll.protocol = etherhdrtype;
496       break;
497     default :
498       return(NETWIB_ERR_LONOTIMPLEMENTED);
499       break;
500   }
501   return(NETWIB_ERR_OK);
502 }
503 
504 /*-------------------------------------------------------------*/
netwib_linkhdr_get_proto(netwib_constlinkhdr * plinkhdr,netwib_linkhdrproto * plinkhdrproto)505 netwib_err netwib_linkhdr_get_proto(netwib_constlinkhdr *plinkhdr,
506                                     netwib_linkhdrproto *plinkhdrproto)
507 {
508   netwib_etherhdrtype etherhdrtype = (netwib_etherhdrtype)0;
509   netwib_ppphdrproto ppphdrproto = (netwib_ppphdrproto)0;
510   netwib_linkhdrproto linkhdrproto = (netwib_linkhdrproto)0;
511   netwib_bool etherset;
512 
513   etherset = NETWIB_TRUE;
514 
515   switch(plinkhdr->type) {
516     case NETWIB_DEVICE_DLTTYPE_EN10MB :
517       etherhdrtype = plinkhdr->hdr.ether.type;
518       break;
519     case NETWIB_DEVICE_DLTTYPE_NULL :
520       etherhdrtype = plinkhdr->hdr.null.type;
521       break;
522     case NETWIB_DEVICE_DLTTYPE_LOOP :
523       etherhdrtype = plinkhdr->hdr.loop.type;
524       break;
525     case NETWIB_DEVICE_DLTTYPE_RAW :
526       /* IPv4 or IPv6, but don't know which one */
527       return(NETWIB_ERR_NOTCONVERTED);
528       break;
529     case NETWIB_DEVICE_DLTTYPE_RAW4 :
530       etherhdrtype = NETWIB_ETHERHDRTYPE_IP4;
531       break;
532     case NETWIB_DEVICE_DLTTYPE_RAW6 :
533       etherhdrtype = NETWIB_ETHERHDRTYPE_IP6;
534       break;
535     case NETWIB_DEVICE_DLTTYPE_PPP :
536       ppphdrproto = plinkhdr->hdr.ppp.protocol;
537       etherset = NETWIB_FALSE;
538       break;
539     case NETWIB_DEVICE_DLTTYPE_LINUX_SLL :
540       etherhdrtype = plinkhdr->hdr.linuxsll.protocol;
541       break;
542     default :
543       return(NETWIB_ERR_LONOTIMPLEMENTED);
544       break;
545   }
546 
547   if (etherset) {
548     switch(etherhdrtype) {
549       case NETWIB_ETHERHDRTYPE_IP4 :
550         linkhdrproto = NETWIB_LINKHDRPROTO_IP4;
551         break;
552       case NETWIB_ETHERHDRTYPE_IP6 :
553         linkhdrproto = NETWIB_LINKHDRPROTO_IP6;
554         break;
555       case NETWIB_ETHERHDRTYPE_ARP :
556         linkhdrproto = NETWIB_LINKHDRPROTO_ARP;
557         break;
558       case NETWIB_ETHERHDRTYPE_RARP :
559         linkhdrproto = NETWIB_LINKHDRPROTO_RARP;
560         break;
561       case NETWIB_ETHERHDRTYPE_IPX :
562         linkhdrproto = NETWIB_LINKHDRPROTO_IPX;
563         break;
564       default :
565         linkhdrproto = NETWIB_LINKHDRPROTO_UNKNOWN;
566         break;
567     }
568   } else {
569     switch(ppphdrproto) {
570       case NETWIB_PPPHDRPROTO_IP4 :
571         linkhdrproto = NETWIB_LINKHDRPROTO_IP4;
572       case NETWIB_PPPHDRPROTO_IP6 :
573         linkhdrproto = NETWIB_LINKHDRPROTO_IP6;
574         break;
575       case NETWIB_PPPHDRPROTO_IPX :
576         linkhdrproto = NETWIB_LINKHDRPROTO_IPX;
577         break;
578       default :
579         linkhdrproto = NETWIB_LINKHDRPROTO_UNKNOWN;
580         break;
581     }
582   }
583 
584   if (plinkhdrproto != NULL) *plinkhdrproto = linkhdrproto;
585   return(NETWIB_ERR_OK);
586 }
587