ddp_output.c revision 165974
1139827Simp/*-
2165974Srwatson * Copyright (c) 1990, 1991 Regents of The University of Michigan.
315885Sjulian * All Rights Reserved.
415885Sjulian *
515885Sjulian * Permission to use, copy, modify, and distribute this software and
615885Sjulian * its documentation for any purpose and without fee is hereby granted,
715885Sjulian * provided that the above copyright notice appears in all copies and
815885Sjulian * that both that copyright notice and this permission notice appear
915885Sjulian * in supporting documentation, and that the name of The University
1015885Sjulian * of Michigan not be used in advertising or publicity pertaining to
1115885Sjulian * distribution of the software without specific, written prior
1215885Sjulian * permission. This software is supplied as is without expressed or
1315885Sjulian * implied warranties of any kind.
1415885Sjulian *
1515885Sjulian *	Research Systems Unix Group
1615885Sjulian *	The University of Michigan
1715885Sjulian *	c/o Mike Clark
1815885Sjulian *	535 W. William Street
1915885Sjulian *	Ann Arbor, Michigan
2015885Sjulian *	+1-313-763-0525
2115885Sjulian *	netatalk@itd.umich.edu
2215885Sjulian */
2315885Sjulian
2460889Sarchie/* $FreeBSD: head/sys/netatalk/ddp_output.c 165974 2007-01-12 15:07:51Z rwatson $ */
2560889Sarchie
26101937Srwatson#include "opt_mac.h"
27101937Srwatson
2815885Sjulian#include <sys/param.h>
2915885Sjulian#include <sys/systm.h>
3015885Sjulian#include <sys/mbuf.h>
3115885Sjulian#include <sys/socket.h>
3223396Sjulian#include <sys/socketvar.h>
3315885Sjulian
3415885Sjulian#include <net/if.h>
3515885Sjulian#include <net/route.h>
3615885Sjulian
3715885Sjulian#undef s_net
3815885Sjulian
3918207Sbde#include <netatalk/at.h>
4018207Sbde#include <netatalk/at_var.h>
4118207Sbde#include <netatalk/ddp.h>
4218207Sbde#include <netatalk/ddp_var.h>
4315885Sjulian#include <netatalk/at_extern.h>
4415885Sjulian
45163606Srwatson#include <security/mac/mac_framework.h>
46163606Srwatson
4715885Sjulianint	ddp_cksum = 1;
4815885Sjulian
4915885Sjulianint
50127288Srwatsonddp_output(struct mbuf *m, struct socket *so)
5115885Sjulian{
52165974Srwatson	struct ddpehdr	*deh;
53165974Srwatson	struct ddpcb *ddp = sotoddpcb(so);
5415885Sjulian
55101937Srwatson#ifdef MAC
56165974Srwatson	SOCK_LOCK(so);
57165974Srwatson	mac_create_mbuf_from_socket(so, m);
58165974Srwatson	SOCK_UNLOCK(so);
59101937Srwatson#endif
60101937Srwatson
61165974Srwatson	M_PREPEND(m, sizeof(struct ddpehdr), M_DONTWAIT);
62165974Srwatson	if (m == NULL)
63127288Srwatson	return (ENOBUFS);
6415885Sjulian
65165974Srwatson	deh = mtod(m, struct ddpehdr *);
66165974Srwatson	deh->deh_pad = 0;
67165974Srwatson	deh->deh_hops = 0;
6815885Sjulian
69165974Srwatson	deh->deh_len = m->m_pkthdr.len;
7015885Sjulian
71165974Srwatson	deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net;
72165974Srwatson	deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node;
73165974Srwatson	deh->deh_dport = ddp->ddp_fsat.sat_port;
74165974Srwatson	deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net;
75165974Srwatson	deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node;
76165974Srwatson	deh->deh_sport = ddp->ddp_lsat.sat_port;
7715885Sjulian
78165974Srwatson	/*
79165974Srwatson	 * The checksum calculation is done after all of the other bytes have
80165974Srwatson	 * been filled in.
81165974Srwatson	 */
82165974Srwatson	if (ddp_cksum)
83165974Srwatson		deh->deh_sum = at_cksum(m, sizeof(int));
84165974Srwatson	else
85165974Srwatson		deh->deh_sum = 0;
86165974Srwatson	deh->deh_bytes = htonl(deh->deh_bytes);
8715885Sjulian
8838114Sjulian#ifdef NETATALK_DEBUG
89165974Srwatson	printf ("ddp_output: from %d.%d:%d to %d.%d:%d\n",
9038114Sjulian	ntohs(deh->deh_snet), deh->deh_snode, deh->deh_sport,
9138114Sjulian	ntohs(deh->deh_dnet), deh->deh_dnode, deh->deh_dport);
9238114Sjulian#endif
93165974Srwatson	return (ddp_route(m, &ddp->ddp_route));
9415885Sjulian}
9515885Sjulian
9615885Sjulianu_short
97127288Srwatsonat_cksum(struct mbuf *m, int skip)
9815885Sjulian{
99165974Srwatson	u_char	*data, *end;
100165974Srwatson	u_long	cksum = 0;
10115885Sjulian
102165974Srwatson	for (; m; m = m->m_next) {
103165974Srwatson		for (data = mtod(m, u_char *), end = data + m->m_len;
104165974Srwatson		    data < end; data++) {
105165974Srwatson			if (skip) {
106165974Srwatson				skip--;
107165974Srwatson				continue;
108165974Srwatson			}
109165974Srwatson			cksum = (cksum + *data) << 1;
110165974Srwatson			if (cksum & 0x00010000)
111165974Srwatson				cksum++;
112165974Srwatson			cksum &= 0x0000ffff;
113165974Srwatson		}
11415885Sjulian	}
11515885Sjulian
116165974Srwatson	if (cksum == 0)
117165974Srwatson		cksum = 0x0000ffff;
118165974Srwatson	return ((u_short)cksum);
11915885Sjulian}
12015885Sjulian
12115885Sjulianint
122127288Srwatsonddp_route(struct mbuf *m, struct route *ro)
12315885Sjulian{
124165974Srwatson	struct sockaddr_at	gate;
125165974Srwatson	struct elaphdr	*elh;
126165974Srwatson	struct mbuf		*m0;
127165974Srwatson	struct at_ifaddr	*aa = NULL;
128165974Srwatson	struct ifnet	*ifp = NULL;
129165974Srwatson	u_short		net;
13015885Sjulian
13136908Sjulian#if 0
132165974Srwatson	/* Check for net zero, node zero ("myself") */
133165974Srwatson	if (satosat(&ro->ro_dst)->sat_addr.s_net == ATADDR_ANYNET
134165974Srwatson	    && satosat(&ro->ro_dst)->sat_addr.s_node == ATADDR_ANYNODE) {
135165974Srwatson		/* Find the loopback interface */
136165974Srwatson	}
13736908Sjulian#endif
13836908Sjulian
139165974Srwatson	/*
140165974Srwatson	 * If we have a route, find the ifa that refers to this route.  I.e
141165974Srwatson	 * the ifa used to get to the gateway.
142165974Srwatson	 */
143165974Srwatson	if ((ro->ro_rt == NULL) || (ro->ro_rt->rt_ifa == NULL) ||
144165974Srwatson	    ((ifp = ro->ro_rt->rt_ifa->ifa_ifp) == NULL))
145165974Srwatson		rtalloc(ro);
146165974Srwatson	if ((ro->ro_rt != NULL) && (ro->ro_rt->rt_ifa) &&
147165974Srwatson	    (ifp = ro->ro_rt->rt_ifa->ifa_ifp)) {
148165974Srwatson		net = ntohs(satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net);
149165974Srwatson		for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
150165974Srwatson			if (((net == 0) || (aa->aa_ifp == ifp)) &&
151165974Srwatson			    net >= ntohs(aa->aa_firstnet) &&
152165974Srwatson			    net <= ntohs(aa->aa_lastnet))
153165974Srwatson				break;
154165974Srwatson		}
155165974Srwatson	} else {
156165974Srwatson		m_freem(m);
15738114Sjulian#ifdef NETATALK_DEBUG
158165974Srwatson		if (ro->ro_rt == NULL)
159165974Srwatson			printf ("ddp_route: no ro_rt.\n");
160165974Srwatson		else if (ro->ro_rt->rt_ifa == NULL)
161165974Srwatson			printf ("ddp_route: no ro_rt->rt_ifa\n");
162165974Srwatson		else
163165974Srwatson			printf ("ddp_route: no ro_rt->rt_ifa->ifa_ifp\n");
16438114Sjulian#endif
165165974Srwatson		return (ENETUNREACH);
166165974Srwatson	}
16728845Sjulian
168165974Srwatson	if (aa == NULL) {
16938114Sjulian#ifdef NETATALK_DEBUG
170165974Srwatson		printf("ddp_route: no atalk address found for %s\n",
171165974Srwatson		    ifp->if_xname);
17238114Sjulian#endif
173165974Srwatson		m_freem(m);
174165974Srwatson		return (ENETUNREACH);
175165974Srwatson	}
17615885Sjulian
177165974Srwatson	/*
178165974Srwatson	 * If the destination address is on a directly attached node use
179165974Srwatson	 * that, else use the official gateway.
180165974Srwatson	 */
181165974Srwatson	if (ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) >=
182127288Srwatson	    ntohs(aa->aa_firstnet) &&
183127288Srwatson	    ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) <=
184165974Srwatson	    ntohs(aa->aa_lastnet))
185165974Srwatson		gate = *satosat(&ro->ro_dst);
186165974Srwatson	else
187165974Srwatson		gate = *satosat(ro->ro_rt->rt_gateway);
18837521Sjulian
189165974Srwatson	/*
190165974Srwatson	 * There are several places in the kernel where data is added to an
191165974Srwatson	 * mbuf without ensuring that the mbuf pointer is aligned.  This is
192165974Srwatson	 * bad for transition routing, since phase 1 and phase 2 packets end
193165974Srwatson	 * up poorly aligned due to the three byte elap header.
194165974Srwatson	 */
195165974Srwatson	if (!(aa->aa_flags & AFA_PHASE2)) {
196165974Srwatson		MGET(m0, M_DONTWAIT, MT_DATA);
197165974Srwatson		if (m0 == NULL) {
198165974Srwatson			m_freem(m);
199165974Srwatson			printf("ddp_route: no buffers\n");
200165974Srwatson			return (ENOBUFS);
201165974Srwatson		}
202101937Srwatson#ifdef MAC
203165974Srwatson		mac_copy_mbuf(m, m0);
204101937Srwatson#endif
205165974Srwatson		m0->m_next = m;
206165974Srwatson		/* XXX perhaps we ought to align the header? */
207165974Srwatson		m0->m_len = SZ_ELAPHDR;
208165974Srwatson		m = m0;
20915885Sjulian
210165974Srwatson		elh = mtod(m, struct elaphdr *);
211165974Srwatson		elh->el_snode = satosat(&aa->aa_addr)->sat_addr.s_node;
212165974Srwatson		elh->el_type = ELAP_DDPEXTEND;
213165974Srwatson		elh->el_dnode = gate.sat_addr.s_node;
214165974Srwatson	}
215165974Srwatson	ro->ro_rt->rt_use++;
21615885Sjulian
21738114Sjulian#ifdef NETATALK_DEBUG
218165974Srwatson	printf ("ddp_route: from %d.%d to %d.%d, via %d.%d (%s)\n",
219165974Srwatson	    ntohs(satosat(&aa->aa_addr)->sat_addr.s_net),
220165974Srwatson	    satosat(&aa->aa_addr)->sat_addr.s_node,
221165974Srwatson	    ntohs(satosat(&ro->ro_dst)->sat_addr.s_net),
222165974Srwatson	    satosat(&ro->ro_dst)->sat_addr.s_node,
223165974Srwatson	    ntohs(gate.sat_addr.s_net), gate.sat_addr.s_node, ifp->if_xname);
22438114Sjulian#endif
22538114Sjulian
226165974Srwatson	/* Short-circuit the output if we're sending this to ourself. */
227165974Srwatson	if ((satosat(&aa->aa_addr)->sat_addr.s_net ==
228165974Srwatson	    satosat(&ro->ro_dst)->sat_addr.s_net) &&
229165974Srwatson	    (satosat(&aa->aa_addr)->sat_addr.s_node ==
230165974Srwatson	    satosat(&ro->ro_dst)->sat_addr.s_node))
231165974Srwatson		return (if_simloop(ifp, m, gate.sat_family, 0));
23238114Sjulian
233165974Srwatson	/* XXX */
234165974Srwatson	return ((*ifp->if_output)(ifp, m, (struct sockaddr *)&gate, NULL));
23515885Sjulian}
236