ddp_output.c revision 17254
1/*
2 * Copyright (c) 1990,1991 Regents of The University of Michigan.
3 * All Rights Reserved.
4 *
5 * Permission to use, copy, modify, and distribute this software and
6 * its documentation for any purpose and without fee is hereby granted,
7 * provided that the above copyright notice appears in all copies and
8 * that both that copyright notice and this permission notice appear
9 * in supporting documentation, and that the name of The University
10 * of Michigan not be used in advertising or publicity pertaining to
11 * distribution of the software without specific, written prior
12 * permission. This software is supplied as is without expressed or
13 * implied warranties of any kind.
14 *
15 *	Research Systems Unix Group
16 *	The University of Michigan
17 *	c/o Mike Clark
18 *	535 W. William Street
19 *	Ann Arbor, Michigan
20 *	+1-313-763-0525
21 *	netatalk@itd.umich.edu
22 */
23
24#include <sys/types.h>
25#include <sys/param.h>
26#include <sys/systm.h>
27#include <sys/mbuf.h>
28#include <sys/socket.h>
29#include <sys/errno.h>
30#include <sys/syslog.h>
31
32#include <net/if.h>
33#include <net/route.h>
34
35#include <netinet/in.h>
36#undef s_net
37#include <netinet/if_ether.h>
38
39#include "at.h"
40#include "at_var.h"
41#include "endian.h"
42#include "ddp.h"
43#include "ddp_var.h"
44#include <netatalk/at_extern.h>
45
46int	ddp_cksum = 1;
47
48int
49ddp_output( struct ddpcb *ddp, struct mbuf *m)
50{
51    struct ddpehdr	*deh;
52
53    M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT );
54
55    deh = mtod( m, struct ddpehdr *);
56    deh->deh_pad = 0;
57    deh->deh_hops = 0;
58
59    deh->deh_len = m->m_pkthdr.len;
60
61    deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net;
62    deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node;
63    deh->deh_dport = ddp->ddp_fsat.sat_port;
64    deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net;
65    deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node;
66    deh->deh_sport = ddp->ddp_lsat.sat_port;
67
68    /*
69     * The checksum calculation is done after all of the other bytes have
70     * been filled in.
71     */
72    if ( ddp_cksum ) {
73	deh->deh_sum = at_cksum( m, sizeof( int ));
74    } else {
75	deh->deh_sum = 0;
76    }
77    deh->deh_bytes = htonl( deh->deh_bytes );
78
79    return( ddp_route( m, &ddp->ddp_route ));
80}
81
82u_short
83at_cksum( struct mbuf *m, int skip)
84{
85    u_char	*data, *end;
86    u_long	cksum = 0;
87
88    for (; m; m = m->m_next ) {
89	for ( data = mtod( m, u_char * ), end = data + m->m_len; data < end;
90		data++ ) {
91	    if ( skip ) {
92		skip--;
93		continue;
94	    }
95	    cksum = ( cksum + *data ) << 1;
96	    if ( cksum & 0x00010000 ) {
97		cksum++;
98	    }
99	    cksum &= 0x0000ffff;
100	}
101    }
102
103    if ( cksum == 0 ) {
104	cksum = 0x0000ffff;
105    }
106    return( (u_short)cksum );
107}
108
109int
110ddp_route( struct mbuf *m, struct route *ro)
111{
112    struct sockaddr_at	gate;
113    struct elaphdr	*elh;
114    struct mbuf		*m0;
115    struct at_ifaddr	*aa = NULL;
116    struct ifnet	*ifp = NULL;
117    u_short		net;
118
119    if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
120	net = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_net;
121	for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
122	    if ( aa->aa_ifp == ifp &&
123		    ntohs( net ) >= ntohs( aa->aa_firstnet ) &&
124		    ntohs( net ) <= ntohs( aa->aa_lastnet )) {
125		break;
126	    }
127	}
128    }
129    if ( aa == NULL ) {
130printf( "ddp_route: oops\n" );
131	m_freem( m );
132	return( EINVAL );
133    }
134
135    /*
136     * There are several places in the kernel where data is added to
137     * an mbuf without ensuring that the mbuf pointer is aligned.
138     * This is bad for transition routing, since phase 1 and phase 2
139     * packets end up poorly aligned due to the three byte elap header.
140     */
141    if ( !(aa->aa_flags & AFA_PHASE2) ) {
142	MGET( m0, M_WAIT, MT_HEADER );
143	if ( m0 == 0 ) {
144	    m_freem( m );
145	    printf("ddp_route: no buffers\n");
146	    return( ENOBUFS );
147	}
148	m0->m_next = m;
149	/* XXX perhaps we ought to align the header? */
150	m0->m_len = SZ_ELAPHDR;
151	m = m0;
152
153	elh = mtod( m, struct elaphdr *);
154	elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node;
155	elh->el_type = ELAP_DDPEXTEND;
156	if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
157		ntohs( aa->aa_firstnet ) &&
158		ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
159		ntohs( aa->aa_lastnet )) {
160	    elh->el_dnode = satosat( &ro->ro_dst )->sat_addr.s_node;
161	} else {
162	    elh->el_dnode = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_node;
163	}
164    }
165
166    if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
167	    ntohs( aa->aa_firstnet ) &&
168	    ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
169	    ntohs( aa->aa_lastnet )) {
170	gate = *satosat( &ro->ro_dst );
171    } else {
172	gate = *satosat( ro->ro_rt->rt_gateway );
173    }
174    ro->ro_rt->rt_use++;
175
176    return((*ifp->if_output)( ifp,
177	m, (struct sockaddr *)&gate, NULL)); /* XXX */
178}
179