1 /* PPPoE support library "libpppoe"
3 * Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
4 * Jamal Hadi Salim <hadi@cyberus.ca>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
14 static int relay_init_disc(struct session
* ses
,
15 struct pppoe_packet
*p_in
,
16 struct pppoe_packet
**p_out
){
19 ses
->retransmits
= -1 ;
27 static int relay_rcv_padi(struct session
* ses
,
28 struct pppoe_packet
*p_in
,
29 struct pppoe_packet
**p_out
){
31 struct pppoe_con
*newpc
= NULL
;
32 struct pppoe_tag
*tag
= (struct pppoe_tag
*) tag_buf
;
35 tag
->tag_type
= PTT_RELAY_SID
;
36 tag
->tag_len
= htons(ETH_ALEN
+ sizeof(struct session
*));
38 memcpy(tag
->tag_data
, p_in
->addr
.sll_addr
, ETH_ALEN
);
39 memcpy(tag
->tag_data
+ ETH_ALEN
, &ses
, sizeof(struct session
*));
41 if(! p_in
->tags
[TAG_RELAY_SID
] ){
46 poe_dbglog(ses
, "Recv'd PADI: %P",p_in
);
47 poe_dbglog(ses
, "Recv'd packet: %P",p_in
);
48 newpc
= get_con( ntohs(tag
->tag_len
), tag
->tag_data
);
51 newpc
= (struct pppoe_con
*) malloc(sizeof(struct pppoe_con
));
52 memset(newpc
, 0, sizeof(struct pppoe_con
));
56 newpc
->key_len
= ntohs(p_in
->tags
[TAG_RELAY_SID
]->tag_len
);
57 memcpy(newpc
->key
, p_in
->tags
[TAG_RELAY_SID
]->tag_data
, newpc
->key_len
);
58 memcpy(newpc
->client
, p_in
->addr
.sll_addr
, ETH_ALEN
);
60 memcpy(newpc
->server
, MAC_BCAST_ADDR
, ETH_ALEN
);
68 memset(p_in
->addr
.sll_addr
, 0xff, ETH_ALEN
);
70 p_in
->addr
.sll_ifindex
= ses
->remote
.sll_ifindex
;
76 static int relay_rcv_pkt(struct session
* ses
,
77 struct pppoe_packet
*p_in
,
78 struct pppoe_packet
**p_out
){
81 struct pppoe_tag
*tag
= p_in
->tags
[TAG_RELAY_SID
];
85 pc
= get_con(ntohs(tag
->tag_len
),tag
->tag_data
);
89 poe_dbglog(ses
, "Recv'd packet: %P",p_in
);
91 if( memcmp(pc
->client
, p_in
->addr
.sll_addr
, ETH_ALEN
) == 0 ){
93 memcpy(p_in
->addr
.sll_addr
, pc
->server
, ETH_ALEN
);
94 p_in
->addr
.sll_ifindex
= ses
->remote
.sll_ifindex
;
97 if( memcmp(pc
->server
, MAC_BCAST_ADDR
, ETH_ALEN
) == 0 ){
98 memcpy(pc
->server
, p_in
->addr
.sll_addr
, ETH_ALEN
);
100 }else if( memcmp(pc
->server
, p_in
->addr
.sll_addr
, ETH_ALEN
) !=0){
104 memcpy(p_in
->addr
.sll_addr
, pc
->client
, ETH_ALEN
);
105 p_in
->addr
.sll_ifindex
= ses
->local
.sll_ifindex
;
111 send_disc(ses
, p_in
);
115 static int relay_rcv_pads(struct session
* ses
,
116 struct pppoe_packet
*p_in
,
117 struct pppoe_packet
**p_out
){
119 struct pppoe_con
*pc
;
121 struct pppoe_tag
*tag
= p_in
->tags
[TAG_RELAY_SID
];
122 struct sockaddr_pppox sp_cl
= { AF_PPPOX
, PX_PROTO_OE
,
123 { p_in
->hdr
->sid
, {0,},{0,}}};
125 struct sockaddr_pppox sp_sv
= { AF_PPPOX
, PX_PROTO_OE
,
126 { p_in
->hdr
->sid
, {0,},{0,}}};
133 pc
= get_con(ntohs(tag
->tag_len
),tag
->tag_data
);
140 pc
->sv_sock
= socket( AF_PPPOX
, SOCK_DGRAM
, PX_PROTO_OE
);
141 if( pc
->sv_sock
< 0){
142 poe_fatal(ses
,"Cannot open PPPoE socket: %i",errno
);
145 pc
->cl_sock
= socket( AF_PPPOX
, SOCK_DGRAM
, PX_PROTO_OE
);
146 if( pc
->cl_sock
< 0){
147 poe_fatal(ses
,"Cannot open PPPoE socket: %i",errno
);
150 memcpy( sp_sv
.sa_addr
.pppoe
.dev
, ses
->fwd_name
, IFNAMSIZ
);
151 memcpy( sp_sv
.sa_addr
.pppoe
.remote
, pc
->server
, ETH_ALEN
);
153 ret
= connect( pc
->sv_sock
,
154 (struct sockaddr
*)&sp_sv
,
155 sizeof(struct sockaddr_pppox
));
157 poe_fatal(ses
,"Cannot connect PPPoE socket: %i",errno
);
160 memcpy( sp_cl
.sa_addr
.pppoe
.dev
, ses
->name
, IFNAMSIZ
);
161 memcpy( sp_cl
.sa_addr
.pppoe
.remote
, pc
->client
, ETH_ALEN
);
163 ret
= connect( pc
->cl_sock
,
164 (struct sockaddr
*)&sp_cl
,
165 sizeof(struct sockaddr_pppox
));
167 poe_fatal(ses
,"Cannot connect PPPoE socket: %i",errno
);
171 ret
= ioctl( pc
->sv_sock
, PPPOEIOCSFWD
, &sp_cl
);
173 poe_fatal(ses
,"Cannot set forwarding on PPPoE socket: %i",errno
);
176 ret
= ioctl( pc
->cl_sock
, PPPOEIOCSFWD
, &sp_sv
);
178 poe_fatal(ses
,"Cannot set forwarding on PPPoE socket: %i",errno
);
184 poe_info(ses
,"PPPoE relay for %E established to %E (sid=%04x)\n",
185 pc
->client
,pc
->server
, p_in
->hdr
->sid
);
187 return relay_rcv_pkt(ses
,p_in
,p_out
);
191 static int relay_rcv_padt(struct session
* ses
,
192 struct pppoe_packet
*p_in
,
193 struct pppoe_packet
**p_out
){
196 struct pppoe_con
*pc
;
198 struct pppoe_tag
*tag
= p_in
->tags
[TAG_RELAY_SID
];
202 pc
= get_con(ntohs(tag
->tag_len
),tag
->tag_data
);
206 ret
= relay_rcv_pkt(ses
,p_in
,p_out
);
218 if( pc
->ref_count
== 0 ){
219 delete_con(pc
->key_len
, pc
->key
);
226 int relay_init_ses(struct session
*ses
, char* from
, char* to
)
228 int retval
= client_init_ses(ses
, from
);
230 if(retval
<0) return retval
;
232 ses
->fwd_sock
= socket(PF_PACKET
, SOCK_DGRAM
, 0);
233 if( ses
->fwd_sock
< 0 ) {
234 poe_fatal(ses
,"Cannot create PF_PACKET socket for PPPoE forwarding\n");
237 /* Verify the device name , construct ses->local */
238 retval
= get_sockaddr_ll(to
, &ses
->remote
);
240 poe_fatal(ses
,"relay_init_ses:get_sockaddr_ll failed %m");
242 retval
= bind( ses
->fwd_sock
,
243 (struct sockaddr
*)&ses
->remote
,
244 sizeof(struct sockaddr_ll
));
247 poe_fatal(ses
,"bind to PF_PACKET socket failed: %m");
250 memcpy(ses
->fwd_name
, to
, IFNAMSIZ
);
251 memcpy(ses
->name
, from
, IFNAMSIZ
);
254 ses
->init_disc
= relay_init_disc
;
255 ses
->rcv_padi
= relay_rcv_padi
;
256 ses
->rcv_pado
= relay_rcv_pkt
;
257 ses
->rcv_padr
= relay_rcv_pkt
;
258 ses
->rcv_pads
= relay_rcv_pads
;
259 ses
->rcv_padt
= relay_rcv_padt
;