ddp_output.c revision 23396
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/socketvar.h>
30#include <sys/errno.h>
31#include <sys/syslog.h>
32
33#include <net/if.h>
34#include <net/route.h>
35
36#include <netinet/in.h>
37#undef s_net
38#include <netinet/if_ether.h>
39
40#include <netatalk/at.h>
41#include <netatalk/at_var.h>
42#include <netatalk/endian.h>
43#include <netatalk/ddp.h>
44#include <netatalk/ddp_var.h>
45#include <netatalk/at_extern.h>
46
47int	ddp_cksum = 1;
48
49int
50/*ddp_output( struct ddpcb *ddp, struct mbuf *m)*/
51ddp_output( struct mbuf *m, struct socket *so)
52{
53    struct ddpehdr	*deh;
54    struct ddpcb *ddp = sotoddpcb( so );
55
56    M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT );
57
58    deh = mtod( m, struct ddpehdr *);
59    deh->deh_pad = 0;
60    deh->deh_hops = 0;
61
62    deh->deh_len = m->m_pkthdr.len;
63
64    deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net;
65    deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node;
66    deh->deh_dport = ddp->ddp_fsat.sat_port;
67    deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net;
68    deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node;
69    deh->deh_sport = ddp->ddp_lsat.sat_port;
70
71    /*
72     * The checksum calculation is done after all of the other bytes have
73     * been filled in.
74     */
75    if ( ddp_cksum ) {
76	deh->deh_sum = at_cksum( m, sizeof( int ));
77    } else {
78	deh->deh_sum = 0;
79    }
80    deh->deh_bytes = htonl( deh->deh_bytes );
81
82    return( ddp_route( m, &ddp->ddp_route ));
83}
84
85u_short
86at_cksum( struct mbuf *m, int skip)
87{
88    u_char	*data, *end;
89    u_long	cksum = 0;
90
91    for (; m; m = m->m_next ) {
92	for ( data = mtod( m, u_char * ), end = data + m->m_len; data < end;
93		data++ ) {
94	    if ( skip ) {
95		skip--;
96		continue;
97	    }
98	    cksum = ( cksum + *data ) << 1;
99	    if ( cksum & 0x00010000 ) {
100		cksum++;
101	    }
102	    cksum &= 0x0000ffff;
103	}
104    }
105
106    if ( cksum == 0 ) {
107	cksum = 0x0000ffff;
108    }
109    return( (u_short)cksum );
110}
111
112int
113ddp_route( struct mbuf *m, struct route *ro)
114{
115    struct sockaddr_at	gate;
116    struct elaphdr	*elh;
117    struct mbuf		*m0;
118    struct at_ifaddr	*aa = NULL;
119    struct ifnet	*ifp = NULL;
120    u_short		net;
121
122    if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
123	net = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_net;
124	for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
125	    if ( aa->aa_ifp == ifp &&
126		    ntohs( net ) >= ntohs( aa->aa_firstnet ) &&
127		    ntohs( net ) <= ntohs( aa->aa_lastnet )) {
128		break;
129	    }
130	}
131    }
132    if ( aa == NULL ) {
133printf( "ddp_route: oops\n" );
134	m_freem( m );
135	return( EINVAL );
136    }
137
138    /*
139     * There are several places in the kernel where data is added to
140     * an mbuf without ensuring that the mbuf pointer is aligned.
141     * This is bad for transition routing, since phase 1 and phase 2
142     * packets end up poorly aligned due to the three byte elap header.
143     */
144    if ( !(aa->aa_flags & AFA_PHASE2) ) {
145	MGET( m0, M_WAIT, MT_HEADER );
146	if ( m0 == 0 ) {
147	    m_freem( m );
148	    printf("ddp_route: no buffers\n");
149	    return( ENOBUFS );
150	}
151	m0->m_next = m;
152	/* XXX perhaps we ought to align the header? */
153	m0->m_len = SZ_ELAPHDR;
154	m = m0;
155
156	elh = mtod( m, struct elaphdr *);
157	elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node;
158	elh->el_type = ELAP_DDPEXTEND;
159	if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
160		ntohs( aa->aa_firstnet ) &&
161		ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
162		ntohs( aa->aa_lastnet )) {
163	    elh->el_dnode = satosat( &ro->ro_dst )->sat_addr.s_node;
164	} else {
165	    elh->el_dnode = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_node;
166	}
167    }
168
169    if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
170	    ntohs( aa->aa_firstnet ) &&
171	    ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
172	    ntohs( aa->aa_lastnet )) {
173	gate = *satosat( &ro->ro_dst );
174    } else {
175	gate = *satosat( ro->ro_rt->rt_gateway );
176    }
177    ro->ro_rt->rt_use++;
178
179    return((*ifp->if_output)( ifp,
180	m, (struct sockaddr *)&gate, NULL)); /* XXX */
181}
182