ddp_output.c revision 165974
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/* $FreeBSD: head/sys/netatalk/ddp_output.c 165974 2007-01-12 15:07:51Z rwatson $ */
25
26#include "opt_mac.h"
27
28#include <sys/param.h>
29#include <sys/systm.h>
30#include <sys/mbuf.h>
31#include <sys/socket.h>
32#include <sys/socketvar.h>
33
34#include <net/if.h>
35#include <net/route.h>
36
37#undef s_net
38
39#include <netatalk/at.h>
40#include <netatalk/at_var.h>
41#include <netatalk/ddp.h>
42#include <netatalk/ddp_var.h>
43#include <netatalk/at_extern.h>
44
45#include <security/mac/mac_framework.h>
46
47int	ddp_cksum = 1;
48
49int
50ddp_output(struct mbuf *m, struct socket *so)
51{
52	struct ddpehdr	*deh;
53	struct ddpcb *ddp = sotoddpcb(so);
54
55#ifdef MAC
56	SOCK_LOCK(so);
57	mac_create_mbuf_from_socket(so, m);
58	SOCK_UNLOCK(so);
59#endif
60
61	M_PREPEND(m, sizeof(struct ddpehdr), M_DONTWAIT);
62	if (m == NULL)
63	return (ENOBUFS);
64
65	deh = mtod(m, struct ddpehdr *);
66	deh->deh_pad = 0;
67	deh->deh_hops = 0;
68
69	deh->deh_len = m->m_pkthdr.len;
70
71	deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net;
72	deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node;
73	deh->deh_dport = ddp->ddp_fsat.sat_port;
74	deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net;
75	deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node;
76	deh->deh_sport = ddp->ddp_lsat.sat_port;
77
78	/*
79	 * The checksum calculation is done after all of the other bytes have
80	 * been filled in.
81	 */
82	if (ddp_cksum)
83		deh->deh_sum = at_cksum(m, sizeof(int));
84	else
85		deh->deh_sum = 0;
86	deh->deh_bytes = htonl(deh->deh_bytes);
87
88#ifdef NETATALK_DEBUG
89	printf ("ddp_output: from %d.%d:%d to %d.%d:%d\n",
90	ntohs(deh->deh_snet), deh->deh_snode, deh->deh_sport,
91	ntohs(deh->deh_dnet), deh->deh_dnode, deh->deh_dport);
92#endif
93	return (ddp_route(m, &ddp->ddp_route));
94}
95
96u_short
97at_cksum(struct mbuf *m, int skip)
98{
99	u_char	*data, *end;
100	u_long	cksum = 0;
101
102	for (; m; m = m->m_next) {
103		for (data = mtod(m, u_char *), end = data + m->m_len;
104		    data < end; data++) {
105			if (skip) {
106				skip--;
107				continue;
108			}
109			cksum = (cksum + *data) << 1;
110			if (cksum & 0x00010000)
111				cksum++;
112			cksum &= 0x0000ffff;
113		}
114	}
115
116	if (cksum == 0)
117		cksum = 0x0000ffff;
118	return ((u_short)cksum);
119}
120
121int
122ddp_route(struct mbuf *m, struct route *ro)
123{
124	struct sockaddr_at	gate;
125	struct elaphdr	*elh;
126	struct mbuf		*m0;
127	struct at_ifaddr	*aa = NULL;
128	struct ifnet	*ifp = NULL;
129	u_short		net;
130
131#if 0
132	/* Check for net zero, node zero ("myself") */
133	if (satosat(&ro->ro_dst)->sat_addr.s_net == ATADDR_ANYNET
134	    && satosat(&ro->ro_dst)->sat_addr.s_node == ATADDR_ANYNODE) {
135		/* Find the loopback interface */
136	}
137#endif
138
139	/*
140	 * If we have a route, find the ifa that refers to this route.  I.e
141	 * the ifa used to get to the gateway.
142	 */
143	if ((ro->ro_rt == NULL) || (ro->ro_rt->rt_ifa == NULL) ||
144	    ((ifp = ro->ro_rt->rt_ifa->ifa_ifp) == NULL))
145		rtalloc(ro);
146	if ((ro->ro_rt != NULL) && (ro->ro_rt->rt_ifa) &&
147	    (ifp = ro->ro_rt->rt_ifa->ifa_ifp)) {
148		net = ntohs(satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net);
149		for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
150			if (((net == 0) || (aa->aa_ifp == ifp)) &&
151			    net >= ntohs(aa->aa_firstnet) &&
152			    net <= ntohs(aa->aa_lastnet))
153				break;
154		}
155	} else {
156		m_freem(m);
157#ifdef NETATALK_DEBUG
158		if (ro->ro_rt == NULL)
159			printf ("ddp_route: no ro_rt.\n");
160		else if (ro->ro_rt->rt_ifa == NULL)
161			printf ("ddp_route: no ro_rt->rt_ifa\n");
162		else
163			printf ("ddp_route: no ro_rt->rt_ifa->ifa_ifp\n");
164#endif
165		return (ENETUNREACH);
166	}
167
168	if (aa == NULL) {
169#ifdef NETATALK_DEBUG
170		printf("ddp_route: no atalk address found for %s\n",
171		    ifp->if_xname);
172#endif
173		m_freem(m);
174		return (ENETUNREACH);
175	}
176
177	/*
178	 * If the destination address is on a directly attached node use
179	 * that, else use the official gateway.
180	 */
181	if (ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) >=
182	    ntohs(aa->aa_firstnet) &&
183	    ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) <=
184	    ntohs(aa->aa_lastnet))
185		gate = *satosat(&ro->ro_dst);
186	else
187		gate = *satosat(ro->ro_rt->rt_gateway);
188
189	/*
190	 * There are several places in the kernel where data is added to an
191	 * mbuf without ensuring that the mbuf pointer is aligned.  This is
192	 * bad for transition routing, since phase 1 and phase 2 packets end
193	 * up poorly aligned due to the three byte elap header.
194	 */
195	if (!(aa->aa_flags & AFA_PHASE2)) {
196		MGET(m0, M_DONTWAIT, MT_DATA);
197		if (m0 == NULL) {
198			m_freem(m);
199			printf("ddp_route: no buffers\n");
200			return (ENOBUFS);
201		}
202#ifdef MAC
203		mac_copy_mbuf(m, m0);
204#endif
205		m0->m_next = m;
206		/* XXX perhaps we ought to align the header? */
207		m0->m_len = SZ_ELAPHDR;
208		m = m0;
209
210		elh = mtod(m, struct elaphdr *);
211		elh->el_snode = satosat(&aa->aa_addr)->sat_addr.s_node;
212		elh->el_type = ELAP_DDPEXTEND;
213		elh->el_dnode = gate.sat_addr.s_node;
214	}
215	ro->ro_rt->rt_use++;
216
217#ifdef NETATALK_DEBUG
218	printf ("ddp_route: from %d.%d to %d.%d, via %d.%d (%s)\n",
219	    ntohs(satosat(&aa->aa_addr)->sat_addr.s_net),
220	    satosat(&aa->aa_addr)->sat_addr.s_node,
221	    ntohs(satosat(&ro->ro_dst)->sat_addr.s_net),
222	    satosat(&ro->ro_dst)->sat_addr.s_node,
223	    ntohs(gate.sat_addr.s_net), gate.sat_addr.s_node, ifp->if_xname);
224#endif
225
226	/* Short-circuit the output if we're sending this to ourself. */
227	if ((satosat(&aa->aa_addr)->sat_addr.s_net ==
228	    satosat(&ro->ro_dst)->sat_addr.s_net) &&
229	    (satosat(&aa->aa_addr)->sat_addr.s_node ==
230	    satosat(&ro->ro_dst)->sat_addr.s_node))
231		return (if_simloop(ifp, m, gate.sat_family, 0));
232
233	/* XXX */
234	return ((*ifp->if_output)(ifp, m, (struct sockaddr *)&gate, NULL));
235}
236