Network API now allows for multiple network devices (although the
[people/oremanj/gpxe.git] / src / net / netdevice.c
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <stdint.h>
20 #include <byteswap.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <gpxe/if_ether.h>
24 #include <gpxe/pkbuff.h>
25 #include <gpxe/tables.h>
26 #include <gpxe/netdevice.h>
27
28 /** @file
29  *
30  * Network device management
31  *
32  */
33
34 /**
35  * Static single instance of a network device
36  *
37  * The gPXE API is designed to accommodate multiple network devices.
38  * However, in the interests of code size, the implementation behind
39  * the API supports only a single instance of a network device.
40  *
41  * No code outside of netdevice.c should ever refer directly to @c
42  * static_single_netdev.
43  *
44  * Callers should always check the return status of alloc_netdev(),
45  * register_netdev() etc.  In the current implementation this code
46  * will be optimised out by the compiler, so there is no penalty.
47  */
48 struct net_device static_single_netdev;
49
50 /** Registered network-layer protocols */
51 static struct net_protocol net_protocols[0] __table_start ( net_protocols );
52 static struct net_protocol net_protocols_end[0] __table_end ( net_protocols );
53
54 /** Network-layer addresses for @c static_single_netdev */
55 static struct net_address static_single_netdev_addresses[0]
56         __table_start ( sgl_netdev_addresses );
57 static struct net_address static_single_netdev_addresses_end[0]
58         __table_end ( sgl_netdev_addresses );
59
60 /** Recevied packet queue */
61 static LIST_HEAD ( rx_queue );
62
63 /**
64  * Identify network protocol
65  *
66  * @v net_proto         Network-layer protocol, in network-byte order
67  * @ret net_protocol    Network-layer protocol, or NULL
68  *
69  * Identify a network-layer protocol from a protocol number, which
70  * must be an ETH_P_XXX constant in network-byte order.
71  */
72 struct net_protocol * net_find_protocol ( uint16_t net_proto ) {
73         struct net_protocol *net_protocol;
74
75         for ( net_protocol = net_protocols ; net_protocol < net_protocols_end ;
76               net_protocol++ ) {
77                 if ( net_protocol->net_proto == net_proto )
78                         return net_protocol;
79         }
80         return NULL;
81 }
82
83 /**
84  * Identify network device by network-layer address
85  *
86  * @v net_protocol      Network-layer protocol
87  * @v net_addr          Network-layer address
88  * @ret netdev          Network device, or NULL
89  *
90  * Searches through all network devices to find the device with the
91  * specified network-layer address.
92  *
93  * Note that even with a static single network device, this function
94  * can still return NULL.
95  */
96 struct net_device * net_find_address ( struct net_protocol *net_protocol,
97                                        void *net_addr ) {
98         struct net_address *net_address;
99         struct net_device *netdev = &static_single_netdev;
100         
101         for ( net_address = static_single_netdev_addresses ;
102               net_address < static_single_netdev_addresses_end ;
103               net_address ++ ) {
104                 if ( ( net_address->net_protocol == net_protocol ) &&
105                      ( memcmp ( net_address->net_addr, net_addr,
106                                 net_protocol->net_addr_len ) == 0 ) )
107                         return netdev;
108         }
109         return NULL;
110 }
111
112 /**
113  * Transmit packet
114  *
115  * @v pkb               Packet buffer
116  * @ret rc              Return status code
117  *
118  * Transmits the packet via the appropriate network device.  If this
119  * function returns success, it has taken ownership of the packet
120  * buffer.
121  */
122 int net_transmit ( struct pk_buff *pkb ) {
123         struct net_protocol *net_protocol;
124         struct net_header nethdr;
125         struct ll_protocol *ll_protocol;
126         struct ll_header llhdr;
127         struct net_device *netdev;
128         int rc;
129
130         /* Perform network-layer routing */
131         net_protocol = pkb->net_protocol;
132         nethdr.net_protocol = net_protocol;
133         if ( ( rc = net_protocol->route ( pkb, &nethdr ) ) != 0 )
134                 goto err;
135
136         /* Identify transmitting network device */
137         netdev = net_find_address ( net_protocol, nethdr.source_net_addr );
138         if ( ! netdev )
139                 goto err;
140
141         /* Perform link-layer routing */
142         ll_protocol = netdev->ll_protocol;
143         llhdr.ll_protocol = ll_protocol;
144         llhdr.net_proto = net_protocol->net_proto;
145         memcpy ( llhdr.source_ll_addr, netdev->ll_addr,
146                  ll_protocol->ll_addr_len);
147         if ( ( rc = ll_protocol->route ( &nethdr, &llhdr ) ) != 0 )
148                 goto err;
149
150         /* Prepend link-layer header */
151         pkb_push ( pkb, ll_protocol->ll_header_len );
152         ll_protocol->fill_llh ( &llhdr, pkb );
153
154         /* Transmit packet */
155         if ( ( rc = netdev->transmit ( netdev, pkb ) ) != 0 )
156                 goto err;
157
158         return 0;
159
160  err:
161         free_pkb ( pkb );
162         return rc;
163 }
164
165 /**
166  * Poll for packet on all network devices
167  *
168  * @ret True            There are packets present in the receive queue
169  * @ret False           There are no packets present in the receive queue
170  *
171  * Polls all network devices for received packets.  Any received
172  * packets will be added to the RX packet queue via netdev_rx().
173  */
174 int net_poll ( void ) {
175         struct net_device *netdev = &static_single_netdev;
176
177         netdev->poll ( netdev );
178
179         return ( ! list_empty ( &rx_queue ) );
180 }
181
182 /**
183  * Add packet to receive queue
184  *
185  * @v netdev            Network device
186  * @v pkb               Packet buffer
187  *
188  * The packet is added to the RX queue.  Ownership of the packet is
189  * transferred to the RX queue; the caller must not touch the packet
190  * buffer after calling netdev_rx().
191  */
192 void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ) {
193         pkb->ll_protocol = netdev->ll_protocol;
194         list_add_tail ( &pkb->list, &rx_queue );
195 }
196
197 /**
198  * Remove packet from receive queue
199  *
200  * @ret pkb             Packet buffer, or NULL
201  *
202  * Removes the first packet from the RX queue and returns it.
203  * Ownership of the packet is transferred to the caller.
204  */
205 struct pk_buff * net_rx_dequeue ( void ) {
206         struct pk_buff *pkb;
207
208         list_for_each_entry ( pkb, &rx_queue, list ) {
209                 list_del ( &pkb->list );
210                 return pkb;
211         }
212         return NULL;
213 }
214
215 void net_run ( void ) {
216         struct pk_buff *pkb;
217         struct ll_protocol *ll_protocol;
218         struct ll_header llhdr;
219         struct net_protocol *net_protocol;
220
221         while ( ( pkb = net_rx_dequeue () ) ) {
222
223                 /* Parse link-layer header */
224                 ll_protocol = pkb->ll_protocol;
225                 ll_protocol->parse_llh ( pkb, &llhdr );
226
227                 /* Identify network-layer protocol */
228                 net_protocol = net_find_protocol ( llhdr.net_proto );
229                 if ( ! net_protocol ) {
230                         DBG ( "Unknown network-layer protocol %02x\n",
231                               ntohs ( llhdr.net_proto ) );
232                         free_pkb ( pkb );
233                         continue;
234                 }
235
236                 /* Strip off link-layer header */
237                 pkb_pull ( pkb, ll_protocol->ll_header_len );
238
239                 /* Hand off to network layer */
240                 if ( net_protocol->rx ( pkb ) != 0 ) {
241                         free_pkb ( pkb );
242                         continue;
243                 }
244         }
245 }
246
247
248