new conventions for obtaining freeing ancillary data
[unix-history] / usr / src / sys / netiso / if_eon.c
CommitLineData
109874b6
KS
1/***********************************************************
2 Copyright IBM Corporation 1987
3
4 All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of IBM not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22******************************************************************/
23
24/*
25 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26 */
27/*
28 * $Header: if_eon.c,v 1.4 88/07/19 15:53:59 hagens Exp $
29 * $Source: /usr/argo/sys/netiso/RCS/if_eon.c,v $
124336d0 30 * @(#)if_eon.c 7.7 (Berkeley) %G% *
109874b6
KS
31 *
32 * EON rfc
33 * Layer between IP and CLNL
34 *
35 * TODO:
36 * Put together a current rfc986 address format and get the right offset
37 * for the nsel
38 */
109874b6
KS
39
40#ifndef lint
41static char *rcsid = "$Header: if_eon.c,v 1.4 88/07/19 15:53:59 hagens Exp $";
42#endif lint
43
a50e2bc0
KS
44#ifdef EON
45#define NEON 1
46
109874b6
KS
47
48#include "param.h"
49#include "systm.h"
50#include "types.h"
51#include "mbuf.h"
52#include "buf.h"
53#include "protosw.h"
54#include "socket.h"
55#include "ioctl.h"
56#include "errno.h"
57#include "types.h"
58
109874b6 59#include "../net/if.h"
4f565be6 60#include "../net/if_types.h"
6ffae239 61#include "../net/if_dl.h"
109874b6
KS
62#include "../net/netisr.h"
63#include "../net/route.h"
d301d150 64#include "machine/mtpr.h"
109874b6
KS
65
66#include "../netinet/in.h"
67#include "../netinet/in_systm.h"
6ffae239 68#include "../netinet/in_var.h"
109874b6
KS
69#include "../netinet/ip.h"
70#include "../netinet/ip_var.h"
71#include "../netinet/if_ether.h"
72
a50e2bc0
KS
73#include "iso.h"
74#include "iso_var.h"
75#include "iso_snpac.h"
76extern struct snpa_cache all_es, all_is;
77#include "argo_debug.h"
78#include "iso_errno.h"
79#include "eonvar.h"
4f565be6 80extern struct timeval time;
109874b6
KS
81
82#define EOK 0
83
84int eoninput();
109874b6
KS
85int eonoutput();
86int eonioctl();
109874b6
KS
87int eonattach();
88int eoninit();
6ffae239 89int eonrtrequest();
109874b6 90extern int ip_output();
6ffae239 91struct ifnet eonif[1];
a50e2bc0
KS
92
93eonprotoinit() {
6ffae239 94 (void) eonattach();
a50e2bc0 95}
109874b6 96
6ffae239
KS
97struct eon_llinfo eon_llinfo;
98#define PROBE_OK 0;
109874b6 99
109874b6
KS
100
101/*
102 * FUNCTION: eonattach
103 *
104 * PURPOSE: autoconf attach routine
105 *
106 * RETURNS: void
107 */
108
6ffae239 109eonattach()
109874b6 110{
6ffae239 111 register struct ifnet *ifp = eonif;
109874b6
KS
112
113 IFDEBUG(D_EON)
114 printf("eonattach()\n");
115 ENDDEBUG
6ffae239 116 ifp->if_unit = 0;
109874b6
KS
117 ifp->if_name = "eon";
118 ifp->if_mtu = ETHERMTU;
119 /* since everything will go out over ether or token ring */
120
121 ifp->if_init = eoninit;
a50e2bc0 122 ifp->if_ioctl = eonioctl;
109874b6 123 ifp->if_output = eonoutput;
a50e2bc0
KS
124 ifp->if_type = IFT_EON;
125 ifp->if_addrlen = 5;
126 ifp->if_hdrlen = EONIPLEN;
109874b6
KS
127 ifp->if_flags = IFF_BROADCAST;
128 if_attach(ifp);
6ffae239
KS
129 eonioctl(ifp, SIOCSIFADDR, (caddr_t)ifp->if_addrlist);
130 eon_llinfo.el_qhdr.link =
131 eon_llinfo.el_qhdr.rlink = &(eon_llinfo.el_qhdr);
109874b6
KS
132
133 IFDEBUG(D_EON)
134 printf("eonattach()\n");
135 ENDDEBUG
109874b6
KS
136}
137
109874b6
KS
138
139/*
140 * FUNCTION: eonioctl
141 *
142 * PURPOSE: io controls - ifconfig
143 * need commands to
144 * link-UP (core addr) (flags: ES, IS)
145 * link-DOWN (core addr) (flags: ES, IS)
146 * must be callable from kernel or user
147 *
148 * RETURNS: nothing
149 */
150eonioctl(ifp, cmd, data)
151 register struct ifnet *ifp;
6ffae239 152 int cmd;
109874b6
KS
153 register caddr_t data;
154{
6ffae239 155 int s = splimp();
109874b6
KS
156 register int error = 0;
157
158 IFDEBUG(D_EON)
159 printf("eonioctl (cmd 0x%x) \n", cmd);
160 ENDDEBUG
161
6ffae239
KS
162 switch (cmd) {
163 register struct ifaddr *ifa;
9f05a572 164 extern link_rtrequest();
109874b6
KS
165
166 case SIOCSIFADDR:
6ffae239
KS
167 if (ifa = (struct ifaddr *)data) {
168 ifp->if_flags |= IFF_UP;
9f05a572
KS
169 if (ifa->ifa_addr->sa_family != AF_LINK)
170 ifa->ifa_rtrequest = eonrtrequest;
6ffae239 171 ifa->ifa_llinfolen = sizeof(struct eon_llinfo);
9f05a572 172 }
109874b6 173 break;
109874b6
KS
174 }
175 splx(s);
176 return(error);
177}
178
6ffae239
KS
179
180eoniphdr(hdr, loc, ro, class, zero)
181struct route *ro;
182register struct eon_iphdr *hdr;
183caddr_t loc;
184{
185 struct mbuf mhead;
186 register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst;
187 if (zero) {
188 bzero((caddr_t)hdr, sizeof (*hdr));
189 bzero((caddr_t)ro, sizeof (*ro));
190 }
191 sin->sin_family = AF_INET;
192 sin->sin_len = sizeof (*sin);
193 bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr));
194 hdr->ei_ip.ip_dst = sin->sin_addr;
195 hdr->ei_ip.ip_p = IPPROTO_EON;
196 hdr->ei_ip.ip_ttl = MAXTTL;
197 hdr->ei_eh.eonh_class = class;
198 hdr->ei_eh.eonh_vers = EON_VERSION;
199 hdr->ei_eh.eonh_csum = 0;
200 mhead.m_data = (caddr_t) &hdr->ei_eh;
201 mhead.m_len = sizeof(struct eon_hdr);
202 mhead.m_next = 0;
203 IFDEBUG(D_EON)
204 printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n",
205 &mhead,
206 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
207 ENDDEBUG
208 iso_gen_csum(&mhead,
209 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
210}
109874b6 211/*
6ffae239 212 * FUNCTION: eonrtrequest
109874b6 213 *
6ffae239
KS
214 * PURPOSE: maintains list of direct eon recipients.
215 * sets up IP route for rest.
109874b6
KS
216 *
217 * RETURNS: nothing
218 */
6ffae239
KS
219eonrtrequest(cmd, rt, gate)
220register struct rtentry *rt;
221struct sockaddr *gate;
109874b6 222{
6ffae239
KS
223 caddr_t ipaddrloc = 0;
224 register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo;
225 register struct rtentry *iprt;
226 register struct sockaddr_in sin;
227
228 if (el == 0)
229 panic("eonrtrequest");
230 iprt = el->el_iproute.ro_rt;
231 /*
232 * Common Housekeeping
233 */
234 switch (cmd) {
235
236 case RTM_ADD:
237 insque(&(el->el_qhdr), &eon_llinfo.el_qhdr);
238 el->el_rt = rt;
239 break;
109874b6 240
6ffae239
KS
241 case RTM_DELETE:
242 remque(&(el->el_qhdr));
243 /* FALLTHROUGH */
244 case RTM_CHANGE:
245 el->el_flags &= ~RTF_UP;
246 if (iprt)
247 RTFREE(iprt);
248 if (cmd = RTM_DELETE)
249 return;
250 }
251 if (gate || (gate = rt->rt_gateway)) switch (gate->sa_family) {
252 case AF_LINK:
253 ipaddrloc = LLADDR((struct sockaddr_dl *)gate);
254 break;
255 case AF_INET:
256 ipaddrloc = (caddr_t) &((struct sockaddr_in *)gate)->sin_addr;
257 break;
258 default:
259 return;
260 }
261 el->el_flags |= RTF_UP;
262 eoniphdr(&el->el_ei, &el->el_iproute, ipaddrloc, EON_NORMAL_ADDR, 0);
263}
109874b6
KS
264
265/*
6ffae239 266 * FUNCTION: eoninit
109874b6 267 *
6ffae239 268 * PURPOSE: initialization
109874b6
KS
269 *
270 * RETURNS: nothing
109874b6
KS
271 */
272
6ffae239
KS
273eoninit(unit)
274 int unit;
109874b6 275{
6ffae239 276 printf("eon driver-init eon%d\n", unit);
109874b6
KS
277}
278
279
280/*
281 * FUNCTION: eonoutput
282 *
283 * PURPOSE: prepend an eon header and hand to IP
284 * ARGUMENTS: (ifp) is points to the ifnet structure for this unit/device
285 * (m) is an mbuf *, *m is a CLNL packet
286 * (dst) is a destination address - have to interp. as
287 * multicast or broadcast or real address.
288 *
289 * RETURNS: unix error code
290 *
291 * NOTES:
292 *
293 */
6ffae239 294eonoutput(ifp, m, dst, rt)
a50e2bc0 295 struct ifnet *ifp;
6ffae239 296 register struct mbuf *m; /* packet */
109874b6 297 struct sockaddr_iso *dst; /* destination addr */
6ffae239 298 struct rtentry *rt;
109874b6 299{
6ffae239
KS
300 register struct eon_llinfo *el;
301 register struct eon_iphdr *ei;
302 struct route *ro;
303 int datalen;
304 struct mbuf *mh;
305 int error = 0;
306 caddr_t ippaddrloc;
307 static struct eon_iphdr eon_iphdr;
308 static struct route route;
109874b6
KS
309
310 IFDEBUG(D_EON)
311 printf("eonoutput \n" );
312 ENDDEBUG
313
4f565be6
KS
314 ifp->if_lastchange = time;
315 ifp->if_opackets++;
6ffae239
KS
316 if (rt == 0 || (el = (struct eon_llinfo *)rt->rt_llinfo) == 0) {
317 if (dst->siso_family == AF_LINK) {
318 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)dst;
319 caddr_t ipaddrloc = LLADDR(sdl);
320 int class = (sdl->sdl_alen == 5) ? 4[(u_char *)ipaddrloc] : 0;
321
322 if (sdl->sdl_alen == 4 || sdl->sdl_alen == 5) {
323 ipaddrloc = LLADDR(sdl);
324 ro = &route;
325 ei = &eon_iphdr;
326 eoniphdr(ei, ipaddrloc, ro, class, 1);
327 goto send;
328 }
329 }
330einval:
a50e2bc0
KS
331 error = EINVAL;
332 goto flush;
333 }
6ffae239
KS
334 if ((el->el_flags & RTF_UP) == 0) {
335 eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0);
336 if ((el->el_flags & RTF_UP) == 0) {
337 error = EHOSTUNREACH;
338 goto flush;
339 }
340 }
341 if ((m->m_flags & M_PKTHDR) == 0) {
a50e2bc0
KS
342 printf("eon: got non headered packet\n");
343 goto einval;
344 }
6ffae239
KS
345 ei = &el->el_ei;
346 ro = &el->el_iproute;
347send:
348 /* put an eon_hdr in the buffer, prepended by an ip header */
349 datalen = m->m_pkthdr.len + EONIPLEN;
a50e2bc0
KS
350 MGETHDR(mh, M_DONTWAIT, MT_HEADER);
351 if(mh == (struct mbuf *)0)
6ffae239
KS
352 goto flush;
353 mh->m_next = m;
354 m = mh;
355 MH_ALIGN(m, sizeof(struct eon_iphdr));
356 m->m_len = sizeof(struct eon_iphdr);
4f565be6 357 ifp->if_obytes +=
6ffae239
KS
358 (ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen));
359 *mtod(m, struct eon_iphdr *) = *ei;
109874b6
KS
360
361 IFDEBUG(D_EON)
6ffae239
KS
362 printf("eonoutput dst ip addr : %x\n", ei->ei_ip.ip_dst.s_addr);
363 printf("eonoutput ip_output : eonip header:\n");
364 dump_buf(ei, sizeof(struct eon_iphdr));
109874b6
KS
365 ENDDEBUG
366
6ffae239
KS
367 error = ip_output(m, (struct mbuf *)0, ro, 0);
368 m = 0;
4f565be6
KS
369 if (error) {
370 ifp->if_oerrors++;
371 ifp->if_opackets--;
6ffae239 372 ifp->if_obytes -= datalen;
4f565be6 373 }
6ffae239
KS
374flush:
375 if (m)
376 m_freem(m);
109874b6
KS
377 return error;
378}
379
a50e2bc0 380eoninput(m, iphlen)
109874b6 381 register struct mbuf *m;
a50e2bc0 382 int iphlen;
109874b6 383{
109874b6
KS
384 register struct eon_hdr *eonhdr;
385 register struct ip *iphdr;
386 struct ifnet *eonifp;
a50e2bc0 387 int s;
109874b6
KS
388
389 eonifp = &eonif[0]; /* kludge - really want to give CLNP
390 * the ifp for eon, not for the real device
391 */
392
393 IFDEBUG(D_EON)
a50e2bc0
KS
394 printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n",
395 m, m?m->m_data:0, m?m->m_len:0);
109874b6
KS
396 ENDDEBUG
397
a50e2bc0
KS
398 if (m == 0)
399 return;
400 if (iphlen > sizeof (struct ip))
401 ip_stripoptions(m, (struct mbuf *)0);
402 if (m->m_len < EONIPLEN) {
403 if ((m = m_pullup(m, EONIPLEN)) == 0) {
404 IncStat(es_badhdr);
405drop:
406 IFDEBUG(D_EON)
407 printf("eoninput: DROP \n" );
408 ENDDEBUG
409 eonifp->if_ierrors ++;
410 m_freem(m);
411 return;
412 }
109874b6 413 }
4f565be6
KS
414 eonif->if_ibytes += m->m_pkthdr.len;
415 eonif->if_lastchange = time;
109874b6 416 iphdr = mtod(m, struct ip *);
109874b6
KS
417 /* do a few checks for debugging */
418 if( iphdr->ip_p != IPPROTO_EON ) {
419 IncStat(es_badhdr);
420 goto drop;
421 }
a50e2bc0
KS
422 /* temporarily drop ip header from the mbuf */
423 m->m_data += sizeof(struct ip);
109874b6 424 eonhdr = mtod(m, struct eon_hdr *);
a50e2bc0
KS
425 if( iso_check_csum( m, sizeof(struct eon_hdr) ) != EOK ) {
426 IncStat(es_badcsum);
427 goto drop;
428 }
429 m->m_data -= sizeof(struct ip);
430
109874b6 431 IFDEBUG(D_EON)
a50e2bc0 432 printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class );
109874b6
KS
433 printf("eoninput: eon header:\n");
434 dump_buf(eonhdr, sizeof(struct eon_hdr));
435 ENDDEBUG
436
437 /* checks for debugging */
438 if( eonhdr->eonh_vers != EON_VERSION) {
439 IncStat(es_badhdr);
440 goto drop;
441 }
a50e2bc0 442 m->m_flags &= ~(M_BCAST|M_MCAST);
109874b6
KS
443 switch( eonhdr->eonh_class) {
444 case EON_BROADCAST:
445 IncStat(es_in_broad);
a50e2bc0 446 m->m_flags |= M_BCAST;
109874b6
KS
447 break;
448 case EON_NORMAL_ADDR:
449 IncStat(es_in_normal);
450 break;
451 case EON_MULTICAST_ES:
109874b6 452 IncStat(es_in_multi_es);
a50e2bc0 453 m->m_flags |= M_MCAST;
109874b6
KS
454 break;
455 case EON_MULTICAST_IS:
109874b6 456 IncStat(es_in_multi_is);
a50e2bc0 457 m->m_flags |= M_MCAST;
109874b6
KS
458 break;
459 }
4f565be6 460 eonifp->if_ipackets++;
109874b6 461
109874b6
KS
462 {
463 /* put it on the CLNP queue and set soft interrupt */
464 struct ifqueue *ifq;
465 extern struct ifqueue clnlintrq;
109874b6 466
a50e2bc0 467 m->m_pkthdr.rcvif = eonifp; /* KLUDGE */
109874b6
KS
468 IFDEBUG(D_EON)
469 printf("eoninput to clnl IFQ\n");
470 ENDDEBUG
471 ifq = &clnlintrq;
a50e2bc0 472 s = splimp();
109874b6
KS
473 if (IF_QFULL(ifq)) {
474 IF_DROP(ifq);
475 m_freem(m);
4f565be6
KS
476 eonifp->if_iqdrops++;
477 eonifp->if_ipackets--;
a50e2bc0 478 splx(s);
109874b6
KS
479 return;
480 }
481 IF_ENQUEUE(ifq, m);
482 IFDEBUG(D_EON)
483 printf(
a50e2bc0
KS
484 "0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n",
485 m, m->m_len, m->m_type, m->m_data);
109874b6
KS
486 dump_buf(mtod(m, caddr_t), m->m_len);
487 ENDDEBUG
a50e2bc0
KS
488 schednetisr(NETISR_ISO);
489 splx(s);
109874b6 490 }
109874b6
KS
491}
492
493int
494eonctlinput(cmd, sin)
495 int cmd;
496 struct sockaddr_in *sin;
497{
498 extern u_char inetctlerrmap[];
499
500 IFDEBUG(D_EON)
501 printf("eonctlinput: cmd 0x%x addr: ", cmd);
502 dump_isoaddr(sin);
503 printf("\n");
504 ENDDEBUG
505
506 if (cmd < 0 || cmd > PRC_NCMDS)
507 return 0;
508
509 IncStat(es_icmp[cmd]);
510 switch (cmd) {
511
109874b6 512 case PRC_QUENCH:
a50e2bc0 513 case PRC_QUENCH2:
109874b6
KS
514 /* TODO: set the dec bit */
515 break;
516 case PRC_TIMXCEED_REASS:
517 case PRC_ROUTEDEAD:
518 case PRC_HOSTUNREACH:
519 case PRC_UNREACH_NET:
520 case PRC_IFDOWN:
521 case PRC_UNREACH_HOST:
522 case PRC_HOSTDEAD:
523 case PRC_TIMXCEED_INTRANS:
524 /* TODO: mark the link down */
525 break;
526
527 case PRC_UNREACH_PROTOCOL:
528 case PRC_UNREACH_PORT:
109874b6
KS
529 case PRC_UNREACH_SRCFAIL:
530 case PRC_REDIRECT_NET:
531 case PRC_REDIRECT_HOST:
532 case PRC_REDIRECT_TOSNET:
533 case PRC_REDIRECT_TOSHOST:
534 case PRC_MSGSIZE:
535 case PRC_PARAMPROB:
536 printf("eonctlinput: ICMP cmd 0x%x\n", cmd );
537 break;
538 }
539 return 0;
540}
541
a50e2bc0 542#endif